diff --git a/AUTHORS b/AUTHORS
index 71308df..1683cc4 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -994,6 +994,7 @@
 Yong Shin <sy3620@gmail.com>
 Yong Wang <ccyongwang@tencent.com>
 Yongha Lee <yongha78.lee@samsung.com>
+Yongseok Choi <yongseok.choi@navercorp.com>
 Yongsheng Zhu <yongsheng.zhu@intel.com>
 Yoonjae Cho <yoonjae.cho92@gmail.com>
 Yoshinori Sano <yoshinori.sano@gmail.com>
diff --git a/DEPS b/DEPS
index dc05ec7..4ebddee 100644
--- a/DEPS
+++ b/DEPS
@@ -145,7 +145,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': 'e5fee78d2626b8d90ff695740e1a07a9432cfa70',
+  'skia_revision': 'da4f12c25bf14ae12b10b9ed7d3ade6d8a2a76fd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -157,15 +157,15 @@
   # 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': '0a3c824625be9b21605bd4599774e3f6568dafb1',
+  'angle_revision': 'cdecd97ceefa28409793d04caf873e7b0d0d723c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '2bcadf49d82078a87c175279930ef5cb3466926d',
+  'swiftshader_revision': 'dadeb009a2977764ae927e5d942bee72ab5290ed',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'd3e3a40519842854cde1e6bce188245e9951011d',
+  'pdfium_revision': 'a7318ae4c6b0f81a742a9fdcda1c2c1fd01c9107',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -208,7 +208,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '2ae52adeeeddfebecc9f4b1a5236b8cbdb42589c',
+  'catapult_revision': '4eafd3bf8da0d61828310afff96c7b7044d1b178',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -280,7 +280,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': '5f8a8aadb96b5ac0302836de219943178f240c20',
+  'dawn_revision': 'ae2415c6f5136fee61beeb48820fd45877bc8c86',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -605,7 +605,7 @@
   },
 
   'src/third_party/android_ndk': {
-      'url': Var('chromium_git') + '/android_ndk.git' + '@' + '4e2cea441bfd43f0863d14f57b1e1844260b9884',
+      'url': Var('chromium_git') + '/android_ndk.git' + '@' + '62582753e869484bf0cc7f7e8d184ce0077033c2',
       'condition': 'checkout_android_native_support',
   },
 
@@ -814,7 +814,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '5d4d933383f0fbe2f4552fcc9b0e2292816e99b4',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '5f03b05008611f2c49049cd87f32411e37bb577f',
       'condition': 'checkout_linux',
   },
 
@@ -839,7 +839,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '26a8b9f35639bbbbe971e8d1364fb25ec4a1266b',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9f4b37db0e36216cdb09dadc07e200ca25c14ea6',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1421,7 +1421,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d105c06506d17dc76347a47a3d629b82f7c5ef34',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0072a1738d33909b49470fe85d3eb49d6988f7b1',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/apps/DEPS b/apps/DEPS
index ca1f2a1..2ba6a95 100644
--- a/apps/DEPS
+++ b/apps/DEPS
@@ -2,6 +2,7 @@
   "+content/public/browser",
   "+content/public/common",
   "+content/public/test",
+  "+components/services/app_service/public",
   "+components/keyed_service",
   "+components/user_manager",
   "+extensions",
diff --git a/apps/launcher.cc b/apps/launcher.cc
index 0b6d73b..e7bad88 100644
--- a/apps/launcher.cc
+++ b/apps/launcher.cc
@@ -18,6 +18,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
+#include "components/services/app_service/public/cpp/file_handler_info.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -251,7 +252,7 @@
       return;
 
     // Find file handler from the platform app for the file being opened.
-    const extensions::FileHandlerInfo* handler = NULL;
+    const FileHandlerInfo* handler = nullptr;
     if (!handler_id_.empty()) {
       handler = FileHandlerForId(*app, handler_id_);
       if (handler) {
@@ -260,7 +261,7 @@
             LOG(WARNING)
                 << "Extension does not provide a valid file handler for "
                 << entry_paths_[i].value();
-            handler = NULL;
+            handler = nullptr;
             break;
           }
         }
diff --git a/ash/app_list/app_list_presenter_delegate_impl.cc b/ash/app_list/app_list_presenter_delegate_impl.cc
index 7b136de..584f24b8 100644
--- a/ash/app_list/app_list_presenter_delegate_impl.cc
+++ b/ash/app_list/app_list_presenter_delegate_impl.cc
@@ -39,8 +39,7 @@
 namespace {
 
 // Whether the shelf is oriented on the side, not on the bottom.
-bool IsSideShelf(aura::Window* root_window) {
-  Shelf* shelf = Shelf::ForWindow(root_window);
+bool IsSideShelf(Shelf* shelf) {
   switch (shelf->alignment()) {
     case SHELF_ALIGNMENT_BOTTOM:
     case SHELF_ALIGNMENT_BOTTOM_LOCKED:
@@ -52,6 +51,23 @@
   return false;
 }
 
+// Whether the shelf background type indicates that shelf has rounded corners.
+bool IsShelfBackgroundTypeWithRoundedCorners(
+    ShelfBackgroundType background_type) {
+  switch (background_type) {
+    case SHELF_BACKGROUND_DEFAULT:
+    case SHELF_BACKGROUND_APP_LIST:
+    case SHELF_BACKGROUND_OVERVIEW:
+      return true;
+    case SHELF_BACKGROUND_MAXIMIZED:
+    case SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST:
+    case SHELF_BACKGROUND_OOBE:
+    case SHELF_BACKGROUND_LOGIN:
+    case SHELF_BACKGROUND_LOGIN_NONBLURRED_WALLPAPER:
+      return false;
+  }
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -59,7 +75,7 @@
 
 AppListPresenterDelegateImpl::AppListPresenterDelegateImpl(
     AppListControllerImpl* controller)
-    : controller_(controller), display_observer_(this) {
+    : controller_(controller), display_observer_(this), shelf_observer_(this) {
   display_observer_.Add(display::Screen::GetScreen());
 }
 
@@ -97,8 +113,16 @@
   Shell::GetPrimaryRootWindowController()
       ->GetShelfLayoutManager()
       ->UpdateAutoHideState();
-  view_->Show(IsSideShelf(view_->GetWidget()->GetNativeView()->GetRootWindow()),
-              IsTabletMode());
+
+  Shelf* shelf =
+      Shelf::ForWindow(view_->GetWidget()->GetNativeView()->GetRootWindow());
+  if (!shelf_observer_.IsObserving(shelf))
+    shelf_observer_.Add(shelf);
+
+  view_->set_shelf_has_rounded_corners(
+      IsShelfBackgroundTypeWithRoundedCorners(shelf->GetBackgroundType()));
+  view_->Show(IsSideShelf(shelf), IsTabletMode());
+
   Shell::Get()->AddPreTargetHandler(this);
   controller_->ViewShown(display_id);
 }
@@ -112,6 +136,8 @@
 }
 
 void AppListPresenterDelegateImpl::OnClosed() {
+  if (!is_visible_)
+    shelf_observer_.RemoveAll();
   controller_->ViewClosed();
 }
 
@@ -152,6 +178,13 @@
   SnapAppListBoundsToDisplayEdge();
 }
 
+void AppListPresenterDelegateImpl::OnBackgroundTypeChanged(
+    ShelfBackgroundType background_type,
+    AnimationChangeType change_type) {
+  view_->set_shelf_has_rounded_corners(
+      IsShelfBackgroundTypeWithRoundedCorners(background_type));
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // AppListPresenterDelegateImpl, private:
 
diff --git a/ash/app_list/app_list_presenter_delegate_impl.h b/ash/app_list/app_list_presenter_delegate_impl.h
index 77069c02a..93e4fd3 100644
--- a/ash/app_list/app_list_presenter_delegate_impl.h
+++ b/ash/app_list/app_list_presenter_delegate_impl.h
@@ -9,6 +9,7 @@
 
 #include "ash/app_list/presenter/app_list_presenter_delegate.h"
 #include "ash/ash_export.h"
+#include "ash/shelf/shelf_observer.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "ui/display/display_observer.h"
@@ -31,6 +32,7 @@
 namespace ash {
 
 class AppListControllerImpl;
+class Shelf;
 
 // Responsible for laying out the app list UI as well as updating the Shelf
 // launch icon as the state of the app list changes. Listens to shell events
@@ -39,7 +41,8 @@
 class ASH_EXPORT AppListPresenterDelegateImpl
     : public app_list::AppListPresenterDelegate,
       public ui::EventHandler,
-      public display::DisplayObserver {
+      public display::DisplayObserver,
+      public ShelfObserver {
  public:
   explicit AppListPresenterDelegateImpl(AppListControllerImpl* controller);
   ~AppListPresenterDelegateImpl() override;
@@ -61,6 +64,10 @@
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override;
 
+  // ShelfObserver:
+  void OnBackgroundTypeChanged(ShelfBackgroundType background_type,
+                               AnimationChangeType change_type) override;
+
  private:
   void ProcessLocatedEvent(ui::LocatedEvent* event);
 
@@ -88,6 +95,9 @@
   // An observer that notifies AppListView when the display has changed.
   ScopedObserver<display::Screen, display::DisplayObserver> display_observer_;
 
+  // An observer that notifies AppListView when the shelf state has changed.
+  ScopedObserver<Shelf, AppListPresenterDelegateImpl> shelf_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(AppListPresenterDelegateImpl);
 };
 
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc
index 4346d49..602a41d8 100644
--- a/ash/app_list/app_list_presenter_delegate_unittest.cc
+++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -780,6 +780,134 @@
             shelf_layout_manager->GetShelfBackgroundType());
 }
 
+// Tests that app list understands shelf rounded corners state while animating
+// out and in, and that it keeps getting notified of shelf state changes if
+// close animation is interrupted by another show request.
+TEST_F(AppListPresenterDelegateTest, AppListShownWhileClosing) {
+  auto window = CreateTestWindow();
+  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+  GetAppListTestHelper()->CheckVisibility(true);
+
+  ShelfLayoutManager* shelf_layout_manager =
+      Shelf::ForWindow(Shell::GetRootWindowForDisplayId(GetPrimaryDisplayId()))
+          ->shelf_layout_manager();
+
+  EXPECT_FALSE(GetAppListView()->shelf_has_rounded_corners());
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST,
+            shelf_layout_manager->GetShelfBackgroundType());
+
+  // Enable animation to account for delay between app list starting to close
+  // and reporting visibility change (which happens when close animation
+  // finishes).
+  ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+  app_list::AppListView::SetShortAnimationForTesting(false);
+
+  // Dismiss and immediately show the app list (before close animation is done).
+  GetAppListTestHelper()->Dismiss();
+
+  EXPECT_FALSE(GetAppListView()->shelf_has_rounded_corners());
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST,
+            shelf_layout_manager->GetShelfBackgroundType());
+
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+
+  // Finish app list animations.
+  ASSERT_TRUE(
+      GetAppListView()->GetWidget()->GetLayer()->GetAnimator()->is_animating());
+  GetAppListView()->GetWidget()->GetLayer()->GetAnimator()->StopAnimating();
+
+  EXPECT_FALSE(GetAppListView()->shelf_has_rounded_corners());
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST,
+            shelf_layout_manager->GetShelfBackgroundType());
+
+  // Verify that the app list still picks up shelf changes.
+  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
+  EXPECT_TRUE(GetAppListView()->shelf_has_rounded_corners());
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_APP_LIST,
+            shelf_layout_manager->GetShelfBackgroundType());
+}
+
+// Tests how shelf state is updated as app list state changes with a maximized
+// window open. It verifies that the app list knows that the maximized shelf had
+// no rounded corners.
+TEST_F(AppListPresenterDelegateTest, AppListWithMaximizedShelf) {
+  auto window = CreateTestWindow();
+  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+  GetAppListTestHelper()->CheckVisibility(true);
+
+  ShelfLayoutManager* shelf_layout_manager =
+      Shelf::ForWindow(Shell::GetRootWindowForDisplayId(GetPrimaryDisplayId()))
+          ->shelf_layout_manager();
+
+  EXPECT_FALSE(GetAppListView()->shelf_has_rounded_corners());
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST,
+            shelf_layout_manager->GetShelfBackgroundType());
+
+  // Enable animation to account for delay between app list starting to close
+  // and reporting visibility change (which happens when close animation
+  // finishes).
+  ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+  app_list::AppListView::SetShortAnimationForTesting(false);
+
+  // Start closing the app list view.
+  GetAppListTestHelper()->Dismiss();
+
+  EXPECT_FALSE(GetAppListView()->shelf_has_rounded_corners());
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST,
+            shelf_layout_manager->GetShelfBackgroundType());
+
+  // Minimize the window, and verify that the shelf state changed from a
+  // maximized state, and that |shelf_has_rounded_corners()| value was updated.
+  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
+
+  EXPECT_TRUE(GetAppListView()->shelf_has_rounded_corners());
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_APP_LIST,
+            shelf_layout_manager->GetShelfBackgroundType());
+
+  // Stop app list hide animation.
+  ASSERT_TRUE(
+      GetAppListView()->GetWidget()->GetLayer()->GetAnimator()->is_animating());
+  GetAppListView()->GetWidget()->GetLayer()->GetAnimator()->StopAnimating();
+
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT,
+            shelf_layout_manager->GetShelfBackgroundType());
+}
+
+// Verifies the shelf background state changes when a window is maximized while
+// app list is shown. Verifies that AppList::shelf_has_rounded_corners() is
+// updated.
+TEST_F(AppListPresenterDelegateTest, WindowMaximizedWithAppListShown) {
+  auto window = CreateTestWindow();
+
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+  GetAppListTestHelper()->CheckVisibility(true);
+
+  ShelfLayoutManager* shelf_layout_manager =
+      Shelf::ForWindow(Shell::GetRootWindowForDisplayId(GetPrimaryDisplayId()))
+          ->shelf_layout_manager();
+
+  EXPECT_TRUE(GetAppListView()->shelf_has_rounded_corners());
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_APP_LIST,
+            shelf_layout_manager->GetShelfBackgroundType());
+
+  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+
+  EXPECT_FALSE(GetAppListView()->shelf_has_rounded_corners());
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST,
+            shelf_layout_manager->GetShelfBackgroundType());
+
+  GetAppListTestHelper()->Dismiss();
+
+  EXPECT_EQ(ShelfBackgroundType::SHELF_BACKGROUND_MAXIMIZED,
+            shelf_layout_manager->GetShelfBackgroundType());
+}
+
 // Tests that the bottom shelf is auto hidden when a window is fullscreened in
 // tablet mode (home launcher is shown behind).
 TEST_F(AppListPresenterDelegateTest, ShelfAutoHiddenWhenFullscreen) {
@@ -1394,6 +1522,169 @@
   GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
 }
 
+// Tests that the app list background corner radius remains constant during app
+// list drag if the shelf is not in maximized state.
+TEST_F(AppListPresenterDelegateTest, BackgroundCornerRadiusDuringDrag) {
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+  GetAppListTestHelper()->CheckState(AppListViewState::kPeeking);
+
+  const gfx::Point shelf_top = GetPrimaryShelf()
+                                   ->GetShelfViewForTesting()
+                                   ->GetBoundsInScreen()
+                                   .top_center();
+  const int background_radius =
+      app_list::AppListConfig::instance().background_radius();
+
+  app_list::AppListView* view = GetAppListView();
+  const views::View* const background_shield =
+      view->GetAppListBackgroundShieldForTest();
+  ui::test::EventGenerator* generator = GetEventGenerator();
+
+  // Start drag at the peeking height, and move to different
+  // positions relative to the shelf top.
+  // Verify that the app list background shield never changes.
+  const gfx::Point peeking_top = view->GetBoundsInScreen().top_center();
+  generator->MoveTouch(peeking_top);
+  generator->PressTouch();
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move above the shelf, with an offset less than the background radius.
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius / 5));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move to the top of the shelf.
+  generator->MoveTouch(shelf_top);
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move to half rounded background radius height.
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius / 2));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move to the height just under the background radius.
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius - 1));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move to the height that equals the background radius.
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move to the height just over the background radius.
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius + 1));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius + 5));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move above the peeking height.
+  generator->MoveTouch(gfx::Point(peeking_top.x(), peeking_top.y() + 5));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move back to peeking height, and end drag.
+  generator->MoveTouch(peeking_top);
+  generator->ReleaseTouch();
+  GetAppListTestHelper()->WaitUntilIdle();
+  GetAppListTestHelper()->CheckState(AppListViewState::kPeeking);
+
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+}
+
+// Tests how app list background rounded corners are changed during a drag while
+// the shelf is in a maximized state (i.e. while a maximized window is shown).
+TEST_F(AppListPresenterDelegateTest,
+       BackgroundCornerRadiusDuringDragWithMaximizedShelf) {
+  auto window = CreateTestWindow();
+  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+  GetAppListTestHelper()->CheckState(AppListViewState::kPeeking);
+
+  const gfx::Point shelf_top = GetPrimaryShelf()
+                                   ->GetShelfViewForTesting()
+                                   ->GetBoundsInScreen()
+                                   .top_center();
+  const int background_radius =
+      app_list::AppListConfig::instance().background_radius();
+
+  app_list::AppListView* view = GetAppListView();
+  const views::View* const background_shield =
+      view->GetAppListBackgroundShieldForTest();
+  ui::test::EventGenerator* generator = GetEventGenerator();
+
+  // Start drag at the peeking app list top.
+  const gfx::Point peeking_top = view->GetBoundsInScreen().top_center();
+  generator->MoveTouch(peeking_top);
+  generator->PressTouch();
+
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move above the shelf, with an offset less than the background radius.
+  // Verify that current background corner radius matches the offset from the
+  // shelf.
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius / 5));
+  EXPECT_EQ(
+      gfx::RoundedCornersF(background_radius / 5, background_radius / 5, 0, 0),
+      background_shield->layer()->rounded_corner_radii());
+
+  // Move to the shelf top - background should have no rounded corners.
+  generator->MoveTouch(shelf_top);
+  EXPECT_EQ(gfx::RoundedCornersF(),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move to half background radius height - the background corner radius should
+  // match the offset from the shelf.
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius / 2));
+  EXPECT_EQ(
+      gfx::RoundedCornersF(background_radius / 2, background_radius / 2, 0, 0),
+      background_shield->layer()->rounded_corner_radii());
+
+  // Move to the height just under the background radius - the current
+  // background corners should be equal to the offset from the shelf.
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius - 1));
+  EXPECT_EQ(
+      gfx::RoundedCornersF(background_radius - 1, background_radius - 1, 0, 0),
+      background_shield->layer()->rounded_corner_radii());
+
+  // Move to the height that equals the background radius - the current
+  // background corners should be equal to the offset from the shelf.
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move to the height just over the background radius - the background corner
+  // radius value should stay at the |background_radius| value.
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius + 1));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+  generator->MoveTouch(shelf_top - gfx::Vector2d(0, background_radius + 5));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move above the peeking height - the background radius should remain the
+  // same.
+  generator->MoveTouch(gfx::Point(peeking_top.x(), peeking_top.y() + 5));
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+
+  // Move back to peeking height, and end drag.
+  generator->MoveTouch(peeking_top);
+  generator->ReleaseTouch();
+  GetAppListTestHelper()->WaitUntilIdle();
+  GetAppListTestHelper()->CheckState(AppListViewState::kPeeking);
+
+  EXPECT_EQ(gfx::RoundedCornersF(background_radius, background_radius, 0, 0),
+            background_shield->layer()->rounded_corner_radii());
+}
+
 // Test a variety of behaviors for home launcher (app list in tablet mode).
 class AppListPresenterDelegateHomeLauncherTest
     : public AppListPresenterDelegateTest {
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 4d80952..053712a 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -156,6 +156,19 @@
 
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kExcludeWindowFromEventHandling, false)
 
+// Gets radius for app list background corners when the app list has the
+// provided height. The rounded corner should match the current app list height
+// (so the rounded corners bottom edge matches the shelf top), until it reaches
+// the app list background radius (i.e. background radius in peeking app list
+// state).
+// |height|: App list view height, relative to the shelf top (i.e. distance
+//           between app list top and shelf top edge).
+double GetBackgroundRadiusForAppListHeight(double height) {
+  return std::min(
+      static_cast<double>(AppListConfig::instance().background_radius()),
+      std::max(height, 0.));
+}
+
 // This targeter prevents routing events to sub-windows, such as
 // RenderHostWindow in order to handle events in context of app list.
 class AppListEventTargeter : public aura::WindowTargeter {
@@ -408,6 +421,10 @@
     }
   }
 
+  void UpdateBackgroundRadius(double radius) {
+    layer()->SetRoundedCornerRadius({radius, radius, 0, 0});
+  }
+
   void UpdateColor(SkColor color) {
     if (color_ == color)
       return;
@@ -489,6 +506,95 @@
   DISALLOW_COPY_AND_ASSIGN(PeekingResetAnimation);
 };
 
+// Animation that vertically translates app list view between different states,
+// updating the background shield's corner radius to match the current app list
+// height as needed. The corner radius should be updated when app list is
+// animated to/from closed state with maximized shelf view (i.e. when target
+// shelf view state has no rounded corners).
+// Using single animation for both background shield and app list view to keep
+// the animation timing in sync.
+// NOTE: The final transform is identity transform - i.e. the app list view is
+// animated into it's current bounds.
+class TranslateWithChangingCornerRadiusAnimation
+    : public ui::LayerAnimationElement {
+ public:
+  TranslateWithChangingCornerRadiusAnimation(
+      double initial_app_list_vertical_offset,
+      double target_app_list_height,
+      AppListView* view,
+      AppListBackgroundShieldView* background_shield,
+      base::TimeDelta duration)
+      : ui::LayerAnimationElement(ui::LayerAnimationElement::TRANSFORM,
+                                  duration),
+        transform_(gfx::PointF(0, initial_app_list_vertical_offset),
+                   gfx::PointF()),
+        initial_app_list_vertical_offset_(initial_app_list_vertical_offset),
+        target_app_list_height_(target_app_list_height),
+        view_(view),
+        background_shield_view_(background_shield) {}
+  ~TranslateWithChangingCornerRadiusAnimation() override = default;
+
+  // ui::LayerAnimationElement:
+  void OnStart(ui::LayerAnimationDelegate* delegate) override {}
+  bool OnProgress(double current,
+                  ui::LayerAnimationDelegate* delegate) override {
+    const double progress =
+        gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, current);
+
+    delegate->SetTransformFromAnimation(
+        transform_.Interpolate(progress),
+        ui::PropertyChangeReason::FROM_ANIMATION);
+
+    // When animating to/from closed state, the app list view UI is moving into
+    // or from the shelf UI. In default state, the app list and shelf have the
+    // same rounded corners, so just translating the shelf into the final state
+    // works well (as the shelf UI matches the app list UI). When shelf is in
+    // maximized state, it has no rounded corners at all - when that is the
+    // case, the app list rounded corner radius should be animated between "no
+    // rounded corners" and the "app list background radius" values.
+    //
+    // NOTE: |shelf_has_rounded_corners()| value can change during animation. If
+    // that happens, for simplicity, immediately start applying rounded corners
+    // so they match the current app list height and shelf state.
+    if (!view_->shelf_has_rounded_corners()) {
+      const double current_offset =
+          (1 - progress) * initial_app_list_vertical_offset_;
+      const double current_height = target_app_list_height_ - current_offset;
+
+      background_shield_view_->UpdateBackgroundRadius(
+          GetBackgroundRadiusForAppListHeight(current_height));
+    } else {
+      background_shield_view_->UpdateBackgroundRadius(
+          AppListConfig::instance().background_radius());
+    }
+    return true;
+  }
+  void OnGetTarget(TargetValue* target) const override {
+    target->transform = gfx::Transform();
+  }
+  void OnAbort(ui::LayerAnimationDelegate* delegate) override {}
+
+ private:
+  ui::InterpolatedTranslation transform_;
+
+  // The app list view's initial vertical offset from the target app list
+  // bounds.
+  const double initial_app_list_vertical_offset_;
+
+  // The target app list view height compared to shelf - i.e. the target
+  // difference from app list view top to the shelf top edge. Used to determine
+  // background corner radius.
+  const double target_app_list_height_;
+
+  // The animated app list view.
+  AppListView* const view_;
+
+  // The app list view's background shield view.
+  AppListBackgroundShieldView* const background_shield_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(TranslateWithChangingCornerRadiusAnimation);
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 // AppListView::TestApi
 
@@ -1534,11 +1640,13 @@
   }
 
   gfx::Rect target_bounds = GetPreferredWidgetBoundsForState(target_state);
+
+  // When closing the view should animate to the shelf bounds. The workspace
+  // area will not reflect an autohidden shelf so ask for the proper bounds.
+  const int target_y_for_closed_state =
+      delegate_->GetTargetYForAppListHide(GetWidget()->GetNativeView());
   if (target_state == ash::AppListViewState::kClosed) {
-    // When closing the view should animate to the shelf bounds. The workspace
-    // area will not reflect an autohidden shelf so ask for the proper bounds.
-    target_bounds.set_y(
-        delegate_->GetTargetYForAppListHide(GetWidget()->GetNativeView()));
+    target_bounds.set_y(target_y_for_closed_state);
   }
 
   // Record the current transform before removing it because this bounds
@@ -1550,14 +1658,7 @@
   layer->SetTransform(gfx::Transform());
   layer->SetBounds(target_bounds);
 
-  gfx::Transform transform;
-  const int y_offset = current_y_with_transform - target_bounds.y();
-  transform.Translate(0, y_offset);
-  layer->SetTransform(transform);
-
   ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
-  animation.SetTransitionDuration(duration_ms);
-  animation.SetTweenType(gfx::Tween::EASE_OUT);
   animation.SetPreemptionStrategy(
       ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);
   animation.SetAnimationMetricsReporter(GetStateTransitionMetricsReporter());
@@ -1571,12 +1672,19 @@
     animation.AddObserver(animation_observer);
   }
 
+  const int y_offset = current_y_with_transform - target_bounds.y();
   if (update_childview_each_frame_) {
     layer->GetAnimator()->StartAnimation(new ui::LayerAnimationSequence(
         std::make_unique<PeekingResetAnimation>(y_offset, duration_ms, this)));
-  } else {
-    layer->SetTransform(gfx::Transform());
+    return;
   }
+
+  const double target_height =
+      std::max(0, target_y_for_closed_state - target_bounds.y());
+  layer->GetAnimator()->StartAnimation(new ui::LayerAnimationSequence(
+      std::make_unique<TranslateWithChangingCornerRadiusAnimation>(
+          y_offset, target_height, this, app_list_background_shield_,
+          duration_ms)));
 }
 
 void AppListView::SetStateFromSearchBoxView(bool search_box_is_empty,
@@ -2077,8 +2185,14 @@
   gfx::Transform transform;
   if (is_in_drag_) {
     float app_list_transition_progress = GetAppListTransitionProgress();
-    if (app_list_transition_progress >= 1 &&
-        app_list_transition_progress <= 2) {
+    if (app_list_transition_progress < 1 && !shelf_has_rounded_corners()) {
+      const float shelf_height =
+          GetScreenBottom() - GetDisplayNearestView().work_area().bottom();
+      app_list_background_shield_->UpdateBackgroundRadius(
+          GetBackgroundRadiusForAppListHeight(GetCurrentAppListHeight() -
+                                              shelf_height));
+    } else if (app_list_transition_progress >= 1 &&
+               app_list_transition_progress <= 2) {
       // Translate background shield so that it ends drag at a y position
       // according to the background radius in peeking and fullscreen.
       transform.Translate(0, -AppListConfig::instance().background_radius() *
diff --git a/ash/app_list/views/app_list_view.h b/ash/app_list/views/app_list_view.h
index 19dec37..22db5f7f5 100644
--- a/ash/app_list/views/app_list_view.h
+++ b/ash/app_list/views/app_list_view.h
@@ -309,6 +309,12 @@
 
   bool is_side_shelf() const { return is_side_shelf_; }
 
+  void set_shelf_has_rounded_corners(bool shelf_has_rounded_corners) {
+    shelf_has_rounded_corners_ = shelf_has_rounded_corners;
+  }
+
+  bool shelf_has_rounded_corners() const { return shelf_has_rounded_corners_; }
+
   bool is_in_drag() const { return is_in_drag_; }
 
   void set_onscreen_keyboard_shown(bool onscreen_keyboard_shown) {
@@ -453,6 +459,9 @@
   // Whether the shelf is oriented on the side.
   bool is_side_shelf_ = false;
 
+  // Whether the shelf has rounded corners.
+  bool shelf_has_rounded_corners_ = false;
+
   // True if the user is in the process of gesture-dragging on opened app list,
   // or dragging the app list from shelf.
   bool is_in_drag_ = false;
diff --git a/ash/public/cpp/shelf_types.h b/ash/public/cpp/shelf_types.h
index 7941219..1c0bed4 100644
--- a/ash/public/cpp/shelf_types.h
+++ b/ash/public/cpp/shelf_types.h
@@ -57,9 +57,14 @@
   // for a split view.
   SHELF_BACKGROUND_MAXIMIZED,
 
-  // The background when fullscreen app list is visible.
+  // The background when app list is visible.
   SHELF_BACKGROUND_APP_LIST,
 
+  // The background when a maximized window exists or two windows are maximized
+  // for a split view, and the app list is visible. If the app list were not
+  // visible, the shelf would be in SHELF_BACKGROUND_MAXIMIZED state.
+  SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST,
+
   // The background when OOBE is active.
   SHELF_BACKGROUND_OOBE,
 
diff --git a/ash/shelf/shelf_background_animator.cc b/ash/shelf/shelf_background_animator.cc
index 7b03596..97f21d6 100644
--- a/ash/shelf/shelf_background_animator.cc
+++ b/ash/shelf/shelf_background_animator.cc
@@ -126,6 +126,7 @@
     case SHELF_BACKGROUND_MAXIMIZED:
       return kShelfTranslucentMaximizedWindow;
     case SHELF_BACKGROUND_APP_LIST:
+    case SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST:
       return kShelfTranslucentOverAppList;
     case SHELF_BACKGROUND_OOBE:
       return SK_AlphaTRANSPARENT;
@@ -200,6 +201,7 @@
   switch (background_type) {
     case SHELF_BACKGROUND_DEFAULT:
     case SHELF_BACKGROUND_APP_LIST:
+    case SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST:
       duration_ms = 500;
       break;
     case SHELF_BACKGROUND_MAXIMIZED:
@@ -244,6 +246,7 @@
   switch (background_type) {
     case SHELF_BACKGROUND_DEFAULT:
     case SHELF_BACKGROUND_APP_LIST:
+    case SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST:
     case SHELF_BACKGROUND_OVERVIEW:
       shelf_target_color = darken_wallpaper(kShelfTranslucentColorDarkenAlpha);
       break;
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index f31032c..22229ba 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -529,25 +529,28 @@
     return SHELF_BACKGROUND_LOGIN;
   }
 
+  const bool in_split_view_mode =
+      Shell::Get()->split_view_controller() &&
+      Shell::Get()->split_view_controller()->InSplitViewMode();
+  const bool maximized =
+      in_split_view_mode ||
+      (state_.visibility_state != SHELF_AUTO_HIDE &&
+       state_.window_state == WorkspaceWindowState::kMaximized &&
+       !Shell::Get()
+            ->home_screen_controller()
+            ->home_launcher_gesture_handler()
+            ->GetActiveWindow());
   if (IsHomeScreenAvailable()) {
     // If the home launcher is shown, being animated, or dragged, show the
     // default background.
     if (is_home_launcher_shown_ || is_home_launcher_target_position_shown_)
       return SHELF_BACKGROUND_DEFAULT;
   } else if (is_app_list_visible_) {
-    return SHELF_BACKGROUND_APP_LIST;
+    return maximized ? SHELF_BACKGROUND_MAXIMIZED_WITH_APP_LIST
+                     : SHELF_BACKGROUND_APP_LIST;
   }
 
-  const bool in_split_view_mode =
-      Shell::Get()->split_view_controller() &&
-      Shell::Get()->split_view_controller()->InSplitViewMode();
-  if (in_split_view_mode ||
-      (state_.visibility_state != SHELF_AUTO_HIDE &&
-       state_.window_state == WorkspaceWindowState::kMaximized &&
-       !Shell::Get()
-            ->home_screen_controller()
-            ->home_launcher_gesture_handler()
-            ->GetActiveWindow())) {
+  if (maximized) {
     return SHELF_BACKGROUND_MAXIMIZED;
   }
 
diff --git a/ash/wallpaper/wallpaper_window_state_manager.cc b/ash/wallpaper/wallpaper_window_state_manager.cc
index e9633b2d..e85b298 100644
--- a/ash/wallpaper/wallpaper_window_state_manager.cc
+++ b/ash/wallpaper/wallpaper_window_state_manager.cc
@@ -6,6 +6,7 @@
 
 #include "ash/shell.h"
 #include "ash/wm/mru_window_tracker.h"
+#include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/window.h"
@@ -84,7 +85,10 @@
     RemoveObserverIfUnreferenced(*iter);
   }
 
-  ActivateMruUnminimizedWindowOnActiveDesk();
+  // If the wallpaper app is closed while the desktop is in overview mode,
+  // do not activate any window, because doing so will disable overview mode.
+  if (!Shell::Get()->overview_controller()->InOverviewSession())
+    ActivateMruUnminimizedWindowOnActiveDesk();
 }
 
 void WallpaperWindowStateManager::RemoveObserverIfUnreferenced(
diff --git a/base/build_time.cc b/base/build_time.cc
index 834b041..c7462b1 100644
--- a/base/build_time.cc
+++ b/base/build_time.cc
@@ -15,8 +15,8 @@
 Time GetBuildTime() {
   Time integral_build_time;
   // BUILD_DATE is exactly "Mmm DD YYYY HH:MM:SS".
-  // See //build/write_build_date_header.py. "HH:MM:SS" is normally expected to
-  // be "05:00:00" but is not enforced here.
+  // See //build/write_build_date_header.py. "HH:MM:SS" is expected to
+  // be "05:00:00" in non-official builds but is not enforced here.
   bool result = Time::FromUTCString(BUILD_DATE, &integral_build_time);
   DCHECK(result);
   return integral_build_time;
diff --git a/base/build_time_unittest.cc b/base/build_time_unittest.cc
index a9cc44590..f032788 100644
--- a/base/build_time_unittest.cc
+++ b/base/build_time_unittest.cc
@@ -15,14 +15,20 @@
   EXPECT_EQ(' ', build_date[3]);
   EXPECT_EQ(' ', build_date[6]);
   EXPECT_EQ(' ', build_date[11]);
+#if !defined(OFFICIAL_BUILD)
   EXPECT_EQ('0', build_date[12]);
   EXPECT_EQ('5', build_date[13]);
+#endif
   EXPECT_EQ(':', build_date[14]);
+#if !defined(OFFICIAL_BUILD)
   EXPECT_EQ('0', build_date[15]);
   EXPECT_EQ('0', build_date[16]);
+#endif
   EXPECT_EQ(':', build_date[17]);
+#if !defined(OFFICIAL_BUILD)
   EXPECT_EQ('0', build_date[18]);
   EXPECT_EQ('0', build_date[19]);
+#endif
 }
 
 TEST(BuildTime, InThePast) {
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 99a836a..ef1672e 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -65,8 +65,8 @@
 
   if (!defined(default_android_ndk_root)) {
     default_android_ndk_root = "//third_party/android_ndk"
-    default_android_ndk_version = "r16"
-    default_android_ndk_major_version = 16
+    default_android_ndk_version = "r20"
+    default_android_ndk_major_version = 20
   } else {
     assert(defined(default_android_ndk_version))
     assert(defined(default_android_ndk_major_version))
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index a4a668d1..45bb125 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8905032235111475984
\ No newline at end of file
+8905005547084838352
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 7626b32..0413d27 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8905033739425045616
\ No newline at end of file
+8905015754853369168
\ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION
index f7078dd..f6e55a1 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=78
 MINOR=0
-BUILD=3885
+BUILD=3886
 PATCH=0
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 51d7bbe9..b843ff4 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1122,6 +1122,10 @@
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionViewProperties.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerText.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerTextNewLayout.java",
+  "java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionView.java",
+  "java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinder.java",
+  "java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewProcessor.java",
+  "java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewProperties.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionHost.java",
   "java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionView.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index a8076ef..a4c953d 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -154,6 +154,7 @@
   "junit/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManagerTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/geo/VisibleNetworksTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/geo/VisibleNetworksTrackerTest.java",
+  "junit/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/suggestions/entity/EntitySuggestionProcessorTest.java",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java
index f6d70b8..93f643f 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java
@@ -7,6 +7,7 @@
 import android.support.annotation.StringRes;
 import android.view.View;
 
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -131,4 +132,9 @@
 
         return tabModel.indexOf(tabs.get(tabs.size() - 1));
     }
+
+    @VisibleForTesting
+    public static void triggerAssertionForTesting() {
+        assert false;
+    }
 }
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/AssertsTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/AssertsTest.java
new file mode 100644
index 0000000..e00b0fa9
--- /dev/null
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/AssertsTest.java
@@ -0,0 +1,59 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.BuildConfig;
+import org.chromium.chrome.browser.tasks.tab_groups.TabGroupUtils;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+
+/**
+ * Test that ensures Java asserts are working in tab_management feature module.
+ *
+ * Not a robolectric test because we want to make sure asserts are enabled after dexing.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+public class AssertsTest {
+    @Test
+    @SmallTest
+    @SuppressWarnings("UseCorrectAssertInTests")
+    public void assertInTests() {
+        if (BuildConfig.DCHECK_IS_ON) {
+            try {
+                assert false;
+            } catch (AssertionError e) {
+                // When DCHECK is on, asserts should throw AssertionErrors.
+                return;
+            }
+            Assert.fail("Java assert unexpectedly didn't fire.");
+        } else {
+            // When DCHECK isn't on, asserts should be removed by proguard.
+            assert false : "Java assert unexpectedly fired.";
+        }
+    }
+
+    @Test
+    @SmallTest
+    @SuppressWarnings("UseCorrectAssertInTests")
+    public void assertInModule() {
+        if (BuildConfig.DCHECK_IS_ON) {
+            try {
+                TabGroupUtils.triggerAssertionForTesting();
+            } catch (AssertionError e) {
+                // When DCHECK is on, asserts should throw AssertionErrors.
+                return;
+            }
+            Assert.fail("Java assert unexpectedly didn't fire.");
+        } else {
+            // When DCHECK isn't on, asserts should be removed by proguard.
+            TabGroupUtils.triggerAssertionForTesting();
+        }
+    }
+}
diff --git a/chrome/android/features/tab_ui/tab_management_java_sources.gni b/chrome/android/features/tab_ui/tab_management_java_sources.gni
index 27ab5477..b0642fad 100644
--- a/chrome/android/features/tab_ui/tab_management_java_sources.gni
+++ b/chrome/android/features/tab_ui/tab_management_java_sources.gni
@@ -18,6 +18,7 @@
 public_tab_management_java_sources += start_surface_public_java_sources
 
 tab_management_test_java_sources = [
+  "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/AssertsTest.java",
   "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParentTest.java",
   "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinderTest.java",
   "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java",
diff --git a/chrome/android/java/res/layout/page_info.xml b/chrome/android/java/res/layout/page_info.xml
index faa040f..78a4af31 100644
--- a/chrome/android/java/res/layout/page_info.xml
+++ b/chrome/android/java/res/layout/page_info.xml
@@ -12,7 +12,7 @@
     android:layout_height="match_parent"
     android:paddingBottom="8dp"
     android:orientation="vertical"
-    android:background="@color/modern_primary_color">
+    android:background="@color/sheet_bg_color">
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index be8b661..19fac6d 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -41,12 +41,6 @@
     <!-- Infobar colors -->
     <color name="infobar_icon_drawable_color">@color/default_icon_color_blue</color>
 
-    <!-- Snackbar colors -->
-    <color name="snackbar_background_color">#282C32</color>
-
-    <!-- Bottom sheet colors -->
-    <color name="sheet_bg_color">@color/default_bg_color_elev_2</color>
-
     <!-- Tab Switcher Colors -->
     <color name="tab_switcher_background">#14181C</color>
     <color name="accessibility_tab_switcher_list_item">#252525</color>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionView.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionView.java
new file mode 100644
index 0000000..36d4f7c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionView.java
@@ -0,0 +1,238 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.omnibox.suggestions.base;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.LayoutRes;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.util.TypedValue;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewDelegate;
+import org.chromium.chrome.browser.util.KeyNavigationUtil;
+
+/**
+ * Base layout for common suggestion types. Includes support for a configurable suggestion content
+ * and the common suggestion patterns shared across suggestion formats.
+ */
+public class BaseSuggestionView extends ViewGroup {
+    /**
+     * Container view for omnibox suggestions allowing soft focus from keyboard.
+     */
+    private static final class DecoratedSuggestionView extends ViewGroup {
+        private View mContentView;
+
+        public DecoratedSuggestionView(Context context) {
+            super(context);
+        }
+
+        protected void setContentView(View view) {
+            if (mContentView != null) removeView(mContentView);
+            mContentView = view;
+            addView(mContentView);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+            mContentView.layout(0, 0, right - left, top - bottom);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            assert MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
+
+            mContentView.measure(widthMeasureSpec, heightMeasureSpec);
+            setMeasuredDimension(
+                    MeasureSpec.getSize(widthMeasureSpec), mContentView.getMeasuredHeight());
+        }
+
+        @Override
+        public boolean isFocused() {
+            return super.isFocused() || (isSelected() && !isInTouchMode());
+        }
+    }
+
+    protected final ImageView mRefineView;
+    protected final DecoratedSuggestionView mContentView;
+
+    private SuggestionViewDelegate mDelegate;
+    private boolean mUseDarkIconTint;
+
+    /**
+     * Constructs a new suggestion view.
+     *
+     * @param context The context used to construct the suggestion view.
+     */
+    public BaseSuggestionView(View view) {
+        super(view.getContext());
+
+        TypedValue themeRes = new TypedValue();
+        getContext().getTheme().resolveAttribute(R.attr.selectableItemBackground, themeRes, true);
+        @DrawableRes
+        int selectableBackgroundRes = themeRes.resourceId;
+
+        mContentView = new DecoratedSuggestionView(getContext());
+        mContentView.setBackgroundResource(selectableBackgroundRes);
+        mContentView.setClickable(true);
+        mContentView.setFocusable(true);
+        mContentView.setOnClickListener(v -> mDelegate.onSelection());
+        mContentView.setOnLongClickListener(v -> {
+            mDelegate.onLongPress();
+            return true;
+        });
+        addView(mContentView);
+
+        // Action icons. Currently we only support the Refine button.
+        mRefineView = new ImageView(getContext());
+        mRefineView.setBackgroundResource(selectableBackgroundRes);
+        mRefineView.setClickable(true);
+        mRefineView.setFocusable(true);
+        mRefineView.setScaleType(ImageView.ScaleType.CENTER);
+        mRefineView.setContentDescription(
+                getResources().getString(R.string.accessibility_omnibox_btn_refine));
+        mRefineView.setImageResource(R.drawable.btn_suggestion_refine);
+        mRefineView.setOnClickListener(v -> mDelegate.onRefineSuggestion());
+
+        // Note: height is technically unused, but the behavior is MATCH_PARENT.
+        mRefineView.setLayoutParams(new LayoutParams(
+                getResources().getDimensionPixelSize(R.dimen.omnibox_suggestion_refine_width),
+                LayoutParams.MATCH_PARENT));
+        addView(mRefineView);
+
+        Resources res = getResources();
+
+        setContentView(view);
+    }
+
+    /**
+     * Constructs a new suggestion view and inflates supplied layout as the contents view.
+     *
+     * @param context The context used to construct the suggestion view.
+     * @param layoutId Layout ID to be inflated as the contents view.
+     */
+    public BaseSuggestionView(Context context, @LayoutRes int layoutId) {
+        this(LayoutInflater.from(context).inflate(layoutId, null));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        // Note: We layout children in the following order:
+        // - first-to-last in LTR orientation and
+        // - last-to-first in RTL orientation.
+        boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        int index = isRtl ? getChildCount() - 1 : 0;
+        int increment = isRtl ? -1 : 1;
+
+        for (; index >= 0 && index < getChildCount(); index += increment) {
+            View v = getChildAt(index);
+            if (v.getVisibility() == GONE) continue;
+            v.layout(left, 0, left + v.getMeasuredWidth(), bottom - top);
+            left += v.getMeasuredWidth();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthSpec, int heightSpec) {
+        int contentViewWidth = MeasureSpec.getSize(widthSpec);
+
+        // Carve out padding at the end of the object.
+        contentViewWidth -= getResources().getDimensionPixelSize(
+                R.dimen.omnibox_suggestion_refine_view_modern_end_padding);
+
+        // Compute and apply space we can offer to content view.
+        for (int index = 0; index < getChildCount(); ++index) {
+            View v = getChildAt(index);
+            // Do not take mContentView into consideration when computing space for it.
+            if (v == mContentView) continue;
+            if (v.getVisibility() == GONE) continue;
+            LayoutParams p = v.getLayoutParams();
+            if (p.width > 0) contentViewWidth -= p.width;
+        }
+
+        // Measure height of the content view given the width constraint.
+        mContentView.measure(MeasureSpec.makeMeasureSpec(contentViewWidth, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+        final int heightPx = mContentView.getMeasuredHeight();
+        heightSpec = MeasureSpec.makeMeasureSpec(heightPx, MeasureSpec.EXACTLY);
+
+        // Apply measured dimensions to all children.
+        for (int index = 0; index < getChildCount(); ++index) {
+            View v = getChildAt(index);
+
+            // Avoid calling (expensive) measure on content view twice.
+            if (v == mContentView) continue;
+
+            v.measure(MeasureSpec.makeMeasureSpec(v.getLayoutParams().width, MeasureSpec.EXACTLY),
+                    heightSpec);
+        }
+
+        setMeasuredDimension(MeasureSpec.getSize(widthSpec), MeasureSpec.getSize(heightSpec));
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        // Whenever the suggestion dropdown is touched, we dispatch onGestureDown which is
+        // used to let autocomplete controller know that it should stop updating suggestions.
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            mDelegate.onGestureDown();
+        } else if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+            mDelegate.onGestureUp(ev.getEventTime());
+        }
+        return super.dispatchTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        if ((!isRtl && KeyNavigationUtil.isGoRight(event))
+                || (isRtl && KeyNavigationUtil.isGoLeft(event))) {
+            mDelegate.onRefineSuggestion();
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public void setSelected(boolean selected) {
+        mContentView.setSelected(selected);
+        mDelegate.onSetUrlToSuggestion();
+    }
+
+    /**
+     * Set the content view to supplied view.
+     *
+     * @param view View to be displayed as suggestion content.
+     */
+    public void setContentView(View view) {
+        mContentView.setContentView(view);
+    }
+
+    /** Sets the delegate for the actions on the suggestion view. */
+    void setDelegate(SuggestionViewDelegate delegate) {
+        mDelegate = delegate;
+    }
+
+    /** Change refine button visibility. */
+    void setRefineVisible(boolean visible) {
+        mRefineView.setVisibility(visible ? View.VISIBLE : View.GONE);
+    }
+
+    /** Update the refine icon tint color. */
+    void updateIconTint(@ColorInt int color) {
+        Drawable drawable = mRefineView.getDrawable();
+        DrawableCompat.setTint(drawable, color);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinder.java
new file mode 100644
index 0000000..1d51230c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinder.java
@@ -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.
+
+package org.chromium.chrome.browser.omnibox.suggestions.base;
+
+import android.support.annotation.CallSuper;
+import android.support.v4.view.ViewCompat;
+
+import org.chromium.chrome.browser.omnibox.suggestions.SuggestionCommonProperties;
+import org.chromium.chrome.browser.util.ColorUtils;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder;
+
+/**
+ * Binds base suggestion view properties.
+ */
+public class BaseSuggestionViewBinder
+        implements ViewBinder<PropertyModel, BaseSuggestionView, PropertyKey> {
+    @Override
+    @CallSuper
+    public void bind(PropertyModel model, BaseSuggestionView view, PropertyKey propertyKey) {
+        if (BaseSuggestionViewProperties.SUGGESTION_DELEGATE == propertyKey) {
+            view.setDelegate(model.get(BaseSuggestionViewProperties.SUGGESTION_DELEGATE));
+        } else if (BaseSuggestionViewProperties.REFINE_VISIBLE == propertyKey) {
+            view.setRefineVisible(model.get(BaseSuggestionViewProperties.REFINE_VISIBLE));
+        } else if (SuggestionCommonProperties.LAYOUT_DIRECTION == propertyKey) {
+            ViewCompat.setLayoutDirection(
+                    view, model.get(SuggestionCommonProperties.LAYOUT_DIRECTION));
+        } else if (SuggestionCommonProperties.USE_DARK_COLORS == propertyKey) {
+            boolean useDarkColors = model.get(SuggestionCommonProperties.USE_DARK_COLORS);
+            int tint = ColorUtils.getIconTint(view.getContext(), !useDarkColors).getDefaultColor();
+            view.updateIconTint(tint);
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewProcessor.java
new file mode 100644
index 0000000..ca1bc74
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewProcessor.java
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.omnibox.suggestions.base;
+
+import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion;
+import org.chromium.chrome.browser.omnibox.suggestions.SuggestionProcessor;
+import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionHost;
+import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewDelegate;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * A class that handles base properties and model for most suggestions.
+ */
+public abstract class BaseSuggestionViewProcessor implements SuggestionProcessor {
+    private final SuggestionHost mSuggestionHost;
+
+    /**
+     * @param host A handle to the object using the suggestions.
+     */
+    public BaseSuggestionViewProcessor(SuggestionHost host) {
+        mSuggestionHost = host;
+    }
+
+    /**
+     * @return whether suggestion can be refined and a refine icon should be shown.
+     */
+    protected boolean canRefine(OmniboxSuggestion suggestion) {
+        return true;
+    }
+
+    @Override
+    public void populateModel(OmniboxSuggestion suggestion, PropertyModel model, int position) {
+        SuggestionViewDelegate delegate =
+                mSuggestionHost.createSuggestionViewDelegate(suggestion, position);
+
+        model.set(BaseSuggestionViewProperties.SUGGESTION_DELEGATE, delegate);
+        model.set(BaseSuggestionViewProperties.REFINE_VISIBLE, canRefine(suggestion));
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewProperties.java
new file mode 100644
index 0000000..e4a4f59
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewProperties.java
@@ -0,0 +1,29 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.omnibox.suggestions.base;
+
+import org.chromium.chrome.browser.omnibox.suggestions.SuggestionCommonProperties;
+import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewDelegate;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
+
+/** The base set of properties for most omnibox suggestions. */
+public class BaseSuggestionViewProperties {
+    /** Whether refine icon should be visible. */
+    public static final WritableBooleanPropertyKey REFINE_VISIBLE =
+            new WritableBooleanPropertyKey();
+
+    /** Delegate receiving user events. */
+    public static final WritableObjectPropertyKey<SuggestionViewDelegate> SUGGESTION_DELEGATE =
+            new WritableObjectPropertyKey<>();
+
+    public static final PropertyKey[] ALL_UNIQUE_KEYS =
+            new PropertyKey[] {REFINE_VISIBLE, SUGGESTION_DELEGATE};
+
+    public static final PropertyKey[] ALL_KEYS =
+            PropertyModel.concatKeys(ALL_UNIQUE_KEYS, SuggestionCommonProperties.ALL_KEYS);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarView.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarView.java
index 2cb7778..5da3d9a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarView.java
@@ -245,7 +245,8 @@
             return snackbar.getBackgroundColor();
         }
 
-        return ApiCompatibilityUtils.getColor(view.getResources(), R.color.modern_primary_color);
+        return ApiCompatibilityUtils.getColor(
+                view.getResources(), R.color.snackbar_background_color);
     }
 
     private static int getTextAppearance(Snackbar snackbar) {
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 218737a..703b96d 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1168,7 +1168,7 @@
 
       <!-- Single site settings -->
       <message name="IDS_NO_SAVED_WEBSITE_SETTINGS" desc="Text to display when there are no saved website settings.">
-        No storage data here
+        Files saved by websites appear here
       </message>
 
       <!-- Languages preferences -->
@@ -3456,7 +3456,7 @@
       </message>
 
       <message name="IDS_STORAGE_CLEAR_BUTTON_TITLE" desc="Title of a button in the storage UI used to clear all storage data. [CHAR-LIMIT=24]">
-        Clear Site Storage…
+        Clear site storage
       </message>
       <message name="IDS_STORAGE_CLEAR_DIALOG_TEXT" desc="Text of the clear storage dialog which give the user a choice to reset the app or delete site storage data.">
         This will clear all <ph name="SIZE_IN_KB">%1$s<ex>101kb</ex></ph> of website storage.
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_NO_SAVED_WEBSITE_SETTINGS.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_NO_SAVED_WEBSITE_SETTINGS.png.sha1
index 4d3c5db..0167ddd 100644
--- a/chrome/android/java/strings/android_chrome_strings_grd/IDS_NO_SAVED_WEBSITE_SETTINGS.png.sha1
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_NO_SAVED_WEBSITE_SETTINGS.png.sha1
@@ -1 +1 @@
-61c67160243523857d934b35eb74acf104e05675
\ No newline at end of file
+6fa5efed5d7bc9786e04f44fe48f9c7dee4362d0
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_STORAGE_CLEAR_BUTTON_TITLE.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_STORAGE_CLEAR_BUTTON_TITLE.png.sha1
new file mode 100644
index 0000000..6e6d7a5
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_STORAGE_CLEAR_BUTTON_TITLE.png.sha1
@@ -0,0 +1 @@
+29a656383244eced37abcdb4dc4b83f9e21a432d
\ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewTest.java
new file mode 100644
index 0000000..a5dc72433
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewTest.java
@@ -0,0 +1,243 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.omnibox.suggestions.base;
+
+import android.app.Activity;
+import android.view.View;
+import android.view.View.MeasureSpec;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+
+import org.chromium.chrome.R;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+/**
+ * Tests for {@link BaseSuggestionView}.
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class BaseSuggestionViewTest {
+    // Used as a (fixed) margin between screen edge and refine icon.
+    private int mSuggestionPaddingEndPx;
+    // Used as a (fixed) width of a refine icon.
+    private int mActionIconWidthPx;
+
+    private BaseSuggestionViewForTest mView;
+    private Activity mActivity;
+    private View mRefineView;
+    private View mDecoratedView;
+    private View mContentView;
+
+    // IMPORTANT: We need to extend the tested class here to support functionality currently
+    // omitted by Robolectric, that is relevant to the tests below (layout direction change).
+    //
+    // TODO(https://github.com/robolectric/robolectric/issues/3910) Remove the class below once
+    // the above issue is resolved and our robolectric version is rolled forward to the version
+    // that supports layout direction changes.
+    class BaseSuggestionViewForTest extends BaseSuggestionView {
+        private int mCurrentDirection = View.LAYOUT_DIRECTION_LTR;
+
+        BaseSuggestionViewForTest(View childView) {
+            super(childView);
+        }
+
+        @Override
+        public void setLayoutDirection(int newDirection) {
+            mCurrentDirection = newDirection;
+        }
+
+        @Override
+        public int getLayoutDirection() {
+            return mCurrentDirection;
+        }
+
+        /**
+         * Test method to force layout update based on specified view dimensions.
+         */
+        void performLayoutForTest(int width) {
+            onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+                    MeasureSpec.UNSPECIFIED);
+
+            // Note: height is computed by onMeasure call.
+            final int height = getMeasuredHeight();
+            onLayout(true, 0, 0, width, height);
+        }
+
+        View getDecoratedView() {
+            return mContentView;
+        }
+
+        View getRefineView() {
+            return mRefineView;
+        }
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
+        mContentView = new View(mActivity);
+        mView = new BaseSuggestionViewForTest(mContentView);
+
+        mSuggestionPaddingEndPx = mActivity.getResources().getDimensionPixelSize(
+                R.dimen.omnibox_suggestion_refine_view_modern_end_padding);
+        mActionIconWidthPx = mActivity.getResources().getDimensionPixelSize(
+                R.dimen.omnibox_suggestion_refine_width);
+
+        mRefineView = mView.getRefineView();
+        mDecoratedView = mView.getDecoratedView();
+    }
+
+    /**
+     * Perform the measure and layout pass on the BaseSuggestionView.
+     * This method sets up the basic properties of the Suggestion container, specifies height of the
+     * content view and executes the measure and layout pass.
+     */
+    private void executeLayoutTest(int containerWidth, int contentHeight, int layoutDirection) {
+        mView.setLayoutDirection(layoutDirection);
+        Assert.assertEquals(
+                "layout direction not supported", layoutDirection, mView.getLayoutDirection());
+
+        // Let ContentView drive the height of the Suggestion. The dummy view could shrink, so let's
+        // prevent that from happening. We don't technically have any content, so we need to prevent
+        // the view from shrinking, too.
+        mContentView.setMinimumHeight(contentHeight);
+
+        mView.performLayoutForTest(containerWidth);
+    }
+
+    /**
+     * Confirm that specified view is positioned at specific coordinates.
+     */
+    private void verifyViewLayout(View v, int left, int top, int right, int bottom) {
+        Assert.assertEquals("left view edge", left, v.getLeft());
+        Assert.assertEquals("top view edge", top, v.getTop());
+        Assert.assertEquals("right view edge", right, v.getRight());
+        Assert.assertEquals("bottom view edge", bottom, v.getBottom());
+        Assert.assertEquals("view width", right - left, v.getMeasuredWidth());
+        Assert.assertEquals("view height", bottom - top, v.getMeasuredHeight());
+    }
+
+    @Test
+    public void layout_LtrRefineVisible() {
+        final int useContentWidth = 120;
+
+        // Expectations (edge to edge):
+        //
+        // +----------------+----+-+  ^
+        // | CONTENT        |ACT1|#|  giveContentHeight
+        // +----------------+----+-+  v
+        //
+        // <- giveSuggestionWidth ->
+        //
+        // where ACT is action button and # is final padding.
+
+        final int giveSuggestionWidth =
+                useContentWidth + mActionIconWidthPx + mSuggestionPaddingEndPx;
+        final int giveContentHeight = 15;
+
+        final int expectedContentLeft = 0;
+        final int expectedContentRight = useContentWidth;
+        final int expectedRefineLeft = expectedContentRight;
+        final int expectedRefineRight = useContentWidth + mActionIconWidthPx;
+
+        executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_LTR);
+
+        verifyViewLayout(
+                mRefineView, expectedRefineLeft, 0, expectedRefineRight, giveContentHeight);
+        verifyViewLayout(
+                mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
+    }
+
+    @Test
+    public void layout_RtlRefineVisible() {
+        final int useContentWidth = 120;
+
+        // Expectations (edge to edge):
+        //
+        // +----+----------------+-+  ^
+        // |ACT1| CONTENT        |#|  giveContentHeight
+        // +----+----------------+-+  v
+        //
+        // <- giveSuggestionWidth ->
+        //
+        // where ACT is action button and # is final padding.
+
+        final int giveSuggestionWidth =
+                useContentWidth + mActionIconWidthPx + mSuggestionPaddingEndPx;
+        final int giveContentHeight = 25;
+
+        final int expectedRefineLeft = 0;
+        final int expectedRefineRight = mActionIconWidthPx;
+        final int expectedContentLeft = expectedRefineRight;
+        final int expectedContentRight = giveSuggestionWidth - mSuggestionPaddingEndPx;
+
+        executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_RTL);
+
+        verifyViewLayout(
+                mRefineView, expectedRefineLeft, 0, expectedRefineRight, giveContentHeight);
+        verifyViewLayout(
+                mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
+    }
+
+    @Test
+    public void layout_LtrRefineInvisible() {
+        // Expectations (edge to edge):
+        //
+        // +---------------------+-+  ^
+        // |CONTENT              |#|  giveContentHeight
+        // +---------------------+-+  v
+        //
+        // <- giveSuggestionWidth ->
+        //
+        // The reason for this is that we want content to align correctly with the end of the
+        // omnibox field. Otherwise, content would end at the right screen edge.
+
+        final int giveSuggestionWidth = 250;
+        final int giveContentHeight = 15;
+
+        final int expectedContentLeft = 0;
+        final int expectedContentRight = giveSuggestionWidth - mSuggestionPaddingEndPx;
+
+        mRefineView.setVisibility(View.GONE);
+
+        executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_LTR);
+        verifyViewLayout(
+                mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
+    }
+
+    @Test
+    public void layout_RtlRefineInvisible() {
+        // Expectations (edge to edge):
+        //
+        // +---------------------+-+  ^
+        // |CONTENT              |#|  giveContentHeight
+        // +---------------------+-+  v
+        //
+        // <- giveSuggestionWidth ->
+        //
+        // The reason for this is that we want content to align correctly with the end of the
+        // omnibox field. Otherwise, content would end (RTL) at the left screen edge.
+
+        final int giveSuggestionWidth = 250;
+        final int giveContentHeight = 15;
+
+        final int expectedContentLeft = 0;
+        final int expectedContentRight = giveSuggestionWidth - mSuggestionPaddingEndPx;
+
+        mRefineView.setVisibility(View.GONE);
+
+        executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_RTL);
+        verifyViewLayout(
+                mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
+    }
+}
diff --git a/chrome/android/static_initializers.gni b/chrome/android/static_initializers.gni
index 48ac0f80..53db994 100644
--- a/chrome/android/static_initializers.gni
+++ b/chrome/android/static_initializers.gni
@@ -12,9 +12,7 @@
 if (current_toolchain == default_toolchain &&
     (!is_debug && !using_sanitizer && proprietary_codecs)) {
   # Define expectations only for target_cpu covered by trybots.
-  if (target_cpu == "arm") {
-    expected_static_initializer_count = 6
-  } else if (target_cpu == "arm64") {
-    expected_static_initializer_count = 5
+  if (target_cpu == "arm" || target_cpu == "arm64") {
+    expected_static_initializer_count = 4
   }
 }
diff --git a/chrome/app/chrome_content_browser_overlay_manifest.cc b/chrome/app/chrome_content_browser_overlay_manifest.cc
index 2511adf..0e2131c 100644
--- a/chrome/app/chrome_content_browser_overlay_manifest.cc
+++ b/chrome/app/chrome_content_browser_overlay_manifest.cc
@@ -57,7 +57,7 @@
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
 #include "chromeos/services/network_config/public/mojom/constants.mojom.h"  // nogncheck
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"  // nogncheck
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_app.mojom.h"
 #endif
 
 #if defined(OS_WIN)
@@ -183,7 +183,8 @@
                 chromeos::ime::mojom::InputEngineManager,
                 chromeos::machine_learning::mojom::PageHandler,
                 chromeos::media_perception::mojom::MediaPerception,
-                cros::mojom::CrosImageCapture,
+                cros::mojom::CameraAppDeviceProvider,
+                cros::mojom::CameraAppHelper,
 #endif
                 contextual_search::mojom::ContextualSearchJsApiService,
                 dom_distiller::mojom::DistillabilityService,
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index ed697cd..7aacd2ac 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3520,6 +3520,7 @@
       "//components/image_fetcher/core",
       "//components/keep_alive_registry",
       "//components/ntp_snippets",
+      "//components/services/app_service/public/cpp:app_file_handling",
       "//components/vector_icons",
       "//components/web_modal",
       "//components/zoom",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 076ca38..a488ceba 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -189,7 +189,7 @@
   "+components/security_state/content",
   "+components/security_state/core",
   "+components/send_tab_to_self",
-  "+components/services/app_service/public/mojom",
+  "+components/services/app_service/public",
   "+components/services/filesystem/public/mojom",
   "+components/services/heap_profiling",
   "+components/services/patch/content",
diff --git a/chrome/browser/badging/badge_manager.cc b/chrome/browser/badging/badge_manager.cc
index 7da354b..6723301 100644
--- a/chrome/browser/badging/badge_manager.cc
+++ b/chrome/browser/badging/badge_manager.cc
@@ -64,26 +64,10 @@
 void BadgeManager::BindRequest(
     mojo::PendingReceiver<blink::mojom::BadgeService> receiver,
     content::RenderFrameHost* frame) {
-  // TODO(crbug.com/983929): Remove these CHECKs once the cause of the bug has
-  // been determined.
-  CHECK(receiver);
-  CHECK(frame);
-  content::WebContents* web_contents =
-      content::WebContents::FromRenderFrameHost(frame);
-  CHECK(web_contents);
-
-  CHECK(web_contents->GetBrowserContext());
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  CHECK(profile);
-
+  Profile* profile = Profile::FromBrowserContext(
+      content::WebContents::FromRenderFrameHost(frame)->GetBrowserContext());
   badging::BadgeManager* badge_manager =
       badging::BadgeManagerFactory::GetInstance()->GetForProfile(profile);
-  CHECK(badge_manager);
-
-  CHECK(frame->GetProcess());
-  CHECK(frame->GetProcess()->GetID());
-  CHECK(frame->GetRoutingID());
   BindingContext context(frame->GetProcess()->GetID(), frame->GetRoutingID());
 
   badge_manager->receivers_.Add(badge_manager, std::move(receiver),
diff --git a/chrome/browser/chromeos/arc/screen_capture/OWNERS b/chrome/browser/chromeos/arc/screen_capture/OWNERS
new file mode 100644
index 0000000..beda97f
--- /dev/null
+++ b/chrome/browser/chromeos/arc/screen_capture/OWNERS
@@ -0,0 +1 @@
+jkardatzke@chromium.org
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.cc b/chrome/browser/chromeos/crostini/crostini_export_import.cc
index 4f87d72..7b27569 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import.cc
+++ b/chrome/browser/chromeos/crostini/crostini_export_import.cc
@@ -218,7 +218,7 @@
     CrostiniManager::CrostiniResultCallback callback,
     const base::FilePath& container_path,
     bool result,
-    const std::string failure_reason) {
+    const std::string& failure_reason) {
   if (!result) {
     LOG(ERROR) << "Error sharing for export " << container_path.value() << ": "
                << failure_reason;
@@ -363,7 +363,7 @@
     CrostiniManager::CrostiniResultCallback callback,
     const base::FilePath& container_path,
     bool result,
-    const std::string failure_reason) {
+    const std::string& failure_reason) {
   if (!result) {
     LOG(ERROR) << "Error sharing for import " << container_path.value() << ": "
                << failure_reason;
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.h b/chrome/browser/chromeos/crostini/crostini_export_import.h
index 7284cdc7..2294ecb 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import.h
+++ b/chrome/browser/chromeos/crostini/crostini_export_import.h
@@ -160,7 +160,7 @@
                           CrostiniManager::CrostiniResultCallback callback,
                           const base::FilePath& container_path,
                           bool result,
-                          const std::string failure_reason);
+                          const std::string& failure_reason);
   void OnExportComplete(const base::Time& start,
                         const ContainerId& container_id,
                         CrostiniManager::CrostiniResultCallback callback,
@@ -170,7 +170,7 @@
                           CrostiniManager::CrostiniResultCallback callback,
                           const base::FilePath& container_path,
                           bool result,
-                          const std::string failure_reason);
+                          const std::string& failure_reason);
   void OnImportComplete(const base::Time& start,
                         const ContainerId& container_id,
                         CrostiniManager::CrostiniResultCallback callback,
diff --git a/chrome/browser/chromeos/crostini/crostini_package_service.cc b/chrome/browser/chromeos/crostini/crostini_package_service.cc
index b095314..c4c9116 100644
--- a/chrome/browser/chromeos/crostini/crostini_package_service.cc
+++ b/chrome/browser/chromeos/crostini/crostini_package_service.cc
@@ -184,7 +184,7 @@
     const base::FilePath& package_path,
     CrostiniManager::GetLinuxPackageInfoCallback callback,
     bool share_success,
-    std::string share_failure_reason) {
+    const std::string& share_failure_reason) {
   if (!share_success) {
     LinuxPackageInfo info;
     info.success = false;
diff --git a/chrome/browser/chromeos/crostini/crostini_package_service.h b/chrome/browser/chromeos/crostini/crostini_package_service.h
index eedcd2b..e417857 100644
--- a/chrome/browser/chromeos/crostini/crostini_package_service.h
+++ b/chrome/browser/chromeos/crostini/crostini_package_service.h
@@ -128,7 +128,7 @@
       const base::FilePath& package_path,
       CrostiniManager::GetLinuxPackageInfoCallback callback,
       bool share_success,
-      std::string share_failure_reason);
+      const std::string& share_failure_reason);
 
   // Wraps the callback provided in GetLinuxPackageInfo().
   void OnGetLinuxPackageInfo(
diff --git a/chrome/browser/chromeos/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc
index b4ac9364..456e554b 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.cc
+++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -113,11 +113,13 @@
     bool display_scaled,
     crostini::LaunchCrostiniAppCallback callback,
     bool success,
-    std::string failure_reason) {
+    const std::string& failure_reason) {
   if (!success) {
     OnLaunchFailed(app_id);
     return std::move(callback).Run(
-        success, success ? "" : "Failed to share paths to launch " + app_id);
+        success, success ? ""
+                         : "Failed to share paths to launch " + app_id + ":" +
+                               failure_reason);
   }
   crostini::CrostiniManager::GetForProfile(profile)->LaunchContainerApplication(
       registration.VmName(), registration.ContainerName(),
diff --git a/chrome/browser/chromeos/crostini/crostini_util.h b/chrome/browser/chromeos/crostini/crostini_util.h
index 9838f5b..bf9f6c8 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.h
+++ b/chrome/browser/chromeos/crostini/crostini_util.h
@@ -33,10 +33,8 @@
 // A unique identifier for our containers. This is <vm_name, container_name>.
 using ContainerId = std::pair<std::string, std::string>;
 
-// TODO(joelhockey): Update guest_os::SharePath::SharePathCallback to be
-// <void(bool success, const std::string& failure_reason)> and use it here.
 using LaunchCrostiniAppCallback =
-    base::OnceCallback<void(bool success, std::string failure_reason)>;
+    base::OnceCallback<void(bool success, const std::string& failure_reason)>;
 
 // Return" (<vm_name>, <container_name>)".
 std::string ContainerIdToString(const ContainerId& container_id);
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index d21b0c8..ea0258f 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -768,7 +768,7 @@
 }
 
 void FileManagerPrivateInternalSharePathsWithCrostiniFunction::
-    SharePathsCallback(bool success, std::string failure_reason) {
+    SharePathsCallback(bool success, const std::string& failure_reason) {
   Respond(success ? NoArguments() : Error(failure_reason));
 }
 
@@ -796,7 +796,7 @@
 }
 
 void FileManagerPrivateInternalUnsharePathWithCrostiniFunction::
-    UnsharePathCallback(bool success, std::string failure_reason) {
+    UnsharePathCallback(bool success, const std::string& failure_reason) {
   Respond(success ? NoArguments() : Error(failure_reason));
 }
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
index 0693650..8676480 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
@@ -330,7 +330,7 @@
 
  private:
   ResponseAction Run() override;
-  void SharePathsCallback(bool success, std::string failure_reason);
+  void SharePathsCallback(bool success, const std::string& failure_reason);
   DISALLOW_COPY_AND_ASSIGN(
       FileManagerPrivateInternalSharePathsWithCrostiniFunction);
 };
@@ -351,7 +351,7 @@
 
  private:
   ResponseAction Run() override;
-  void UnsharePathCallback(bool success, std::string failure_reason);
+  void UnsharePathCallback(bool success, const std::string& failure_reason);
   DISALLOW_COPY_AND_ASSIGN(
       FileManagerPrivateInternalUnsharePathWithCrostiniFunction);
 };
diff --git a/chrome/browser/chromeos/file_manager/crostini_file_tasks.cc b/chrome/browser/chromeos/file_manager/crostini_file_tasks.cc
index 4b1ea1f0..c95117e 100644
--- a/chrome/browser/chromeos/file_manager/crostini_file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/crostini_file_tasks.cc
@@ -86,14 +86,14 @@
 
 void OnTaskComplete(FileTaskFinishedCallback done,
                     bool success,
-                    std::string failure_reason) {
+                    const std::string& failure_reason) {
   if (!success) {
     LOG(ERROR) << "Crostini task error: " << failure_reason;
   }
   std::move(done).Run(
       success ? extensions::api::file_manager_private::TASK_RESULT_MESSAGE_SENT
               : extensions::api::file_manager_private::TASK_RESULT_FAILED,
-      std::move(failure_reason));
+      failure_reason);
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 8b2b236..489fe216 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -287,9 +287,8 @@
         TestCase("fileDisplayWithoutVolumes")
             .DontMountVolumes()
             .EnableMyFilesVolume(),
-        // TODO(lucmult): Fix this test with MyFilesVolume flag.
         TestCase("fileDisplayWithoutVolumesThenMountDownloads")
-            .DisableMyFilesVolume()
+            .EnableMyFilesVolume()
             .DontMountVolumes(),
         TestCase("fileDisplayWithoutVolumesThenMountDrive")
             .DontMountVolumes()
@@ -513,7 +512,9 @@
                       TestCase("toolbarDeleteEntry"),
                       // TODO(lucmult): Figure out why this Arc test is failing
                       // with MyFiles.
-                      TestCase("toolbarRefreshButtonWithSelection").EnableArc(),
+                      TestCase("toolbarRefreshButtonWithSelection")
+                          .EnableArc()
+                          .DisableMyFilesVolume(),
                       TestCase("toolbarRefreshButtonHiddenInRecents")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
@@ -604,11 +605,13 @@
         TestCase("dirContextMenuUsbs"),
         TestCase("dirContextMenuFsp"),
         // TODO(lucmult): Fix ARC tests with MyFilesVolume.
-        TestCase("dirContextMenuDocumentsProvider").EnableDocumentsProvider(),
+        TestCase("dirContextMenuDocumentsProvider")
+            .EnableDocumentsProvider()
+            .DisableMyFilesVolume(),
         TestCase("dirContextMenuUsbDcim"),
         TestCase("dirContextMenuMtp"),
         // TODO(lucmult): Fix ARC tests with MyFilesVolume.
-        TestCase("dirContextMenuMediaView").EnableArc(),
+        TestCase("dirContextMenuMediaView").EnableArc().DisableMyFilesVolume(),
         TestCase("dirContextMenuMyDrive"),
         TestCase("dirContextMenuSharedDrive"),
         TestCase("dirContextMenuSharedWithMe"),
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index 17c509b9..8825886a 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -1724,7 +1724,7 @@
 }
 
 bool FileManagerBrowserTestBase::GetEnableMyFilesVolume() const {
-  return false;
+  return true;
 }
 
 bool FileManagerBrowserTestBase::GetEnableDriveFs() const {
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index de1244ff..60afd944 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -44,6 +44,7 @@
 #include "components/drive/drive_api_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/services/app_service/public/cpp/file_handler_info.h"
 #include "extensions/browser/api/file_handlers/mime_util.h"
 #include "extensions/browser/entry_info.h"
 #include "extensions/browser/extension_host.h"
@@ -445,9 +446,8 @@
   return false;
 }
 
-bool IsGoodMatchFileHandler(
-    const extensions::FileHandlerInfo& file_handler_info,
-    const std::vector<extensions::EntryInfo>& entries) {
+bool IsGoodMatchFileHandler(const apps::FileHandlerInfo& file_handler_info,
+                            const std::vector<extensions::EntryInfo>& entries) {
   if (file_handler_info.extensions.count("*") > 0 ||
       file_handler_info.types.count("*") > 0 ||
       file_handler_info.types.count("*/*") > 0)
@@ -517,7 +517,7 @@
     // entries that corresponds to the app. If there doesn't exist such handler,
     // show the first matching handler of the verb.
     for (const auto& handler_match : file_handlers) {
-      const extensions::FileHandlerInfo* handler = handler_match.handler;
+      const apps::FileHandlerInfo* handler = handler_match.handler;
       bool good_match = IsGoodMatchFileHandler(*handler, entries);
       auto it = handlers_for_entries.find(handler->verb);
       if (it == handlers_for_entries.end() ||
@@ -530,7 +530,7 @@
 
     for (const auto& entry : handlers_for_entries) {
       const extensions::FileHandlerMatch* match = entry.second.first;
-      const extensions::FileHandlerInfo* handler = match->handler;
+      const apps::FileHandlerInfo* handler = match->handler;
       std::string task_id = file_tasks::MakeTaskID(
           extension->id(), file_tasks::TASK_TYPE_FILE_HANDLER, handler->id);
 
@@ -544,16 +544,16 @@
       const bool is_generic_file_handler =
           !IsGoodMatchFileHandler(*handler, entries);
       Verb verb;
-      if (handler->verb == extensions::file_handler_verbs::kAddTo) {
+      if (handler->verb == apps::file_handler_verbs::kAddTo) {
         verb = Verb::VERB_ADD_TO;
-      } else if (handler->verb == extensions::file_handler_verbs::kPackWith) {
+      } else if (handler->verb == apps::file_handler_verbs::kPackWith) {
         verb = Verb::VERB_PACK_WITH;
-      } else if (handler->verb == extensions::file_handler_verbs::kShareWith) {
+      } else if (handler->verb == apps::file_handler_verbs::kShareWith) {
         verb = Verb::VERB_SHARE_WITH;
       } else {
         // Only kOpenWith is a valid remaining verb. Invalid verbs should fall
         // back to it.
-        DCHECK(handler->verb == extensions::file_handler_verbs::kOpenWith);
+        DCHECK(handler->verb == apps::file_handler_verbs::kOpenWith);
         verb = Verb::VERB_OPEN_WITH;
       }
       // If the handler was matched purely on the file name extension then
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.h b/chrome/browser/chromeos/file_manager/file_tasks.h
index 3f8d994..fd6b3c6 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.h
+++ b/chrome/browser/chromeos/file_manager/file_tasks.h
@@ -106,6 +106,10 @@
 class PrefService;
 class Profile;
 
+namespace apps {
+struct FileHandlerInfo;
+}
+
 namespace extensions {
 struct EntryInfo;
 }
@@ -266,9 +270,8 @@
                      FileTaskFinishedCallback done);
 
 // Returns true if a file handler matches with entries as good match.
-bool IsGoodMatchFileHandler(
-    const extensions::FileHandlerInfo& file_handler_info,
-    const std::vector<extensions::EntryInfo>& entries);
+bool IsGoodMatchFileHandler(const apps::FileHandlerInfo& file_handler_info,
+                            const std::vector<extensions::EntryInfo>& entries);
 
 // Finds the file handler tasks (apps declaring "file_handlers" in
 // manifest.json) that can be used with the given entries, appending them to
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
index 650d89f..4841ed8 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
@@ -28,6 +28,7 @@
 #include "chromeos/dbus/fake_concierge_client.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
+#include "components/services/app_service/public/cpp/file_handler_info.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/browser/entry_info.h"
 #include "extensions/browser/extension_prefs.h"
@@ -306,7 +307,7 @@
 // Test IsGoodMatchFileHandler which returns whether a file handle info matches
 // with files as good match or not.
 TEST(FileManagerFileTasksTest, IsGoodMatchFileHandler) {
-  using FileHandlerInfo = extensions::FileHandlerInfo;
+  using FileHandlerInfo = apps::FileHandlerInfo;
 
   std::vector<extensions::EntryInfo> entries_1;
   entries_1.emplace_back(base::FilePath(FILE_PATH_LITERAL("foo.jpg")),
diff --git a/chrome/browser/chromeos/guest_os/guest_os_share_path.cc b/chrome/browser/chromeos/guest_os/guest_os_share_path.cc
index 1f0606df..c394234 100644
--- a/chrome/browser/chromeos/guest_os/guest_os_share_path.cc
+++ b/chrome/browser/chromeos/guest_os/guest_os_share_path.cc
@@ -67,7 +67,7 @@
 }
 
 void OnSeneschalUnsharePathResponse(
-    base::OnceCallback<void(bool, std::string)> callback,
+    guest_os::SuccessCallback callback,
     base::Optional<vm_tools::seneschal::UnsharePathResponse> response) {
   if (!response) {
     std::move(callback).Run(false, "System error");
@@ -81,7 +81,7 @@
                     const base::FilePath& cros_path,
                     const base::FilePath& container_path,
                     bool result,
-                    std::string failure_reason) {
+                    const std::string& failure_reason) {
   if (!result) {
     LOG(WARNING) << "Error " << operation << " " << cros_path << ": "
                  << failure_reason;
@@ -91,8 +91,7 @@
 // Barrier Closure that captures the first instance of error.
 class ErrorCapture {
  public:
-  ErrorCapture(int num_callbacks_left,
-               base::OnceCallback<void(bool, std::string)> callback)
+  ErrorCapture(int num_callbacks_left, guest_os::SuccessCallback callback)
       : num_callbacks_left_(num_callbacks_left),
         callback_(std::move(callback)) {
     DCHECK_GE(num_callbacks_left, 0);
@@ -103,7 +102,7 @@
   void Run(const base::FilePath& cros_path,
            const base::FilePath& container_path,
            bool success,
-           std::string failure_reason) {
+           const std::string& failure_reason) {
     if (!success) {
       LOG(WARNING) << "Error SharePath=" << cros_path.value()
                    << ", FailureReason=" << failure_reason;
@@ -119,7 +118,7 @@
 
  private:
   int num_callbacks_left_;
-  base::OnceCallback<void(bool, std::string)> callback_;
+  guest_os::SuccessCallback callback_;
   bool success_ = true;
   std::string first_failure_reason_;
 };  // class
@@ -338,10 +337,9 @@
       base::BindOnce(&OnSeneschalSharePathResponse, std::move(callback)));
 }
 
-void GuestOsSharePath::CallSeneschalUnsharePath(
-    const std::string& vm_name,
-    const base::FilePath& path,
-    base::OnceCallback<void(bool, std::string)> callback) {
+void GuestOsSharePath::CallSeneschalUnsharePath(const std::string& vm_name,
+                                                const base::FilePath& path,
+                                                SuccessCallback callback) {
   vm_tools::seneschal::UnsharePathRequest request;
 
   // Return success if VM is not currently running.
@@ -399,13 +397,12 @@
   CallSeneschalSharePath(vm_name, path, persist, std::move(callback));
 }
 
-void GuestOsSharePath::SharePaths(
-    const std::string& vm_name,
-    std::vector<base::FilePath> paths,
-    bool persist,
-    base::OnceCallback<void(bool, std::string)> callback) {
+void GuestOsSharePath::SharePaths(const std::string& vm_name,
+                                  std::vector<base::FilePath> paths,
+                                  bool persist,
+                                  SuccessCallback callback) {
   base::RepeatingCallback<void(const base::FilePath&, const base::FilePath&,
-                               bool, std::string)>
+                               bool, const std::string&)>
       barrier = base::BindRepeating(
           &ErrorCapture::Run,
           base::Owned(new ErrorCapture(paths.size(), std::move(callback))));
@@ -415,11 +412,10 @@
   }
 }
 
-void GuestOsSharePath::UnsharePath(
-    const std::string& vm_name,
-    const base::FilePath& path,
-    bool unpersist,
-    base::OnceCallback<void(bool, std::string)> callback) {
+void GuestOsSharePath::UnsharePath(const std::string& vm_name,
+                                   const base::FilePath& path,
+                                   bool unpersist,
+                                   SuccessCallback callback) {
   if (auto* info = FindSharedPathInfo(path)) {
     info->vm_names.erase(vm_name);
     if (info->vm_names.empty()) {
@@ -471,9 +467,8 @@
   return result;
 }
 
-void GuestOsSharePath::SharePersistedPaths(
-    const std::string& vm_name,
-    base::OnceCallback<void(bool, std::string)> callback) {
+void GuestOsSharePath::SharePersistedPaths(const std::string& vm_name,
+                                           SuccessCallback callback) {
   SharePaths(vm_name, GetPersistedSharedPaths(vm_name),
              /*persist=*/false, std::move(callback));
 }
diff --git a/chrome/browser/chromeos/guest_os/guest_os_share_path.h b/chrome/browser/chromeos/guest_os/guest_os_share_path.h
index afc7d13..9dae0ae 100644
--- a/chrome/browser/chromeos/guest_os/guest_os_share_path.h
+++ b/chrome/browser/chromeos/guest_os/guest_os_share_path.h
@@ -21,10 +21,14 @@
 #include "chromeos/dbus/seneschal/seneschal_service.pb.h"
 #include "components/keyed_service/core/keyed_service.h"
 
+class PrefService;
 class Profile;
 
 namespace guest_os {
 
+using SuccessCallback =
+    base::OnceCallback<void(bool success, const std::string& failure_reason)>;
+
 struct SharedPathInfo {
   explicit SharedPathInfo(const std::string& vm_name);
   SharedPathInfo(SharedPathInfo&&);
@@ -41,13 +45,13 @@
                          public drivefs::DriveFsHostObserver {
  public:
   using SharePathCallback =
-      base::OnceCallback<void(const base::FilePath&, bool, std::string)>;
+      base::OnceCallback<void(const base::FilePath&, bool, const std::string&)>;
   using SeneschalCallback =
       base::RepeatingCallback<void(const std::string& operation,
                                    const base::FilePath& cros_path,
                                    const base::FilePath& container_path,
                                    bool result,
-                                   std::string failure_reason)>;
+                                   const std::string& failure_reason)>;
   class Observer {
    public:
     virtual void OnUnshare(const std::string& vm_name,
@@ -86,7 +90,7 @@
   void SharePaths(const std::string& vm_name,
                   std::vector<base::FilePath> paths,
                   bool persist,
-                  base::OnceCallback<void(bool, std::string)> callback);
+                  SuccessCallback callback);
 
   // Unshare specified |path| with |vm_name|.  If |unpersist| is set, the path
   // is removed from prefs, and will not be shared at container startup.
@@ -94,7 +98,7 @@
   void UnsharePath(const std::string& vm_name,
                    const base::FilePath& path,
                    bool unpersist,
-                   base::OnceCallback<void(bool, std::string)> callback);
+                   SuccessCallback callback);
 
   // Returns true the first time it is called on this service.
   bool GetAndSetFirstForSession();
@@ -105,9 +109,8 @@
 
   // Share all paths configured in prefs for the specified VM.
   // Called at container startup.  Callback is invoked once complete.
-  void SharePersistedPaths(
-      const std::string& vm_name,
-      base::OnceCallback<void(bool, std::string)> callback);
+  void SharePersistedPaths(const std::string& vm_name,
+                           SuccessCallback callback);
 
   // Save |path| into prefs for |vm_name|.
   void RegisterPersistedPath(const std::string& vm_name,
@@ -145,10 +148,9 @@
                               bool persist,
                               SharePathCallback callback);
 
-  void CallSeneschalUnsharePath(
-      const std::string& vm_name,
-      const base::FilePath& path,
-      base::OnceCallback<void(bool, std::string)> callback);
+  void CallSeneschalUnsharePath(const std::string& vm_name,
+                                const base::FilePath& path,
+                                SuccessCallback callback);
 
   void StartFileWatcher(const base::FilePath& path);
 
diff --git a/chrome/browser/chromeos/guest_os/guest_os_share_path_unittest.cc b/chrome/browser/chromeos/guest_os/guest_os_share_path_unittest.cc
index 9735aeed..a02b6f1 100644
--- a/chrome/browser/chromeos/guest_os/guest_os_share_path_unittest.cc
+++ b/chrome/browser/chromeos/guest_os/guest_os_share_path_unittest.cc
@@ -75,7 +75,7 @@
       const std::string& expected_failure_reason,
       const base::FilePath& container_path,
       bool success,
-      std::string failure_reason) {
+      const std::string& failure_reason) {
     const base::DictionaryValue* prefs =
         profile()->GetPrefs()->GetDictionary(prefs::kGuestOSPathsSharedToVms);
     EXPECT_TRUE(prefs->HasKey(shared_path_.value()));
@@ -122,7 +122,7 @@
       const base::FilePath& cros_path,
       const base::FilePath& container_path,
       bool success,
-      std::string failure_reason) {
+      const std::string& failure_reason) {
     EXPECT_EQ(expected_operation, operation);
     EXPECT_EQ(expected_path, cros_path);
     SharePathCallback(
@@ -132,7 +132,8 @@
         failure_reason);
   }
 
-  void SharePersistedPathsCallback(bool success, std::string failure_reason) {
+  void SharePersistedPathsCallback(bool success,
+                                   const std::string& failure_reason) {
     EXPECT_TRUE(success);
     EXPECT_EQ(profile()
                   ->GetPrefs()
@@ -159,7 +160,7 @@
       Success expected_success,
       const std::string& expected_failure_reason,
       bool success,
-      std::string failure_reason) {
+      const std::string& failure_reason) {
     const base::DictionaryValue* prefs =
         profile()->GetPrefs()->GetDictionary(prefs::kGuestOSPathsSharedToVms);
     if (expected_persist == Persist::YES) {
@@ -190,7 +191,7 @@
       const base::FilePath& cros_path,
       const base::FilePath& container_path,
       bool success,
-      std::string failure_reason) {
+      const std::string& failure_reason) {
     EXPECT_EQ(expected_operation, operation);
     EXPECT_EQ(expected_path, cros_path);
     UnsharePathCallback(cros_path, expected_persist,
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_manager.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_manager.cc
index 23ffdc2..9e90ace 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_manager.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_manager.cc
@@ -330,7 +330,7 @@
     guest_os::GuestOsSharePath::GetForProfile(profile_)->SharePath(
         kPluginVmName, dir, false,
         base::BindOnce([](const base::FilePath& dir, bool success,
-                          std::string failure_reason) {
+                          const std::string& failure_reason) {
           if (!success) {
             LOG(ERROR) << "Error sharing PluginVm default dir " << dir.value()
                        << ": " << failure_reason;
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc
index 34fde93..82466bb 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings.cc
@@ -152,19 +152,6 @@
 }
 
 // static
-void TabSpecificContentSettings::DOMStorageAccessed(int render_process_id,
-                                                    int render_frame_id,
-                                                    const GURL& url,
-                                                    bool local,
-                                                    bool blocked_by_policy) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  TabSpecificContentSettings* settings = GetForFrame(
-      render_process_id, render_frame_id);
-  if (settings)
-    settings->OnLocalStorageAccessed(url, local, blocked_by_policy);
-}
-
-// static
 void TabSpecificContentSettings::IndexedDBAccessed(
     int render_process_id,
     int render_frame_id,
@@ -364,6 +351,24 @@
     content_settings::UpdateLocationBarUiForWebContents(web_contents());
 }
 
+void TabSpecificContentSettings::OnDomStorageAccessed(const GURL& url,
+                                                      bool local,
+                                                      bool blocked_by_policy) {
+  LocalSharedObjectsContainer& container = blocked_by_policy
+                                               ? blocked_local_shared_objects_
+                                               : allowed_local_shared_objects_;
+  CannedBrowsingDataLocalStorageHelper* helper =
+      local ? container.local_storages() : container.session_storages();
+  helper->Add(url::Origin::Create(url));
+
+  if (blocked_by_policy)
+    OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
+  else
+    OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
+
+  NotifySiteDataObservers();
+}
+
 void TabSpecificContentSettings::OnCookiesRead(
     const GURL& url,
     const GURL& frame_url,
@@ -431,24 +436,6 @@
   NotifySiteDataObservers();
 }
 
-void TabSpecificContentSettings::OnLocalStorageAccessed(
-    const GURL& url,
-    bool local,
-    bool blocked_by_policy) {
-  LocalSharedObjectsContainer& container = blocked_by_policy ?
-      blocked_local_shared_objects_ : allowed_local_shared_objects_;
-  CannedBrowsingDataLocalStorageHelper* helper =
-      local ? container.local_storages() : container.session_storages();
-  helper->Add(url::Origin::Create(url));
-
-  if (blocked_by_policy)
-    OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
-  else
-    OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
-
-  NotifySiteDataObservers();
-}
-
 void TabSpecificContentSettings::OnServiceWorkerAccessed(
     const GURL& scope,
     bool blocked_by_policy_javascript,
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.h b/chrome/browser/content_settings/tab_specific_content_settings.h
index 0daf97f..95277f2 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.h
+++ b/chrome/browser/content_settings/tab_specific_content_settings.h
@@ -105,16 +105,6 @@
                                   const GURL& url,
                                   bool blocked_by_policy);
 
-  // Called when a specific DOM storage area in the current page was
-  // accessed. If access was blocked due to the user's content settings,
-  // |blocked_by_policy| should be true, and this function should invoke
-  // OnContentBlocked.
-  static void DOMStorageAccessed(int render_process_id,
-                                 int render_frame_id,
-                                 const GURL& url,
-                                 bool local,
-                                 bool blocked_by_policy);
-
   // Called when a specific indexed db factory in the current page was
   // accessed. If access was blocked due to the user's content settings,
   // |blocked_by_policy| should be true, and this function should invoke
@@ -293,15 +283,18 @@
                                   const base::string16& details);
   void OnContentAllowed(ContentSettingsType type);
 
+  // These methods are invoked on the UI thread forwarded from the
+  // ChromeRenderMessageFilter.
+  void OnDomStorageAccessed(const GURL& url,
+                            bool local,
+                            bool blocked_by_policy);
+
   // These methods are invoked on the UI thread by the static functions above.
   // Only public for tests.
   void OnFileSystemAccessed(const GURL& url,
                             bool blocked_by_policy);
   void OnIndexedDBAccessed(const GURL& url, bool blocked_by_policy);
   void OnCacheStorageAccessed(const GURL& url, bool blocked_by_policy);
-  void OnLocalStorageAccessed(const GURL& url,
-                              bool local,
-                              bool blocked_by_policy);
   void OnServiceWorkerAccessed(const GURL& scope,
                                bool blocked_by_policy_javascript,
                                bool blocked_by_policy_cookie);
diff --git a/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc b/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc
index 8d660db..1380a47b 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc
@@ -263,9 +263,8 @@
                                               blocked_by_policy);
   content_settings->OnIndexedDBAccessed(GURL("http://google.com"),
                                         blocked_by_policy);
-  content_settings->OnLocalStorageAccessed(GURL("http://google.com"),
-                                           true,
-                                           blocked_by_policy);
+  content_settings->OnDomStorageAccessed(GURL("http://google.com"), true,
+                                         blocked_by_policy);
   content_settings->OnWebDatabaseAccessed(GURL("http://google.com"),
                                           blocked_by_policy);
 }
@@ -284,8 +283,8 @@
                                          blocked_by_policy);
   content_settings->OnIndexedDBAccessed(GURL("https://localhost"),
                                         blocked_by_policy);
-  content_settings->OnLocalStorageAccessed(GURL("http://maps.google.com:8080"),
-                                           true, blocked_by_policy);
+  content_settings->OnDomStorageAccessed(GURL("http://maps.google.com:8080"),
+                                         true, blocked_by_policy);
   content_settings->OnWebDatabaseAccessed(GURL("http://192.168.0.1"),
                                           blocked_by_policy);
   content_settings->OnSharedWorkerAccessed(
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host.cc b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
index fa65b8f..4efb28c 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
@@ -107,7 +107,8 @@
           allow_user_level, native_view,
           GetProfilePathIfEnabled(Profile::FromBrowserContext(browser_context),
                                   source_extension_id, native_host_name),
-          /* require_native_initiated_connections = */ false));
+          /* require_native_initiated_connections = */ false,
+          /* connect_id = */ ""));
 }
 
 // static
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
index ddab3fb..8d93459f 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
@@ -315,6 +315,10 @@
   const base::Value* args = nullptr;
   ASSERT_TRUE(last_message_parsed_->Get("args", &args));
   EXPECT_TRUE(args->is_none());
+
+  const base::Value* connect_id_value = nullptr;
+  ASSERT_TRUE(last_message_parsed_->Get("connect_id", &connect_id_value));
+  EXPECT_TRUE(connect_id_value->is_none());
 }
 
 // Test send message with a real client. The args passed when launching the
@@ -425,6 +429,10 @@
   const base::Value* args_value = nullptr;
   ASSERT_TRUE(last_message_parsed_->Get("args", &args_value));
   EXPECT_TRUE(args_value->is_none());
+
+  const base::Value* connect_id_value = nullptr;
+  ASSERT_TRUE(last_message_parsed_->Get("connect_id", &connect_id_value));
+  EXPECT_TRUE(connect_id_value->is_none());
 }
 
 TEST_F(NativeMessagingTest, UserLevel) {
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc b/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
index e8cc9ae6..33042b3 100644
--- a/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
+++ b/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
@@ -92,6 +92,8 @@
       switches::kNativeMessagingConnectHost,
       ScopedTestNativeMessagingHost::
           kSupportsNativeInitiatedConnectionsHostName);
+  command_line.AppendSwitchASCII(switches::kNativeMessagingConnectId,
+                                 "test-connect-id");
 
   StartupBrowserCreator::ProcessCommandLineAlreadyRunning(command_line, {},
                                                           profile()->GetPath());
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc
index eabfae99..d0ccab7 100644
--- a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc
+++ b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/strings/string_util.h"
 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
 #include "chrome/browser/extensions/api/messaging/native_message_process_host.h"
 #include "chrome/browser/extensions/api/messaging/native_process_launcher.h"
@@ -94,9 +95,21 @@
   g_allow_native_app_connection_for_test = nullptr;
 }
 
+bool IsValidConnectionId(const base::StringPiece connection_id) {
+  return connection_id.size() <= 20 &&
+         base::ContainsOnlyChars(
+             connection_id,
+             "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-");
+}
+
 void LaunchNativeMessageHostFromNativeApp(const std::string& extension_id,
                                           const std::string& host_id,
+                                          const std::string& connection_id,
                                           Profile* profile) {
+  if (!IsValidConnectionId(connection_id)) {
+    // TODO(crbug.com/967262): Report errors to the native messaging host.
+    return;
+  }
   if (!ExtensionSupportsConnectionFromNativeApp(extension_id, host_id, profile,
                                                 /* log_errors = */ true)) {
     // TODO(crbug.com/967262): Report errors to the native messaging host.
@@ -112,7 +125,7 @@
       NativeProcessLauncher::CreateDefault(
           /* allow_user_level = */ true, /* native_view = */ nullptr,
           profile->GetPath(),
-          /* require_native_initiated_connections = */ true));
+          /* require_native_initiated_connections = */ true, connection_id));
   auto native_message_port = std::make_unique<extensions::NativeMessagePort>(
       message_service->GetChannelDelegate(), port_id,
       std::move(native_message_host));
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h
index d730422c..2bb10467 100644
--- a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h
+++ b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h
@@ -24,6 +24,7 @@
 // |host_id|.
 void LaunchNativeMessageHostFromNativeApp(const std::string& extension_id,
                                           const std::string& host_id,
+                                          const std::string& connection_id,
                                           Profile* profile);
 
 class ScopedAllowNativeAppConnectionForTest {
diff --git a/chrome/browser/extensions/api/messaging/native_process_launcher.cc b/chrome/browser/extensions/api/messaging/native_process_launcher.cc
index c0d8491b..c5670d60 100644
--- a/chrome/browser/extensions/api/messaging/native_process_launcher.cc
+++ b/chrome/browser/extensions/api/messaging/native_process_launcher.cc
@@ -47,7 +47,8 @@
   NativeProcessLauncherImpl(bool allow_user_level_hosts,
                             intptr_t native_window,
                             const base::FilePath& profile_directory,
-                            bool require_native_initiated_connections);
+                            bool require_native_initiated_connections,
+                            const std::string& connect_id);
   ~NativeProcessLauncherImpl() override;
 
   void Launch(const GURL& origin,
@@ -60,7 +61,8 @@
     Core(bool allow_user_level_hosts,
          intptr_t native_window,
          const base::FilePath& profile_directory,
-         bool require_native_initiated_connections);
+         bool require_native_initiated_connections,
+         const std::string& connect_id);
     void Launch(const GURL& origin,
                 const std::string& native_host_name,
                 const LaunchedCallback& callback);
@@ -91,6 +93,8 @@
     const base::FilePath profile_directory_;
 
     const bool require_native_initiated_connections_;
+
+    const std::string connect_id_;
 #if defined(OS_WIN)
     // Handle of the native window corresponding to the extension.
     intptr_t window_handle_;
@@ -107,12 +111,14 @@
 NativeProcessLauncherImpl::Core::Core(bool allow_user_level_hosts,
                                       intptr_t window_handle,
                                       const base::FilePath& profile_directory,
-                                      bool require_native_initiated_connections)
+                                      bool require_native_initiated_connections,
+                                      const std::string& connect_id)
     : detached_(false),
       allow_user_level_hosts_(allow_user_level_hosts),
       profile_directory_(profile_directory),
       require_native_initiated_connections_(
-          require_native_initiated_connections)
+          require_native_initiated_connections),
+      connect_id_(connect_id)
 #if defined(OS_WIN)
       ,
       window_handle_(window_handle)
@@ -260,6 +266,11 @@
     base::Base64Encode(encoded_reconnect_command, &encoded_reconnect_command);
     command_line.AppendArg(
         base::StrCat({"--reconnect-command=", encoded_reconnect_command}));
+
+    if (!connect_id_.empty()) {
+      command_line.AppendArg(base::StrCat(
+          {"--", switches::kNativeMessagingConnectId, "=", connect_id_}));
+    }
   }
 
   base::Process process;
@@ -314,11 +325,13 @@
     bool allow_user_level_hosts,
     intptr_t window_handle,
     const base::FilePath& profile_directory,
-    bool require_native_initiated_connections)
+    bool require_native_initiated_connections,
+    const std::string& connect_id)
     : core_(new Core(allow_user_level_hosts,
                      window_handle,
                      profile_directory,
-                     require_native_initiated_connections)) {}
+                     require_native_initiated_connections,
+                     connect_id)) {}
 
 NativeProcessLauncherImpl::~NativeProcessLauncherImpl() {
   core_->Detach();
@@ -337,7 +350,8 @@
     bool allow_user_level_hosts,
     gfx::NativeView native_view,
     const base::FilePath& profile_directory,
-    bool require_native_initiated_connections) {
+    bool require_native_initiated_connections,
+    const std::string& connect_id) {
   intptr_t window_handle = 0;
 #if defined(OS_WIN)
   window_handle = reinterpret_cast<intptr_t>(
@@ -345,7 +359,7 @@
 #endif
   return std::make_unique<NativeProcessLauncherImpl>(
       allow_user_level_hosts, window_handle, profile_directory,
-      require_native_initiated_connections);
+      require_native_initiated_connections, connect_id);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/native_process_launcher.h b/chrome/browser/extensions/api/messaging/native_process_launcher.h
index 51102bc..9ee0a8f3 100644
--- a/chrome/browser/extensions/api/messaging/native_process_launcher.h
+++ b/chrome/browser/extensions/api/messaging/native_process_launcher.h
@@ -51,7 +51,8 @@
       bool allow_user_level_hosts,
       gfx::NativeView native_view,
       const base::FilePath& profile_directory,
-      bool require_native_initiated_connections);
+      bool require_native_initiated_connections,
+      const std::string& connect_id);
 
   NativeProcessLauncher() {}
   virtual ~NativeProcessLauncher() {}
diff --git a/chrome/browser/extensions/chrome_extensions_interface_registration.cc b/chrome/browser/extensions/chrome_extensions_interface_registration.cc
index 2f30fb8e..a938a28e 100644
--- a/chrome/browser/extensions/chrome_extensions_interface_registration.cc
+++ b/chrome/browser/extensions/chrome_extensions_interface_registration.cc
@@ -35,10 +35,11 @@
 #include "content/public/browser/media_device_id.h"
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/api/media_perception_private/media_perception_api_delegate.h"
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
-#include "media/capture/video/chromeos/renderer_facing_cros_image_capture.h"
+#include "media/capture/video/chromeos/camera_app_device_provider_impl.h"
+#include "media/capture/video/chromeos/camera_app_helper_impl.h"
+#include "media/capture/video/chromeos/mojom/camera_app.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #endif
@@ -86,17 +87,17 @@
   intent_helper->OnCameraIntentHandled(intent_id, is_success, captured_data);
 }
 
-// Binds CrosImageCaptureRequest to a proxy which translates the source id into
-// video device id and then forward the request to video capture service.
-void BindRendererFacingCrosImageCapture(
-    cros::mojom::CrosImageCaptureRequest request,
+// Connects to CameraAppDeviceProvider which could be used to get
+// CameraAppDevice from video capture service through CameraAppDeviceBridge.
+void ConnectToCameraAppDeviceProvider(
+    cros::mojom::CameraAppDeviceProviderRequest request,
     content::RenderFrameHost* source) {
-  cros::mojom::CrosImageCapturePtr proxy_ptr;
-  auto proxy_request = mojo::MakeRequest(&proxy_ptr);
+  mojo::PendingRemote<cros::mojom::CameraAppDeviceBridge> device_bridge;
+  auto device_bridge_receiver = device_bridge.InitWithNewPipeAndPassReceiver();
 
-  // Bind the interface through the Video Capture service.
-  content::GetVideoCaptureService().BindCrosImageCapture(
-      std::move(proxy_request));
+  // Connects to CameraAppDeviceBridge from video_capture service.
+  content::GetVideoCaptureService().ConnectToCameraAppDeviceBridge(
+      std::move(device_bridge_receiver));
 
   auto security_origin = source->GetLastCommittedOrigin();
   auto media_device_id_salt =
@@ -105,14 +106,22 @@
   auto mapping_callback =
       base::BindRepeating(&TranslateVideoDeviceId, media_device_id_salt,
                           std::move(security_origin));
+
+  auto camera_app_device_provider =
+      std::make_unique<media::CameraAppDeviceProviderImpl>(
+          std::move(device_bridge), std::move(mapping_callback));
+  mojo::MakeStrongBinding(std::move(camera_app_device_provider),
+                          std::move(request));
+}
+
+// Connects to CameraAppHelper that could handle camera intents.
+void ConnectToCameraAppHelper(cros::mojom::CameraAppHelperRequest request,
+                              content::RenderFrameHost* source) {
   auto intent_callback = base::BindRepeating(
       &TriggerCameraIntent, source->GetProcess()->GetBrowserContext());
-
-  // Bind origin request to proxy implementation.
-  auto api_proxy = std::make_unique<media::RendererFacingCrosImageCapture>(
-      std::move(proxy_ptr), std::move(mapping_callback),
-      std::move(intent_callback));
-  mojo::MakeStrongBinding(std::move(api_proxy), std::move(request));
+  auto camera_app_helper =
+      std::make_unique<media::CameraAppHelperImpl>(std::move(intent_callback));
+  mojo::MakeStrongBinding(std::move(camera_app_helper), std::move(request));
 }
 #endif
 
@@ -164,7 +173,8 @@
   if (extension->id().compare(extension_misc::kChromeCameraAppId) == 0 ||
       extension->id().compare(extension_misc::kChromeCameraAppDevId) == 0) {
     registry->AddInterface(
-        base::BindRepeating(&BindRendererFacingCrosImageCapture));
+        base::BindRepeating(&ConnectToCameraAppDeviceProvider));
+    registry->AddInterface(base::BindRepeating(&ConnectToCameraAppHelper));
   }
 #endif
 }
diff --git a/chrome/browser/extensions/convert_web_app.cc b/chrome/browser/extensions/convert_web_app.cc
index 42ab440..882dd14 100644
--- a/chrome/browser/extensions/convert_web_app.cc
+++ b/chrome/browser/extensions/convert_web_app.cc
@@ -62,7 +62,7 @@
     file_handler.SetKey(keys::kFileHandlerIncludeDirectories,
                         base::Value(false));
     file_handler.SetKey(keys::kFileHandlerVerb,
-                        base::Value(extensions::file_handler_verbs::kOpenWith));
+                        base::Value(apps::file_handler_verbs::kOpenWith));
 
     base::Value mime_types(base::Value::Type::LIST);
     base::Value file_extensions(base::Value::Type::LIST);
diff --git a/chrome/browser/extensions/convert_web_app_unittest.cc b/chrome/browser/extensions/convert_web_app_unittest.cc
index 1b90973..452ab737 100644
--- a/chrome/browser/extensions/convert_web_app_unittest.cc
+++ b/chrome/browser/extensions/convert_web_app_unittest.cc
@@ -22,6 +22,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/web_application_info.h"
+#include "components/services/app_service/public/cpp/file_handler_info.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_icon_set.h"
 #include "extensions/common/extension_resource.h"
@@ -449,15 +450,14 @@
 
   ASSERT_TRUE(extension.get());
 
-  const std::vector<extensions::FileHandlerInfo> file_handler_info =
+  const std::vector<apps::FileHandlerInfo> file_handler_info =
       *extensions::FileHandlers::GetFileHandlers(extension.get());
 
   EXPECT_EQ(2u, file_handler_info.size());
 
   EXPECT_EQ("https://graphr.n/open-file/?name=Graph", file_handler_info[0].id);
   EXPECT_FALSE(file_handler_info[0].include_directories);
-  EXPECT_EQ(extensions::file_handler_verbs::kOpenWith,
-            file_handler_info[0].verb);
+  EXPECT_EQ(apps::file_handler_verbs::kOpenWith, file_handler_info[0].verb);
   // Extensions should contain SVG, and only SVG
   EXPECT_THAT(file_handler_info[0].extensions,
               testing::UnorderedElementsAre("svg"));
@@ -467,8 +467,7 @@
 
   EXPECT_EQ("https://graphr.n/open-file/?name=Raw", file_handler_info[1].id);
   EXPECT_FALSE(file_handler_info[1].include_directories);
-  EXPECT_EQ(extensions::file_handler_verbs::kOpenWith,
-            file_handler_info[1].verb);
+  EXPECT_EQ(apps::file_handler_verbs::kOpenWith, file_handler_info[1].verb);
   // Extensions should contain csv, and only csv
   EXPECT_THAT(file_handler_info[1].extensions,
               testing::UnorderedElementsAre("csv"));
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 89660ca..c165a06 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2154,8 +2154,8 @@
   },
   {
     "name": "handwriting-gesture",
-    "owners": [ "shend" ],
-    "expiry_milestone": 76
+    "owners": [ "essential-inputs-team@google.com" ],
+    "expiry_milestone": 80
   },
   {
     "name": "happiness-tracking-surveys-for-desktop",
diff --git a/chrome/browser/media/router/discovery/dial/dial_url_fetcher.h b/chrome/browser/media/router/discovery/dial/dial_url_fetcher.h
index 539611ca..2019a5e4 100644
--- a/chrome/browser/media/router/discovery/dial/dial_url_fetcher.h
+++ b/chrome/browser/media/router/discovery/dial/dial_url_fetcher.h
@@ -11,6 +11,7 @@
 
 #include "base/callback.h"
 #include "base/optional.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
index a28f8567..4747ab690 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
@@ -384,6 +384,16 @@
                                     blocked_by_policy);
 }
 
+void MetricsWebContentsObserver::OnDomStorageAccessed(
+    const GURL& url,
+    const GURL& first_party_url,
+    bool local,
+    bool blocked_by_policy) {
+  if (committed_load_)
+    committed_load_->OnDomStorageAccessed(url, first_party_url, local,
+                                          blocked_by_policy);
+}
+
 const PageLoadExtraInfo
 MetricsWebContentsObserver::GetPageLoadExtraInfoForCommittedLoad() {
   DCHECK(committed_load_);
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.h b/chrome/browser/page_load_metrics/metrics_web_contents_observer.h
index 716571c7..7059633 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.h
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.h
@@ -126,6 +126,12 @@
                       const net::CanonicalCookie& cookie,
                       bool blocked_by_policy) override;
 
+  // These methods are forwarded from the ChromeRenderMessageFilter.
+  void OnDomStorageAccessed(const GURL& url,
+                            const GURL& first_party_url,
+                            bool local,
+                            bool blocked_by_policy);
+
   // These methods are forwarded from the MetricsNavigationThrottle.
   void WillStartNavigationRequest(content::NavigationHandle* navigation_handle);
   void WillProcessNavigationResponse(
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
index ca533579..35fc5bf69 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
@@ -145,6 +145,15 @@
                                 blocked_by_policy);
 }
 
+void PageLoadMetricsObserverTestHarness::SimulateDomStorageAccess(
+    const GURL& url,
+    const GURL& first_party_url,
+    bool local,
+    bool blocked_by_policy) {
+  tester_->SimulateDomStorageAccess(url, first_party_url, local,
+                                    blocked_by_policy);
+}
+
 const base::HistogramTester&
 PageLoadMetricsObserverTestHarness::histogram_tester() const {
   return histogram_tester_;
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
index 83f94bc..e50121229 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
@@ -124,6 +124,12 @@
                             const net::CanonicalCookie& cookie,
                             bool blocked_by_policy);
 
+  // Simulate accessing the local storage or session storage.
+  void SimulateDomStorageAccess(const GURL& url,
+                                const GURL& first_party_url,
+                                bool local,
+                                bool blocked_by_policy);
+
   const base::HistogramTester& histogram_tester() const;
 
   MetricsWebContentsObserver* observer() const;
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc
index d6aad600d..203f491 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc
@@ -251,6 +251,15 @@
   observer_->OnCookieChange(url, first_party_url, cookie, blocked_by_policy);
 }
 
+void PageLoadMetricsObserverTester::SimulateDomStorageAccess(
+    const GURL& url,
+    const GURL& first_party_url,
+    bool local,
+    bool blocked_by_policy) {
+  observer_->OnDomStorageAccessed(url, first_party_url, local,
+                                  blocked_by_policy);
+}
+
 MetricsWebContentsObserver* PageLoadMetricsObserverTester::observer() const {
   return observer_;
 }
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.h b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.h
index dcca3d6..7f8d7504 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.h
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.h
@@ -101,6 +101,12 @@
                             const net::CanonicalCookie& cookie,
                             bool blocked_by_policy);
 
+  // Simulate accessing the local storage or session storage.
+  void SimulateDomStorageAccess(const GURL& url,
+                                const GURL& first_party_url,
+                                bool local,
+                                bool blocked_by_policy);
+
   MetricsWebContentsObserver* observer() const;
 
   // Gets the PageLoadExtraInfo for the committed_load_ in observer_.
diff --git a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc
index 50fc3a8..19c5322 100644
--- a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc
@@ -19,6 +19,18 @@
   }
 }
 
+ThirdPartyMetricsObserver::StorageAccessTypes::StorageAccessTypes(
+    StorageType storage_type) {
+  switch (storage_type) {
+    case StorageType::kLocalStorage:
+      local_storage = true;
+      break;
+    case StorageType::kSessionStorage:
+      session_storage = true;
+      break;
+  }
+}
+
 ThirdPartyMetricsObserver::ThirdPartyMetricsObserver() = default;
 ThirdPartyMetricsObserver::~ThirdPartyMetricsObserver() = default;
 
@@ -54,12 +66,47 @@
   OnCookieAccess(url, first_party_url, blocked_by_policy, AccessType::kWrite);
 }
 
+void ThirdPartyMetricsObserver::OnDomStorageAccessed(
+    const GURL& url,
+    const GURL& first_party_url,
+    bool local,
+    bool blocked_by_policy) {
+  if (blocked_by_policy) {
+    // When 3p DOM storage access is blocked, it must be that the "block third
+    // party cookies" setting is set. In this case we don't want to record any
+    // metrics for the page.
+    should_record_metrics_ = false;
+    return;
+  }
+  url::Origin origin = url::Origin::Create(url);
+  if (origin.IsSameOriginWith(url::Origin::Create(first_party_url)))
+    return;
+
+  auto it = third_party_storage_access_types_.find(origin);
+
+  if (it != third_party_storage_access_types_.end()) {
+    if (local)
+      it->second.local_storage = true;
+    else
+      it->second.session_storage = true;
+    return;
+  }
+
+  // Don't let the map grow unbounded.
+  if (third_party_storage_access_types_.size() >= 1000)
+    return;
+
+  third_party_storage_access_types_.emplace(
+      origin,
+      local ? StorageType::kLocalStorage : StorageType::kSessionStorage);
+}
+
 void ThirdPartyMetricsObserver::OnCookieAccess(const GURL& url,
                                                const GURL& first_party_url,
                                                bool blocked_by_policy,
                                                AccessType access_type) {
   if (blocked_by_policy) {
-    page_has_blocked_cookies_ = true;
+    should_record_metrics_ = false;
     return;
   }
 
@@ -78,9 +125,9 @@
   if (registrable_domain.empty())
     return;
 
-  auto it = third_party_access_types_.find(registrable_domain);
+  auto it = third_party_cookie_access_types_.find(registrable_domain);
 
-  if (it != third_party_access_types_.end()) {
+  if (it != third_party_cookie_access_types_.end()) {
     switch (access_type) {
       case AccessType::kRead:
         it->second.read = true;
@@ -93,24 +140,39 @@
   }
 
   // Don't let the map grow unbounded.
-  if (third_party_access_types_.size() >= 1000)
+  if (third_party_cookie_access_types_.size() >= 1000)
     return;
 
-  third_party_access_types_.emplace(registrable_domain, access_type);
+  third_party_cookie_access_types_.emplace(registrable_domain, access_type);
 }
 
 void ThirdPartyMetricsObserver::RecordMetrics() {
-  if (page_has_blocked_cookies_)
+  if (!should_record_metrics_)
     return;
 
-  int origin_reads = 0;
-  int origin_writes = 0;
-  for (auto it : third_party_access_types_) {
-    origin_reads += it.second.read;
-    origin_writes += it.second.write;
+  int cookie_origin_reads = 0;
+  int cookie_origin_writes = 0;
+  int local_storage_origin_access = 0;
+  int session_storage_origin_access = 0;
+
+  for (auto it : third_party_cookie_access_types_) {
+    cookie_origin_reads += it.second.read;
+    cookie_origin_writes += it.second.write;
   }
-  UMA_HISTOGRAM_COUNTS_1000("PageLoad.Clients.ThirdParty.Origins.Read",
-                            origin_reads);
-  UMA_HISTOGRAM_COUNTS_1000("PageLoad.Clients.ThirdParty.Origins.Write",
-                            origin_writes);
+
+  for (auto it : third_party_storage_access_types_) {
+    local_storage_origin_access += it.second.local_storage;
+    session_storage_origin_access += it.second.session_storage;
+  }
+
+  UMA_HISTOGRAM_COUNTS_1000("PageLoad.Clients.ThirdParty.Origins.CookieRead",
+                            cookie_origin_reads);
+  UMA_HISTOGRAM_COUNTS_1000("PageLoad.Clients.ThirdParty.Origins.CookieWrite",
+                            cookie_origin_writes);
+  UMA_HISTOGRAM_COUNTS_1000(
+      "PageLoad.Clients.ThirdParty.Origins.LocalStorageAccess",
+      local_storage_origin_access);
+  UMA_HISTOGRAM_COUNTS_1000(
+      "PageLoad.Clients.ThirdParty.Origins.SessionStorageAccess",
+      session_storage_origin_access);
 }
diff --git a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.h b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.h
index 235cc149..d58221a 100644
--- a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.h
@@ -35,6 +35,10 @@
                       const GURL& first_party_url,
                       const net::CanonicalCookie& cookie,
                       bool blocked_by_policy) override;
+  void OnDomStorageAccessed(const GURL& url,
+                            const GURL& first_party_url,
+                            bool local,
+                            bool blocked_by_policy) override;
 
  private:
   enum class AccessType { kRead, kWrite };
@@ -45,6 +49,14 @@
     bool write = false;
   };
 
+  enum class StorageType { kLocalStorage, kSessionStorage };
+
+  struct StorageAccessTypes {
+    explicit StorageAccessTypes(StorageType storage_type);
+    bool local_storage = false;
+    bool session_storage = false;
+  };
+
   void OnCookieAccess(const GURL& url,
                       const GURL& first_party_url,
                       bool blocked_by_policy,
@@ -57,12 +69,17 @@
   // happens when the URL request's registrable domain differs from the main
   // frame's. URLs which have no registrable domain are not considered third
   // party.
-  std::map<std::string, CookieAccessTypes> third_party_access_types_;
+  std::map<std::string, CookieAccessTypes> third_party_cookie_access_types_;
 
-  // If the page has any blocked_by_policy cookie reads or writes (e.g., block
-  // third-party cookies is enabled) then we don't want to record any cookie
+  // A map of third parties that have accessed storage other than cookies. A
+  // third party access happens when the context's origin differs from the main
+  // frame's.
+  std::map<url::Origin, StorageAccessTypes> third_party_storage_access_types_;
+
+  // If the page has any blocked_by_policy cookie or DOM storage access (e.g.,
+  // block third-party cookies is enabled) then we don't want to record any
   // metrics for the page.
-  bool page_has_blocked_cookies_ = false;
+  bool should_record_metrics_ = true;
 
   DISALLOW_COPY_AND_ASSIGN(ThirdPartyMetricsObserver);
 };
diff --git a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc
index ab0b228a9..afc7615 100644
--- a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc
@@ -14,9 +14,14 @@
 
 namespace {
 
-const char kReadCookieHistogram[] = "PageLoad.Clients.ThirdParty.Origins.Read";
+const char kReadCookieHistogram[] =
+    "PageLoad.Clients.ThirdParty.Origins.CookieRead";
 const char kWriteCookieHistogram[] =
-    "PageLoad.Clients.ThirdParty.Origins.Write";
+    "PageLoad.Clients.ThirdParty.Origins.CookieWrite";
+const char kAccessLocalStorageHistogram[] =
+    "PageLoad.Clients.ThirdParty.Origins.LocalStorageAccess";
+const char kAccessSessionStorageHistogram[] =
+    "PageLoad.Clients.ThirdParty.Origins.SessionStorageAccess";
 
 class ThirdPartyMetricsObserverBrowserTest : public InProcessBrowserTest {
  protected:
@@ -39,22 +44,25 @@
 
   void NavigateFrameTo(const std::string& host, const std::string& path) {
     GURL page = embedded_test_server()->GetURL(host, path);
-    content::WebContents* web_contents =
-        browser()->tab_strip_model()->GetActiveWebContents();
-    EXPECT_TRUE(NavigateIframeToURL(web_contents, "test", page));
+    EXPECT_TRUE(NavigateIframeToURL(web_contents(), "test", page));
+  }
+
+  content::WebContents* web_contents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
   }
 
   DISALLOW_COPY_AND_ASSIGN(ThirdPartyMetricsObserverBrowserTest);
 };
 
-IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest,
-                       NoCookiesReadOrWritten) {
+IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest, NoStorageEvent) {
   base::HistogramTester histogram_tester;
   NavigateToPageWithFrame("a.com");
   NavigateToUntrackedUrl();
 
   histogram_tester.ExpectUniqueSample(kReadCookieHistogram, 0, 1);
   histogram_tester.ExpectUniqueSample(kWriteCookieHistogram, 0, 1);
+  histogram_tester.ExpectUniqueSample(kAccessLocalStorageHistogram, 0, 1);
+  histogram_tester.ExpectUniqueSample(kAccessSessionStorageHistogram, 0, 1);
 }
 
 IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest,
@@ -99,10 +107,8 @@
   base::HistogramTester histogram_tester;
   NavigateToPageWithFrame("a.com");  // Same origin cookie read.
   NavigateFrameTo("a.com", "/empty.html");
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
   content::RenderFrameHost* frame =
-      ChildFrameAt(web_contents->GetMainFrame(), 0);
+      ChildFrameAt(web_contents()->GetMainFrame(), 0);
 
   // Write a first-party cookie.
   EXPECT_TRUE(content::ExecJs(frame, "document.cookie = 'foo=bar';"));
@@ -120,10 +126,8 @@
   base::HistogramTester histogram_tester;
   NavigateToPageWithFrame("a.com");  // Same origin cookie read.
   NavigateFrameTo("b.com", "/empty.html");
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
   content::RenderFrameHost* frame =
-      ChildFrameAt(web_contents->GetMainFrame(), 0);
+      ChildFrameAt(web_contents()->GetMainFrame(), 0);
 
   // Write a third-party cookie.
   EXPECT_TRUE(content::ExecJs(frame, "document.cookie = 'foo=bar';"));
@@ -141,10 +145,8 @@
   base::HistogramTester histogram_tester;
   NavigateToPageWithFrame("a.com");  // Same origin cookie read.
   NavigateFrameTo("b.com", "/empty.html");
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
   content::RenderFrameHost* frame =
-      ChildFrameAt(web_contents->GetMainFrame(), 0);
+      ChildFrameAt(web_contents()->GetMainFrame(), 0);
 
   // Read a third-party cookie.
   EXPECT_TRUE(content::ExecJs(frame, "let x = document.cookie;"));
@@ -160,10 +162,8 @@
   base::HistogramTester histogram_tester;
   NavigateToPageWithFrame("a.com");  // Same origin cookie read.
   NavigateFrameTo("b.com", "/empty.html");
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
   content::RenderFrameHost* frame =
-      ChildFrameAt(web_contents->GetMainFrame(), 0);
+      ChildFrameAt(web_contents()->GetMainFrame(), 0);
 
   // Write a third-party cookie.
   EXPECT_TRUE(content::ExecJs(frame, "document.cookie = 'foo=bar';"));
@@ -173,4 +173,82 @@
   histogram_tester.ExpectUniqueSample(kWriteCookieHistogram, 1, 1);
 }
 
+class ThirdPartyDomStorageAccessMetricsObserverBrowserTest
+    : public ThirdPartyMetricsObserverBrowserTest,
+      public ::testing::WithParamInterface<bool /* is_local_access */> {
+ public:
+  void InvokeStorageAccessOnFrame(content::RenderFrameHost* frame) const {
+    if (GetParam()) {
+      EXPECT_TRUE(content::ExecJs(frame, "window.localStorage;"));
+    } else {
+      EXPECT_TRUE(content::ExecJs(frame, "window.sessionStorage;"));
+    }
+  }
+
+  const char* DomStorageHistogramName() const {
+    return GetParam() ? kAccessLocalStorageHistogram
+                      : kAccessSessionStorageHistogram;
+  }
+};
+
+IN_PROC_BROWSER_TEST_P(ThirdPartyDomStorageAccessMetricsObserverBrowserTest,
+                       FirstPartyDomStorageAccess) {
+  base::HistogramTester histogram_tester;
+  NavigateToPageWithFrame("a.com");
+  NavigateFrameTo("a.com", "/empty.html");
+  InvokeStorageAccessOnFrame(ChildFrameAt(web_contents()->GetMainFrame(), 0));
+
+  NavigateToUntrackedUrl();
+
+  histogram_tester.ExpectUniqueSample(DomStorageHistogramName(), 0, 1);
+}
+
+IN_PROC_BROWSER_TEST_P(ThirdPartyDomStorageAccessMetricsObserverBrowserTest,
+                       ThirdPartyDomStorageAccess) {
+  base::HistogramTester histogram_tester;
+  NavigateToPageWithFrame("a.com");
+  NavigateFrameTo("b.com", "/empty.html");
+  InvokeStorageAccessOnFrame(ChildFrameAt(web_contents()->GetMainFrame(), 0));
+
+  NavigateToUntrackedUrl();
+
+  histogram_tester.ExpectUniqueSample(DomStorageHistogramName(), 1, 1);
+}
+
+IN_PROC_BROWSER_TEST_P(ThirdPartyDomStorageAccessMetricsObserverBrowserTest,
+                       DuplicateThirdPartyDomStorageAccess) {
+  base::HistogramTester histogram_tester;
+  NavigateToPageWithFrame("a.com");
+  NavigateFrameTo("b.com", "/empty.html");
+  InvokeStorageAccessOnFrame(ChildFrameAt(web_contents()->GetMainFrame(), 0));
+
+  NavigateFrameTo("c.com", "/empty.html");
+  NavigateFrameTo("b.com", "/empty.html");
+  InvokeStorageAccessOnFrame(ChildFrameAt(web_contents()->GetMainFrame(), 0));
+
+  NavigateToUntrackedUrl();
+
+  histogram_tester.ExpectUniqueSample(DomStorageHistogramName(), 1, 1);
+}
+
+IN_PROC_BROWSER_TEST_P(ThirdPartyDomStorageAccessMetricsObserverBrowserTest,
+                       MultipleThirdPartyDomStorageAccess) {
+  base::HistogramTester histogram_tester;
+  NavigateToPageWithFrame("a.com");
+  NavigateFrameTo("b.com", "/empty.html");
+  InvokeStorageAccessOnFrame(ChildFrameAt(web_contents()->GetMainFrame(), 0));
+
+  NavigateFrameTo("c.com", "/empty.html");
+  InvokeStorageAccessOnFrame(ChildFrameAt(web_contents()->GetMainFrame(), 0));
+
+  NavigateToUntrackedUrl();
+
+  histogram_tester.ExpectUniqueSample(DomStorageHistogramName(), 2, 1);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    /* no prefix */,
+    ThirdPartyDomStorageAccessMetricsObserverBrowserTest,
+    ::testing::Values(false, true));
+
 }  // namespace
diff --git a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_unittest.cc
index 0ab6f12..f6c0bbd 100644
--- a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_unittest.cc
@@ -9,9 +9,14 @@
 #include "net/cookies/canonical_cookie.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-const char kReadCookieHistogram[] = "PageLoad.Clients.ThirdParty.Origins.Read";
+const char kReadCookieHistogram[] =
+    "PageLoad.Clients.ThirdParty.Origins.CookieRead";
 const char kWriteCookieHistogram[] =
-    "PageLoad.Clients.ThirdParty.Origins.Write";
+    "PageLoad.Clients.ThirdParty.Origins.CookieWrite";
+const char kAccessLocalStorageHistogram[] =
+    "PageLoad.Clients.ThirdParty.Origins.LocalStorageAccess";
+const char kAccessSessionStorageHistogram[] =
+    "PageLoad.Clients.ThirdParty.Origins.SessionStorageAccess";
 
 class ThirdPartyMetricsObserverTest
     : public page_load_metrics::PageLoadMetricsObserverTestHarness {
@@ -206,3 +211,122 @@
   histogram_tester().ExpectUniqueSample(kReadCookieHistogram, 1, 1);
   histogram_tester().ExpectUniqueSample(kWriteCookieHistogram, 1, 1);
 }
+
+TEST_F(ThirdPartyMetricsObserverTest, NoDomStorageAccess_NoneRecorded) {
+  NavigateAndCommit(GURL("https://top.com"));
+  NavigateToUntrackedUrl();
+
+  histogram_tester().ExpectUniqueSample(kAccessLocalStorageHistogram, 0, 1);
+  histogram_tester().ExpectUniqueSample(kAccessSessionStorageHistogram, 0, 1);
+}
+
+TEST_F(ThirdPartyMetricsObserverTest,
+       LocalAndSessionStorageAccess_BothRecorded) {
+  NavigateAndCommit(GURL("https://top.com"));
+
+  SimulateDomStorageAccess(GURL("https://a.com"), GURL("https://top.com"),
+                           true /* local */, false /* blocked_by_policy */);
+  SimulateDomStorageAccess(GURL("https://a.com"), GURL("https://top.com"),
+                           false /* local */, false /* blocked_by_policy */);
+  NavigateToUntrackedUrl();
+
+  histogram_tester().ExpectUniqueSample(kAccessLocalStorageHistogram, 1, 1);
+  histogram_tester().ExpectUniqueSample(kAccessSessionStorageHistogram, 1, 1);
+}
+
+class ThirdPartyDomStorageAccessMetricsObserverTest
+    : public ThirdPartyMetricsObserverTest,
+      public ::testing::WithParamInterface<bool /* is_local_access */> {
+ public:
+  bool IsLocal() const { return GetParam(); }
+
+  const char* DomStorageHistogramName() const {
+    return IsLocal() ? kAccessLocalStorageHistogram
+                     : kAccessSessionStorageHistogram;
+  }
+};
+
+TEST_P(ThirdPartyDomStorageAccessMetricsObserverTest,
+       BlockedDomStorageAccess_NotRecorded) {
+  NavigateAndCommit(GURL("https://top.com"));
+
+  // If there are any blocked_by_policy access, nothing should be recorded. Even
+  // if there are subsequent non-blocked third-party access.
+  SimulateDomStorageAccess(GURL("https://a.com"), GURL("https://top.com"),
+                           IsLocal(), true /* blocked_by_policy */);
+  SimulateDomStorageAccess(GURL("https://a.com"), GURL("https://top.com"),
+                           IsLocal(), false /* blocked_by_policy */);
+
+  NavigateToUntrackedUrl();
+
+  histogram_tester().ExpectTotalCount(DomStorageHistogramName(), 0);
+}
+
+TEST_P(ThirdPartyDomStorageAccessMetricsObserverTest,
+       NoRegistrableDomainDomStorageAccess_OneRecorded) {
+  NavigateAndCommit(GURL("https://top.com"));
+
+  SimulateDomStorageAccess(GURL("data:,Hello%2C%20World!"),
+                           GURL("https://top.com"), IsLocal(),
+                           false /* blocked_by_policy */);
+  NavigateToUntrackedUrl();
+
+  histogram_tester().ExpectUniqueSample(DomStorageHistogramName(), 1, 1);
+}
+
+TEST_P(ThirdPartyDomStorageAccessMetricsObserverTest,
+       OnlyFirstPartyDomStorageAccess_NotRecorded) {
+  NavigateAndCommit(GURL("https://top.com"));
+
+  SimulateDomStorageAccess(GURL("https://top.com"), GURL("https://top.com"),
+                           IsLocal(), false /* blocked_by_policy */);
+  NavigateToUntrackedUrl();
+
+  histogram_tester().ExpectUniqueSample(DomStorageHistogramName(), 0, 1);
+}
+
+TEST_P(ThirdPartyDomStorageAccessMetricsObserverTest,
+       OneDomStorageAccess_OneRecorded) {
+  NavigateAndCommit(GURL("https://top.com"));
+
+  SimulateDomStorageAccess(GURL("https://a.com"), GURL("https://top.com"),
+                           IsLocal(), false /* blocked_by_policy */);
+  NavigateToUntrackedUrl();
+
+  histogram_tester().ExpectUniqueSample(DomStorageHistogramName(), 1, 1);
+}
+
+TEST_P(ThirdPartyDomStorageAccessMetricsObserverTest,
+       SameRegistrableDomainDifferentOrigin_TwoRecorded) {
+  NavigateAndCommit(GURL("https://top.com"));
+
+  SimulateDomStorageAccess(GURL("https://a.com"), GURL("https://top.com"),
+                           IsLocal(), false /* blocked_by_policy */);
+  SimulateDomStorageAccess(GURL("https://sub.a.com"), GURL("https://top.com"),
+                           IsLocal(), false /* blocked_by_policy */);
+
+  NavigateToUntrackedUrl();
+
+  histogram_tester().ExpectUniqueSample(DomStorageHistogramName(), 2, 1);
+}
+
+TEST_P(ThirdPartyDomStorageAccessMetricsObserverTest,
+       DomStorageAccessMultipleThirdParties_MultipleRecorded) {
+  NavigateAndCommit(GURL("https://top.com"));
+
+  // Simulate third-party DOM storage access from two different origins.
+  SimulateDomStorageAccess(GURL("https://a.com"), GURL("https://top.com"),
+                           IsLocal(), false /* blocked_by_policy */);
+  SimulateDomStorageAccess(GURL("https://a.com"), GURL("https://top.com"),
+                           IsLocal(), false /* blocked_by_policy */);
+  SimulateDomStorageAccess(GURL("https://b.com"), GURL("https://top.com"),
+                           IsLocal(), false /* blocked_by_policy */);
+  NavigateToUntrackedUrl();
+
+  histogram_tester().ExpectUniqueSample(DomStorageHistogramName(), 2, 1);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    /* no prefix */,
+    ThirdPartyDomStorageAccessMetricsObserverTest,
+    ::testing::Values(false, true));
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.h b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
index 69a55be..b1167b0 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
@@ -546,6 +546,13 @@
                               const net::CanonicalCookie& cookie,
                               bool blocked_by_policy) {}
 
+  // Called when a DOM storage is accessed via Window.localStorage or
+  // Window.sessionStorage.
+  virtual void OnDomStorageAccessed(const GURL& url,
+                                    const GURL& first_party_url,
+                                    bool local,
+                                    bool blocked_by_policy) {}
+
   // Called when the event corresponding to |event_key| occurs in this page
   // load.
   virtual void OnEventOccurred(const void* const event_key) {}
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc
index fefd7c5..894646c 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.cc
+++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -494,6 +494,16 @@
   }
 }
 
+void PageLoadTracker::OnDomStorageAccessed(const GURL& url,
+                                           const GURL& first_party_url,
+                                           bool local,
+                                           bool blocked_by_policy) {
+  for (const auto& observer : observers_) {
+    observer->OnDomStorageAccessed(url, first_party_url, local,
+                                   blocked_by_policy);
+  }
+}
+
 void PageLoadTracker::StopTracking() {
   did_stop_tracking_ = true;
   observers_.clear();
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.h b/chrome/browser/page_load_metrics/page_load_tracker.h
index 845f948..fca4839 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.h
+++ b/chrome/browser/page_load_metrics/page_load_tracker.h
@@ -274,6 +274,11 @@
                       const net::CanonicalCookie& cookie,
                       bool blocked_by_policy);
 
+  void OnDomStorageAccessed(const GURL& url,
+                            const GURL& first_party_url,
+                            bool local,
+                            bool blocked_by_policy);
+
   // Signals that we should stop tracking metrics for the associated page load.
   // We may stop tracking a page load if it doesn't meet the criteria for
   // tracking metrics in DidFinishNavigation.
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index 8aee10f4..7ec6253 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
+#include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
 #include "chrome/browser/predictors/loading_predictor.h"
 #include "chrome/browser/predictors/loading_predictor_factory.h"
 #include "chrome/browser/predictors/preconnect_manager.h"
@@ -47,6 +48,33 @@
 
 namespace {
 
+void OnDomStorageAccessedUI(int process_id,
+                            int routing_id,
+                            const GURL& origin_url,
+                            const GURL& top_origin_url,
+                            bool local,
+                            bool blocked_by_policy) {
+  content::RenderFrameHost* frame =
+      content::RenderFrameHost::FromID(process_id, routing_id);
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(frame);
+
+  if (!web_contents)
+    return;
+
+  TabSpecificContentSettings* tab_settings =
+      TabSpecificContentSettings::FromWebContents(web_contents);
+  if (tab_settings)
+    tab_settings->OnDomStorageAccessed(origin_url, local, blocked_by_policy);
+
+  page_load_metrics::MetricsWebContentsObserver* metrics_observer =
+      page_load_metrics::MetricsWebContentsObserver::FromWebContents(
+          web_contents);
+  if (metrics_observer)
+    metrics_observer->OnDomStorageAccessed(origin_url, top_origin_url, local,
+                                           blocked_by_policy);
+}
+
 const uint32_t kRenderFilteredMessageClasses[] = {
     ChromeMsgStart, NetworkHintsMsgStart,
 };
@@ -196,8 +224,8 @@
       cookie_settings_->IsCookieAccessAllowed(origin_url, top_origin_url);
   // Record access to DOM storage for potential display in UI.
   base::PostTask(FROM_HERE, {BrowserThread::UI},
-                 base::BindOnce(&TabSpecificContentSettings::DOMStorageAccessed,
-                                render_process_id_, render_frame_id, origin_url,
+                 base::BindOnce(&OnDomStorageAccessedUI, render_process_id_,
+                                render_frame_id, origin_url, top_origin_url,
                                 local, !*allowed));
 }
 
diff --git a/chrome/browser/resources/chromeos/camera/BUILD.gn b/chrome/browser/resources/chromeos/camera/BUILD.gn
index 0804b35..4a2a774 100644
--- a/chrome/browser/resources/chromeos/camera/BUILD.gn
+++ b/chrome/browser/resources/chromeos/camera/BUILD.gn
@@ -232,17 +232,21 @@
 copy("chrome_camera_app_mojo_generated") {
   sources = [
     "$root_gen_dir/media/capture/mojom/image_capture.mojom-lite.js",
+    "$root_gen_dir/media/capture/video/chromeos/mojom/camera_app.mojom-lite.js",
     "$root_gen_dir/media/capture/video/chromeos/mojom/camera_common.mojom-lite.js",
     "$root_gen_dir/media/capture/video/chromeos/mojom/camera_metadata.mojom-lite.js",
     "$root_gen_dir/media/capture/video/chromeos/mojom/camera_metadata_tags.mojom-lite.js",
-    "$root_gen_dir/media/capture/video/chromeos/mojom/cros_image_capture.mojom-lite.js",
     "$root_gen_dir/mojo/public/js/mojo_bindings_lite.js",
+    "$root_gen_dir/ui/gfx/geometry/mojom/geometry.mojom-lite.js",
+    "$root_gen_dir/ui/gfx/range/mojom/range.mojom-lite.js",
   ]
 
   deps = [
     "//media/capture/mojom:image_capture_js",
     "//media/capture/video/chromeos/mojom:cros_camera_js",
     "//mojo/public/js:bindings_lite",
+    "//ui/gfx/geometry/mojom:mojom_js",
+    "//ui/gfx/range/mojom:mojom_js",
   ]
 
   outputs = [
diff --git a/chrome/browser/resources/chromeos/camera/camera_resources.grd b/chrome/browser/resources/chromeos/camera/camera_resources.grd
index f4da463..a4c245a5 100644
--- a/chrome/browser/resources/chromeos/camera/camera_resources.grd
+++ b/chrome/browser/resources/chromeos/camera/camera_resources.grd
@@ -68,8 +68,8 @@
           file="${root_gen_dir}/media/capture/video/chromeos/mojom/camera_metadata_tags.mojom-lite.js"
           use_base_dir="false"
           type="BINDATA"/>
-      <include name="IDR_CAMERA_CROS_IMAGE_CAPTURE_MOJOM_LITE_JS"
-          file="${root_gen_dir}/media/capture/video/chromeos/mojom/cros_image_capture.mojom-lite.js"
+      <include name="IDR_CAMERA_APP_MOJOM_LITE_JS"
+          file="${root_gen_dir}/media/capture/video/chromeos/mojom/camera_app.mojom-lite.js"
           use_base_dir="false"
           type="BINDATA"/>
 
diff --git a/chrome/browser/resources/chromeos/camera/src/js/mojo/imagecapture.js b/chrome/browser/resources/chromeos/camera/src/js/mojo/imagecapture.js
index 78ab374..59846c9d 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/mojo/imagecapture.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/mojo/imagecapture.js
@@ -25,32 +25,80 @@
 cca.mojo.PhotoCapabilities.prototype.supportedEffects;
 
 /**
- * The mojo interface of CrOS Image Capture API. It provides a singleton
+ * The mojo interface of CrOS Camera App API. It provides a singleton
  * instance.
  */
 cca.mojo.MojoInterface = class {
   /** @public */
   constructor() {
     /**
-     * @type {cros.mojom.CrosImageCaptureRemote} A interface remote that used to
-     *     construct the mojo interface.
+     * @type {cros.mojom.CameraAppDeviceProviderRemote} An interface remote that
+     *     used to construct the mojo interface.
      */
-    this.remote = cros.mojom.CrosImageCapture.getRemote();
+    this.deviceProvider = cros.mojom.CameraAppDeviceProvider.getRemote();
+
+    /**
+     * @type {Map<string, Promise<cros.mojom.CameraAppDeviceRemote>>} A map
+     *     that stores the promise of remote that could be used to communicate
+     *     with camera device through mojo interface.
+     */
+    this.devices_ = new Map();
   }
 
   /**
-   * Gets the mojo interface remote which could be used to communicate with
-   * Chrome.
-   * @return {cros.mojom.CrosImageCaptureRemote} The mojo interface remote.
+   * Gets the singleton instance.
+   * @return {cca.mojo.MojoInterface} The singleton instance of this object.
    */
-  static getRemote() {
+  static getInstance() {
     if (!cca.mojo.MojoInterface.instance_) {
       /**
        * @type {cca.mojo.MojoInterface} The singleton instance of this object.
        */
       cca.mojo.MojoInterface.instance_ = new cca.mojo.MojoInterface();
     }
-    return cca.mojo.MojoInterface.instance_.remote;
+    return cca.mojo.MojoInterface.instance_;
+  }
+
+  /**
+   * Gets the mojo interface remote which could be used to get the
+   * CameraAppDevice from Chrome.
+   * @return {cros.mojom.CameraAppDeviceProviderRemote} The mojo interface
+   *     remote.
+   */
+  getDeviceProvider() {
+    return this.deviceProvider;
+  }
+
+  /**
+   * Gets the mojo interface remote which could be used to communicate with
+   * Camera device in Chrome.
+   * @param {string} deviceId The id of the target camera device.
+   * @return {Promise<cros.mojom.CameraAppDeviceRemote>} The mojo interface
+   *     remote of the camera device.
+   */
+  getDevice(deviceId) {
+    if (this.devices_.has(deviceId)) {
+      return this.devices_.get(deviceId);
+    }
+
+    let device = this.deviceProvider.getCameraAppDevice(deviceId).then(
+        ({status, device}) => {
+          if (status !== cros.mojom.GetCameraAppDeviceStatus.SUCCESS) {
+            console.error(
+                'Failed to get CameraAppDevice, error code: ', status);
+            // TODO(wtlee): Handle by different status.
+          }
+          return device;
+        });
+    this.devices_.set(deviceId, device);
+    return device;
+  }
+
+  /**
+   * Closes all mojo connections to devices.
+   */
+  closeConnections() {
+    this.devices_.clear();
   }
 };
 
@@ -139,11 +187,17 @@
   const portraitModeTag =
       /** @type{cros.mojom.CameraMetadataTag} */ (-0x80000000);
 
+  let device =
+      await cca.mojo.MojoInterface.getInstance().getDevice(this.deviceId_);
+  if (device === null) {
+    throw new Error('Fail to construct device remote.');
+  }
+
   let [/** @type {cca.mojo.PhotoCapabilities} */capabilities,
        {/** @type {cros.mojom.CameraInfo} */cameraInfo},
   ] = await Promise.all([
     this.capture_.getPhotoCapabilities(),
-    cca.mojo.MojoInterface.getRemote().getCameraInfo(this.deviceId_),
+    device.getCameraInfo(),
   ]);
 
   if (cameraInfo === null) {
@@ -173,16 +227,20 @@
   const takes = [];
   if (photoEffects) {
     photoEffects.forEach((effect) => {
-      takes.push((cca.mojo.MojoInterface.getRemote().setReprocessOption(
-                      this.deviceId_, effect))
-                     .then(({status, blob}) => {
-                       if (status != 0) {
-                         throw new Error('Mojo image capture error: ' + status);
-                       }
-                       const {data, mimeType} = blob;
-                       return new Blob(
-                           [new Uint8Array(data)], {type: mimeType});
-                     }));
+      const take = (async () => {
+        let device = await cca.mojo.MojoInterface.getInstance().getDevice(
+            this.deviceId_);
+        if (device === null) {
+          throw new Error('Failed to construct the device connection.');
+        }
+        let {status, blob} = await device.setReprocessOption(effect);
+        if (status !== 0) {
+          throw new Error('Mojo image capture error: ' + status);
+        }
+        const {data, mimeType} = blob;
+        return new Blob([new Uint8Array(data)], {type: mimeType});
+      })();
+      takes.push(take);
     });
   }
   takes.splice(0, 0, this.capture_.takePhoto(photoSettings));
@@ -201,12 +259,12 @@
   const typeOutputStream = 0;
   const numElementPerEntry = 4;
 
-  let {cameraInfo} =
-      await cca.mojo.MojoInterface.getRemote().getCameraInfo(deviceId);
-  if (cameraInfo === null) {
-    throw new Error('No photo resolutions is found for given device id.');
+  let device = await cca.mojo.MojoInterface.getInstance().getDevice(deviceId);
+  if (device === null) {
+    throw new Error('Failed to construct the device connection.');
   }
 
+  let {cameraInfo} = await device.getCameraInfo();
   const staticMetadata = cameraInfo.staticCameraCharacteristics;
   const streamConfigs = cca.mojo.getMetadataData_(
       staticMetadata,
@@ -243,11 +301,12 @@
   const oneSecondInNs = 1000000000;
   const numElementPerEntry = 4;
 
-  let {cameraInfo} =
-      await cca.mojo.MojoInterface.getRemote().getCameraInfo(deviceId);
-  if (cameraInfo === null) {
-    throw new Error('No video configs is found for given device id.');
+  let device = await cca.mojo.MojoInterface.getInstance().getDevice(deviceId);
+  if (device === null) {
+    throw new Error('Failed to construct the device connection.');
   }
+
+  let {cameraInfo} = await device.getCameraInfo();
   const staticMetadata = cameraInfo.staticCameraCharacteristics;
   const minFrameDurationConfigs = cca.mojo.getMetadataData_(
       staticMetadata,
@@ -280,11 +339,12 @@
  * @return {Promise<cros.mojom.CameraFacing>} Promise of device facing.
  */
 cca.mojo.getCameraFacing = async function(deviceId) {
-  let {cameraInfo} =
-      await cca.mojo.MojoInterface.getRemote().getCameraInfo(deviceId);
-  if (cameraInfo === null) {
-    throw new Error('No camera facing is found for given device id.');
+  let device = await cca.mojo.MojoInterface.getInstance().getDevice(deviceId);
+  if (device === null) {
+    throw new Error('Failed to construct the device connection.');
   }
+
+  let {cameraInfo} = await device.getCameraInfo();
   return cameraInfo.facing;
 };
 
@@ -298,12 +358,12 @@
 cca.mojo.getSupportedFpsRanges = async function(deviceId) {
   const numElementPerEntry = 2;
 
-  let {cameraInfo} =
-      await cca.mojo.MojoInterface.getRemote().getCameraInfo(deviceId);
-  if (cameraInfo === null) {
-    throw new Error('No supported Fps Ranges is found for given device id.');
+  let device = await cca.mojo.MojoInterface.getInstance().getDevice(deviceId);
+  if (device === null) {
+    throw new Error('Failed to construct the device connection.');
   }
 
+  let {cameraInfo} = await device.getCameraInfo();
   const staticMetadata = cameraInfo.staticCameraCharacteristics;
   const availableFpsRanges = cca.mojo.getMetadataData_(
       staticMetadata,
@@ -326,7 +386,7 @@
 };
 
 /**
- * Gets user media with custom negotiation through CrosImageCapture API,
+ * Gets user media with custom negotiation through CrOS Camera App API,
  * such as frame rate range negotiation.
  * @param {string} deviceId The renderer-facing device Id of the target camera
  *     which could be retrieved from MediaDeviceInfo.deviceId.
@@ -373,8 +433,14 @@
     // |constraints| , we assume the app wants to use default frame rate range.
     // We set the frame rate range to an invalid range (e.g. 0 fps) so that it
     // will fallback to use the default one.
-    const {isSuccess} = await cca.mojo.MojoInterface.getRemote().setFpsRange(
-        deviceId, streamWidth, streamHeight, minFrameRate, maxFrameRate);
+    let device = await cca.mojo.MojoInterface.getInstance().getDevice(deviceId);
+    if (device === null) {
+      throw new Error('Failed to construct the device connection.');
+    }
+
+    const {isSuccess} = await device.setFpsRange(
+        {'width': streamWidth, 'height': streamHeight},
+        {'start': minFrameRate, 'end': maxFrameRate});
 
     if (!isSuccess && hasSpecifiedFrameRateRange) {
       console.error('Failed to negotiate the frame rate range.');
@@ -384,3 +450,10 @@
   }
   return navigator.mediaDevices.getUserMedia(constraints);
 };
+
+/**
+ * Closes all mojo devices connections.
+ */
+cca.mojo.closeConnections = function() {
+  cca.mojo.MojoInterface.getInstance().closeConnections();
+};
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
index 5b9efd7..a6fc1b0 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
@@ -259,6 +259,9 @@
         Promise.resolve(!cca.state.get('taking') || this.endTake_()),
       ])
       .finally(() => {
+        // We should close all mojo connections since any communication to a
+        // closed stream should be avoided.
+        cca.mojo.closeConnections();
         this.preview_.stop();
         this.start_();
         return this.started_;
diff --git a/chrome/browser/resources/chromeos/camera/src/views/main.html b/chrome/browser/resources/chromeos/camera/src/views/main.html
index 78dea4f88..7c233cdf 100644
--- a/chrome/browser/resources/chromeos/camera/src/views/main.html
+++ b/chrome/browser/resources/chromeos/camera/src/views/main.html
@@ -31,7 +31,9 @@
     <script src="../js/mojo/camera_metadata.mojom-lite.js"></script>
     <script src="../js/mojo/camera_common.mojom-lite.js"></script>
     <script src="../js/mojo/image_capture.mojom-lite.js"></script>
-    <script src="../js/mojo/cros_image_capture.mojom-lite.js"></script>
+    <script src="../js/mojo/geometry.mojom-lite.js"></script>
+    <script src="../js/mojo/range.mojom-lite.js"></script>
+    <script src="../js/mojo/camera_app.mojom-lite.js"></script>
     <script src="../js/mojo/imagecapture.js"></script>
     <script src="../js/views/view.js"></script>
     <script src="../js/views/gallery_base.js"></script>
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index ef12bb678..f9d2bcd 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3636,6 +3636,7 @@
       deps += [
         "//chrome/services/app_service/public/cpp:app_update",
         "//chrome/services/app_service/public/cpp:icon_loader",
+        "//components/services/app_service/public/cpp:app_file_handling",
       ]
     }
   }
diff --git a/chrome/browser/ui/app_list/arc/arc_app_icon.cc b/chrome/browser/ui/app_list/arc/arc_app_icon.cc
index 78c1638..f82ef42 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_icon.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_icon.cc
@@ -289,9 +289,10 @@
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
   DCHECK(prefs);
 
-  // ArcAppListPrefs notifies ArcAppModelBuilder via Observer when icon is ready
-  // and ArcAppModelBuilder refreshes the icon of the corresponding item by
-  // calling LoadScaleFactor.
+  // ArcAppListPrefs notifies the ArcAppIconLoader (which is an
+  // ArcAppListPrefs::Observer) when the icon is updated, and
+  // ArcAppIconLoader::OnAppIconUpdated calls ArcAppIcon::LoadForScaleFactor on
+  // the corresponding ArcAppIcon.
   prefs->MaybeRequestIcon(
       mapped_app_id_,
       ArcAppIconDescriptor(resource_size_in_dip_, scale_factor));
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc
index ed4dd5b..5fb8cd9 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.cc
@@ -208,9 +208,13 @@
                           InitializationStatus::kInitialized);
 
   // If OnLoadFromDisk returned nullptr, no saved ranker proto was available on
-  // disk, and there is nothing to load.
-  if (!proto)
+  // disk, and there is nothing to load. Save a blank ranker to prevent metrics
+  // from reporting no ranker exists on future loads. Use SaveToDisk rather than
+  // MaybeSave because the time of last save is set to the time at construction.
+  if (!proto) {
+    SaveToDisk();
     return;
+  }
 
   if (!proto->has_config_hash() || proto->config_hash() != config_hash_) {
     // The configuration of the saved ranker doesn't match the configuration for
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
index 6ce9c7c..52477af 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc
@@ -69,7 +69,11 @@
   std::unique_ptr<RecurrenceRanker> MakeSimpleRanker() {
     auto ranker = std::make_unique<RecurrenceRanker>(
         "MyModel", ranker_filepath_, MakeSimpleConfig(), false);
+    // There should be no model file written to disk immediately after
+    // construction, but there should be one once initialization is complete.
+    EXPECT_FALSE(base::PathExists(ranker_filepath_));
     Wait();
+    EXPECT_TRUE(base::PathExists(ranker_filepath_));
     return ranker;
   }
 
@@ -133,10 +137,14 @@
                     bool has_saved = false) {
     // Total count of serialization reports:
     //  - one for either a kLoadOk or kModelReadError
-    //  - one if has_saved is true
+    //  - one if |fresh_model_created| because model is written to disk with a
+    //    kSaveOk on initialization.
+    //  - one if |has_saved| because model is again written to disk with a
+    //    kSaveOk.
     histogram_tester_.ExpectTotalCount(
         "RecurrenceRanker.SerializationStatus.MyModel",
-        static_cast<int>(has_saved) + 1);
+        1 + static_cast<int>(has_saved) +
+            static_cast<int>(fresh_model_created));
 
     // If a model doesn't already exist, a read error is logged.
     if (fresh_model_created) {
@@ -149,11 +157,10 @@
           SerializationStatus::kLoadOk, 1);
     }
 
-    if (has_saved) {
-      histogram_tester_.ExpectBucketCount(
-          "RecurrenceRanker.SerializationStatus.MyModel",
-          SerializationStatus::kSaveOk, 1);
-    }
+    histogram_tester_.ExpectBucketCount(
+        "RecurrenceRanker.SerializationStatus.MyModel",
+        SerializationStatus::kSaveOk,
+        static_cast<int>(has_saved) + static_cast<int>(fresh_model_created));
 
     // Initialising with the fake predictor logs an UMA error, because it should
     // be used only in tests and not in production.
@@ -309,8 +316,8 @@
   ASSERT_TRUE(ranker->load_from_disk_completed_);
   EXPECT_TRUE(ranker->Rank().empty());
 
-  // Check the ranker file is not created.
-  EXPECT_FALSE(base::PathExists(ranker_filepath_));
+  // Check the ranker file should have been created on initialization.
+  EXPECT_TRUE(base::PathExists(ranker_filepath_));
 
   // Make the ranker do a save.
   ranker->Record("A");
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
index bde9089..77c1759 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
@@ -48,6 +48,8 @@
 // Returns the model relevant for predicting launches for results with the given
 // |type|.
 Model ModelForType(RankingItemType type) {
+  // TODO(959679): Update this with zero-state item types once zero-state
+  // search providers have been implemented.
   switch (type) {
     case RankingItemType::kFile:
     case RankingItemType::kOmniboxGeneric:
@@ -207,26 +209,33 @@
   }
 
   if (app_list_features::IsZeroStateMixedTypesRankerEnabled()) {
+    zero_state_item_coeff_ = base::GetFieldTrialParamByFeatureAsDouble(
+        app_list_features::kEnableZeroStateMixedTypesRanker, "item_coeff",
+        zero_state_item_coeff_);
+    zero_state_group_coeff_ = base::GetFieldTrialParamByFeatureAsDouble(
+        app_list_features::kEnableZeroStateMixedTypesRanker, "group_coeff",
+        zero_state_group_coeff_);
+    zero_state_paired_coeff_ = base::GetFieldTrialParamByFeatureAsDouble(
+        app_list_features::kEnableZeroStateMixedTypesRanker, "paired_coeff",
+        zero_state_paired_coeff_);
+    zero_state_default_group_score_ = base::GetFieldTrialParamByFeatureAsDouble(
+        app_list_features::kEnableZeroStateMixedTypesRanker,
+        "default_group_score", zero_state_default_group_score_);
+
+    // TODO(959679): Setup json deployment.
+    // TODO(959679): Swap to a stochastic model by default and tweak params.
     RecurrenceRankerConfigProto config;
     config.set_min_seconds_between_saves(240u);
     config.set_condition_limit(1u);
     config.set_condition_decay(0.5f);
-
-    config.set_target_limit(base::GetFieldTrialParamByFeatureAsInt(
-        app_list_features::kEnableZeroStateMixedTypesRanker, "target_limit",
-        200));
-    config.set_target_decay(base::GetFieldTrialParamByFeatureAsDouble(
-        app_list_features::kEnableZeroStateMixedTypesRanker, "target_decay",
-        0.8f));
-
-    // Despite not changing any fields, this sets the predictor to the default
-    // predictor.
+    config.set_target_limit(5u);
+    config.set_target_decay(0.8f);
     config.mutable_predictor()->mutable_default_predictor();
 
-    zero_state_mixed_types_ranker_ = std::make_unique<RecurrenceRanker>(
-        "ZeroStateMixedTypes",
-        profile_->GetPath().AppendASCII("zero_state_mixed_types_ranker.proto"),
-        config, chromeos::ProfileHelper::IsEphemeralUserProfile(profile_));
+    zero_state_group_ranker_ = std::make_unique<RecurrenceRanker>(
+        "ZeroStateGroups",
+        profile_->GetPath().AppendASCII("zero_state_group_ranker.pb"), config,
+        chromeos::ProfileHelper::IsEphemeralUserProfile(profile_));
   }
 
   if (app_list_features::IsAppRankerEnabled() &&
@@ -235,9 +244,9 @@
     RecurrenceRankerConfigProto config;
     config.set_min_seconds_between_saves(240u);
     config.set_condition_limit(1u);
-    config.set_condition_decay(0.5f);
+    config.set_condition_decay(0.5);
     config.set_target_limit(200);
-    config.set_target_decay(0.8f);
+    config.set_target_decay(0.8);
     config.mutable_predictor()->mutable_default_predictor();
 
     app_ranker_ = std::make_unique<RecurrenceRanker>(
@@ -254,6 +263,12 @@
   if (now - time_of_last_fetch_ < kMinSecondsBetweenFetches)
     return;
   time_of_last_fetch_ = now;
+  last_query_ = query;
+
+  if (query.empty() && zero_state_group_ranker_) {
+    zero_state_group_ranks_.clear();
+    zero_state_group_ranks_ = zero_state_group_ranker_->Rank();
+  }
 
   if (results_list_group_ranker_) {
     group_ranks_.clear();
@@ -277,7 +292,20 @@
     const auto& model = ModelForType(type);
 
     if (model == Model::MIXED_TYPES) {
-      if (results_list_group_ranker_) {
+      if (last_query_.empty() && zero_state_group_ranker_) {
+        const auto& rank_it = zero_state_group_ranks_.find(
+            base::NumberToString(static_cast<int>(type)));
+        const float group_score = (rank_it != zero_state_group_ranks_.end())
+                                      ? rank_it->second
+                                      : zero_state_default_group_score_;
+        const float score =
+            zero_state_item_coeff_ * result.score +
+            zero_state_group_coeff_ * group_score +
+            zero_state_paired_coeff_ * result.score * group_score;
+        result.score =
+            score / (zero_state_item_coeff_ + zero_state_group_coeff_ +
+                     zero_state_paired_coeff_);
+      } else if (results_list_group_ranker_) {
         const auto& rank_it =
             group_ranks_.find(base::NumberToString(static_cast<int>(type)));
         // The ranker only contains entries trained with types relating to files
@@ -325,7 +353,10 @@
 
   auto model = ModelForType(app_launch_data.ranking_item_type);
   if (model == Model::MIXED_TYPES) {
-    if (results_list_group_ranker_) {
+    if (app_launch_data.query.empty() && zero_state_group_ranker_) {
+      zero_state_group_ranker_->Record(base::NumberToString(
+          static_cast<int>(app_launch_data.ranking_item_type)));
+    } else if (results_list_group_ranker_) {
       results_list_group_ranker_->Record(base::NumberToString(
           static_cast<int>(app_launch_data.ranking_item_type)));
     } else if (query_based_mixed_types_ranker_) {
@@ -340,10 +371,6 @@
 
 void SearchResultRanker::OnFilesOpened(
     const std::vector<FileOpenEvent>& file_opens) {
-  if (zero_state_mixed_types_ranker_) {
-    for (const auto& file_open : file_opens)
-      zero_state_mixed_types_ranker_->Record(file_open.path.value());
-  }
   // Log the open type of file open events
   for (const auto& file_open : file_opens)
     UMA_HISTOGRAM_ENUMERATION(kLogFileOpenType,
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
index 5eaaf7ca..b099021 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
@@ -73,10 +73,6 @@
   void OnURLsDeleted(history::HistoryService* history_service,
                      const history::DeletionInfo& deletion_info) override;
 
-  RecurrenceRanker* get_zero_state_mixed_types_ranker() {
-    return zero_state_mixed_types_ranker_.get();
-  }
-
   // Sets a testing-only closure to inform tests when a JSON config has been
   // parsed.
   void set_json_config_parsed_for_testing(base::OnceClosure closure) {
@@ -97,6 +93,9 @@
   // limit the number of queries to the models within a short timespan.
   base::Time time_of_last_fetch_;
 
+  // The query last provided to FetchRankings.
+  base::string16 last_query_;
+
   // How much the scores produced by |results_list_group_ranker_| affect the
   // final scores. Controlled by Finch.
   float results_list_boost_coefficient_ = 0.0f;
@@ -119,8 +118,16 @@
   // prevent several delayed tasks from being created.
   bool query_mixed_ranker_save_queued_ = false;
 
-  // Ranks files and previous queries for launcher zero-state.
-  std::unique_ptr<RecurrenceRanker> zero_state_mixed_types_ranker_;
+  // Ranks the kinds of results possible in the zero state results list.
+  std::unique_ptr<RecurrenceRanker> zero_state_group_ranker_;
+  std::map<std::string, float> zero_state_group_ranks_;
+
+  // Coefficients that control the weighting between different parts of the
+  // score of a result in the zero-state results list.
+  float zero_state_item_coeff_ = 1.0f;
+  float zero_state_group_coeff_ = 0.0f;
+  float zero_state_paired_coeff_ = 0.0f;
+  float zero_state_default_group_score_ = 1.0f;
 
   // Ranks apps.
   std::unique_ptr<RecurrenceRanker> app_ranker_;
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
index 27fdbc2f..a0cbc24b 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
@@ -450,6 +450,7 @@
 
   // Now delete |url_1| from the history service and ensure we save the model to
   // disk.
+  base::DeleteFile(model_path, false);
   EXPECT_FALSE(base::PathExists(model_path));
   history_service()->AddPage(GURL(url_1), base::Time::Now(),
                              history::VisitSource::SOURCE_BROWSED);
@@ -497,4 +498,72 @@
   }
 }
 
+TEST_F(SearchResultRankerTest, ZeroStateGroupModelDisabledWithFlag) {
+  DisableAllFeatures();
+  auto ranker = MakeRanker();
+  ranker->InitializeRankers();
+  Wait();
+
+  // TODO(959679): Update the types used in this test once zero-state-related
+  // search providers have been implemented.
+
+  AppLaunchData app_launch_data_a;
+  app_launch_data_a.id = "A";
+  app_launch_data_a.ranking_item_type = RankingItemType::kFile;
+  app_launch_data_a.query = "";
+
+  for (int i = 0; i < 10; ++i) {
+    ranker->Train(app_launch_data_a);
+  }
+  ranker->FetchRankings(base::string16());
+
+  // A and B should be ranked first because their group score should be higher.
+  auto results =
+      MakeSearchResults({"A", "B", "C", "D"},
+                        {ResultType::kLauncher, ResultType::kLauncher,
+                         ResultType::kOmnibox, ResultType::kOmnibox},
+                        {0.1f, 0.2f, 0.5f, 0.6f});
+  ranker->Rank(&results);
+
+  EXPECT_THAT(results, WhenSorted(ElementsAre(HasId("D"), HasId("C"),
+                                              HasId("B"), HasId("A"))));
+}
+
+TEST_F(SearchResultRankerTest, ZeroStateGroupModelImprovesScores) {
+  EnableOneFeature(app_list_features::kEnableZeroStateMixedTypesRanker,
+                   {
+                       {"item_coeff", "1.0"},
+                       {"group_coeff", "1.0"},
+                       {"paired_coeff", "0.0"},
+                       {"default_group_score", "0.1"},
+                   });
+  auto ranker = MakeRanker();
+  ranker->InitializeRankers();
+  Wait();
+
+  // TODO(959679): Update the types used in this test once zero-state-related
+  // search providers have been implemented.
+
+  AppLaunchData app_launch_data_a;
+  app_launch_data_a.id = "A";
+  app_launch_data_a.ranking_item_type = RankingItemType::kFile;
+  app_launch_data_a.query = "";
+
+  for (int i = 0; i < 10; ++i) {
+    ranker->Train(app_launch_data_a);
+  }
+  ranker->FetchRankings(base::string16());
+
+  // A and B should be ranked first because their group score should be higher.
+  auto results =
+      MakeSearchResults({"A", "B", "C", "D"},
+                        {ResultType::kLauncher, ResultType::kLauncher,
+                         ResultType::kOmnibox, ResultType::kOmnibox},
+                        {0.1f, 0.2f, 0.5f, 0.6f});
+  ranker->Rank(&results);
+
+  EXPECT_THAT(results, WhenSorted(ElementsAre(HasId("B"), HasId("A"),
+                                              HasId("D"), HasId("C"))));
+}
+
 }  // namespace app_list
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.h b/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.h
index d0e2042a..5e8e2733 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.h
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.h
@@ -24,6 +24,7 @@
 class TemplateURLService;
 
 namespace network {
+struct ResourceResponseHead;
 class SharedURLLoaderFactory;
 class SimpleURLLoader;
 }
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index 3cdd049..ab67b6f 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -702,6 +702,7 @@
         command_line.GetSwitchValueASCII(
             switches::kNativeMessagingConnectExtension),
         command_line.GetSwitchValueASCII(switches::kNativeMessagingConnectHost),
+        command_line.GetSwitchValueASCII(switches::kNativeMessagingConnectId),
         last_used_profile);
   }
 #endif
diff --git a/chrome/browser/ui/views/tabs/tab_spinner_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_spinner_interactive_uitest.cc
new file mode 100644
index 0000000..de76c87
--- /dev/null
+++ b/chrome/browser/ui/views/tabs/tab_spinner_interactive_uitest.cc
@@ -0,0 +1,99 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/macros.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ui/ui_features.h"
+#include "chrome/test/base/perf/performance_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+
+static const int kNumTabs = 4;
+
+// Gauge performance of the tab spinner animation.
+class TabSpinnerTest : public UIPerformanceTest {
+ public:
+  TabSpinnerTest() {
+    // Disable hover cards to ensure they never get painted. Prevent scenarios
+    // where the mouse may accidentally trigger a hover card by disabling hover
+    // cards altogether.
+    scoped_feature_list_.InitAndDisableFeature(features::kTabHoverCards);
+
+    test_page_url_ = ui_test_utils::GetTestUrl(
+        base::FilePath(base::FilePath::kCurrentDirectory),
+        base::FilePath(FILE_PATH_LITERAL("perf/tab-spinner-case.html")));
+  }
+
+  ~TabSpinnerTest() override = default;
+
+  void IgnorePriorHistogramSamples() {
+    // Take the snapshot delta; so that the samples created so far will be
+    // eliminated from the samples.
+    for (const auto& name : GetUMAHistogramNames()) {
+      auto* histogram = base::StatisticsRecorder::FindHistogram(name);
+      if (!histogram)
+        continue;
+      histogram->SnapshotDelta();
+    }
+  }
+
+  GURL test_page_url() const { return test_page_url_; }
+
+ private:
+  std::vector<std::string> GetUMAHistogramNames() const override {
+    // Report each step in the Pipeline Reporter. Note that the UMA mean
+    // will only be printed if the following command line flag is provided:
+    // --perf-test-print-uma-means. Each measurement is in microseconds.
+    return {"SingleThreadedCompositorLatency.TotalLatency",
+            "SingleThreadedCompositorLatency.SendBeginMainFrameToCommit",
+            "SingleThreadedCompositorLatency.Commit",
+            "SingleThreadedCompositorLatency.Activation",
+            "SingleThreadedCompositorLatency.EndCommitToActivation"};
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+  GURL test_page_url_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabSpinnerTest);
+};
+
+IN_PROC_BROWSER_TEST_F(TabSpinnerTest, LoadTabsOneByOne) {
+  IgnorePriorHistogramSamples();
+
+  // Navigate to a custom page that takes 10 seconds to load. Wait for the
+  // tab to finish loading before opening a new tab. Repeat the process for
+  // each tab.
+
+  for (int i = 0; i < kNumTabs; ++i) {
+    WindowOpenDisposition disposition =
+        i == 0 ? WindowOpenDisposition::CURRENT_TAB
+               : WindowOpenDisposition::NEW_FOREGROUND_TAB;
+    ui_test_utils::NavigateToURLWithDisposition(
+        browser(), test_page_url(), disposition,
+        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(TabSpinnerTest, LoadTabsTogether) {
+  IgnorePriorHistogramSamples();
+
+  // Open each tab in quick succession, all of which are simultaneously loading
+  // the same custom page which takes 10 seconds to load. Wait for navigation
+  // to finish on the last tab opened. We may assume the last tab opened is the
+  // last tab to finish executing BROWSER_TEST_WAIT_FOR_NAVIGATION because it
+  // is the last to navigate to the page.
+
+  for (int i = 0; i < kNumTabs; ++i) {
+    WindowOpenDisposition disposition =
+        i == 0 ? WindowOpenDisposition::CURRENT_TAB
+               : WindowOpenDisposition::NEW_FOREGROUND_TAB;
+    ui_test_utils::BrowserTestWaitFlags flag =
+        i < kNumTabs - 1 ? ui_test_utils::BROWSER_TEST_NONE
+                         : ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION;
+
+    ui_test_utils::NavigateToURLWithDisposition(browser(), test_page_url(),
+                                                disposition, flag);
+  }
+}
diff --git a/chrome/browser/ui/webui/chromeos/camera/camera_ui.cc b/chrome/browser/ui/webui/chromeos/camera/camera_ui.cc
index c6110b2..d1f983f 100644
--- a/chrome/browser/ui/webui/chromeos/camera/camera_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/camera/camera_ui.cc
@@ -45,8 +45,8 @@
                           IDR_CAMERA_CAMERA_METADATA_MOJOM_LITE_JS);
   source->AddResourcePath("src/js/mojo/camera_metadata_tags.mojom-lite.js",
                           IDR_CAMERA_CAMERA_METADATA_TAGS_MOJOM_LITE_JS);
-  source->AddResourcePath("src/js/mojo/cros_image_capture.mojom-lite.js",
-                          IDR_CAMERA_CROS_IMAGE_CAPTURE_MOJOM_LITE_JS);
+  source->AddResourcePath("src/js/mojo/camera_app.mojom-lite.js",
+                          IDR_CAMERA_APP_MOJOM_LITE_JS);
   source->AddResourcePath("src/js/mojo/mojo_bindings_lite.js",
                           IDR_MOJO_MOJO_BINDINGS_LITE_JS);
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
index 5277d3b..81cd734 100644
--- a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
@@ -134,7 +134,8 @@
       vm_name, base::FilePath(path),
       /*unpersist=*/true,
       base::BindOnce(
-          [](const std::string& path, bool result, std::string failure_reason) {
+          [](const std::string& path, bool result,
+             const std::string& failure_reason) {
             if (!result) {
               LOG(ERROR) << "Error unsharing " << path << ": "
                          << failure_reason;
diff --git a/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc b/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc
index 09518e99..e7a4691 100644
--- a/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/plugin_vm_handler.cc
@@ -59,7 +59,8 @@
       vm_name, base::FilePath(path),
       /*unpersist=*/true,
       base::BindOnce(
-          [](const std::string& path, bool result, std::string failure_reason) {
+          [](const std::string& path, bool result,
+             const std::string& failure_reason) {
             if (!result) {
               LOG(ERROR) << "Error unsharing " << path << ": "
                          << failure_reason;
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_util.cc b/chrome/browser/web_applications/extensions/bookmark_app_util.cc
index 0ea5f31..8d0911e2 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_util.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_util.cc
@@ -7,7 +7,6 @@
 #include "base/strings/string_piece.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/web_applications/extensions/bookmark_app_util.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index d5cd5ca..6af0051 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -399,6 +399,11 @@
 const char kNativeMessagingConnectExtension[] =
     "native-messaging-connect-extension";
 
+// If set when kNativeMessagingConnectHost and kNativeMessagingConnectExtension
+// are specified, is reflected to the native messaging host as a command line
+// parameter.
+const char kNativeMessagingConnectId[] = "native-messaging-connect-id";
+
 // Disables the default browser check. Useful for UI/browser tests where we
 // want to avoid having the default browser info-bar displayed.
 const char kNoDefaultBrowserCheck[]         = "no-default-browser-check";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 8958f38..8eba1d1 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -126,6 +126,7 @@
 extern const char kMonitoringDestinationID[];
 extern const char kNativeMessagingConnectHost[];
 extern const char kNativeMessagingConnectExtension[];
+extern const char kNativeMessagingConnectId[];
 extern const char kNewNetErrorPageUI[];
 extern const char kNoDefaultBrowserCheck[];
 extern const char kNoExperiments[];
diff --git a/chrome/elevation_service/elevated_recovery_impl.cc b/chrome/elevation_service/elevated_recovery_impl.cc
index e2f36a01..813364f 100644
--- a/chrome/elevation_service/elevated_recovery_impl.cc
+++ b/chrome/elevation_service/elevated_recovery_impl.cc
@@ -29,6 +29,13 @@
 
 namespace {
 
+// Input CRX files over 10 MB are considered invalid.
+constexpr int64_t kMaxFileSize = 10u * 1000u * 1000u;
+
+// The hard-coded file name that the Recovery CRX is copied to.
+constexpr base::FilePath::CharType kCRXFileName[] =
+    FILE_PATH_LITERAL("ChromeRecoveryCRX.crx");
+
 // The hard-coded Recovery subdirectory where the CRX is unpacked and executed.
 constexpr base::FilePath::CharType kRecoveryDirectory[] =
     FILE_PATH_LITERAL("ChromeRecovery");
@@ -60,24 +67,93 @@
 // Opens and returns the COM caller's |process| given the process id, or the
 // current process if |proc_id| is 0.
 HRESULT OpenCallingProcess(uint32_t proc_id, base::Process* process) {
+  DCHECK(proc_id);
   DCHECK(process);
 
-  if (!proc_id) {
-    *process = base::Process::Current();
-    return S_OK;
-  }
-
   HRESULT hr = ::CoImpersonateClient();
   if (FAILED(hr))
     return hr;
 
   base::ScopedClosureRunner revert_to_self(
-      base::BindOnce(base::IgnoreResult(&::CoRevertToSelf)));
+      base::BindOnce([]() { ::CoRevertToSelf(); }));
 
   *process = base::Process::OpenWithAccess(proc_id, PROCESS_DUP_HANDLE);
   return process->IsValid() ? S_OK : HRESULTFromLastError();
 }
 
+// Opens and returns a base::File instance for the |file_path|. We impersonate
+// the COM caller when opening the base::File instance. This is to ensure that
+// the COM caller has access to the file.
+HRESULT OpenFileImpersonated(const base::FilePath& file_path,
+                             int flags,
+                             base::File* file) {
+  DCHECK(file);
+
+  HRESULT hr = ::CoImpersonateClient();
+  if (FAILED(hr))
+    return hr;
+
+  base::ScopedClosureRunner revert_to_self(
+      base::BindOnce([]() { ::CoRevertToSelf(); }));
+
+  file->Initialize(file_path, flags);
+  if (!file->IsValid())
+    return HRESULTFromLastError();
+
+  if (::GetFileType(file->GetPlatformFile()) != FILE_TYPE_DISK)
+    return E_INVALIDARG;
+
+  int64_t from_length = file->GetLength();
+  return from_length > 0 && from_length < kMaxFileSize ? S_OK : E_INVALIDARG;
+}
+
+// Opens |from| while impersonating the COM caller, and then copies the contents
+// of |from| to |to|. |from| is opened impersonated to ensure that the COM
+// caller has access to the file.
+HRESULT CopyFileImpersonated(const base::FilePath from,
+                             const base::FilePath& to) {
+  base::File from_file;
+  HRESULT hr =
+      OpenFileImpersonated(from,
+                           base::File::FLAG_READ | base::File::FLAG_OPEN |
+                               base::File::FLAG_SEQUENTIAL_SCAN,
+                           &from_file);
+  if (FAILED(hr))
+    return hr;
+
+  base::File to_file;
+  to_file.Initialize(to, base::File::FLAG_WRITE |
+                             base::File::FLAG_CREATE_ALWAYS |
+                             base::File::FLAG_SEQUENTIAL_SCAN);
+  if (!to_file.IsValid())
+    return HRESULTFromLastError();
+
+  constexpr size_t kBufferSize = 0x10000;
+  std::vector<char> buffer(kBufferSize);
+
+  for (uint64_t total_bytes_read = 0;;) {
+    const int bytes_read =
+        from_file.ReadAtCurrentPos(buffer.data(), buffer.size());
+    if (bytes_read < 0)
+      return HRESULTFromLastError();
+    if (bytes_read == 0)
+      return S_OK;
+
+    total_bytes_read += bytes_read;
+    if (total_bytes_read > kMaxFileSize)
+      return E_INVALIDARG;
+
+    const int bytes_written = to_file.WriteAtCurrentPos(&buffer[0], bytes_read);
+    if (bytes_written < 0)
+      return HRESULTFromLastError();
+    if (bytes_written != bytes_read)
+      return E_UNEXPECTED;
+  }
+
+  NOTREACHED();
+  return S_OK;
+}
+
 // Validates the provided CRX using the |crx_hash|, and if validation succeeds,
 // unpacks the CRX under |unpack_under_path|. Returns the unpacked CRX
 // directory in |unpacked_crx_dir|.
@@ -92,19 +168,13 @@
   if (!to_dir.CreateUniqueTempDirUnderPath(unpack_under_path))
     return HRESULTFromLastError();
 
-  const base::FilePath to_crx_path =
-      to_dir.GetPath().Append(from_crx_path.BaseName());
+  const base::FilePath to_crx_path = to_dir.GetPath().Append(kCRXFileName);
 
-  // We check the input file for CRX and signature validity before copying to
-  // the secure location. This is to prevent us from copying unintended files,
-  // including files that may be private to a particular user or group.
-  if (crx_file::Verify(from_crx_path, crx_format, {crx_hash}, {}, nullptr,
-                       nullptr) != crx_file::VerifierResult::OK_FULL) {
-    return CRYPT_E_NO_MATCH;
-  }
-
-  if (!base::CopyFile(from_crx_path, to_crx_path))
-    return HRESULTFromLastError();
+  // Copy |from_crx_path| impersonated. This is to prevent us from copying files
+  // that may not be accessible to the calling COM user.
+  HRESULT hr = CopyFileImpersonated(from_crx_path, to_crx_path);
+  if (FAILED(hr))
+    return hr;
 
   std::string public_key;
   if (crx_file::Verify(to_crx_path, crx_format, {crx_hash}, {}, &public_key,
@@ -240,7 +310,7 @@
                              const base::string16& session_id,
                              uint32_t caller_proc_id,
                              base::win::ScopedHandle* proc_handle) {
-  if (crx_path.empty() || !proc_handle)
+  if (crx_path.empty() || !caller_proc_id || !proc_handle)
     return E_INVALIDARG;
 
   HRESULT hr = ValidateCRXArgs(browser_appid, browser_version, session_id);
@@ -273,11 +343,12 @@
                const base::FilePath& exe_filename,
                uint32_t caller_proc_id,
                base::win::ScopedHandle* proc_handle) {
-  DCHECK(proc_handle);
   DCHECK(!crx_path.empty());
   DCHECK(!crx_hash.empty());
   DCHECK(!unpack_under_path.empty());
   DCHECK(!exe_filename.empty());
+  DCHECK(caller_proc_id);
+  DCHECK(proc_handle);
 
   base::Process calling_process;
   HRESULT hr = OpenCallingProcess(caller_proc_id, &calling_process);
diff --git a/chrome/elevation_service/elevated_recovery_unittest.cc b/chrome/elevation_service/elevated_recovery_unittest.cc
index 895ae00..3b7bd67 100644
--- a/chrome/elevation_service/elevated_recovery_unittest.cc
+++ b/chrome/elevation_service/elevated_recovery_unittest.cc
@@ -5,6 +5,8 @@
 #include "chrome/elevation_service/elevated_recovery_impl.h"
 
 #include <windows.h>
+#include <wrl/implements.h>
+
 #include <memory>
 #include <vector>
 
@@ -59,48 +61,117 @@
       .AppendASCII(file);
 }
 
+// A mock implementation of IServerSecurity that allows for the production code
+// that calls ::CoImpersonateClient() to work.
+class MockServerSecurity
+    : public Microsoft::WRL::RuntimeClass<
+          Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+          IServerSecurity> {
+ public:
+  MockServerSecurity() : is_impersonating_(false) {}
+
+  IFACEMETHOD(QueryBlanket)
+  (DWORD* authentication_service,
+   DWORD* authorization_service,
+   OLECHAR** server_principal_name,
+   DWORD* authentication_level,
+   DWORD* impersonation_level,
+   void** privilege,
+   DWORD* capabilities) {
+    return E_NOTIMPL;
+  }
+  IFACEMETHOD(ImpersonateClient)() {
+    is_impersonating_ = true;
+    return S_OK;
+  }
+  IFACEMETHOD(RevertToSelf)() {
+    is_impersonating_ = false;
+    return S_OK;
+  }
+  IFACEMETHOD_(BOOL, IsImpersonating)() { return is_impersonating_; }
+
+ private:
+  ~MockServerSecurity() override { EXPECT_FALSE(is_impersonating_); }
+
+  bool is_impersonating_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockServerSecurity);
+};
+
 }  // namespace
 
-TEST(ElevatedRecoveryTest, Do_RunChromeRecoveryCRX_InvalidArgs) {
+void SetupMockContext() {
+  auto server_security = Microsoft::WRL::Make<MockServerSecurity>();
+  server_security->AddRef();
+  Microsoft::WRL::ComPtr<IUnknown> original_call_context;
+
+  // We set the call context to a mock object that implements IServerSecurity.
+  // This allows for the production code that calls ::CoImpersonateClient() to
+  // succeed.
+  EXPECT_HRESULT_SUCCEEDED(
+      ::CoSwitchCallContext(server_security.Get(), &original_call_context));
+  EXPECT_EQ(nullptr, original_call_context.Get());
+}
+
+void TeardownMockContext() {
+  Microsoft::WRL::ComPtr<IUnknown> call_context;
+  EXPECT_HRESULT_SUCCEEDED(::CoSwitchCallContext(nullptr, &call_context));
+  EXPECT_NE(nullptr, call_context.Get());
+}
+
+class ElevatedRecoveryTest : public testing::Test {
+ protected:
+  ElevatedRecoveryTest() = default;
+
+  void SetUp() override { SetupMockContext(); }
+
+  void TearDown() override { TeardownMockContext(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ElevatedRecoveryTest);
+};
+
+TEST_F(ElevatedRecoveryTest, Do_RunChromeRecoveryCRX_InvalidArgs) {
   base::win::ScopedHandle proc_handle;
 
   // Empty browser_appid/browser_version/session_id.
-  EXPECT_EQ(E_INVALIDARG,
-            elevation_service::RunChromeRecoveryCRX(
-                TestFile("valid_publisher.crx3"), base::string16(),
-                base::string16(), base::string16(), 0, &proc_handle));
+  EXPECT_EQ(
+      E_INVALIDARG,
+      elevation_service::RunChromeRecoveryCRX(
+          TestFile("valid_publisher.crx3"), base::string16(), base::string16(),
+          base::string16(), ::GetCurrentProcessId(), &proc_handle));
 
   // Invalid browser_appid, valid browser_version/session_id.
   EXPECT_EQ(E_INVALIDARG,
             elevation_service::RunChromeRecoveryCRX(
-                TestFile("valid_publisher.crx3"), L"invalidappid",
-                L"1.2.3.4", L"{c49ab053-2387-4809-b188-1902648802e1}", 0,
-                &proc_handle));
+                TestFile("valid_publisher.crx3"), L"invalidappid", L"1.2.3.4",
+                L"{c49ab053-2387-4809-b188-1902648802e1}",
+                ::GetCurrentProcessId(), &proc_handle));
 
   // Empty browser_appid, invalid browser_version, valid session_id.
-  EXPECT_EQ(E_INVALIDARG,
-            elevation_service::RunChromeRecoveryCRX(
-                TestFile("valid_publisher.crx3"), base::string16(),
-                L"invalidbrowserversion",
-                L"{c49ab053-2387-4809-b188-1902648802e1}", 0, &proc_handle));
+  EXPECT_EQ(E_INVALIDARG, elevation_service::RunChromeRecoveryCRX(
+                              TestFile("valid_publisher.crx3"),
+                              base::string16(), L"invalidbrowserversion",
+                              L"{c49ab053-2387-4809-b188-1902648802e1}",
+                              ::GetCurrentProcessId(), &proc_handle));
 
   // Valid browser_appid, invalid browser_version, valid session_id.
-  EXPECT_EQ(
-      E_INVALIDARG,
-      elevation_service::RunChromeRecoveryCRX(
-          TestFile("valid_publisher.crx3"),
-          L"{c49ab053-2387-4809-b188-1902648802e1}", L"invalidbrowserversion",
-          L"{c49ab053-2387-4809-b188-1902648802e1}", 0, &proc_handle));
+  EXPECT_EQ(E_INVALIDARG, elevation_service::RunChromeRecoveryCRX(
+                              TestFile("valid_publisher.crx3"),
+                              L"{c49ab053-2387-4809-b188-1902648802e1}",
+                              L"invalidbrowserversion",
+                              L"{c49ab053-2387-4809-b188-1902648802e1}",
+                              ::GetCurrentProcessId(), &proc_handle));
 
   // Valid browser_appid, valid browser_version, invalid session_id.
   EXPECT_EQ(E_INVALIDARG,
             elevation_service::RunChromeRecoveryCRX(
                 TestFile("valid_publisher.crx3"),
                 L"{c49ab053-2387-4809-b188-1902648802e1}", L"57.8.0.1",
-                L"invalidsessionid", 0, &proc_handle));
+                L"invalidsessionid", ::GetCurrentProcessId(), &proc_handle));
 }
 
-TEST(ElevatedRecoveryTest, Do_RunCRX_InvalidArgs) {
+TEST_F(ElevatedRecoveryTest, Do_RunCRX_InvalidArgs) {
   base::win::ScopedHandle proc_handle;
 
   // Non-matching CRX/CRX-hash.
@@ -110,16 +181,18 @@
                 base::CommandLine(base::CommandLine::NO_PROGRAM),
                 crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF,
                 GetValidPublisherCrx3Hash(), GetUnpackDir(),
-                base::FilePath(kManifestJSONFileName), 0, &proc_handle));
+                base::FilePath(kManifestJSONFileName), ::GetCurrentProcessId(),
+                &proc_handle));
 
   // Non-existent CRX file.
-  EXPECT_EQ(CRYPT_E_NO_MATCH,
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
             elevation_service::RunCRX(
                 TestFile("nonexistent.crx3"),
                 base::CommandLine(base::CommandLine::NO_PROGRAM),
                 crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF,
                 GetValidPublisherCrx3Hash(), GetUnpackDir(),
-                base::FilePath(kManifestJSONFileName), 0, &proc_handle));
+                base::FilePath(kManifestJSONFileName), ::GetCurrentProcessId(),
+                &proc_handle));
 
   // manifest.json is not a Windows executable, ::CreateProcess therefore
   // returns ERROR_BAD_EXE_FORMAT.
@@ -129,20 +202,22 @@
                 base::CommandLine(base::CommandLine::NO_PROGRAM),
                 crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF,
                 GetValidPublisherCrx3Hash(), GetUnpackDir(),
-                base::FilePath(kManifestJSONFileName), 0, &proc_handle));
+                base::FilePath(kManifestJSONFileName), ::GetCurrentProcessId(),
+                &proc_handle));
 }
 
-TEST(ElevatedRecoveryTest, Do_RunCRX_ValidArgs) {
+TEST_F(ElevatedRecoveryTest, Do_RunCRX_ValidArgs) {
   base::win::ScopedHandle proc_handle;
 
   // ChromeRecovery.crx3 contains ChromeRecovery.exe which returns a hardcoded
   // value of 1877345072.
-  EXPECT_EQ(S_OK, elevation_service::RunCRX(
-                      TestFile("ChromeRecovery.crx3"),
-                      base::CommandLine(base::CommandLine::NO_PROGRAM),
-                      crx_file::VerifierFormat::CRX3,
-                      GetRunactionTestWinCrx3Hash(), GetUnpackDir(),
-                      base::FilePath(kRecoveryExeName), 0, &proc_handle));
+  EXPECT_EQ(S_OK,
+            elevation_service::RunCRX(
+                TestFile("ChromeRecovery.crx3"),
+                base::CommandLine(base::CommandLine::NO_PROGRAM),
+                crx_file::VerifierFormat::CRX3, GetRunactionTestWinCrx3Hash(),
+                GetUnpackDir(), base::FilePath(kRecoveryExeName),
+                ::GetCurrentProcessId(), &proc_handle));
 
   EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(proc_handle.Get(), 500));
   DWORD exit_code = 0;
@@ -150,7 +225,7 @@
   EXPECT_EQ(1877345072UL, exit_code);
 }
 
-TEST(ElevatedRecoveryTest, Do_CleanupChromeRecoveryDirectory) {
+TEST(ElevatedRecoveryCleanupTest, Do_CleanupChromeRecoveryDirectory) {
   base::FilePath recovery_dir;
   ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &recovery_dir));
   recovery_dir = recovery_dir.DirName().DirName().Append(
diff --git a/chrome/elevation_service/run_all_unittests.cc b/chrome/elevation_service/run_all_unittests.cc
index d38e1c1..3ac9279 100644
--- a/chrome/elevation_service/run_all_unittests.cc
+++ b/chrome/elevation_service/run_all_unittests.cc
@@ -5,12 +5,28 @@
 #include "base/bind.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
+#include "chrome/elevation_service/service_main.h"
 #include "chrome/install_static/test/scoped_install_details.h"
 
+namespace {
+
+class DefaultEnvironment final : public ::testing::Environment {
+ public:
+  DefaultEnvironment() = default;
+
+  void SetUp() override {
+    elevation_service::ServiceMain::GetInstance()->CreateWRLModule();
+  }
+};
+
+}  // namespace
+
 int main(int argc, char** argv) {
   base::TestSuite test_suite(argc, argv);
   install_static::ScopedInstallDetails scoped_install_details;
 
+  testing::AddGlobalTestEnvironment(new DefaultEnvironment);
+
   return base::LaunchUnitTestsSerially(
       argc, argv,
       base::BindRepeating(&base::TestSuite::Run,
diff --git a/chrome/elevation_service/service_main.cc b/chrome/elevation_service/service_main.cc
index 83e4b1c..f529c32 100644
--- a/chrome/elevation_service/service_main.cc
+++ b/chrome/elevation_service/service_main.cc
@@ -11,12 +11,12 @@
 
 #include "chrome/elevation_service/service_main.h"
 
-#include <type_traits>
-
 #include <atlsecurity.h>
 #include <sddl.h>
 #include <wrl/module.h>
 
+#include <type_traits>
+
 #include "base/command_line.h"
 #include "base/stl_util.h"
 #include "base/win/scoped_com_initializer.h"
@@ -59,12 +59,15 @@
   return (this->*run_routine_)();
 }
 
+void ServiceMain::CreateWRLModule() {
+  Microsoft::WRL::Module<Microsoft::WRL::OutOfProc>::Create(
+      this, &ServiceMain::SignalExit);
+}
+
 // When _ServiceMain gets called, it initializes COM, and then calls Run().
 // Run() initializes security, then calls RegisterClassObject().
 HRESULT ServiceMain::RegisterClassObject() {
-  // Create an out-of-proc COM module with caching disabled.
-  auto& module = Microsoft::WRL::Module<Microsoft::WRL::OutOfProc>::Create(
-      this, &ServiceMain::SignalExit);
+  auto& module = Microsoft::WRL::Module<Microsoft::WRL::OutOfProc>::GetModule();
 
   // We hand-register a unique CLSID for each Chrome channel.
   Microsoft::WRL::ComPtr<IUnknown> factory;
@@ -118,6 +121,10 @@
   return exit_signal_.IsSignaled();
 }
 
+void ServiceMain::ResetExitSignaled() {
+  exit_signal_.Reset();
+}
+
 ServiceMain::ServiceMain()
     : run_routine_(&ServiceMain::RunAsService),
       service_status_handle_(nullptr),
@@ -212,6 +219,7 @@
   if (FAILED(hr))
     return hr;
 
+  CreateWRLModule();
   hr = RegisterClassObject();
   if (SUCCEEDED(hr)) {
     WaitForExitSignal();
diff --git a/chrome/elevation_service/service_main.h b/chrome/elevation_service/service_main.h
index 53845bb..67cc5b3 100644
--- a/chrome/elevation_service/service_main.h
+++ b/chrome/elevation_service/service_main.h
@@ -32,6 +32,9 @@
 
   // The following methods are public for the sake of testing.
 
+  // Creates an out-of-proc WRL Module.
+  void CreateWRLModule();
+
   // Registers the Service COM class factory object so other applications can
   // connect to it. Returns the registration status.
   HRESULT RegisterClassObject();
@@ -43,6 +46,9 @@
   // asked to exit.
   bool IsExitSignaled();
 
+  // Resets the state of the |exit_signal_| event.
+  void ResetExitSignaled();
+
  private:
   ServiceMain();
   ~ServiceMain();
diff --git a/chrome/elevation_service/service_main_unittest.cc b/chrome/elevation_service/service_main_unittest.cc
index 62bdca7..a0508a3 100644
--- a/chrome/elevation_service/service_main_unittest.cc
+++ b/chrome/elevation_service/service_main_unittest.cc
@@ -25,6 +25,13 @@
 
 }  // namespace
 
+namespace elevation_service {
+
+void SetupMockContext();
+void TeardownMockContext();
+
+}  // namespace elevation_service
+
 class ServiceMainTest : public testing::Test {
  protected:
   ServiceMainTest() = default;
@@ -37,8 +44,9 @@
     HRESULT hr = service_main_->RegisterClassObject();
     if (SUCCEEDED(hr))
       class_registration_succeeded_ = true;
-
     ASSERT_HRESULT_SUCCEEDED(hr);
+
+    service_main_->ResetExitSignaled();
   }
 
   void TearDown() override {
@@ -62,6 +70,8 @@
   // The waitable event starts unsignaled.
   ASSERT_FALSE(service_main()->IsExitSignaled());
 
+  elevation_service::SetupMockContext();
+
   Microsoft::WRL::ComPtr<IUnknown> unknown;
   ASSERT_HRESULT_SUCCEEDED(
       ::CoCreateInstance(install_static::GetElevatorClsid(), nullptr,
@@ -76,7 +86,8 @@
             elevator->RunRecoveryCRXElevated(
                 TestFile("ChromeRecovery.crx3").value().c_str(),
                 L"{c49ab053-2387-4809-b188-1902648802e1}", L"57.8.0.1",
-                L"{c49ab053-2387-4809-b188-1902648802e1}", 0, &proc_handle));
+                L"{c49ab053-2387-4809-b188-1902648802e1}",
+                ::GetCurrentProcessId(), &proc_handle));
 
   // An object instance has been created upon the request, and is held by the
   // server module. Therefore, the waitable event remains unsignaled.
@@ -85,5 +96,7 @@
   // Release the instance object. Now that the last (and the only) instance
   // object of the module is released, the event becomes signaled.
   elevator.Reset();
+  elevation_service::TeardownMockContext();
+
   ASSERT_TRUE(service_main()->IsExitSignaled());
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 08a0ed8b..6485dba7 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -5331,6 +5331,7 @@
       "../browser/ui/translate/translate_bubble_test_utils.h",
       "../browser/ui/views/accessibility/navigation_accessibility_uitest_win.cc",
       "../browser/ui/views/permission_bubble/permission_bubble_views_interactive_uitest_mac.mm",
+      "../browser/ui/views/tabs/tab_spinner_interactive_uitest.cc",
       "../browser/webauth_interactive_uitest.cc",
       "//ui/base/clipboard/clipboard_unittest.cc",
       "base/always_on_top_window_killer_win.cc",
diff --git a/chrome/test/data/extensions/api_test/native_messaging_launch/test.js b/chrome/test/data/extensions/api_test/native_messaging_launch/test.js
index ed8e5e2..c3db3a6 100644
--- a/chrome/test/data/extensions/api_test/native_messaging_launch/test.js
+++ b/chrome/test/data/extensions/api_test/native_messaging_launch/test.js
@@ -24,6 +24,15 @@
           chrome.test.assertEq(messagesToSend[currentMessage], message.echo);
           chrome.test.assertEq(
               message.caller_url, window.location.origin + '/');
+
+          chrome.test.assertTrue(!!message.args);
+          chrome.test.assertTrue(message.args.includes(
+              '--native-messaging-connect-extension=' +
+              document.location.host));
+          chrome.test.assertTrue(message.args.includes(
+              '--native-messaging-connect-host=' + appName));
+          chrome.test.assertEq('test-connect-id', message.connect_id);
+
           currentMessage++;
 
           if (currentMessage == messagesToSend.length) {
diff --git a/chrome/test/data/native_messaging/native_hosts/echo.py b/chrome/test/data/native_messaging/native_hosts/echo.py
index 5e36ea6..aca1d6f 100755
--- a/chrome/test/data/native_messaging/native_hosts/echo.py
+++ b/chrome/test/data/native_messaging/native_hosts/echo.py
@@ -28,6 +28,7 @@
   parser = argparse.ArgumentParser()
   parser.add_argument('--parent-window', type=int)
   parser.add_argument('--reconnect-command')
+  parser.add_argument('--native-messaging-connect-id')
   parser.add_argument('origin')
   return parser.parse_args()
 
@@ -94,7 +95,7 @@
 
     message = json.dumps({
         'id': message_number, 'echo': text, 'caller_url': caller_url,
-        'args': reconnect_args
+        'args': reconnect_args, 'connect_id': args.native_messaging_connect_id,
     }).encode('utf-8')
     if not WriteMessage(message):
       break
diff --git a/chrome/test/data/perf/tab-spinner-case.html b/chrome/test/data/perf/tab-spinner-case.html
new file mode 100644
index 0000000..7fc794a8
--- /dev/null
+++ b/chrome/test/data/perf/tab-spinner-case.html
@@ -0,0 +1,7 @@
+<body>
+  <div>This document is going to take a long time to load.</div>
+<script>
+  const now = new Date();
+  const seconds = 1000;
+  while ((new Date() - now) < 10 * seconds) {};
+</script>
\ No newline at end of file
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 1d1df1f..32f57fc 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -13,6 +13,7 @@
     "bookmarks/bookmarks_focus_test.js",
     "cr_elements/cr_elements_focus_test.js",
     "cr_elements/cr_elements_v3_focus_test.js",
+    "cr_focus_outline_manager_test.js",
     "cr_focus_row_behavior_interactive_test.js",
     "extensions/cr_extensions_interactive_ui_tests.js",
     "history/history_focus_test.js",
diff --git a/chrome/test/data/webui/cr_focus_outline_manager_test.js b/chrome/test/data/webui/cr_focus_outline_manager_test.js
new file mode 100644
index 0000000..9577233
--- /dev/null
+++ b/chrome/test/data/webui/cr_focus_outline_manager_test.js
@@ -0,0 +1,81 @@
+// 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.
+
+/**
+ * @fileoverview Tests for FocusOutlineManager. Runs in interactive_ui_tests
+ * because it manipulates window focus.
+ */
+
+GEN_INCLUDE(['//chrome/test/data/webui/polymer_interactive_ui_test.js']);
+
+// eslint-disable-next-line no-var
+var FocusOutlineManagerTest = class extends PolymerInteractiveUITest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://resources/html/cr/ui/focus_outline_manager.html';
+  }
+};
+
+TEST_F('FocusOutlineManagerTest', 'AllJsTests', function() {
+  suite('FocusOutlineManager', function() {
+    const documentClassList = document.documentElement.classList;
+
+    // Inspired by test_util.flushTasks(), but without the Polymer flush.
+    function flushTasks() {
+      return new Promise(function(resolve, reject) {
+        window.setTimeout(resolve, 0);
+      });
+    }
+
+    setup(function() {
+      // Start with a focused element.
+      document.body.innerHTML = '<input type="text">';
+      document.querySelector('input').focus();
+
+      // Create an instance of FocusOutlineManager.
+      cr.ui.FocusOutlineManager.forDocument(document);
+    });
+
+    test('key event adds focus css class to document', function() {
+      window.dispatchEvent(new KeyboardEvent('keydown', {key: 'a'}));
+      assertTrue(documentClassList.contains('focus-outline-visible'));
+    });
+
+    test('mouse event removes focus css class from document', function() {
+      document.body.dispatchEvent(new KeyboardEvent('keydown', {key: 'a'}));
+      document.body.dispatchEvent(new MouseEvent('mousedown'));
+      assertFalse(documentClassList.contains('focus-outline-visible'));
+    });
+
+    // Regression test for settings side navigation focus outline appearing
+    // when a new window was opened on top. https://crbug.com/993677
+    test('opening a new window does not add css class', async function() {
+      document.body.dispatchEvent(new MouseEvent('mousedown'));
+      assertFalse(documentClassList.contains('focus-outline-visible'));
+
+      const newWindow = window.open('about:blank', '_blank', 'resizable');
+      await flushTasks();
+      assertFalse(documentClassList.contains('focus-outline-visible'));
+
+      newWindow.close();
+      await flushTasks();
+      assertFalse(documentClassList.contains('focus-outline-visible'));
+    });
+
+    test('opening a new window does not remove css class', async function() {
+      document.body.dispatchEvent(new KeyboardEvent('keydown', {key: 'a'}));
+      assertTrue(documentClassList.contains('focus-outline-visible'));
+
+      const newWindow = window.open('about:blank', '_blank', 'resizable');
+      await flushTasks();
+      assertTrue(documentClassList.contains('focus-outline-visible'));
+
+      newWindow.close();
+      await flushTasks();
+      assertTrue(documentClassList.contains('focus-outline-visible'));
+    });
+  });
+
+  mocha.run();
+});
diff --git a/chromeos/services/secure_channel/secure_channel_service_unittest.cc b/chromeos/services/secure_channel/secure_channel_service_unittest.cc
index 041bcd8..0cdf2b7 100644
--- a/chromeos/services/secure_channel/secure_channel_service_unittest.cc
+++ b/chromeos/services/secure_channel/secure_channel_service_unittest.cc
@@ -28,7 +28,6 @@
 #include "chromeos/services/secure_channel/fake_timer_factory.h"
 #include "chromeos/services/secure_channel/pending_connection_manager_impl.h"
 #include "chromeos/services/secure_channel/public/cpp/shared/connection_priority.h"
-#include "chromeos/services/secure_channel/public/mojom/constants.mojom.h"
 #include "chromeos/services/secure_channel/public/mojom/secure_channel.mojom.h"
 #include "chromeos/services/secure_channel/secure_channel_initializer.h"
 #include "chromeos/services/secure_channel/timer_factory_impl.h"
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc
index 9fdef26..cf1d2aa 100644
--- a/components/download/internal/common/download_item_impl.cc
+++ b/components/download/internal/common/download_item_impl.cc
@@ -2288,19 +2288,6 @@
                          TRACE_EVENT_SCOPE_THREAD, "danger_type",
                          GetDownloadDangerNames(danger_type).c_str());
   }
-  // Only record the Malicious UMA stat if it's going from {not malicious} ->
-  // {malicious}.
-  if ((danger_type_ == DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
-       danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
-       danger_type_ == DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
-       danger_type_ == DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT ||
-       danger_type_ == DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY) &&
-      (danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
-       danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
-       danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
-       danger_type == DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED)) {
-    RecordMaliciousDownloadClassified(danger_type);
-  }
   danger_type_ = danger_type;
 }
 
diff --git a/components/download/internal/common/download_stats.cc b/components/download/internal/common/download_stats.cc
index 06dce39aa..d12e862 100644
--- a/components/download/internal/common/download_stats.cc
+++ b/components/download/internal/common/download_stats.cc
@@ -668,11 +668,6 @@
   }
 }
 
-void RecordMaliciousDownloadClassified(DownloadDangerType danger_type) {
-  UMA_HISTOGRAM_ENUMERATION("Download.MaliciousDownloadClassified", danger_type,
-                            DOWNLOAD_DANGER_TYPE_MAX);
-}
-
 void RecordDangerousDownloadAccept(DownloadDangerType danger_type,
                                    const base::FilePath& file_path) {
   UMA_HISTOGRAM_ENUMERATION("Download.DangerousDownloadValidated", danger_type,
diff --git a/components/download/public/common/download_stats.h b/components/download/public/common/download_stats.h
index 031d4ba..ffafffa18 100644
--- a/components/download/public/common/download_stats.h
+++ b/components/download/public/common/download_stats.h
@@ -269,10 +269,6 @@
     bool is_parallel_download_enabled,
     DownloadSource download_source);
 
-// Record that a download has been classified as malicious.
-COMPONENTS_DOWNLOAD_EXPORT void RecordMaliciousDownloadClassified(
-    DownloadDangerType danger_type);
-
 // Record a dangerous download accept event.
 COMPONENTS_DOWNLOAD_EXPORT void RecordDangerousDownloadAccept(
     DownloadDangerType danger_type,
diff --git a/components/invalidation/OWNERS b/components/invalidation/OWNERS
index 7a57abd..ea3ae77 100644
--- a/components/invalidation/OWNERS
+++ b/components/invalidation/OWNERS
@@ -4,3 +4,4 @@
 melandory@chromium.org
 
 # COMPONENT: Services>Invalidation
+# TEAM: chromium-reviews@chromium.org
diff --git a/components/leveldb_proto/internal/proto_database_selector.cc b/components/leveldb_proto/internal/proto_database_selector.cc
index 417b23f..f453865 100644
--- a/components/leveldb_proto/internal/proto_database_selector.cc
+++ b/components/leveldb_proto/internal/proto_database_selector.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/metrics/histogram_macros.h"
 #include "components/leveldb_proto/internal/migration_delegate.h"
 #include "components/leveldb_proto/internal/shared_proto_database.h"
 #include "components/leveldb_proto/internal/shared_proto_database_provider.h"
@@ -25,6 +26,12 @@
 
 }  // namespace
 
+// static
+void ProtoDatabaseSelector::RecordInitState(
+    ProtoDatabaseSelector::ProtoDatabaseInitState state) {
+  UMA_HISTOGRAM_ENUMERATION("ProtoDB.SharedDbInitStatus", state);
+}
+
 ProtoDatabaseSelector::ProtoDatabaseSelector(
     ProtoDbType db_type,
     scoped_refptr<base::SequencedTaskRunner> task_runner,
@@ -57,7 +64,7 @@
       database, database_dir, options, false,
       base::BindOnce(&RunInitCallbackOnTaskRunner, std::move(callback),
                      callback_task_runner));
-  OnInitDone();
+  OnInitDone(ProtoDatabaseInitState::kLegacyInitCalled);
 }
 
 void ProtoDatabaseSelector::InitUniqueOrShared(
@@ -67,6 +74,7 @@
     bool use_shared_db,
     scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
     Callbacks::InitStatusCallback callback) {
+  RecordInitState(ProtoDatabaseInitState::kSharedDbInitAttempted);
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   init_status_ = InitStatus::IN_PROGRESS;
   unique_database_dir_ = db_dir;
@@ -112,7 +120,7 @@
   if (status == Enums::InitStatus::kCorrupt) {
     db_ = std::move(unique_db);
     std::move(callback).Run(Enums::InitStatus::kCorrupt);
-    OnInitDone();
+    OnInitDone(ProtoDatabaseInitState::kFailureUniqueDbCorrupted);
     return;
   }
 
@@ -127,7 +135,7 @@
   if (!db_provider_ || unique_database_dir_.empty()) {
     db_ = std::move(unique_db);
     std::move(callback).Run(status);
-    OnInitDone();
+    OnInitDone(ProtoDatabaseInitState::kFailureNoDatabaseProvider);
     return;
   }
 
@@ -175,7 +183,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!unique_db && !client) {
     std::move(callback).Run(Enums::InitStatus::kError);
-    OnInitDone();
+    OnInitDone(ProtoDatabaseInitState::kBothUniqueAndSharedFailedOpen);
     return;
   }
 
@@ -184,7 +192,7 @@
       // If there's no shared client and one is requested we return an error,
       // because it should be created if missing.
       std::move(callback).Run(Enums::InitStatus::kError);
-      OnInitDone();
+      OnInitDone(ProtoDatabaseInitState::kSharedDbClientMissingInitFailed);
       return;
     } else {
       // ProtoLevelDBWrapper::InitWithDatabase() returns kInvalidOperation when
@@ -194,13 +202,14 @@
         // return the unique DB.
         db_ = std::move(unique_db);
         std::move(callback).Run(Enums::InitStatus::kOK);
-        OnInitDone();
+        OnInitDone(
+            ProtoDatabaseInitState::kSharedDbClientMissingUniqueReturned);
         return;
       } else {
         // If the shared DB failed to open and a unique DB is requested then we
         // throw an error, as the shared DB may contain unmigrated data.
         std::move(callback).Run(Enums::InitStatus::kError);
-        OnInitDone();
+        OnInitDone(ProtoDatabaseInitState::kSharedDbOpenFailed);
         return;
       }
     }
@@ -221,14 +230,14 @@
               SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL);
           db_ = std::move(client);
           std::move(callback).Run(Enums::InitStatus::kOK);
-          OnInitDone();
+          OnInitDone(ProtoDatabaseInitState::kUniqueDbMissingSharedReturned);
           return;
         } else {
           // If the unique DB failed to open and the migration status is not
           // attempted then we return an error, as we don't know if the unique
           // DB contains any data.
           std::move(callback).Run(Enums::InitStatus::kError);
-          OnInitDone();
+          OnInitDone(ProtoDatabaseInitState::kUniqueDbOpenFailed);
           return;
         }
         break;
@@ -241,7 +250,7 @@
         // and there's no way to migrate.
         db_ = std::move(client);
         std::move(callback).Run(Enums::InitStatus::kOK);
-        OnInitDone();
+        OnInitDone(ProtoDatabaseInitState::kMigratedSharedDbOpened);
         return;
         break;
       case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL:
@@ -250,7 +259,7 @@
         // we throw an error. We ignore the deletion flag because we want both
         // databases to be open before we delete the shared DB.
         std::move(callback).Run(Enums::InitStatus::kError);
-        OnInitDone();
+        OnInitDone(ProtoDatabaseInitState::kUniqueDbOpenFailed);
         return;
         break;
     }
@@ -264,6 +273,7 @@
         // Migrate from unique to shared.
         UniqueProtoDatabase* from = unique_db.get();
         UniqueProtoDatabase* to = client.get();
+        RecordInitState(ProtoDatabaseInitState::kMigrateToSharedAttempted);
         migration_delegate_->DoMigration(
             from, to,
             base::BindOnce(&ProtoDatabaseSelector::OnMigrationTransferComplete,
@@ -294,6 +304,7 @@
         // Migrate from shared to unique.
         UniqueProtoDatabase* from = client.get();
         UniqueProtoDatabase* to = unique_db.get();
+        RecordInitState(ProtoDatabaseInitState::kMigrateToUniqueAttempted);
         migration_delegate_->DoMigration(
             from, to,
             base::BindOnce(&ProtoDatabaseSelector::OnMigrationTransferComplete,
@@ -358,12 +369,15 @@
             : SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED);
     db_ = use_shared_db ? std::move(unique_db) : std::move(client);
     std::move(callback).Run(Enums::InitStatus::kOK);
-    OnInitDone();
+    OnInitDone(ProtoDatabaseInitState::kDeletionOfOldDataFailed);
     return;
   }
 
   auto* from = use_shared_db ? unique_db.get() : client.get();
   auto* to = use_shared_db ? client.get() : unique_db.get();
+  RecordInitState(use_shared_db
+                      ? ProtoDatabaseInitState::kMigrateToSharedAttempted
+                      : ProtoDatabaseInitState::kMigrateToUniqueAttempted);
   migration_delegate_->DoMigration(
       from, to,
       base::BindOnce(&ProtoDatabaseSelector::OnMigrationTransferComplete, this,
@@ -397,7 +411,8 @@
           : SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED);
   db_ = use_shared_db ? std::move(unique_db) : std::move(client);
   std::move(callback).Run(Enums::InitStatus::kOK);
-  OnInitDone();
+  OnInitDone(use_shared_db ? ProtoDatabaseInitState::kMigrateToSharedFailed
+                           : ProtoDatabaseInitState::kMigrateToUniqueFailed);
 }
 
 void ProtoDatabaseSelector::OnMigrationCleanupComplete(
@@ -410,20 +425,27 @@
   // We still return true in our callback below because we do have a database as
   // far as the original caller is concerned. As long as |db_| is assigned, we
   // return true.
+  ProtoDatabaseInitState state;
   if (success) {
     client->UpdateClientInitMetadata(
         use_shared_db ? SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL
                       : SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL);
+    state = use_shared_db ? ProtoDatabaseInitState::kMigrateToSharedSuccess
+                          : ProtoDatabaseInitState::kMigrateToUniqueSuccess;
   } else {
     client->UpdateClientInitMetadata(
         use_shared_db
             ? SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED
             : SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED);
+    state =
+        use_shared_db
+            ? ProtoDatabaseInitState::kMigrateToUniqueCompleteDeletionFailed
+            : ProtoDatabaseInitState::kMigrateToSharedCompleteDeletionFailed;
   }
   // Migration transfer was complete. So, we should use the requested database.
   db_ = use_shared_db ? std::move(client) : std::move(unique_db);
   std::move(callback).Run(Enums::InitStatus::kOK);
-  OnInitDone();
+  OnInitDone(state);
 }
 
 void ProtoDatabaseSelector::AddTransaction(base::OnceClosure task) {
@@ -579,7 +601,10 @@
   db_->RemoveKeysForTesting(key_filter, target_prefix, std::move(callback));
 }
 
-void ProtoDatabaseSelector::OnInitDone() {
+void ProtoDatabaseSelector::OnInitDone(
+    ProtoDatabaseSelector::ProtoDatabaseInitState state) {
+  RecordInitState(state);
+
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   init_status_ = InitStatus::DONE;
   while (!pending_tasks_.empty()) {
diff --git a/components/leveldb_proto/internal/proto_database_selector.h b/components/leveldb_proto/internal/proto_database_selector.h
index 73ee4a4..3d15888 100644
--- a/components/leveldb_proto/internal/proto_database_selector.h
+++ b/components/leveldb_proto/internal/proto_database_selector.h
@@ -29,6 +29,41 @@
 class COMPONENT_EXPORT(LEVELDB_PROTO) ProtoDatabaseSelector
     : public base::RefCountedThreadSafe<ProtoDatabaseSelector> {
  public:
+  // These values are logged to UMA. Entries should not be renumbered and
+  // numeric values should never be reused. Please keep in sync with
+  // "ProtoDatabaseInitState" in src/tools/metrics/histograms/enums.xml.
+  enum class ProtoDatabaseInitState {
+    kSharedDbInitAttempted = 0,
+    kFailureUniqueDbCorrupted = 1,
+    kFailureNoDatabaseProvider = 2,
+    kBothUniqueAndSharedFailedOpen = 3,
+    kSharedDbClientMissingInitFailed = 4,
+    kSharedDbClientMissingUniqueReturned = 5,
+    kSharedDbOpenFailed = 6,
+    kUniqueDbMissingSharedReturned = 7,
+    kUniqueDbOpenFailed = 8,
+    kMigrateToSharedAttempted = 9,
+    kMigrateToUniqueAttempted = 10,
+    kMigratedSharedDbOpened = 11,
+    kDeletionOfOldDataFailed = 12,
+    kMigrateToSharedFailed = 13,
+    kMigrateToUniqueFailed = 14,
+    kMigrateToSharedCompleteDeletionFailed = 15,
+    kMigrateToUniqueCompleteDeletionFailed = 16,
+    kMigrateToSharedSuccess = 17,
+    kMigrateToUniqueSuccess = 18,
+    kLegacyInitCalled = 19,
+    kSharedDbMetadataLoadFailed = 20,
+    kSharedDbMetadataWriteFailed = 21,
+    kSharedDbClientCorrupt = 22,
+    kSharedDbClientSuccess = 23,
+    kSharedLevelDbInitFailure = 24,
+    kSharedDbClientMissing = 25,
+    kMaxValue = kSharedDbClientMissing
+  };
+
+  static void RecordInitState(ProtoDatabaseInitState state);
+
   ProtoDatabaseSelector(
       ProtoDbType db_type,
       scoped_refptr<base::SequencedTaskRunner> task_runner,
@@ -147,7 +182,7 @@
       bool use_shared_db,
       Callbacks::InitStatusCallback callback,
       bool success);
-  void OnInitDone();
+  void OnInitDone(ProtoDatabaseInitState state);
 
   ProtoDbType db_type_;
   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
diff --git a/components/leveldb_proto/internal/shared_proto_database.cc b/components/leveldb_proto/internal/shared_proto_database.cc
index cd65ddf..350c0cb 100644
--- a/components/leveldb_proto/internal/shared_proto_database.cc
+++ b/components/leveldb_proto/internal/shared_proto_database.cc
@@ -11,6 +11,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/task/post_task.h"
 #include "components/leveldb_proto/internal/leveldb_database.h"
+#include "components/leveldb_proto/internal/proto_database_selector.h"
 #include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
 
@@ -37,7 +38,9 @@
     SharedProtoDatabase::SharedClientInitCallback callback,
     scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
     Enums::InitStatus status,
-    SharedDBMetadataProto::MigrationStatus migration_status) {
+    SharedDBMetadataProto::MigrationStatus migration_status,
+    ProtoDatabaseSelector::ProtoDatabaseInitState metric) {
+  ProtoDatabaseSelector::RecordInitState(metric);
   callback_task_runner->PostTask(
       FROM_HERE, base::BindOnce(std::move(callback), status, migration_status));
 }
@@ -140,7 +143,9 @@
   if (!success) {
     RunInitStatusCallbackOnCallingSequence(
         std::move(callback), std::move(callback_task_runner),
-        Enums::InitStatus::kOK, SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED);
+        Enums::InitStatus::kOK, SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED,
+        ProtoDatabaseSelector::ProtoDatabaseInitState::
+            kSharedDbMetadataLoadFailed);
     return;
   }
   if (!proto || !proto->has_migration_status()) {
@@ -155,19 +160,24 @@
               RunInitStatusCallbackOnCallingSequence(
                   std::move(callback), std::move(callback_task_runner),
                   Enums::InitStatus::kOK,
-                  SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED);
+                  SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED,
+                  ProtoDatabaseSelector::ProtoDatabaseInitState::
+                      kSharedDbMetadataWriteFailed);
             },
             std::move(callback), std::move(callback_task_runner)));
     return;
   }
   // If we've made it here, we know that the current status of our database is
   // OK. Make it return corrupt if the metadata disagrees.
+  bool is_corrupt = metadata_->corruptions() != proto->corruptions();
   RunInitStatusCallbackOnCallingSequence(
       std::move(callback), std::move(callback_task_runner),
-      metadata_->corruptions() != proto->corruptions()
-          ? Enums::InitStatus::kCorrupt
-          : Enums::InitStatus::kOK,
-      proto->migration_status());
+      is_corrupt ? Enums::InitStatus::kCorrupt : Enums::InitStatus::kOK,
+      proto->migration_status(),
+      is_corrupt ? ProtoDatabaseSelector::ProtoDatabaseInitState::
+                       kSharedDbClientCorrupt
+                 : ProtoDatabaseSelector::ProtoDatabaseInitState::
+                       kSharedDbClientSuccess);
 }
 
 void SharedProtoDatabase::CheckCorruptionAndRunInitCallback(
@@ -182,7 +192,8 @@
   }
   RunInitStatusCallbackOnCallingSequence(
       std::move(callback), std::move(callback_task_runner), init_status_,
-      SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED);
+      SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED,
+      ProtoDatabaseSelector::ProtoDatabaseInitState::kSharedLevelDbInitFailure);
 }
 
 // Setting |create_if_missing| to false allows us to test whether or not the
@@ -226,7 +237,9 @@
       RunInitStatusCallbackOnCallingSequence(
           std::move(callback), std::move(callback_task_runner),
           Enums::InitStatus::kError,
-          SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED);
+          SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED,
+          ProtoDatabaseSelector::ProtoDatabaseInitState::
+              kSharedLevelDbInitFailure);
       break;
 
     case InitState::kNotFound:
@@ -245,7 +258,9 @@
         RunInitStatusCallbackOnCallingSequence(
             std::move(callback), std::move(callback_task_runner),
             Enums::InitStatus::kInvalidOperation,
-            SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED);
+            SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED,
+            ProtoDatabaseSelector::ProtoDatabaseInitState::
+                kSharedDbClientMissing);
       }
       break;
   }
diff --git a/components/services/app_service/public/cpp/BUILD.gn b/components/services/app_service/public/cpp/BUILD.gn
new file mode 100644
index 0000000..502f85c
--- /dev/null
+++ b/components/services/app_service/public/cpp/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("app_file_handling") {
+  sources = [
+    "file_handler_info.cc",
+    "file_handler_info.h",
+  ]
+}
diff --git a/components/services/app_service/public/cpp/file_handler_info.cc b/components/services/app_service/public/cpp/file_handler_info.cc
new file mode 100644
index 0000000..d073c49
--- /dev/null
+++ b/components/services/app_service/public/cpp/file_handler_info.cc
@@ -0,0 +1,25 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/services/app_service/public/cpp/file_handler_info.h"
+
+namespace apps {
+
+namespace file_handler_verbs {
+
+const char kOpenWith[] = "open_with";
+const char kAddTo[] = "add_to";
+const char kPackWith[] = "pack_with";
+const char kShareWith[] = "share_with";
+
+}  // namespace file_handler_verbs
+
+FileHandlerInfo::FileHandlerInfo()
+    : include_directories(false), verb(file_handler_verbs::kOpenWith) {}
+
+FileHandlerInfo::FileHandlerInfo(const FileHandlerInfo& other) = default;
+
+FileHandlerInfo::~FileHandlerInfo() {}
+
+}  // namespace apps
diff --git a/components/services/app_service/public/cpp/file_handler_info.h b/components/services/app_service/public/cpp/file_handler_info.h
new file mode 100644
index 0000000..c122fc20
--- /dev/null
+++ b/components/services/app_service/public/cpp/file_handler_info.h
@@ -0,0 +1,47 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_FILE_HANDLER_INFO_H_
+#define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_FILE_HANDLER_INFO_H_
+
+#include <set>
+#include <string>
+
+namespace apps {
+
+namespace file_handler_verbs {
+
+// Supported verbs for file handlers.
+extern const char kOpenWith[];
+extern const char kAddTo[];
+extern const char kPackWith[];
+extern const char kShareWith[];
+
+}  // namespace file_handler_verbs
+
+// Contains information about a file handler for an app.
+struct FileHandlerInfo {
+  FileHandlerInfo();
+  FileHandlerInfo(const FileHandlerInfo& other);
+  ~FileHandlerInfo();
+
+  // The id of this handler.
+  std::string id;
+
+  // File extensions associated with this handler.
+  std::set<std::string> extensions;
+
+  // MIME types associated with this handler.
+  std::set<std::string> types;
+
+  // True if the handler can manage directories.
+  bool include_directories;
+
+  // A verb describing the intent of the handler.
+  std::string verb;
+};
+
+}  // namespace apps
+
+#endif  // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_FILE_HANDLER_INFO_H_
\ No newline at end of file
diff --git a/components/test/data/payments/render_tests/PaymentRequestFreeShippingTest.NightModeEnabled-free_shipping.Nexus_5-19.png.sha1 b/components/test/data/payments/render_tests/PaymentRequestFreeShippingTest.NightModeEnabled-free_shipping.Nexus_5-19.png.sha1
index 5147936..208f827 100644
--- a/components/test/data/payments/render_tests/PaymentRequestFreeShippingTest.NightModeEnabled-free_shipping.Nexus_5-19.png.sha1
+++ b/components/test/data/payments/render_tests/PaymentRequestFreeShippingTest.NightModeEnabled-free_shipping.Nexus_5-19.png.sha1
@@ -1 +1 @@
-efd8747fb730baf33b2bb6169ea6fc1eb97f0129
\ No newline at end of file
+e274c8ea0773890604772fe16c57c29e157e52c5
\ No newline at end of file
diff --git a/components/ui_devtools/views/BUILD.gn b/components/ui_devtools/views/BUILD.gn
index e9fb3b2..8a422954 100644
--- a/components/ui_devtools/views/BUILD.gn
+++ b/components/ui_devtools/views/BUILD.gn
@@ -29,7 +29,6 @@
 
   deps = [
     "//components/ui_devtools",
-    "//extensions/common",
     "//skia",
     "//ui/views",
   ]
diff --git a/components/ui_devtools/views/DEPS b/components/ui_devtools/views/DEPS
index 7484cad79..f97255e 100644
--- a/components/ui_devtools/views/DEPS
+++ b/components/ui_devtools/views/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+extensions/common/image_util.h",
   "+third_party/skia/include",
   "+ui"
 ]
diff --git a/components/ui_devtools/views/element_utility.cc b/components/ui_devtools/views/element_utility.cc
index ff2eb56..eb1eef6d 100644
--- a/components/ui_devtools/views/element_utility.cc
+++ b/components/ui_devtools/views/element_utility.cc
@@ -50,14 +50,4 @@
   }
 }
 
-bool ParseColorFromFrontend(const std::string& input, std::string* output) {
-  std::string value;
-  base::TrimWhitespaceASCII(input, base::TRIM_ALL, &value);
-  SkColor color;
-  if (!extensions::image_util::ParseCssColorString(value, &color))
-    return false;
-  *output = base::NumberToString(color);
-  return true;
-}
-
 }  // namespace ui_devtools
diff --git a/components/ui_devtools/views/element_utility.h b/components/ui_devtools/views/element_utility.h
index df87e4e..7aa19a1f 100644
--- a/components/ui_devtools/views/element_utility.h
+++ b/components/ui_devtools/views/element_utility.h
@@ -9,8 +9,6 @@
 #include <vector>
 
 #include "components/ui_devtools/ui_element.h"
-#include "extensions/common/image_util.h"
-#include "third_party/skia/include/core/SkColor.h"
 
 namespace ui {
 class Layer;
@@ -26,11 +24,6 @@
 void AppendLayerPropertiesMatchedStyle(const ui::Layer* layer,
                                        std::vector<UIElement::UIProperty>* ret);
 
-// Takes in color property from DevTools frontend as string in rgba()/rgb(),
-// hex, or hsla()/hsl() format and sets |output| to the SkColor value as a
-// string. Returns true if successful.
-bool ParseColorFromFrontend(const std::string& input, std::string* output);
-
 }  // namespace ui_devtools
 
 #endif  // COMPONENTS_UI_DEVTOOLS_VIEWS_ELEMENT_UTILITY_H_
diff --git a/components/ui_devtools/views/view_element.cc b/components/ui_devtools/views/view_element.cc
index 6115ce9..69886d2f 100644
--- a/components/ui_devtools/views/view_element.cc
+++ b/components/ui_devtools/views/view_element.cc
@@ -9,30 +9,10 @@
 #include "components/ui_devtools/Protocol.h"
 #include "components/ui_devtools/ui_element_delegate.h"
 #include "components/ui_devtools/views/element_utility.h"
-#include "ui/gfx/color_utils.h"
 #include "ui/views/widget/widget.h"
 
 namespace ui_devtools {
 
-namespace {
-
-// Returns true if |property_name| is type SkColor, false if not. If type
-// SkColor, remove the "--" from the name.
-bool GetSkColorPropertyName(std::string& property_name) {
-  if (property_name.length() < 2U)
-    return false;
-
-  // Check if property starts with "--", meaning its type is SkColor.
-  if (property_name[0] == '-' && property_name[1] == '-') {
-    // Remove "--" from |property_name|.
-    base::TrimString(property_name, "-", &property_name);
-    return true;
-  }
-  return false;
-}
-
-}  // namespace
-
 ViewElement::ViewElement(views::View* view,
                          UIElementDelegate* ui_element_delegate,
                          UIElement* parent)
@@ -110,19 +90,9 @@
                                       base::UTF16ToUTF8(description));
     }
 
-    // Check if type is SkColor and add "--" to property name so that DevTools
-    // frontend will interpret this field as a color. Also convert SkColor value
-    // to rgba string.
-    if ((*member)->member_type() == "SkColor") {
-      SkColor color;
-      if (base::StringToUint(
-              base::UTF16ToUTF8((*member)->GetValueAsString(view_)), &color))
-        class_properties.emplace_back("--" + (*member)->member_name(),
-                                      color_utils::SkColorToRgbaString(color));
-    } else
-      class_properties.emplace_back(
-          (*member)->member_name(),
-          base::UTF16ToUTF8((*member)->GetValueAsString(view_)));
+    class_properties.emplace_back(
+        (*member)->member_name(),
+        base::UTF16ToUTF8((*member)->GetValueAsString(view_)));
 
     if (member.IsLastMember()) {
       ret.emplace_back(member.GetCurrentCollectionName(), class_properties);
@@ -151,7 +121,6 @@
 }
 
 bool ViewElement::SetPropertiesFromString(const std::string& text) {
-  bool property_set = false;
   std::vector<std::string> tokens = base::SplitString(
       text, ":;", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 
@@ -159,15 +128,8 @@
     return false;
 
   for (size_t i = 0; i < tokens.size() - 1; i += 2) {
-    std::string property_name = tokens.at(i);
-    std::string property_value = base::ToLowerASCII(tokens.at(i + 1));
-
-    // Check if property is type SkColor.
-    if (GetSkColorPropertyName(property_name)) {
-      // Convert from CSS color format to SkColor.
-      if (!ParseColorFromFrontend(property_value, &property_value))
-        continue;
-    }
+    const std::string& property_name = tokens.at(i);
+    const std::string& property_value = base::ToLowerASCII(tokens.at(i + 1));
 
     views::metadata::ClassMetaData* metadata = view_->GetClassMetaData();
     views::metadata::MemberMetaDataBase* member =
@@ -188,10 +150,9 @@
     }
 
     member->SetValueAsString(view_, base::UTF8ToUTF16(property_value));
-    property_set = true;
   }
 
-  return property_set;
+  return true;
 }
 
 std::vector<std::string> ViewElement::GetAttributes() const {
diff --git a/components/ui_devtools/views/view_element_unittest.cc b/components/ui_devtools/views/view_element_unittest.cc
index 81dc700..6e1d0bd 100644
--- a/components/ui_devtools/views/view_element_unittest.cc
+++ b/components/ui_devtools/views/view_element_unittest.cc
@@ -73,18 +73,13 @@
   int GetBoolProperty() const { return bool_property_; }
   void SetBoolProperty(bool bool_property) { bool_property_ = bool_property; }
 
-  SkColor GetColorProperty() const { return color_property_; }
-  void SetColorProperty(SkColor color) { color_property_ = color; }
-
  private:
   bool bool_property_ = false;
-  SkColor color_property_;
 };
 
 BEGIN_METADATA(NamedTestView)
 METADATA_PARENT_CLASS(views::View)
 ADD_PROPERTY_METADATA(NamedTestView, bool, BoolProperty)
-ADD_PROPERTY_METADATA(NamedTestView, SkColor, ColorProperty)
 END_METADATA()
 
 class ViewElementTest : public views::ViewsTestBase {
@@ -252,42 +247,6 @@
   view()->parent()->RemoveChildView(view());
 }
 
-TEST_F(ViewElementTest, ColorProperty) {
-  EXPECT_EQ(GetPropertyIndices(element(), "--ColorProperty").first, 0U);
-
-  view()->SetColorProperty(SkColorSetARGB(1, 4, 16, 64));
-  DCHECK_EQ(view()->GetColorProperty(), SkColorSetARGB(1, 4, 16, 64));
-
-  EXPECT_TRUE(element()->SetPropertiesFromString(
-      "--ColorProperty: rgba(0,0,  255, 1);"));
-  EXPECT_EQ(view()->GetColorProperty(), SK_ColorBLUE);
-
-  EXPECT_TRUE(element()->SetPropertiesFromString("--ColorProperty: #0352fc"));
-  EXPECT_EQ(view()->GetColorProperty(), SkColorSetARGB(255, 3, 82, 252));
-
-  EXPECT_TRUE(element()->SetPropertiesFromString(
-      "--ColorProperty: hsl(240, 84%, 28%);"));
-  EXPECT_EQ(view()->GetColorProperty(), SkColorSetARGB(255, 11, 11, 131));
-}
-
-TEST_F(ViewElementTest, BadColorProperty) {
-  view()->SetColorProperty(SK_ColorGRAY);
-  DCHECK_EQ(view()->GetColorProperty(), SK_ColorGRAY);
-
-  EXPECT_FALSE(
-      element()->SetPropertiesFromString("-ColorProperty: rgba(1,2,3,4);"));
-  EXPECT_EQ(view()->GetColorProperty(), SK_ColorGRAY);
-
-  EXPECT_FALSE(
-      element()->SetPropertiesFromString("--ColorProperty: rgba(1,2,3,4;"));
-  EXPECT_EQ(view()->GetColorProperty(), SK_ColorGRAY);
-
-  EXPECT_FALSE(
-      element()->SetPropertiesFromString("--ColorProperty: rgb(1,2,3,4;)"));
-  EXPECT_EQ(view()->GetColorProperty(), SK_ColorGRAY);
-
-}
-
 TEST_F(ViewElementTest, GetSources) {
   std::vector<UIElement::Source> sources = element()->GetSources();
 
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc
index b6223fe..d69d7213 100644
--- a/components/viz/service/display/renderer_pixeltest.cc
+++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -1321,8 +1321,7 @@
     ::testing::Types<GLRenderer, cc::GLRendererWithExpandedViewport>;
 
 TYPED_TEST_SUITE(IntersectingQuadPixelTest, RendererTypes);
-// TODO(crbug.gom/939442): Enable these tests for SkiaRenderer.
-TYPED_TEST_SUITE(IntersectingVideoQuadPixelTest, GLRendererTypes);
+TYPED_TEST_SUITE(IntersectingVideoQuadPixelTest, GPURendererTypes);
 TYPED_TEST_SUITE(IntersectingQuadSoftwareTest, SoftwareRendererTypes);
 
 TYPED_TEST(IntersectingQuadPixelTest, SolidColorQuads) {
@@ -1534,7 +1533,7 @@
       this->child_context_provider_.get());
 
   this->AppendBackgroundAndRunTest(
-      cc::FuzzyPixelOffByOneComparator(false),
+      cc::FuzzyPixelComparator(true, 0.50f, 0.f, 1.2f, 2, 0),
       FILE_PATH_LITERAL("intersecting_blue_green_squares_video.png"));
 }
 
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 3bff348..b9935023 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -269,6 +269,8 @@
     case DrawQuad::Material::kTiledContent:
       return TileDrawQuad::MaterialCast(quad)->force_anti_aliasing_off;
     case DrawQuad::Material::kYuvVideoContent:
+    case DrawQuad::Material::kStreamVideoContent:
+    case DrawQuad::Material::kTextureContent:
       // This is done to match the behaviour of GLRenderer and we can revisit it
       // later.
       return true;
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index dfcd97c..8d58aed 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -87,29 +87,41 @@
 
 // Service workers
 ServiceWorkerRunningInfo GetContextForHost(ServiceWorkerProviderHost* host) {
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
+
   // TODO(crbug.com/993409): pass Origin instead of GURL
   return {host->running_hosted_version()->script_origin().GetURL(),
           host->running_hosted_version()->version_id(), host->process_id()};
 }
 
 void PopulateServiceWorkerBinders(ServiceWorkerProviderHost* host,
-                                  service_manager::BinderMap* map) {}
+                                  service_manager::BinderMap* map) {
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
+}
 
 void PopulateBinderMapWithContext(
     ServiceWorkerProviderHost* host,
     service_manager::BinderMapWithContext<const ServiceWorkerRunningInfo&>*
         map) {
-  // Using a task runner since ServiceWorkerProviderHost lives on the IO thread,
-  // and CreateForWorker() needs to be called on the UI thread.
-  map->Add<blink::mojom::BackgroundFetchService>(
-      base::BindRepeating(&BackgroundFetchServiceImpl::CreateForWorker),
-      base::CreateSingleThreadTaskRunnerWithTraits(BrowserThread::UI));
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
+
+  // Use a task runner if ServiceWorkerProviderHost lives on the IO
+  // thread, as CreateForWorker() needs to be called on the UI thread.
+  if (ServiceWorkerContextWrapper::IsServiceWorkerOnUIEnabled()) {
+    map->Add<blink::mojom::BackgroundFetchService>(
+        base::BindRepeating(&BackgroundFetchServiceImpl::CreateForWorker));
+  } else {
+    map->Add<blink::mojom::BackgroundFetchService>(
+        base::BindRepeating(&BackgroundFetchServiceImpl::CreateForWorker),
+        base::CreateSingleThreadTaskRunnerWithTraits(BrowserThread::UI));
+  }
 }
 
 void PopulateBinderMap(ServiceWorkerProviderHost* host,
                        service_manager::BinderMap* map) {
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   PopulateServiceWorkerBinders(host, map);
 }
 
 }  // namespace internal
-}  // namespace content
\ No newline at end of file
+}  // namespace content
diff --git a/content/browser/devtools/devtools_renderer_channel.cc b/content/browser/devtools/devtools_renderer_channel.cc
index bdc94a7..f0cb4ee 100644
--- a/content/browser/devtools/devtools_renderer_channel.cc
+++ b/content/browser/devtools/devtools_renderer_channel.cc
@@ -27,7 +27,6 @@
     mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote,
     mojo::PendingReceiver<blink::mojom::DevToolsAgentHost> host_receiver,
     int process_id,
-    RenderFrameHostImpl* frame_host,
     base::OnceClosure connection_error) {
   CleanupConnection();
   blink::mojom::DevToolsAgent* agent = nullptr;
@@ -39,7 +38,7 @@
     agent_remote_.set_disconnect_handler(std::move(connection_error));
   if (host_receiver)
     receiver_.Bind(std::move(host_receiver));
-  SetRendererInternal(agent, process_id, frame_host);
+  SetRendererInternal(agent, process_id, nullptr);
 }
 
 void DevToolsRendererChannel::SetRendererAssociated(
diff --git a/content/browser/devtools/devtools_renderer_channel.h b/content/browser/devtools/devtools_renderer_channel.h
index 9ef9129..0ab7b2c 100644
--- a/content/browser/devtools/devtools_renderer_channel.h
+++ b/content/browser/devtools/devtools_renderer_channel.h
@@ -50,7 +50,6 @@
       mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote,
       mojo::PendingReceiver<blink::mojom::DevToolsAgentHost> host_receiver,
       int process_id,
-      RenderFrameHostImpl* frame_host,
       base::OnceClosure connection_error = base::NullCallback());
   void SetRendererAssociated(
       mojo::PendingAssociatedRemote<blink::mojom::DevToolsAgent> agent_remote,
diff --git a/content/browser/devtools/service_worker_devtools_agent_host.cc b/content/browser/devtools/service_worker_devtools_agent_host.cc
index 9a60aa7..d89c902 100644
--- a/content/browser/devtools/service_worker_devtools_agent_host.cc
+++ b/content/browser/devtools/service_worker_devtools_agent_host.cc
@@ -164,9 +164,8 @@
     mojo::PendingReceiver<blink::mojom::DevToolsAgentHost> host_receiver) {
   DCHECK_EQ(WORKER_NOT_READY, state_);
   state_ = WORKER_READY;
-  GetRendererChannel()->SetRenderer(std::move(agent_remote),
-                                    std::move(host_receiver),
-                                    worker_process_id_, nullptr);
+  GetRendererChannel()->SetRenderer(
+      std::move(agent_remote), std::move(host_receiver), worker_process_id_);
   for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
     inspector->TargetReloadedAfterCrash();
   if (!sessions().empty())
@@ -187,8 +186,7 @@
   for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
     inspector->TargetCrashed();
   GetRendererChannel()->SetRenderer(mojo::NullRemote(), mojo::NullReceiver(),
-                                    ChildProcessHost::kInvalidUniqueID,
-                                    nullptr);
+                                    ChildProcessHost::kInvalidUniqueID);
   if (!sessions().empty())
     UpdateIsAttached(false);
 }
diff --git a/content/browser/devtools/shared_worker_devtools_agent_host.cc b/content/browser/devtools/shared_worker_devtools_agent_host.cc
index 8fc1f74..1452e48e 100644
--- a/content/browser/devtools/shared_worker_devtools_agent_host.cc
+++ b/content/browser/devtools/shared_worker_devtools_agent_host.cc
@@ -98,7 +98,7 @@
   state_ = WORKER_READY;
   GetRendererChannel()->SetRenderer(std::move(agent_remote),
                                     std::move(agent_host_receiver),
-                                    worker_host_->worker_process_id(), nullptr);
+                                    worker_host_->worker_process_id());
   for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
     inspector->TargetReloadedAfterCrash();
 }
@@ -119,8 +119,7 @@
     inspector->TargetCrashed();
   worker_host_ = nullptr;
   GetRendererChannel()->SetRenderer(mojo::NullRemote(), mojo::NullReceiver(),
-                                    ChildProcessHost::kInvalidUniqueID,
-                                    nullptr);
+                                    ChildProcessHost::kInvalidUniqueID);
 }
 
 }  // namespace content
diff --git a/content/browser/devtools/worker_devtools_agent_host.cc b/content/browser/devtools/worker_devtools_agent_host.cc
index f028744..0ad1c25 100644
--- a/content/browser/devtools/worker_devtools_agent_host.cc
+++ b/content/browser/devtools/worker_devtools_agent_host.cc
@@ -35,7 +35,7 @@
   NotifyCreated();
   GetRendererChannel()->SetRenderer(std::move(agent_remote),
                                     std::move(host_receiver), process_id,
-                                    nullptr, std::move(connection_error));
+                                    std::move(connection_error));
 }
 
 WorkerDevToolsAgentHost::~WorkerDevToolsAgentHost() {}
@@ -43,8 +43,7 @@
 void WorkerDevToolsAgentHost::Disconnected() {
   ForceDetachAllSessions();
   GetRendererChannel()->SetRenderer(mojo::NullRemote(), mojo::NullReceiver(),
-                                    ChildProcessHost::kInvalidUniqueID,
-                                    nullptr);
+                                    ChildProcessHost::kInvalidUniqueID);
   std::move(destroyed_callback_).Run(this);
   Release();  // Matches AddRef() in constructor.
 }
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 03fba97..82c83a3 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -28,7 +28,6 @@
 #include "content/browser/service_worker/service_worker_script_loader_factory.h"
 #include "content/browser/url_loader_factory_getter.h"
 #include "content/common/content_switches_internal.h"
-#include "content/common/renderer.mojom.h"
 #include "content/common/url_schemes.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -189,8 +188,7 @@
   // the process. If the process dies, |client_|'s connection error callback
   // will be called on the IO thread.
   if (request.is_pending()) {
-    rph->GetRendererInterface()->SetUpEmbeddedWorkerChannelForServiceWorker(
-        std::move(request));
+    BindInterface(rph, std::move(request));
   }
 
   // Register to DevTools and update params accordingly.
diff --git a/content/browser/service_worker/embedded_worker_instance.h b/content/browser/service_worker/embedded_worker_instance.h
index d890f56..56bee23 100644
--- a/content/browser/service_worker/embedded_worker_instance.h
+++ b/content/browser/service_worker/embedded_worker_instance.h
@@ -128,10 +128,11 @@
   // Starts the worker. It is invalid to call this when the worker is not in
   // STOPPED status.
   //
-  // |sent_start_callback| is invoked once the Start IPC is sent, or if an error
-  // prevented that from happening. The callback is not invoked in some cases,
-  // e.g., when Stop() is called and aborts the start procedure. Note that when
-  // the callback is invoked with kOk status, the service worker has not yet
+  // |sent_start_callback| is invoked once the Start IPC is sent, and in some
+  // cases may be invoked if an error prevented that from happening. It's not
+  // invoked in some cases, like if the Mojo connection fails to connect, or
+  // when Stop() is called and aborts the start procedure. Note that when the
+  // callback is invoked with kOk status, the service worker has not yet
   // finished starting. Observe OnStarted()/OnStopped() for when start completed
   // or failed.
   void Start(blink::mojom::EmbeddedWorkerStartParamsPtr params,
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index 6ed4247..dd5bb4ee 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -553,25 +553,15 @@
   auto worker = std::make_unique<EmbeddedWorkerInstance>(pair.second.get());
   worker->AddObserver(this);
 
-  // Attempt to start the worker. From the browser process's point of view, the
-  // start IPC was sent.
-  base::Optional<blink::ServiceWorkerStatusCode> status;
-  base::RunLoop loop;
-  worker->Start(CreateStartParams(pair.second),
-                ReceiveStatus(&status, loop.QuitClosure()));
-  loop.Run();
-  EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status.value());
-
-  // But the renderer should not receive the message and the binding is broken.
-  // Worker should handle the failure of binding on the remote side as detach.
+  // Attempt to start the worker. Pass DoNothing() as the |sent_start_callback|
+  // as it won't be called when mojo IPC fails to connect.
+  worker->Start(CreateStartParams(pair.second), base::DoNothing());
   base::RunLoop().RunUntilIdle();
 
-  ASSERT_EQ(3u, events_.size());
-  EXPECT_EQ(PROCESS_ALLOCATED, events_[0].type);
-  EXPECT_EQ(START_WORKER_MESSAGE_SENT, events_[1].type);
-  EXPECT_EQ(DETACHED, events_[2].type);
-  EXPECT_EQ(EmbeddedWorkerStatus::STARTING, events_[2].status.value());
-  EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, worker->status());
+  // Worker should handle the failure of binding on the remote side as detach.
+  ASSERT_EQ(1u, events_.size());
+  EXPECT_EQ(DETACHED, events_[0].type);
+  EXPECT_EQ(EmbeddedWorkerStatus::STARTING, events_[0].status.value());
 }
 
 TEST_F(EmbeddedWorkerInstanceTest, RemoveRemoteInterface) {
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index 52521a8..5974b3e 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -13,7 +13,6 @@
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
-#include "content/common/renderer.mojom.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/test/fake_network_url_loader_factory.h"
@@ -24,75 +23,6 @@
 
 namespace content {
 
-class EmbeddedWorkerTestHelper::MockRendererInterface : public mojom::Renderer {
- public:
-  // |helper| must outlive this.
-  explicit MockRendererInterface(EmbeddedWorkerTestHelper* helper)
-      : helper_(helper) {}
-
-  void AddBinding(mojom::RendererAssociatedRequest request) {
-    bindings_.AddBinding(this, std::move(request));
-  }
-
- private:
-  void CreateView(mojom::CreateViewParamsPtr) override { NOTREACHED(); }
-  void DestroyView(int32_t) override { NOTREACHED(); }
-  void CreateFrame(mojom::CreateFrameParamsPtr) override { NOTREACHED(); }
-  void SetUpEmbeddedWorkerChannelForServiceWorker(
-      blink::mojom::EmbeddedWorkerInstanceClientRequest client_request)
-      override {
-    helper_->OnInstanceClientRequest(std::move(client_request));
-  }
-  void CreateFrameProxy(
-      int32_t routing_id,
-      int32_t render_view_routing_id,
-      int32_t opener_routing_id,
-      int32_t parent_routing_id,
-      const FrameReplicationState& replicated_state,
-      const base::UnguessableToken& devtools_frame_token) override {
-    NOTREACHED();
-  }
-  void OnNetworkConnectionChanged(
-      net::NetworkChangeNotifier::ConnectionType type,
-      double max_bandwidth_mbps) override {
-    NOTREACHED();
-  }
-  void OnNetworkQualityChanged(net::EffectiveConnectionType type,
-                               base::TimeDelta http_rtt,
-                               base::TimeDelta transport_rtt,
-                               double bandwidth_kbps) override {
-    NOTREACHED();
-  }
-  void SetWebKitSharedTimersSuspended(bool suspend) override { NOTREACHED(); }
-  void SetUserAgent(const std::string& user_agent) override { NOTREACHED(); }
-  void SetUserAgentMetadata(const blink::UserAgentMetadata& metadata) override {
-    NOTREACHED();
-  }
-  void UpdateScrollbarTheme(
-      mojom::UpdateScrollbarThemeParamsPtr params) override {
-    NOTREACHED();
-  }
-  void OnSystemColorsChanged(int32_t aqua_color_variant,
-                             const std::string& highlight_text_color,
-                             const std::string& highlight_color) override {
-    NOTREACHED();
-  }
-  void UpdateSystemColorInfo(
-      mojom::UpdateSystemColorInfoParamsPtr params) override {
-    NOTREACHED();
-  }
-  void PurgePluginListCache(bool reload_pages) override { NOTREACHED(); }
-  void SetProcessState(mojom::RenderProcessState process_state) override {
-    NOTREACHED();
-  }
-  void SetSchedulerKeepActive(bool keep_active) override { NOTREACHED(); }
-  void SetIsLockedToSite() override { NOTREACHED(); }
-  void EnableV8LowMemoryMode() override { NOTREACHED(); }
-
-  EmbeddedWorkerTestHelper* helper_;
-  mojo::AssociatedBindingSet<mojom::Renderer> bindings_;
-};
-
 EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
     const base::FilePath& user_data_directory)
     : browser_context_(std::make_unique<TestBrowserContext>()),
@@ -120,25 +50,14 @@
   wrapper_->process_manager()->SetNewProcessIdForTest(new_render_process_id());
   wrapper_->InitializeResourceContext(browser_context_->GetResourceContext());
 
-  // Install a mocked mojom::Renderer interface to catch requests to
-  // establish Mojo connection for EWInstanceClient.
-  mock_renderer_interface_ = std::make_unique<MockRendererInterface>(this);
-
-  auto renderer_interface_ptr =
-      std::make_unique<mojom::RendererAssociatedPtr>();
-  mock_renderer_interface_->AddBinding(
-      mojo::MakeRequestAssociatedWithDedicatedPipe(
-          renderer_interface_ptr.get()));
-  render_process_host_->OverrideRendererInterfaceForTesting(
-      std::move(renderer_interface_ptr));
-
-  auto new_renderer_interface_ptr =
-      std::make_unique<mojom::RendererAssociatedPtr>();
-  mock_renderer_interface_->AddBinding(
-      mojo::MakeRequestAssociatedWithDedicatedPipe(
-          new_renderer_interface_ptr.get()));
-  new_render_process_host_->OverrideRendererInterfaceForTesting(
-      std::move(new_renderer_interface_ptr));
+  render_process_host_->OverrideBinderForTesting(
+      blink::mojom::EmbeddedWorkerInstanceClient::Name_,
+      base::BindRepeating(&EmbeddedWorkerTestHelper::OnInstanceClientRequest,
+                          base::Unretained(this)));
+  new_render_process_host_->OverrideBinderForTesting(
+      blink::mojom::EmbeddedWorkerInstanceClient::Name_,
+      base::BindRepeating(&EmbeddedWorkerTestHelper::OnInstanceClientRequest,
+                          base::Unretained(this)));
 
   default_network_loader_factory_ =
       std::make_unique<FakeNetworkURLLoaderFactory>();
@@ -170,7 +89,9 @@
 }
 
 void EmbeddedWorkerTestHelper::OnInstanceClientRequest(
-    blink::mojom::EmbeddedWorkerInstanceClientRequest request) {
+    mojo::ScopedMessagePipeHandle request_handle) {
+  blink::mojom::EmbeddedWorkerInstanceClientRequest request(
+      std::move(request_handle));
   std::unique_ptr<FakeEmbeddedWorkerInstanceClient> client;
   if (!pending_embedded_worker_instance_clients_.empty()) {
     // Use the instance client that was registered for this message.
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index b715b0a..178890f 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -131,10 +131,9 @@
   // The following are exposed to public so the fake embedded worker and service
   // worker implementations and their subclasses can call them.
 
-  // Called when |request| is received. It takes the object from a previous
-  // AddPending*() call if any and calls Create*() otherwise.
-  void OnInstanceClientRequest(
-      blink::mojom::EmbeddedWorkerInstanceClientRequest request);
+  // Called when |request_handle| is received. It takes the object from a
+  // previous AddPending*() call if any and calls Create*() otherwise.
+  void OnInstanceClientRequest(mojo::ScopedMessagePipeHandle request_handle);
   void OnServiceWorkerRequest(blink::mojom::ServiceWorkerRequest request);
 
   // Called by the fakes to destroy themselves.
@@ -155,16 +154,12 @@
   virtual std::unique_ptr<FakeServiceWorker> CreateServiceWorker();
 
  private:
-  class MockRendererInterface;
-
   std::unique_ptr<TestBrowserContext> browser_context_;
   std::unique_ptr<MockRenderProcessHost> render_process_host_;
   std::unique_ptr<MockRenderProcessHost> new_render_process_host_;
 
   scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
 
-  std::unique_ptr<MockRendererInterface> mock_renderer_interface_;
-
   base::queue<std::unique_ptr<FakeEmbeddedWorkerInstanceClient>>
       pending_embedded_worker_instance_clients_;
   base::flat_set<std::unique_ptr<FakeEmbeddedWorkerInstanceClient>,
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc
index 75d7a70..a87f5d6 100644
--- a/content/browser/service_worker/service_worker_context_core.cc
+++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -156,11 +156,11 @@
  public:
   explicit ClearAllServiceWorkersHelper(base::OnceClosure callback)
       : callback_(std::move(callback)) {
-    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   }
 
   void OnResult(blink::ServiceWorkerStatusCode) {
-    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
     // We do nothing in this method. We use this class to wait for all callbacks
     // to be called using the refcount.
   }
@@ -192,7 +192,7 @@
  private:
   friend class base::RefCounted<ClearAllServiceWorkersHelper>;
   ~ClearAllServiceWorkersHelper() {
-    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
     base::PostTask(FROM_HERE, {BrowserThread::UI}, std::move(callback_));
   }
 
@@ -305,14 +305,14 @@
 
 void ServiceWorkerContextCore::AddProviderHost(
     std::unique_ptr<ServiceWorkerProviderHost> host) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   int provider_id = host->provider_id();
   providers_->emplace(provider_id, std::move(host));
 }
 
 ServiceWorkerProviderHost* ServiceWorkerContextCore::GetProviderHost(
     int provider_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   auto found = providers_->find(provider_id);
   if (found == providers_->end())
     return nullptr;
@@ -320,7 +320,7 @@
 }
 
 void ServiceWorkerContextCore::RemoveProviderHost(int provider_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   providers_->erase(provider_id);
 }
 
@@ -328,7 +328,7 @@
 ServiceWorkerContextCore::GetClientProviderHostIterator(
     const GURL& origin,
     bool include_reserved_clients) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   return base::WrapUnique(new ProviderHostIterator(
       providers_.get(), base::BindRepeating(IsSameOriginClientProviderHost,
                                             origin, include_reserved_clients)));
@@ -337,7 +337,7 @@
 void ServiceWorkerContextCore::HasMainFrameProviderHost(
     const GURL& origin,
     BoolCallback callback) const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   ProviderHostIterator provider_host_iterator(
       providers_.get(),
       base::BindRepeating(IsSameOriginWindowProviderHost, origin));
@@ -359,10 +359,17 @@
     provider_host_iterator.Advance();
   }
 
-  base::PostTaskAndReplyWithResult(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(&FrameListContainsMainFrameOnUI, std::move(render_frames)),
-      std::move(callback));
+  if (ServiceWorkerContextWrapper::IsServiceWorkerOnUIEnabled()) {
+    bool result = FrameListContainsMainFrameOnUI(std::move(render_frames));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), result));
+  } else {
+    base::PostTaskAndReplyWithResult(
+        FROM_HERE, {BrowserThread::UI},
+        base::BindOnce(&FrameListContainsMainFrameOnUI,
+                       std::move(render_frames)),
+        std::move(callback));
+  }
 }
 
 void ServiceWorkerContextCore::RegisterProviderHostByClientID(
@@ -390,7 +397,7 @@
     const GURL& script_url,
     const blink::mojom::ServiceWorkerRegistrationOptions& options,
     RegistrationCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   std::string error_message;
   if (!IsValidRegisterRequest(script_url, options.scope, &error_message)) {
     std::move(callback).Run(
@@ -408,7 +415,7 @@
 void ServiceWorkerContextCore::UpdateServiceWorker(
     ServiceWorkerRegistration* registration,
     bool force_bypass_cache) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   job_coordinator_->Update(registration, force_bypass_cache);
 }
 
@@ -417,7 +424,7 @@
     bool force_bypass_cache,
     bool skip_script_comparison,
     UpdateCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   job_coordinator_->Update(
       registration, force_bypass_cache, skip_script_comparison,
       base::BindOnce(&ServiceWorkerContextCore::UpdateComplete, AsWeakPtr(),
@@ -427,7 +434,7 @@
 void ServiceWorkerContextCore::UnregisterServiceWorker(
     const GURL& scope,
     UnregistrationCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   job_coordinator_->Unregister(
       scope, base::BindOnce(&ServiceWorkerContextCore::UnregistrationComplete,
                             AsWeakPtr(), scope, std::move(callback)));
@@ -435,7 +442,7 @@
 
 void ServiceWorkerContextCore::DeleteForOrigin(const GURL& origin,
                                                StatusCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   storage()->GetRegistrationsForOrigin(
       origin,
       base::BindOnce(
@@ -445,7 +452,7 @@
 
 void ServiceWorkerContextCore::PerformStorageCleanup(
     base::OnceClosure callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   storage()->PerformStorageCleanup(std::move(callback));
 }
 
@@ -496,7 +503,7 @@
 
 scoped_refptr<blink::URLLoaderFactoryBundle>
 ServiceWorkerContextCore::GetLoaderFactoryBundleForUpdateCheck() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   DCHECK(blink::ServiceWorkerUtils::IsImportedScriptUpdateCheckEnabled());
 
   // Update the default factory in the bundle with a newly cloned network
@@ -682,7 +689,7 @@
 
 void ServiceWorkerContextCore::ClearAllServiceWorkersForTest(
     base::OnceClosure callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   // |callback| will be called in the destructor of |helper| on the UI thread.
   auto helper =
       base::MakeRefCounted<ClearAllServiceWorkersHelper>(std::move(callback));
@@ -746,7 +753,7 @@
 
 void ServiceWorkerContextCore::NotifyRegistrationStored(int64_t registration_id,
                                                         const GURL& scope) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   observer_list_->Notify(
       FROM_HERE, &ServiceWorkerContextCoreObserver::OnRegistrationStored,
       registration_id, scope);
@@ -815,7 +822,7 @@
     const base::string16& message,
     int line_number,
     const GURL& source_url) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   // NOTE: This differs slightly from
   // RenderFrameHostImpl::DidAddMessageToConsole, which also asks the
   // content embedder whether to classify the message as a builtin component.
diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h
index 1757310..164c4ef 100644
--- a/content/browser/service_worker/service_worker_context_core.h
+++ b/content/browser/service_worker/service_worker_context_core.h
@@ -174,6 +174,8 @@
   // Runs the callback with true if there is a ProviderHost for |origin| of type
   // blink::mojom::ServiceWorkerProviderType::kForWindow which is a main
   // (top-level) frame. Reserved clients are ignored.
+  // TODO(crbug.com/824858): Make this synchronously return bool when the core
+  // thread is UI.
   void HasMainFrameProviderHost(const GURL& origin,
                                 BoolCallback callback) const;
 
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 7ccd7d6..d751bfc 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -327,6 +327,17 @@
   return resource_context_;
 }
 
+// static
+bool ServiceWorkerContextWrapper::IsServiceWorkerOnUIEnabled() {
+  return base::FeatureList::IsEnabled(features::kServiceWorkerOnUI);
+}
+
+// static
+BrowserThread::ID ServiceWorkerContextWrapper::GetCoreThreadId() {
+  return IsServiceWorkerOnUIEnabled() ? BrowserThread::UI : BrowserThread::IO;
+}
+
+// static
 bool ServiceWorkerContextWrapper::OnCoreThread() {
   return BrowserThread::CurrentlyOn(GetCoreThreadId());
 }
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h
index 4a1e326..87f152d 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.h
+++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -114,7 +114,8 @@
   }
 
   // Temporary for crbug.com/824858. The thread the context core lives on.
-  static BrowserThread::ID GetCoreThreadId() { return BrowserThread::IO; }
+  static bool IsServiceWorkerOnUIEnabled();
+  static BrowserThread::ID GetCoreThreadId();
   static bool OnCoreThread();
 
   // ServiceWorkerContextCoreObserver implementation:
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 f22bff9..89ae84ff 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -254,16 +254,16 @@
   }
 
   bool allow_service_worker = false;
-  if (ServiceWorkerContextWrapper::GetCoreThreadId() == BrowserThread::IO) {
-    allow_service_worker =
-        GetContentClient()->browser()->AllowServiceWorkerOnIO(
-            registration->scope(), provider_host_->site_for_cookies(), GURL(),
-            resource_context_, provider_host_->web_contents_getter());
-  } else {
+  if (ServiceWorkerContextWrapper::IsServiceWorkerOnUIEnabled()) {
     allow_service_worker =
         GetContentClient()->browser()->AllowServiceWorkerOnUI(
             registration->scope(), provider_host_->site_for_cookies(), GURL(),
             browser_context_, provider_host_->web_contents_getter());
+  } else {
+    allow_service_worker =
+        GetContentClient()->browser()->AllowServiceWorkerOnIO(
+            registration->scope(), provider_host_->site_for_cookies(), GURL(),
+            resource_context_, provider_host_->web_contents_getter());
   }
 
   if (!allow_service_worker) {
diff --git a/content/browser/service_worker/service_worker_navigation_handle.cc b/content/browser/service_worker/service_worker_navigation_handle.cc
index e65fdc17..f696155 100644
--- a/content/browser/service_worker/service_worker_navigation_handle.cc
+++ b/content/browser/service_worker/service_worker_navigation_handle.cc
@@ -26,8 +26,9 @@
 
 ServiceWorkerNavigationHandle::~ServiceWorkerNavigationHandle() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // Delete the ServiceWorkerNavigationHandleCore on the IO thread.
-  BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, core_);
+  // Delete the ServiceWorkerNavigationHandleCore on the core thread.
+  BrowserThread::DeleteSoon(ServiceWorkerContextWrapper::GetCoreThreadId(),
+                            FROM_HERE, core_);
 }
 
 void ServiceWorkerNavigationHandle::OnCreatedProviderHost(
@@ -47,8 +48,8 @@
   // We may have failed to pre-create the provider host.
   if (!provider_info_)
     return;
-  base::PostTask(
-      FROM_HERE, {BrowserThread::IO},
+  ServiceWorkerContextWrapper::RunOrPostTaskOnCoreThread(
+      FROM_HERE,
       base::BindOnce(
           &ServiceWorkerNavigationHandleCore::OnBeginNavigationCommit,
           base::Unretained(core_), render_process_id, render_frame_id));
@@ -57,8 +58,8 @@
 
 void ServiceWorkerNavigationHandle::OnBeginWorkerCommit() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  base::PostTask(
-      FROM_HERE, {BrowserThread::IO},
+  ServiceWorkerContextWrapper::RunOrPostTaskOnCoreThread(
+      FROM_HERE,
       base::BindOnce(&ServiceWorkerNavigationHandleCore::OnBeginWorkerCommit,
                      base::Unretained(core_)));
 }
diff --git a/content/browser/service_worker/service_worker_navigation_handle.h b/content/browser/service_worker/service_worker_navigation_handle.h
index c7427eb..50b4dc7 100644
--- a/content/browser/service_worker/service_worker_navigation_handle.h
+++ b/content/browser/service_worker/service_worker_navigation_handle.h
@@ -17,7 +17,7 @@
 
 // This class is used to manage the lifetime of ServiceWorkerProviderHosts
 // created for main resource requests (navigations and web workers). This is a
-// UI thread class, with a pendant class on the IO thread, the
+// UI thread class, with a pendant class on the core thread, the
 // ServiceWorkerNavigationHandleCore.
 //
 // The lifetime of the ServiceWorkerNavigationHandle, the
@@ -27,7 +27,7 @@
 //   populating the member service worker provider info. This also leads to the
 //   creation of a ServiceWorkerNavigationHandleCore.
 //
-//   2) When the navigation request is sent to the IO thread, we include a
+//   2) When the navigation request is sent to the core thread, we include a
 //   pointer to the ServiceWorkerNavigationHandleCore.
 //
 //   3) If we pre-create a ServiceWorkerProviderHost for this navigation, it
@@ -46,7 +46,7 @@
 //   destroyed. The destructor of the ServiceWorkerNavigationHandle destroys
 //   the provider info which in turn leads to the destruction of an unclaimed
 //   ServiceWorkerProviderHost, and posts a task to destroy the
-//   ServiceWorkerNavigationHandleCore on the IO thread.
+//   ServiceWorkerNavigationHandleCore on the core thread.
 //
 // TODO(falken): Rename ServiceWorkerMainResourceHandle.
 class CONTENT_EXPORT ServiceWorkerNavigationHandle {
@@ -92,8 +92,6 @@
  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};
diff --git a/content/browser/service_worker/service_worker_navigation_handle_core.cc b/content/browser/service_worker/service_worker_navigation_handle_core.cc
index 2d58f84..3d39f6e 100644
--- a/content/browser/service_worker/service_worker_navigation_handle_core.cc
+++ b/content/browser/service_worker/service_worker_navigation_handle_core.cc
@@ -20,25 +20,25 @@
     ServiceWorkerContextWrapper* context_wrapper)
     : context_wrapper_(context_wrapper), ui_handle_(ui_handle) {
   // The ServiceWorkerNavigationHandleCore is created on the UI thread but
-  // should only be accessed from the IO thread afterwards.
+  // should only be accessed from the core thread afterwards.
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 ServiceWorkerNavigationHandleCore::~ServiceWorkerNavigationHandleCore() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
 }
 
 void ServiceWorkerNavigationHandleCore::OnCreatedProviderHost(
     base::WeakPtr<ServiceWorkerProviderHost> provider_host,
     blink::mojom::ServiceWorkerProviderInfoForClientPtr provider_info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   DCHECK(provider_host);
   provider_host_ = std::move(provider_host);
 
   DCHECK(provider_info->host_ptr_info.is_valid() &&
          provider_info->client_request.is_pending());
-  base::PostTask(
-      FROM_HERE, {BrowserThread::UI},
+  RunOrPostTaskOnThread(
+      FROM_HERE, BrowserThread::UI,
       base::BindOnce(&ServiceWorkerNavigationHandle::OnCreatedProviderHost,
                      ui_handle_, std::move(provider_info)));
 }
@@ -46,13 +46,13 @@
 void ServiceWorkerNavigationHandleCore::OnBeginNavigationCommit(
     int render_process_id,
     int render_frame_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   if (provider_host_)
     provider_host_->OnBeginNavigationCommit(render_process_id, render_frame_id);
 }
 
 void ServiceWorkerNavigationHandleCore::OnBeginWorkerCommit() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   if (provider_host_)
     provider_host_->CompleteWebWorkerPreparation();
 }
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 331422b..b21b881 100644
--- a/content/browser/service_worker/service_worker_navigation_handle_core.h
+++ b/content/browser/service_worker/service_worker_navigation_handle_core.h
@@ -22,9 +22,12 @@
 class ServiceWorkerNavigationHandle;
 
 // This class is created on the UI thread, but should only be accessed from the
-// IO thread afterwards. It is the IO thread pendant of
+// service worker core thread afterwards. It is the core thread pendant of
 // ServiceWorkerNavigationHandle. See the ServiceWorkerNavigationHandle header
 // for more details about the lifetime of both classes.
+//
+// TODO(crbug.com/824858): Merge this class into ServiceWorkerNavigationHandle
+// when the core thread moves to the UI thread.
 class CONTENT_EXPORT ServiceWorkerNavigationHandleCore {
  public:
   ServiceWorkerNavigationHandleCore(
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 60ab3dd5..e4abc53 100644
--- a/content/browser/service_worker/service_worker_navigation_loader_interceptor.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader_interceptor.cc
@@ -90,9 +90,9 @@
   ServiceWorkerContextCore* context_core =
       handle_core->context_wrapper()->context();
   ResourceContext* resource_context =
-      ServiceWorkerContextWrapper::GetCoreThreadId() == BrowserThread::IO
-          ? handle_core->context_wrapper()->resource_context()
-          : nullptr;
+      ServiceWorkerContextWrapper::IsServiceWorkerOnUIEnabled()
+          ? nullptr
+          : handle_core->context_wrapper()->resource_context();
   if (!context_core || (!resource_context && !browser_context)) {
     LoaderCallbackWrapperOnCoreThread(handle_core, std::move(interceptor_on_ui),
                                       std::move(loader_callback),
@@ -201,7 +201,7 @@
 
   bool initialize_provider_only = false;
   LoaderCallback original_callback;
-  if (ServiceWorkerContextWrapper::GetCoreThreadId() == BrowserThread::IO &&
+  if (!ServiceWorkerContextWrapper::IsServiceWorkerOnUIEnabled() &&
       !handle_->context_wrapper()->HasRegistrationForOrigin(
           tentative_resource_request.url.GetOrigin())) {
     // We have no registrations, so it's safe to continue the request now
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 2ac8bf3..be3bc61 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -252,7 +252,7 @@
 }
 
 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
 
   if (context_)
     context_->UnregisterProviderHostByClientID(client_uuid_);
@@ -560,7 +560,7 @@
 
 void ServiceWorkerProviderHost::RemoveServiceWorkerObjectHost(
     int64_t version_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   DCHECK(base::Contains(service_worker_object_hosts_, version_id));
   service_worker_object_hosts_.erase(version_id);
 }
@@ -568,11 +568,19 @@
 bool ServiceWorkerProviderHost::AllowServiceWorker(const GURL& scope,
                                                    const GURL& script_url) {
   DCHECK(IsContextAlive());
-  return GetContentClient()->browser()->AllowServiceWorkerOnIO(
-      scope, site_for_cookies(), script_url,
-      context_->wrapper()->resource_context(),
-      base::BindRepeating(&WebContentsImpl::FromRenderFrameHostID,
-                          render_process_id_, frame_id()));
+  if (ServiceWorkerContextWrapper::IsServiceWorkerOnUIEnabled()) {
+    return GetContentClient()->browser()->AllowServiceWorkerOnUI(
+        scope, site_for_cookies(), script_url,
+        context_->wrapper()->browser_context(),
+        base::BindRepeating(&WebContentsImpl::FromRenderFrameHostID,
+                            render_process_id_, frame_id()));
+  } else {
+    return GetContentClient()->browser()->AllowServiceWorkerOnIO(
+        scope, site_for_cookies(), script_url,
+        context_->wrapper()->resource_context(),
+        base::BindRepeating(&WebContentsImpl::FromRenderFrameHostID,
+                            render_process_id_, frame_id()));
+  }
 }
 
 void ServiceWorkerProviderHost::NotifyControllerLost() {
@@ -648,7 +656,7 @@
 
 void ServiceWorkerProviderHost::OnBeginNavigationCommit(int render_process_id,
                                                         int render_frame_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   DCHECK_EQ(blink::mojom::ServiceWorkerProviderType::kForWindow, type_);
 
   DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, render_process_id_);
@@ -1242,13 +1250,13 @@
 void ServiceWorkerProviderHost::GetInterface(
     const std::string& interface_name,
     mojo::ScopedMessagePipeHandle interface_pipe) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(ServiceWorkerContextWrapper::GetCoreThreadId());
   DCHECK(IsProviderForServiceWorker());
-  base::PostTask(FROM_HERE, {BrowserThread::UI},
-                 base::BindOnce(&GetInterfaceImpl, interface_name,
-                                std::move(interface_pipe),
-                                running_hosted_version_->script_origin(),
-                                render_process_id_));
+  RunOrPostTaskOnThread(FROM_HERE, BrowserThread::UI,
+                        base::BindOnce(&GetInterfaceImpl, interface_name,
+                                       std::move(interface_pipe),
+                                       running_hosted_version_->script_origin(),
+                                       render_process_id_));
 }
 
 blink::mojom::ServiceWorkerRegistrationObjectInfoPtr
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index acc005c..e227f780 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -16,6 +16,7 @@
 import "mojo/public/mojom/base/string16.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "mojo/public/mojom/base/values.mojom";
+import "services/network/public/mojom/url_response_head.mojom";
 import "services/network/public/mojom/url_loader.mojom";
 import "services/network/public/mojom/url_loader_factory.mojom";
 import "services/service_manager/public/mojom/interface_provider.mojom";
diff --git a/content/common/navigation_client.mojom b/content/common/navigation_client.mojom
index 4f891bf..d7c327d 100644
--- a/content/common/navigation_client.mojom
+++ b/content/common/navigation_client.mojom
@@ -4,6 +4,7 @@
 
 module content.mojom;
 
+import "services/network/public/mojom/url_response_head.mojom";
 import "services/network/public/mojom/url_loader.mojom";
 import "services/network/public/mojom/url_loader_factory.mojom";
 import "content/common/frame_messages.mojom";
diff --git a/content/common/navigation_params.mojom b/content/common/navigation_params.mojom
index bdcc940..f1b326d39 100644
--- a/content/common/navigation_params.mojom
+++ b/content/common/navigation_params.mojom
@@ -9,6 +9,7 @@
 import "mojo/public/mojom/base/time.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "mojo/public/mojom/base/values.mojom";
+import "services/network/public/mojom/url_response_head.mojom";
 import "services/network/public/mojom/url_loader.mojom";
 import "third_party/blink/public/mojom/fetch/fetch_api_request.mojom";
 import "third_party/blink/public/mojom/referrer.mojom";
diff --git a/content/common/prefetched_signed_exchange_info.mojom b/content/common/prefetched_signed_exchange_info.mojom
index 4264f19..df3f11d 100644
--- a/content/common/prefetched_signed_exchange_info.mojom
+++ b/content/common/prefetched_signed_exchange_info.mojom
@@ -6,6 +6,7 @@
 
 import "services/network/public/mojom/url_loader_factory.mojom";
 import "services/network/public/mojom/url_loader.mojom";
+import "services/network/public/mojom/url_response_head.mojom";
 import "url/mojom/url.mojom";
 
 [Native]
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom
index 860f29a0..bf94500 100644
--- a/content/common/renderer.mojom
+++ b/content/common/renderer.mojom
@@ -11,8 +11,8 @@
 import "mojo/public/mojom/base/time.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "services/network/public/mojom/network_types.mojom";
+import "third_party/blink/public/mojom/manifest/manifest.mojom";
 import "third_party/blink/public/mojom/renderer_preferences.mojom";
-import "third_party/blink/public/mojom/service_worker/embedded_worker.mojom";
 import "third_party/blink/public/mojom/user_agent/user_agent_metadata.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
 
@@ -205,13 +205,6 @@
                    FrameReplicationState replication_state,
                    mojo_base.mojom.UnguessableToken devtools_frame_token);
 
-  // Tells the renderer to create an EmbeddedWorkerInstanceClient, which is what
-  // manages service worker startup and shutdown.
-  // TODO(shimazu): Send all params for starting service worker to reduce the
-  // number of IPCs.
-  SetUpEmbeddedWorkerChannelForServiceWorker(
-      blink.mojom.EmbeddedWorkerInstanceClient& client_request);
-
   // Tells the renderer that the network type has changed so that
   // navigator.onLine and navigator.connection can be updated.
   OnNetworkConnectionChanged(NetworkConnectionType connection_type,
diff --git a/content/public/app/content_renderer_manifest.cc b/content/public/app/content_renderer_manifest.cc
index 30b6f1f..625e51f 100644
--- a/content/public/app/content_renderer_manifest.cc
+++ b/content/public/app/content_renderer_manifest.cc
@@ -21,6 +21,7 @@
               std::set<const char*>{
                   "blink.mojom.CodeCacheHost",
                   "blink.mojom.CrashMemoryMetricsReporter",
+                  "blink.mojom.EmbeddedWorkerInstanceClient",
                   "blink.mojom.LeakDetector",
                   "blink.mojom.OomIntervention",
                   "blink.mojom.SharedWorkerFactory",
diff --git a/content/public/app/v8_snapshot_overlay_manifest.cc b/content/public/app/v8_snapshot_overlay_manifest.cc
index 46977557..b07152e 100644
--- a/content/public/app/v8_snapshot_overlay_manifest.cc
+++ b/content/public/app/v8_snapshot_overlay_manifest.cc
@@ -31,19 +31,25 @@
             kV8NativesDataDescriptor,
             base::FilePath(FILE_PATH_LITERAL("assets/natives_blob.bin")))
 #if defined(USE_V8_CONTEXT_SNAPSHOT)
-        .PreloadFile(kV8Snapshot32DataDescriptor,
-                     base::FilePath(FILE_PATH_LITERAL(
-                         "assets/v8_context_snapshot_32.bin")))
+#if defined(ARCH_CPU_64_BITS)
         .PreloadFile(kV8Snapshot64DataDescriptor,
                      base::FilePath(FILE_PATH_LITERAL(
                          "assets/v8_context_snapshot_64.bin")))
 #else
-        .PreloadFile(
-            kV8Snapshot32DataDescriptor,
-            base::FilePath(FILE_PATH_LITERAL("assets/snapshot_blob_32.bin")))
+        .PreloadFile(kV8Snapshot32DataDescriptor,
+                     base::FilePath(FILE_PATH_LITERAL(
+                         "assets/v8_context_snapshot_32.bin")))
+#endif
+#else
+#if defined(ARCH_CPU_64_BITS)
         .PreloadFile(
             kV8Snapshot64DataDescriptor,
             base::FilePath(FILE_PATH_LITERAL("assets/snapshot_blob_64.bin")))
+#else
+        .PreloadFile(
+            kV8Snapshot32DataDescriptor,
+            base::FilePath(FILE_PATH_LITERAL("assets/snapshot_blob_32.bin")))
+#endif
 #endif  // defined(USE_V8_CONTEXT_SNAPSHOT)
 #endif
         .Build()
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index 452fe8ef..b9585ac 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -363,7 +363,6 @@
   sources = [
     "drop_data.mojom",
     "fullscreen_video_element.mojom",
-    "load_timing_info.mojom",
     "resource_load_info.mojom",
     "resource_usage_reporter.mojom",
     "transferrable_url_loader.mojom",
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index d0fc0594..a5fad1e 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -468,6 +468,12 @@
 const base::Feature kServiceWorkerLongRunningMessage{
     "ServiceWorkerLongRunningMessage", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// If enabled, ServiceWorkerContextCore lives on the UI thread rather than the
+// IO thread.
+// https://crbug.com/824858
+const base::Feature kServiceWorkerOnUI{"ServiceWorkerOnUI",
+                                       base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Service worker based payment apps as defined by w3c here:
 // https://w3c.github.io/webpayments-payment-apps-api/
 // TODO(rouslan): Remove this.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 9dbd000..103cc3c 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -106,6 +106,7 @@
 CONTENT_EXPORT extern const base::Feature
     kSendBeaconThrowForBlobWithNonSimpleType;
 CONTENT_EXPORT extern const base::Feature kServiceWorkerLongRunningMessage;
+CONTENT_EXPORT extern const base::Feature kServiceWorkerOnUI;
 CONTENT_EXPORT extern const base::Feature kServiceWorkerPaymentApps;
 CONTENT_EXPORT extern const base::Feature kSharedArrayBuffer;
 CONTENT_EXPORT extern const base::Feature
diff --git a/content/public/common/load_timing_info.typemap b/content/public/common/load_timing_info.typemap
deleted file mode 100644
index 84af0d11..0000000
--- a/content/public/common/load_timing_info.typemap
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//content/public/common/load_timing_info.mojom"
-public_headers = [ "//net/base/load_timing_info.h" ]
-traits_headers = [ "//content/public/common/load_timing_info_mojom_traits.h" ]
-sources = [
-  "//content/public/common/load_timing_info_mojom_traits.cc",
-]
-type_mappings = [
-  "content.mojom.LoadTimingInfo=net::LoadTimingInfo",
-  "content.mojom.LoadTimingInfoConnectTiming=net::LoadTimingInfo::ConnectTiming",
-]
diff --git a/content/public/common/resource_load_info.mojom b/content/public/common/resource_load_info.mojom
index 5194656..4df49e71 100644
--- a/content/public/common/resource_load_info.mojom
+++ b/content/public/common/resource_load_info.mojom
@@ -4,10 +4,10 @@
 
 module content.mojom;
 
-import "content/public/common/load_timing_info.mojom";
 import "content/public/common/resource_type.mojom";
 import "services/network/public/mojom/ip_address.mojom";
 import "services/network/public/mojom/ip_endpoint.mojom";
+import "services/network/public/mojom/load_timing_info.mojom";
 import "services/network/public/mojom/network_param.mojom";
 import "services/network/public/mojom/url_loader.mojom";
 import "url/mojom/url.mojom";
@@ -72,7 +72,7 @@
   int32 net_error;
 
   // The timing info.
-  content.mojom.LoadTimingInfo load_timing_info;
+  network.mojom.LoadTimingInfo load_timing_info;
 
   // The size of the response body before removing any content encodings.
   // Does not include redirects or sub-requests issued at lower levels (range
diff --git a/content/public/common/transferrable_url_loader.mojom b/content/public/common/transferrable_url_loader.mojom
index ce53a09..a57eee8 100644
--- a/content/public/common/transferrable_url_loader.mojom
+++ b/content/public/common/transferrable_url_loader.mojom
@@ -4,6 +4,7 @@
 
 module content.mojom;
 
+import "services/network/public/mojom/url_response_head.mojom";
 import "services/network/public/mojom/url_loader.mojom";
 import "url/mojom/url.mojom";
 
diff --git a/content/public/common/typemaps.gni b/content/public/common/typemaps.gni
index 7b77ccb..7b4138b 100644
--- a/content/public/common/typemaps.gni
+++ b/content/public/common/typemaps.gni
@@ -4,7 +4,6 @@
 
 typemaps = [
   "//content/public/common/drop_data.typemap",
-  "//content/public/common/load_timing_info.typemap",
   "//content/public/common/resource_type.typemap",
   "//content/public/common/webplugininfo.typemap",
 ]
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 8158e72..9d92ab0 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -797,6 +797,19 @@
                                              weak_factory_.GetWeakPtr()),
                          base::ThreadTaskRunnerHandle::Get());
 
+  if (base::FeatureList::IsEnabled(
+          blink::features::kOffMainThreadServiceWorkerStartup)) {
+    registry->AddInterface(
+        base::BindRepeating(&EmbeddedWorkerInstanceClientImpl::Create,
+                            GetIOTaskRunner()),
+        GetIOTaskRunner());
+  } else {
+    registry->AddInterface(
+        base::BindRepeating(&EmbeddedWorkerInstanceClientImpl::Create,
+                            GetWebMainThreadScheduler()->DefaultTaskRunner()),
+        GetWebMainThreadScheduler()->DefaultTaskRunner());
+  }
+
   GetServiceManagerConnection()->AddConnectionFilter(
       std::make_unique<SimpleConnectionFilter>(std::move(registry)));
 
@@ -2089,13 +2102,6 @@
       replicated_state, devtools_frame_token);
 }
 
-void RenderThreadImpl::SetUpEmbeddedWorkerChannelForServiceWorker(
-    blink::mojom::EmbeddedWorkerInstanceClientRequest client_request) {
-  EmbeddedWorkerInstanceClientImpl::Create(
-      std::move(client_request),
-      GetWebMainThreadScheduler()->DefaultTaskRunner());
-}
-
 void RenderThreadImpl::OnNetworkConnectionChanged(
     net::NetworkChangeNotifier::ConnectionType type,
     double max_bandwidth_mbps) {
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index a27a381..8790ef6 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -516,9 +516,6 @@
       int32_t parent_routing_id,
       const FrameReplicationState& replicated_state,
       const base::UnguessableToken& devtools_frame_token) override;
-  void SetUpEmbeddedWorkerChannelForServiceWorker(
-      blink::mojom::EmbeddedWorkerInstanceClientRequest client_request)
-      override;
   void OnNetworkConnectionChanged(
       net::NetworkChangeNotifier::ConnectionType type,
       double max_bandwidth_mbps) override;
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index 061b18a..f2733e5e 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -27,8 +27,8 @@
 
 // static
 void EmbeddedWorkerInstanceClientImpl::Create(
-    blink::mojom::EmbeddedWorkerInstanceClientRequest request,
-    scoped_refptr<base::SingleThreadTaskRunner> initiator_thread_task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> initiator_thread_task_runner,
+    blink::mojom::EmbeddedWorkerInstanceClientRequest request) {
   // This won't be leaked because the lifetime will be managed internally.
   // See the class documentation for detail.
   // We can't use MakeStrongBinding because must give the worker thread
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.h b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
index 7e3c7d7..4bb85dd6 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.h
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
@@ -45,8 +45,8 @@
   // TODO(shimazu): Create a service worker's execution context by this method
   // instead of just creating an instance of EmbeddedWorkerInstanceClient.
   static void Create(
-      blink::mojom::EmbeddedWorkerInstanceClientRequest request,
-      scoped_refptr<base::SingleThreadTaskRunner> initiator_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> initiator_task_runner,
+      blink::mojom::EmbeddedWorkerInstanceClientRequest request);
 
   ~EmbeddedWorkerInstanceClientImpl() override;
 
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 0a0760d..2760f4f 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -170,7 +170,7 @@
     const blink::WebEmbeddedWorkerStartData& start_data) {
   DCHECK(initiator_thread_task_runner_->RunsTasksInCurrentSequence());
   worker_ = std::move(worker);
-  worker_->StartWorkerContext(start_data);
+  worker_->StartWorkerContext(start_data, initiator_thread_task_runner_);
 }
 
 blink::WebEmbeddedWorker& ServiceWorkerContextClient::worker() {
diff --git a/docs/enterprise/policies.md b/docs/enterprise/policies.md
index d99f0335..b774df6 100644
--- a/docs/enterprise/policies.md
+++ b/docs/enterprise/policies.md
@@ -1,20 +1,20 @@
 # Enterprise policies
 
-Under enterprise management organization admins can configure the way
+Under enterprise management, organization admins can configure the way a
 ChromeOS device / browser operates using policies.
 
-On most operating systems policies are applied to specific users / all users
+On most operating systems, policies are applied to specific users / all users
 of the browser, but on ChromeOS there are also policies that control the device
 itself.
 
-On all platforms cloud-based policies are fetched and applied when a managed
+On all platforms, cloud-based policies are fetched and applied when a managed
 user signs in.
 
 [TOC]
 
 ## Policy sources
 
-On different operating systems there can be different methods for enterprise
+On different operating systems, there can be different methods for an enterprise
 to propagate policies for all users (including non-managed ones):
 
 **Windows** Policies can be set up via Windows Registry ([GPO](https://en.wikipedia.org/wiki/Group_Policy)).
@@ -23,12 +23,11 @@
 
 **Linux** Policies can be set via files in specific directories:
 
-Base directory is `/etc/chromium/policies` for Chromium builds,
+The base directory is `/etc/chromium/policies` for Chromium builds,
  `/etc/opt/chrome/policies/` for official Chrome builds.
-Base directory contains two subdirectories: `managed/` for mandatory policies
-and `recommended/` for recommended policies. All files inside these
-directories are treated as JSON files containing
-policies.
+The base directory contains two subdirectories: `managed/` for mandatory
+policies and `recommended/` for recommended policies. All files inside these
+directories are treated as JSON files containing policies.
 
 On these systems it is also possible to set machine-wide cloud-based policies.
 
@@ -67,16 +66,16 @@
 Implementation-wise, these policies can have complex structure, and are
 usually accessed via
 [DeviceSettingsProvider](https://cs.chromium.org/chromium/src/chrome/browser/chromeos/settings/device_settings_provider.h)
-or it's wrapper [CrosSettings](https://cs.chromium.org/chromium/src/chrome/browser/chromeos/settings/cros_settings.h).
+or its wrapper [CrosSettings](https://cs.chromium.org/chromium/src/chrome/browser/chromeos/settings/cros_settings.h).
 
 ## User policies
 
-User policies are defined in the [policy templates file](https://cs.chromium.org/chromium/src/components/policy/resources/policy_templates.json)ббб,
+User policies are defined in the [policy templates file](https://cs.chromium.org/chromium/src/components/policy/resources/policy_templates.json);
 only entries without `'device_only': True` are user policies.
 
 User policies are bound to user accounts, so a personal account on
 an enterprise-enrolled device would be affected only by device policy, while
-an enterprise-owned account on personal device would only be affected by user
+an enterprise-owned account on a personal device would only be affected by user
 policy for that account.
 
 ### ChromeOS
@@ -92,15 +91,15 @@
 
 ## Extension policies
 
-Organization admins can [configure particular extensions](http://dev.chromium.org/administrators/configuring-policy-for-extensions)
+Organization admins can [configure particular extensions](https://www.chromium.org/administrators/configuring-policy-for-extensions)
 for the user. Such extensions have to define the schema of the configuration
 in their manifest.
 
-When Chrome OS device is cloud-managed, there is a limit on policy size.
+When a Chrome OS device is cloud-managed, there is a limit on policy size.
 As such configuration can be relatively large, it is not provided as a part
-of user policy. Instead, user policy would only include URL and hash signature
-for external data, and browser would fetch that data, validate signature,
-validate data against schema from extension manifest and provide the
+of user policy. Instead, user policy will only include URL and hash signature
+for external data, and browser will fetch that data, validate its signature,
+validate the data against the schema from extension manifest, and provide the
 extension with such configuration.
 
 The same approach is used for other large objects that can be set via
@@ -108,4 +107,4 @@
 
 ## Adding new policies
 
-See [adding new policies HowTo](http://dev.chromium.org/developers/how-tos/enterprise/adding-new-policies)
+See [adding new policies HowTo](https://www.chromium.org/developers/how-tos/enterprise/adding-new-policies).
diff --git a/docs/updating_clang.md b/docs/updating_clang.md
index 654152c..255cfdb5 100644
--- a/docs/updating_clang.md
+++ b/docs/updating_clang.md
@@ -46,7 +46,7 @@
       -b linux_chromium_chromeos_asan_rel_ng -b linux_chromium_msan_rel_ng \
       -b linux_chromium_chromeos_msan_rel_ng -b linux-chromeos-dbg \
       -b win-asan -b chromeos-amd64-generic-cfi-thin-lto-rel \
-      -b linux_chromium_compile_dbg_32_ng &&
+      -b linux_chromium_compile_dbg_32_ng -b win7-rel &&
     git cl try -B luci.chrome.try -b iphone-device -b ipad-device
     ```
 
diff --git a/extensions/DEPS b/extensions/DEPS
index 9470811..077597e 100644
--- a/extensions/DEPS
+++ b/extensions/DEPS
@@ -4,6 +4,7 @@
   "+components/crx_file",
   "+components/guest_view",
   "+components/prefs",
+  "+components/services/app_service/public",
   "+components/url_matcher",
   "+components/version_info",
   "-content",
diff --git a/extensions/browser/api/file_handlers/app_file_handler_util.cc b/extensions/browser/api/file_handlers/app_file_handler_util.cc
index d160e06..0b705f4 100644
--- a/extensions/browser/api/file_handlers/app_file_handler_util.cc
+++ b/extensions/browser/api/file_handlers/app_file_handler_util.cc
@@ -11,6 +11,7 @@
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "build/build_config.h"
+#include "components/services/app_service/public/cpp/file_handler_info.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
@@ -37,7 +38,7 @@
 
 namespace {
 
-bool FileHandlerCanHandleFileWithExtension(const FileHandlerInfo& handler,
+bool FileHandlerCanHandleFileWithExtension(const apps::FileHandlerInfo& handler,
                                            const base::FilePath& path) {
   for (auto extension = handler.extensions.cbegin();
        extension != handler.extensions.cend(); ++extension) {
@@ -66,7 +67,7 @@
   return false;
 }
 
-bool FileHandlerCanHandleFileWithMimeType(const FileHandlerInfo& handler,
+bool FileHandlerCanHandleFileWithMimeType(const apps::FileHandlerInfo& handler,
                                           const std::string& mime_type) {
   for (auto type = handler.types.cbegin(); type != handler.types.cend();
        ++type) {
@@ -208,8 +209,8 @@
 
 }  // namespace
 
-const FileHandlerInfo* FileHandlerForId(const Extension& app,
-                                        const std::string& handler_id) {
+const apps::FileHandlerInfo* FileHandlerForId(const Extension& app,
+                                              const std::string& handler_id) {
   const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
   if (!file_handlers)
     return NULL;
@@ -234,7 +235,7 @@
   if (!file_handlers)
     return matches;
 
-  for (const FileHandlerInfo& handler : *file_handlers) {
+  for (const apps::FileHandlerInfo& handler : *file_handlers) {
     bool handles_all_types = true;
     FileHandlerMatch match;
 
@@ -268,7 +269,7 @@
   return matches;
 }
 
-bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler,
+bool FileHandlerCanHandleEntry(const apps::FileHandlerInfo& handler,
                                const EntryInfo& entry) {
   if (entry.is_directory)
     return handler.include_directories;
diff --git a/extensions/browser/api/file_handlers/app_file_handler_util.h b/extensions/browser/api/file_handlers/app_file_handler_util.h
index 428f0343..1b38026 100644
--- a/extensions/browser/api/file_handlers/app_file_handler_util.h
+++ b/extensions/browser/api/file_handlers/app_file_handler_util.h
@@ -18,10 +18,13 @@
 class BrowserContext;
 }
 
+namespace apps {
+struct FileHandlerInfo;
+}
+
 namespace extensions {
 
 struct EntryInfo;
-struct FileHandlerInfo;
 struct FileHandlerMatch;
 struct GrantedFileEntry;
 
@@ -34,8 +37,8 @@
 
 // Returns the file handler with the specified |handler_id|, or NULL if there
 // is no such handler.
-const FileHandlerInfo* FileHandlerForId(const Extension& app,
-                                        const std::string& handler_id);
+const apps::FileHandlerInfo* FileHandlerForId(const Extension& app,
+                                              const std::string& handler_id);
 
 // Returns the handlers that can handle all files in |entries|
 // along with metadata about how the handler matched (MIME or file extension)
@@ -43,7 +46,7 @@
     const Extension& extension,
     const std::vector<EntryInfo>& entries);
 
-bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler,
+bool FileHandlerCanHandleEntry(const apps::FileHandlerInfo& handler,
                                const EntryInfo& entry);
 
 // Creates a new file entry and allows |renderer_id| to access |path|. This
diff --git a/extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc b/extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc
index dffb7ab..0275a92 100644
--- a/extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc
+++ b/extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "extensions/browser/api/file_handlers/app_file_handler_util.h"
 
+#include "components/services/app_service/public/cpp/file_handler_info.h"
 #include "extensions/browser/entry_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -11,15 +12,16 @@
 namespace app_file_handler_util {
 namespace {
 
-FileHandlerInfo CreateHandlerInfoFromExtension(const std::string& extension) {
-  FileHandlerInfo handler_info;
+apps::FileHandlerInfo CreateHandlerInfoFromExtension(
+    const std::string& extension) {
+  apps::FileHandlerInfo handler_info;
   handler_info.extensions.insert(extension);
   return handler_info;
 }
 
-FileHandlerInfo CreateHandlerInfoFromIncludeDirectories(
+apps::FileHandlerInfo CreateHandlerInfoFromIncludeDirectories(
     bool include_directories) {
-  FileHandlerInfo handler_info;
+  apps::FileHandlerInfo handler_info;
   handler_info.include_directories = include_directories;
   return handler_info;
 }
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn
index 2fd27d6..1e6a09b 100644
--- a/extensions/common/BUILD.gn
+++ b/extensions/common/BUILD.gn
@@ -311,6 +311,7 @@
     public_deps = [
       ":common_constants",
       ":mojom",
+      "//components/services/app_service/public/cpp:app_file_handling",
       "//content/public/common",
       "//ipc",
       "//skia",
diff --git a/extensions/common/DEPS b/extensions/common/DEPS
index 61bac3b..2179e703 100644
--- a/extensions/common/DEPS
+++ b/extensions/common/DEPS
@@ -2,7 +2,6 @@
   "+components/crx_file",
   "+components/url_formatter",
   "+components/nacl/common/buildflags.h",
-  "+components/services/app_service/public/mojom",
   "+device/bluetooth",  # For BluetoothPermission
   "+grit/extensions_strings.h",
   "+libxml",
diff --git a/extensions/common/manifest_handlers/file_handler_info.cc b/extensions/common/manifest_handlers/file_handler_info.cc
index bad091bb..dc9a6f11 100644
--- a/extensions/common/manifest_handlers/file_handler_info.cc
+++ b/extensions/common/manifest_handlers/file_handler_info.cc
@@ -21,34 +21,20 @@
 namespace keys = manifest_keys;
 namespace errors = manifest_errors;
 
-namespace file_handler_verbs {
-
-const char kOpenWith[] = "open_with";
-const char kAddTo[] = "add_to";
-const char kPackWith[] = "pack_with";
-const char kShareWith[] = "share_with";
-
-}  // namespace file_handler_verbs
-
 namespace {
 
 const int kMaxTypeAndExtensionHandlers = 200;
 const char kNotRecognized[] = "'%s' is not a recognized file handler property.";
 
 bool IsSupportedVerb(const std::string& verb) {
-  return verb == file_handler_verbs::kOpenWith ||
-         verb == file_handler_verbs::kAddTo ||
-         verb == file_handler_verbs::kPackWith ||
-         verb == file_handler_verbs::kShareWith;
+  return verb == apps::file_handler_verbs::kOpenWith ||
+         verb == apps::file_handler_verbs::kAddTo ||
+         verb == apps::file_handler_verbs::kPackWith ||
+         verb == apps::file_handler_verbs::kShareWith;
 }
 
 }  // namespace
 
-FileHandlerInfo::FileHandlerInfo()
-    : include_directories(false), verb(file_handler_verbs::kOpenWith) {}
-FileHandlerInfo::FileHandlerInfo(const FileHandlerInfo& other) = default;
-FileHandlerInfo::~FileHandlerInfo() {}
-
 FileHandlerMatch::FileHandlerMatch() = default;
 FileHandlerMatch::~FileHandlerMatch() = default;
 
@@ -75,7 +61,7 @@
                      base::string16* error,
                      std::vector<InstallWarning>* install_warnings) {
   DCHECK(error);
-  FileHandlerInfo handler;
+  apps::FileHandlerInfo handler;
 
   handler.id = handler_id;
 
@@ -106,7 +92,7 @@
     }
   }
 
-  handler.verb = file_handler_verbs::kOpenWith;
+  handler.verb = apps::file_handler_verbs::kOpenWith;
   const base::Value* file_handler =
       handler_info.FindKey(keys::kFileHandlerVerb);
   if (file_handler != nullptr) {
diff --git a/extensions/common/manifest_handlers/file_handler_info.h b/extensions/common/manifest_handlers/file_handler_info.h
index 4a18fc1c..b771dec 100644
--- a/extensions/common/manifest_handlers/file_handler_info.h
+++ b/extensions/common/manifest_handlers/file_handler_info.h
@@ -10,38 +10,18 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "components/services/app_service/public/cpp/file_handler_info.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest_handler.h"
 
 namespace extensions {
 
-struct FileHandlerInfo {
-  FileHandlerInfo();
-  FileHandlerInfo(const FileHandlerInfo& other);
-  ~FileHandlerInfo();
-
-  // The id of this handler.
-  std::string id;
-
-  // File extensions associated with this handler.
-  std::set<std::string> extensions;
-
-  // MIME types associated with this handler.
-  std::set<std::string> types;
-
-  // True if the handler can manage directories.
-  bool include_directories;
-
-  // A verb describing the intent of the handler.
-  std::string verb;
-};
-
-typedef std::vector<FileHandlerInfo> FileHandlersInfo;
+using FileHandlersInfo = std::vector<apps::FileHandlerInfo>;
 
 struct FileHandlerMatch {
   FileHandlerMatch();
   ~FileHandlerMatch();
-  const FileHandlerInfo* handler = nullptr;
+  const apps::FileHandlerInfo* handler = nullptr;
 
   // True if the handler matched on MIME type
   bool matched_mime = false;
@@ -73,16 +53,6 @@
   DISALLOW_COPY_AND_ASSIGN(FileHandlersParser);
 };
 
-namespace file_handler_verbs {
-
-// Supported verbs for file handlers.
-extern const char kOpenWith[];
-extern const char kAddTo[];
-extern const char kPackWith[];
-extern const char kShareWith[];
-
-}  // namespace file_handler_verbs
-
 }  // namespace extensions
 
 #endif  // EXTENSIONS_COMMON_MANIFEST_HANDLERS_FILE_HANDLER_INFO_H_
diff --git a/extensions/common/manifest_handlers/file_handler_manifest_unittest.cc b/extensions/common/manifest_handlers/file_handler_manifest_unittest.cc
index aacce84..6e95c8b 100644
--- a/extensions/common/manifest_handlers/file_handler_manifest_unittest.cc
+++ b/extensions/common/manifest_handlers/file_handler_manifest_unittest.cc
@@ -5,6 +5,7 @@
 #include <vector>
 
 #include "base/stl_util.h"
+#include "components/services/app_service/public/cpp/file_handler_info.h"
 #include "extensions/common/install_warning.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
@@ -52,7 +53,7 @@
   ASSERT_TRUE(handlers != NULL);
   ASSERT_EQ(3U, handlers->size());
 
-  FileHandlerInfo handler = handlers->at(0);
+  apps::FileHandlerInfo handler = handlers->at(0);
   EXPECT_EQ("directories", handler.id);
   EXPECT_EQ(0U, handler.types.size());
   EXPECT_EQ(1U, handler.extensions.size());
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index f6b0693..a61ad62 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -2435,6 +2435,10 @@
       mixins: "linux-gpu-fyi-ci-tester"
     }
     builders {
+      name: "Win10 FYI x86 Release (NVIDIA)"
+      mixins: "linux-gpu-fyi-ci-tester"
+    }
+    builders {
       name: "Win7 FYI Debug (AMD)"
       mixins: "linux-gpu-fyi-ci-tester"
     }
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index b62a568..c77aabc4 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -3225,7 +3225,7 @@
     category: "Windows|Builder|XR"
     short_name: "x64"
   }
-  builders {
+   builders {
     name: "buildbucket/luci.chromium.ci/Win10 FYI x64 Debug (NVIDIA)"
     category: "Windows|10|x64|Nvidia"
     short_name: "dbg"
@@ -3281,6 +3281,11 @@
     short_name: "gtx"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Win10 FYI x86 Release (NVIDIA)"
+    category: "Windows|10|x86|Nvidia"
+    short_name: "rel"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Win7 FYI Debug (AMD)"
     category: "Windows|7|x86|AMD"
     short_name: "dbg"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index 2428dec..23c4343 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -2812,6 +2812,17 @@
 }
 
 job {
+  id: "Win10 FYI x86 Release (NVIDIA)"
+  # Triggered by "GPU FYI Win Builder"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Win10 FYI x86 Release (NVIDIA)"
+  }
+}
+
+job {
   id: "Win7 ANGLE Tryserver (AMD)"
   # Triggered by "GPU FYI Win Builder"
   acl_sets: "triggered-by-parent-builders"
diff --git a/ios/chrome/browser/ssl/BUILD.gn b/ios/chrome/browser/ssl/BUILD.gn
index 99e3dee..850bff8 100644
--- a/ios/chrome/browser/ssl/BUILD.gn
+++ b/ios/chrome/browser/ssl/BUILD.gn
@@ -21,6 +21,8 @@
     "ios_ssl_blocking_page.mm",
     "ios_ssl_error_handler.h",
     "ios_ssl_error_handler.mm",
+    "ios_ssl_error_tab_helper.h",
+    "ios_ssl_error_tab_helper.mm",
   ]
   deps = [
     ":feature_flags",
@@ -66,6 +68,7 @@
     "ios_captive_portal_blocking_page_unittest.mm",
     "ios_security_state_tab_helper_unittest.mm",
     "ios_ssl_error_handler_unittest.mm",
+    "ios_ssl_error_tab_helper_unittest.mm",
   ]
   deps = [
     ":feature_flags",
@@ -73,6 +76,7 @@
     "//base/test:test_support",
     "//components/security_state/core",
     "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/interstitials",
     "//ios/chrome/browser/web:test_support",
     "//ios/web",
     "//ios/web/public/security",
diff --git a/ios/chrome/browser/ssl/ios_ssl_error_tab_helper.h b/ios/chrome/browser/ssl/ios_ssl_error_tab_helper.h
new file mode 100644
index 0000000..fd6e655
--- /dev/null
+++ b/ios/chrome/browser/ssl/ios_ssl_error_tab_helper.h
@@ -0,0 +1,67 @@
+// 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 IOS_CHROME_BROWSER_SSL_IOS_SSL_ERROR_TAB_HELPER_H_
+#define IOS_CHROME_BROWSER_SSL_IOS_SSL_ERROR_TAB_HELPER_H_
+
+#include "ios/chrome/browser/interstitials/ios_security_interstitial_page.h"
+#include "ios/web/public/web_state/web_state_observer.h"
+#import "ios/web/public/web_state/web_state_user_data.h"
+
+namespace web {
+class WebState;
+}  // namespace web
+
+// Helps manage IOSSecurityInterstitialPage lifetime independent from
+// interstitial code. Stores an IOSSecurityInterstitialPage while an SSL error
+// is currently being shown, then cleans it up when the user navigates away
+// from the SSL error.
+class IOSSSLErrorTabHelper
+    : public web::WebStateObserver,
+      public web::WebStateUserData<IOSSSLErrorTabHelper> {
+ public:
+  ~IOSSSLErrorTabHelper() override;
+
+  // Associates |blocking_page| with an IOSSSLErrorTabHelper to manage the
+  // |blocking_page|'s lifetime.
+  static void AssociateBlockingPage(
+      web::WebState* web_state,
+      int64_t navigation_id,
+      std::unique_ptr<IOSSecurityInterstitialPage> blocking_page);
+
+  // web::WebStateObserver implementation.
+  void DidFinishNavigation(web::WebState* web_state,
+                           web::NavigationContext* navigation_context) override;
+  void WebStateDestroyed(web::WebState* web_state) override;
+
+ private:
+  explicit IOSSSLErrorTabHelper(web::WebState* web_state);
+  friend class web::WebStateUserData<IOSSSLErrorTabHelper>;
+
+  void SetBlockingPage(
+      int64_t navigation_id,
+      std::unique_ptr<IOSSecurityInterstitialPage> blocking_page);
+
+  // Keeps track of blocking pages for navigations that have encountered
+  // certificate errors in this WebState. When a navigation commits, the
+  // corresponding blocking page is moved out and stored in
+  // |blocking_page_for_currently_committed_navigation_|.
+  std::map<int64_t, std::unique_ptr<IOSSecurityInterstitialPage>>
+      blocking_pages_for_navigations_;
+  // Keeps track of the blocking page for the currently committed navigation, if
+  // there is one. The value is replaced (if the new committed navigation has a
+  // blocking page) or reset on every committed navigation.
+  std::unique_ptr<IOSSecurityInterstitialPage>
+      blocking_page_for_currently_committed_navigation_;
+
+  // The WebState this instance is observing. Will be null after
+  // WebStateDestroyed has been called.
+  web::WebState* web_state_ = nullptr;
+
+  WEB_STATE_USER_DATA_KEY_DECL();
+
+  DISALLOW_COPY_AND_ASSIGN(IOSSSLErrorTabHelper);
+};
+
+#endif  // IOS_CHROME_BROWSER_SSL_IOS_SSL_ERROR_TAB_HELPER_H_
diff --git a/ios/chrome/browser/ssl/ios_ssl_error_tab_helper.mm b/ios/chrome/browser/ssl/ios_ssl_error_tab_helper.mm
new file mode 100644
index 0000000..5e53054
--- /dev/null
+++ b/ios/chrome/browser/ssl/ios_ssl_error_tab_helper.mm
@@ -0,0 +1,79 @@
+// 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 "ios/chrome/browser/ssl/ios_ssl_error_tab_helper.h"
+
+#include "ios/chrome/browser/interstitials/ios_security_interstitial_page.h"
+#import "ios/web/public/navigation/navigation_context.h"
+#import "ios/web/public/web_state.h"
+#import "ios/web/public/web_state/web_state_user_data.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+IOSSSLErrorTabHelper::IOSSSLErrorTabHelper(web::WebState* web_state)
+    : web_state_(web_state) {
+  web_state_->AddObserver(this);
+}
+
+IOSSSLErrorTabHelper::~IOSSSLErrorTabHelper() = default;
+
+// static
+void IOSSSLErrorTabHelper::AssociateBlockingPage(
+    web::WebState* web_state,
+    int64_t navigation_id,
+    std::unique_ptr<IOSSecurityInterstitialPage> blocking_page) {
+  // CreateForWebState() creates a tab helper if it doesn't exist for
+  // |web_state| yet.
+  IOSSSLErrorTabHelper::CreateForWebState(web_state);
+
+  IOSSSLErrorTabHelper* helper = IOSSSLErrorTabHelper::FromWebState(web_state);
+  helper->SetBlockingPage(navigation_id, std::move(blocking_page));
+}
+
+// When the navigation finishes and commits the SSL error page, store the
+// IOSSecurityInterstitialPage in a member variable so that it can handle
+// commands. Clean up the member variable when a subsequent navigation commits,
+// since the IOSSecurityInterstitialPage is no longer needed.
+void IOSSSLErrorTabHelper::DidFinishNavigation(
+    web::WebState* web_state,
+    web::NavigationContext* navigation_context) {
+  DCHECK_EQ(web_state_, web_state);
+  if (navigation_context->IsSameDocument()) {
+    return;
+  }
+
+  auto it = blocking_pages_for_navigations_.find(
+      navigation_context->GetNavigationId());
+
+  if (navigation_context->HasCommitted()) {
+    if (it == blocking_pages_for_navigations_.end()) {
+      blocking_page_for_currently_committed_navigation_.reset();
+    } else {
+      blocking_page_for_currently_committed_navigation_ = std::move(it->second);
+    }
+  }
+
+  if (it != blocking_pages_for_navigations_.end()) {
+    blocking_pages_for_navigations_.erase(it);
+  }
+
+  // Interstitials may change the visibility of the URL or other security state.
+  web_state_->DidChangeVisibleSecurityState();
+}
+
+void IOSSSLErrorTabHelper::WebStateDestroyed(web::WebState* web_state) {
+  DCHECK_EQ(web_state_, web_state);
+  web_state_->RemoveObserver(this);
+  web_state_ = nullptr;
+}
+
+void IOSSSLErrorTabHelper::SetBlockingPage(
+    int64_t navigation_id,
+    std::unique_ptr<IOSSecurityInterstitialPage> blocking_page) {
+  blocking_pages_for_navigations_[navigation_id] = std::move(blocking_page);
+}
+
+WEB_STATE_USER_DATA_KEY_IMPL(IOSSSLErrorTabHelper)
diff --git a/ios/chrome/browser/ssl/ios_ssl_error_tab_helper_unittest.mm b/ios/chrome/browser/ssl/ios_ssl_error_tab_helper_unittest.mm
new file mode 100644
index 0000000..b1efaea
--- /dev/null
+++ b/ios/chrome/browser/ssl/ios_ssl_error_tab_helper_unittest.mm
@@ -0,0 +1,190 @@
+// 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 "ios/chrome/browser/ssl/ios_ssl_error_tab_helper.h"
+
+#include "ios/chrome/browser/interstitials/ios_security_interstitial_page.h"
+#import "ios/web/public/test/fakes/fake_navigation_context.h"
+#import "ios/web/public/test/web_test_with_web_state.h"
+#import "ios/web/public/web_state.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+class TestInterstitialPage : public IOSSecurityInterstitialPage {
+ public:
+  // |*destroyed_tracker| is set to true in the destructor.
+  TestInterstitialPage(web::WebState* web_state,
+                       const GURL& request_url,
+                       bool* destroyed_tracker)
+      : IOSSecurityInterstitialPage(web_state, request_url),
+        destroyed_tracker_(destroyed_tracker) {}
+
+  ~TestInterstitialPage() override { *destroyed_tracker_ = true; }
+
+ protected:
+  bool ShouldCreateNewNavigation() const override { return false; }
+
+  void PopulateInterstitialStrings(
+      base::DictionaryValue* load_time_data) const override {}
+
+  void AfterShow() override {}
+
+ private:
+  bool* destroyed_tracker_;
+};
+
+class IOSSSLErrorTabHelperTest : public web::WebTestWithWebState {
+ protected:
+  void SetUp() override {
+    web::WebTestWithWebState::SetUp();
+    IOSSSLErrorTabHelper::CreateForWebState(web_state());
+  }
+
+  std::unique_ptr<web::NavigationContext> CreateContext(bool committed,
+                                                        bool is_same_document) {
+    std::unique_ptr<web::FakeNavigationContext> context =
+        std::make_unique<web::FakeNavigationContext>();
+    context->SetHasCommitted(committed);
+    context->SetIsSameDocument(is_same_document);
+    return context;
+  }
+
+  // The lifetime of the blocking page is managed by the
+  // IOSSSLErrorTabHelper for the test's web_state.
+  // |destroyed_tracker| will be set to true when the corresponding blocking
+  // page is destroyed.
+  void CreateAssociatedBlockingPage(web::NavigationContext* context,
+                                    bool* destroyed_tracker) {
+    IOSSSLErrorTabHelper::AssociateBlockingPage(
+        web_state(), context->GetNavigationId(),
+        std::make_unique<TestInterstitialPage>(web_state(), GURL(),
+                                               destroyed_tracker));
+  }
+};
+
+// Tests that the helper properly handles the lifetime of a single blocking
+// page, interleaved with other navigations.
+TEST_F(IOSSSLErrorTabHelperTest, SingleBlockingPage) {
+  std::unique_ptr<web::NavigationContext> blocking_page_context =
+      CreateContext(true, false);
+  bool blocking_page_destroyed = false;
+  CreateAssociatedBlockingPage(blocking_page_context.get(),
+                               &blocking_page_destroyed);
+  IOSSSLErrorTabHelper* helper =
+      IOSSSLErrorTabHelper::FromWebState(web_state());
+
+  // Test that a same-document navigation doesn't destroy the blocking page if
+  // its navigation hasn't committed yet.
+  std::unique_ptr<web::NavigationContext> same_document_context =
+      CreateContext(true, true);
+  helper->DidFinishNavigation(web_state(), same_document_context.get());
+  EXPECT_FALSE(blocking_page_destroyed);
+
+  // Test that a committed (non-same-document) navigation doesn't destroy the
+  // blocking page if its navigation hasn't committed yet.
+  std::unique_ptr<web::NavigationContext> committed_context1 =
+      CreateContext(true, false);
+  helper->DidFinishNavigation(web_state(), committed_context1.get());
+  EXPECT_FALSE(blocking_page_destroyed);
+
+  // Simulate committing the interstitial.
+  helper->DidFinishNavigation(web_state(), blocking_page_context.get());
+  EXPECT_FALSE(blocking_page_destroyed);
+
+  // Test that a subsequent committed navigation releases the blocking page
+  // stored for the currently committed navigation.
+  std::unique_ptr<web::NavigationContext> committed_context2 =
+      CreateContext(true, false);
+  helper->DidFinishNavigation(web_state(), committed_context2.get());
+  EXPECT_TRUE(blocking_page_destroyed);
+}
+
+// Tests that the helper properly handles the lifetime of multiple blocking
+// pages, committed in a different order than they are created.
+TEST_F(IOSSSLErrorTabHelperTest, MultipleBlockingPage) {
+  // Simulate associating the first interstitial.
+  std::unique_ptr<web::NavigationContext> context1 = CreateContext(true, false);
+  bool blocking_page1_destroyed = false;
+  CreateAssociatedBlockingPage(context1.get(), &blocking_page1_destroyed);
+
+  // We can directly retrieve the helper for testing once
+  // CreateAssociatedBlockingPage() was called.
+  IOSSSLErrorTabHelper* helper =
+      IOSSSLErrorTabHelper::FromWebState(web_state());
+
+  // Simulate commiting the first interstitial.
+  helper->DidFinishNavigation(web_state(), context1.get());
+  EXPECT_FALSE(blocking_page1_destroyed);
+
+  // Associate the second interstitial.
+  std::unique_ptr<web::NavigationContext> context2 = CreateContext(true, false);
+  bool blocking_page2_destroyed = false;
+  CreateAssociatedBlockingPage(context2.get(), &blocking_page2_destroyed);
+  EXPECT_FALSE(blocking_page1_destroyed);
+  EXPECT_FALSE(blocking_page2_destroyed);
+
+  // Associate the third interstitial.
+  std::unique_ptr<web::NavigationContext> context3 = CreateContext(true, false);
+  bool blocking_page3_destroyed = false;
+  CreateAssociatedBlockingPage(context3.get(), &blocking_page3_destroyed);
+  EXPECT_FALSE(blocking_page1_destroyed);
+  EXPECT_FALSE(blocking_page2_destroyed);
+  EXPECT_FALSE(blocking_page3_destroyed);
+
+  // Simulate committing the third interstitial.
+  helper->DidFinishNavigation(web_state(), context3.get());
+  EXPECT_TRUE(blocking_page1_destroyed);
+  EXPECT_FALSE(blocking_page2_destroyed);
+  EXPECT_FALSE(blocking_page3_destroyed);
+
+  // Simulate committing the second interstitial.
+  helper->DidFinishNavigation(web_state(), context2.get());
+  EXPECT_TRUE(blocking_page1_destroyed);
+  EXPECT_FALSE(blocking_page2_destroyed);
+  EXPECT_TRUE(blocking_page3_destroyed);
+
+  // Test that a subsequent committed navigation releases the last blocking
+  // page.
+  std::unique_ptr<web::NavigationContext> committed_context4 =
+      CreateContext(true, false);
+  helper->DidFinishNavigation(web_state(), committed_context4.get());
+  EXPECT_TRUE(blocking_page2_destroyed);
+}
+
+// Tests that the helper properly handles a navigation that finishes without
+// committing.
+TEST_F(IOSSSLErrorTabHelperTest, NavigationDoesNotCommit) {
+  std::unique_ptr<web::NavigationContext> committed_context =
+      CreateContext(true, false);
+  bool committed_blocking_page_destroyed = false;
+  CreateAssociatedBlockingPage(committed_context.get(),
+                               &committed_blocking_page_destroyed);
+  IOSSSLErrorTabHelper* helper =
+      IOSSSLErrorTabHelper::FromWebState(web_state());
+  helper->DidFinishNavigation(web_state(), committed_context.get());
+  EXPECT_FALSE(committed_blocking_page_destroyed);
+
+  // Simulate a navigation that does not commit.
+  std::unique_ptr<web::NavigationContext> non_committed_context =
+      CreateContext(false, false);
+  bool non_committed_blocking_page_destroyed = false;
+  CreateAssociatedBlockingPage(non_committed_context.get(),
+                               &non_committed_blocking_page_destroyed);
+  helper->DidFinishNavigation(web_state(), non_committed_context.get());
+
+  // The blocking page for the non-committed navigation should have been cleaned
+  // up, but the one for the previous committed navigation should still be
+  // around.
+  EXPECT_TRUE(non_committed_blocking_page_destroyed);
+  EXPECT_FALSE(committed_blocking_page_destroyed);
+
+  // When a navigation does commit, the previous one should be cleaned up.
+  std::unique_ptr<web::NavigationContext> next_committed_context =
+      CreateContext(true, false);
+  helper->DidFinishNavigation(web_state(), next_committed_context.get());
+  EXPECT_TRUE(committed_blocking_page_destroyed);
+}
diff --git a/ios/chrome/browser/ui/badges/badge_button.mm b/ios/chrome/browser/ui/badges/badge_button.mm
index db79dcd1..ef2f173f 100644
--- a/ios/chrome/browser/ui/badges/badge_button.mm
+++ b/ios/chrome/browser/ui/badges/badge_button.mm
@@ -14,8 +14,6 @@
 namespace {
 // Duration of button animations, in seconds.
 const CGFloat kButtonAnimationDuration = 0.2;
-// Edge insets of button.
-const CGFloat kButtonEdgeInset = 6;
 // To achieve a circular corner radius, divide length of a side by 2.
 const CGFloat kButtonCircularCornerRadiusDivisor = 2.0;
 }  // namespace
@@ -38,12 +36,6 @@
   return button;
 }
 
-- (void)willMoveToSuperview:(UIView*)newSuperview {
-  self.imageEdgeInsets = UIEdgeInsetsMake(kButtonEdgeInset, kButtonEdgeInset,
-                                          kButtonEdgeInset, kButtonEdgeInset);
-  [super willMoveToSuperview:newSuperview];
-}
-
 - (void)layoutSubviews {
   [super layoutSubviews];
   self.layer.cornerRadius =
diff --git a/ios/chrome/browser/ui/badges/badge_button_factory.mm b/ios/chrome/browser/ui/badges/badge_button_factory.mm
index 5054b13..04c47a11 100644
--- a/ios/chrome/browser/ui/badges/badge_button_factory.mm
+++ b/ios/chrome/browser/ui/badges/badge_button_factory.mm
@@ -89,7 +89,6 @@
   UIImage* image = [[UIImage imageNamed:imageName]
       imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
   [button setImage:image forState:UIControlStateNormal];
-  button.translatesAutoresizingMaskIntoConstraints = NO;
   button.imageView.contentMode = UIViewContentModeScaleAspectFit;
   [NSLayoutConstraint
       activateConstraints:@[ [button.widthAnchor
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm b/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm
index efd9e1dc..8647812 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm
@@ -332,7 +332,8 @@
     ];
 
     self.badgeViewFullScreenDisabledConstraints = @[
-      [self.badgeView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
+      [self.badgeView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor
+                                                   constant:5],
       [self.badgeView.trailingAnchor
           constraintLessThanOrEqualToAnchor:self.locationContainerView
                                                 .leadingAnchor],
diff --git a/media/base/scopedfd_helper.cc b/media/base/scopedfd_helper.cc
index 1b310a3..e506ccc 100644
--- a/media/base/scopedfd_helper.cc
+++ b/media/base/scopedfd_helper.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
 #include "media/base/scopedfd_helper.h"
 
@@ -17,10 +18,7 @@
 
   for (auto& fd : fds) {
     base::ScopedFD dup_fd = base::ScopedFD(HANDLE_EINTR(dup(fd.get())));
-    if (!dup_fd.is_valid()) {
-      DPLOG(ERROR) << "Failed to duplicate ScopedFD's file descriptor";
-      return std::vector<base::ScopedFD>();
-    }
+    PCHECK(dup_fd.is_valid());
     ret.push_back(std::move(dup_fd));
   }
 
diff --git a/media/base/scopedfd_helper.h b/media/base/scopedfd_helper.h
index 7a784b7..52dd9cdd 100644
--- a/media/base/scopedfd_helper.h
+++ b/media/base/scopedfd_helper.h
@@ -16,8 +16,8 @@
 // this and BUILD.gn as our needs evolve.
 #if defined(OS_LINUX)
 
-// Return a new vector containing duplicates of |fds|, or an empty vector in
-// case of error.
+// Return a new vector containing duplicates of |fds|, or PCHECKs in case of an
+// error.
 MEDIA_EXPORT std::vector<base::ScopedFD> DuplicateFDs(
     const std::vector<base::ScopedFD>& fds);
 
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn
index ebc81e0..97c40033 100644
--- a/media/capture/BUILD.gn
+++ b/media/capture/BUILD.gn
@@ -241,6 +241,14 @@
     sources += [
       "video/chromeos/camera_3a_controller.cc",
       "video/chromeos/camera_3a_controller.h",
+      "video/chromeos/camera_app_device_bridge_impl.cc",
+      "video/chromeos/camera_app_device_bridge_impl.h",
+      "video/chromeos/camera_app_device_impl.cc",
+      "video/chromeos/camera_app_device_impl.h",
+      "video/chromeos/camera_app_device_provider_impl.cc",
+      "video/chromeos/camera_app_device_provider_impl.h",
+      "video/chromeos/camera_app_helper_impl.cc",
+      "video/chromeos/camera_app_helper_impl.h",
       "video/chromeos/camera_buffer_factory.cc",
       "video/chromeos/camera_buffer_factory.h",
       "video/chromeos/camera_device_context.cc",
@@ -253,18 +261,12 @@
       "video/chromeos/camera_hal_dispatcher_impl.h",
       "video/chromeos/camera_metadata_utils.cc",
       "video/chromeos/camera_metadata_utils.h",
-      "video/chromeos/cros_image_capture_impl.cc",
-      "video/chromeos/cros_image_capture_impl.h",
       "video/chromeos/display_rotation_observer.cc",
       "video/chromeos/display_rotation_observer.h",
       "video/chromeos/gpu_memory_buffer_tracker.cc",
       "video/chromeos/gpu_memory_buffer_tracker.h",
       "video/chromeos/pixel_format_utils.cc",
       "video/chromeos/pixel_format_utils.h",
-      "video/chromeos/renderer_facing_cros_image_capture.cc",
-      "video/chromeos/renderer_facing_cros_image_capture.h",
-      "video/chromeos/reprocess_manager.cc",
-      "video/chromeos/reprocess_manager.h",
       "video/chromeos/request_builder.cc",
       "video/chromeos/request_builder.h",
       "video/chromeos/request_manager.cc",
diff --git a/media/capture/video/chromeos/camera_app_device_bridge_impl.cc b/media/capture/video/chromeos/camera_app_device_bridge_impl.cc
new file mode 100644
index 0000000..185095f
--- /dev/null
+++ b/media/capture/video/chromeos/camera_app_device_bridge_impl.cc
@@ -0,0 +1,80 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
+
+#include <string>
+
+#include "base/command_line.h"
+#include "media/base/media_switches.h"
+#include "media/capture/video/chromeos/public/cros_features.h"
+#include "media/capture/video/chromeos/video_capture_device_chromeos_halv3.h"
+
+namespace media {
+
+CameraAppDeviceBridgeImpl::CameraAppDeviceBridgeImpl() {}
+
+CameraAppDeviceBridgeImpl::~CameraAppDeviceBridgeImpl() = default;
+
+void CameraAppDeviceBridgeImpl::SetIsSupported(bool is_supported) {
+  is_supported_ = is_supported;
+}
+
+void CameraAppDeviceBridgeImpl::BindReceiver(
+    mojo::PendingReceiver<cros::mojom::CameraAppDeviceBridge> receiver) {
+  receivers_.Add(this, std::move(receiver));
+}
+
+void CameraAppDeviceBridgeImpl::OnDeviceClosed(const std::string& device_id) {
+  auto it = camera_app_devices_.find(device_id);
+  if (it != camera_app_devices_.end()) {
+    camera_app_devices_.erase(it);
+  }
+}
+
+void CameraAppDeviceBridgeImpl::SetCameraInfoGetter(
+    CameraInfoGetter camera_info_getter) {
+  camera_info_getter_ = std::move(camera_info_getter);
+}
+
+void CameraAppDeviceBridgeImpl::UnsetCameraInfoGetter() {
+  camera_info_getter_ = {};
+}
+
+CameraAppDeviceImpl* CameraAppDeviceBridgeImpl::GetCameraAppDevice(
+    const std::string& device_id) {
+  auto it = camera_app_devices_.find(device_id);
+  if (it != camera_app_devices_.end()) {
+    return it->second.get();
+  }
+  return CreateCameraAppDevice(device_id);
+}
+
+void CameraAppDeviceBridgeImpl::GetCameraAppDevice(
+    const std::string& device_id,
+    GetCameraAppDeviceCallback callback) {
+  if (!is_supported_) {
+    std::move(callback).Run(cros::mojom::GetCameraAppDeviceStatus::ERROR_NON_V3,
+                            {});
+    return;
+  }
+
+  mojo::PendingRemote<cros::mojom::CameraAppDevice> device;
+  GetCameraAppDevice(device_id)->BindReceiver(
+      device.InitWithNewPipeAndPassReceiver());
+  std::move(callback).Run(cros::mojom::GetCameraAppDeviceStatus::SUCCESS,
+                          std::move(device));
+}
+
+media::CameraAppDeviceImpl* CameraAppDeviceBridgeImpl::CreateCameraAppDevice(
+    const std::string& device_id) {
+  DCHECK(camera_info_getter_);
+  auto device_info = camera_info_getter_.Run(device_id);
+  auto device_impl = std::make_unique<media::CameraAppDeviceImpl>(
+      device_id, std::move(device_info));
+  auto result = camera_app_devices_.emplace(device_id, std::move(device_impl));
+  return result.first->second.get();
+}
+
+}  // namespace media
diff --git a/media/capture/video/chromeos/camera_app_device_bridge_impl.h b/media/capture/video/chromeos/camera_app_device_bridge_impl.h
new file mode 100644
index 0000000..619767c
--- /dev/null
+++ b/media/capture/video/chromeos/camera_app_device_bridge_impl.h
@@ -0,0 +1,63 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_DEVICE_BRIDGE_IMPL_H_
+#define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_DEVICE_BRIDGE_IMPL_H_
+
+#include <string>
+
+#include "media/capture/capture_export.h"
+#include "media/capture/video/chromeos/camera_app_device_impl.h"
+#include "media/capture/video/chromeos/mojom/camera_app.mojom.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+
+namespace media {
+
+// A bridge class which helps to construct the connection of CameraAppDevice
+// between remote side (Chrome) and receiver side (Video Capture Service).
+class CAPTURE_EXPORT CameraAppDeviceBridgeImpl
+    : public cros::mojom::CameraAppDeviceBridge {
+ public:
+  using CameraInfoGetter =
+      base::RepeatingCallback<cros::mojom::CameraInfoPtr(const std::string&)>;
+
+  CameraAppDeviceBridgeImpl();
+
+  ~CameraAppDeviceBridgeImpl() override;
+
+  void SetIsSupported(bool is_supported);
+
+  void BindReceiver(
+      mojo::PendingReceiver<cros::mojom::CameraAppDeviceBridge> receiver);
+
+  void OnDeviceClosed(const std::string& device_id);
+
+  void SetCameraInfoGetter(CameraInfoGetter camera_info_getter);
+
+  void UnsetCameraInfoGetter();
+
+  CameraAppDeviceImpl* GetCameraAppDevice(const std::string& device_id);
+
+  // cros::mojom::CameraAppDeviceBridge implementations.
+  void GetCameraAppDevice(const std::string& device_id,
+                          GetCameraAppDeviceCallback callback) override;
+
+ private:
+  CameraAppDeviceImpl* CreateCameraAppDevice(const std::string& device_id);
+
+  bool is_supported_;
+
+  CameraInfoGetter camera_info_getter_;
+
+  mojo::ReceiverSet<cros::mojom::CameraAppDeviceBridge> receivers_;
+
+  base::flat_map<std::string, std::unique_ptr<media::CameraAppDeviceImpl>>
+      camera_app_devices_;
+
+  DISALLOW_COPY_AND_ASSIGN(CameraAppDeviceBridgeImpl);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_DEVICE_BRIDGE_IMPL_H_
\ No newline at end of file
diff --git a/media/capture/video/chromeos/camera_app_device_impl.cc b/media/capture/video/chromeos/camera_app_device_impl.cc
new file mode 100644
index 0000000..41973c5
--- /dev/null
+++ b/media/capture/video/chromeos/camera_app_device_impl.cc
@@ -0,0 +1,198 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/capture/video/chromeos/camera_app_device_impl.h"
+
+#include "media/capture/video/chromeos/camera_metadata_utils.h"
+
+namespace media {
+
+namespace {
+
+void OnStillCaptureDone(media::mojom::ImageCapture::TakePhotoCallback callback,
+                        int status,
+                        mojom::BlobPtr blob) {
+  DCHECK_EQ(status, kReprocessSuccess);
+  std::move(callback).Run(std::move(blob));
+}
+
+}  // namespace
+
+ReprocessTask::ReprocessTask() = default;
+
+ReprocessTask::ReprocessTask(ReprocessTask&& other)
+    : effect(other.effect),
+      callback(std::move(other.callback)),
+      extra_metadata(std::move(other.extra_metadata)) {}
+
+ReprocessTask::~ReprocessTask() = default;
+
+bool CameraAppDeviceImpl::SizeComparator::operator()(
+    const gfx::Size& size_1,
+    const gfx::Size& size_2) const {
+  return size_1.width() < size_2.width() || (size_1.width() == size_2.width() &&
+                                             size_1.height() < size_2.height());
+}
+
+// static
+int CameraAppDeviceImpl::GetReprocessReturnCode(
+    cros::mojom::Effect effect,
+    const cros::mojom::CameraMetadataPtr* metadata) {
+  if (effect == cros::mojom::Effect::PORTRAIT_MODE) {
+    auto portrait_mode_segmentation_result = GetMetadataEntryAsSpan<uint8_t>(
+        *metadata, static_cast<cros::mojom::CameraMetadataTag>(
+                       kPortraitModeSegmentationResultVendorKey));
+    DCHECK(!portrait_mode_segmentation_result.empty());
+    return static_cast<int>(portrait_mode_segmentation_result[0]);
+  }
+  return kReprocessSuccess;
+}
+
+// static
+ReprocessTaskQueue CameraAppDeviceImpl::GetSingleShotReprocessOptions(
+    media::mojom::ImageCapture::TakePhotoCallback take_photo_callback) {
+  ReprocessTaskQueue result_task_queue;
+  ReprocessTask still_capture_task;
+  still_capture_task.effect = cros::mojom::Effect::NO_EFFECT;
+  still_capture_task.callback =
+      base::BindOnce(&OnStillCaptureDone, std::move(take_photo_callback));
+  result_task_queue.push(std::move(still_capture_task));
+  return result_task_queue;
+}
+
+CameraAppDeviceImpl::CameraAppDeviceImpl(const std::string& device_id,
+                                         cros::mojom::CameraInfoPtr camera_info)
+    : device_id_(device_id),
+      camera_info_(std::move(camera_info)),
+      task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      weak_ptr_factory_(
+          std::make_unique<base::WeakPtrFactory<CameraAppDeviceImpl>>(this)) {}
+
+CameraAppDeviceImpl::~CameraAppDeviceImpl() {
+  task_runner_->DeleteSoon(FROM_HERE, std::move(weak_ptr_factory_));
+}
+
+void CameraAppDeviceImpl::BindReceiver(
+    mojo::PendingReceiver<cros::mojom::CameraAppDevice> receiver) {
+  receivers_.Add(this, std::move(receiver));
+}
+
+void CameraAppDeviceImpl::ConsumeReprocessOptions(
+    media::mojom::ImageCapture::TakePhotoCallback take_photo_callback,
+    base::OnceCallback<void(ReprocessTaskQueue)> consumption_callback) {
+  ReprocessTaskQueue result_task_queue;
+
+  ReprocessTask still_capture_task;
+  still_capture_task.effect = cros::mojom::Effect::NO_EFFECT;
+  still_capture_task.callback =
+      base::BindOnce(&OnStillCaptureDone, std::move(take_photo_callback));
+  result_task_queue.push(std::move(still_capture_task));
+
+  base::AutoLock lock(reprocess_tasks_lock_);
+
+  while (!reprocess_task_queue_.empty()) {
+    result_task_queue.push(std::move(reprocess_task_queue_.front()));
+    reprocess_task_queue_.pop();
+  }
+  std::move(consumption_callback).Run(std::move(result_task_queue));
+}
+
+void CameraAppDeviceImpl::GetFpsRange(const gfx::Size& resolution,
+                                      GetFpsRangeCallback callback) {
+  base::AutoLock lock(fps_ranges_lock_);
+
+  auto it = resolution_fps_range_map_.find(resolution);
+  if (it == resolution_fps_range_map_.end()) {
+    std::move(callback).Run({});
+    return;
+  }
+  std::move(callback).Run(it->second);
+}
+
+void CameraAppDeviceImpl::SetReprocessResult(
+    SetReprocessOptionCallback callback,
+    const int32_t status,
+    media::mojom::BlobPtr blob) {
+  auto callback_on_mojo_thread = base::BindOnce(
+      [](const int32_t status, media::mojom::BlobPtr blob,
+         SetReprocessOptionCallback callback) {
+        std::move(callback).Run(status, std::move(blob));
+      },
+      status, std::move(blob), std::move(callback));
+  task_runner_->PostTask(FROM_HERE, std::move(callback_on_mojo_thread));
+}
+
+void CameraAppDeviceImpl::GetCameraInfo(GetCameraInfoCallback callback) {
+  DCHECK(camera_info_);
+  std::move(callback).Run(camera_info_.Clone());
+}
+
+void CameraAppDeviceImpl::SetReprocessOption(
+    cros::mojom::Effect effect,
+    SetReprocessOptionCallback reprocess_result_callback) {
+  ReprocessTask task;
+  task.effect = effect;
+  task.callback = base::BindOnce(&CameraAppDeviceImpl::SetReprocessResult,
+                                 weak_ptr_factory_->GetWeakPtr(),
+                                 std::move(reprocess_result_callback));
+
+  if (effect == cros::mojom::Effect::PORTRAIT_MODE) {
+    std::vector<uint8_t> portrait_mode_value(sizeof(int32_t));
+    *reinterpret_cast<int32_t*>(portrait_mode_value.data()) = 1;
+    cros::mojom::CameraMetadataEntryPtr e =
+        cros::mojom::CameraMetadataEntry::New();
+    e->tag =
+        static_cast<cros::mojom::CameraMetadataTag>(kPortraitModeVendorKey);
+    e->type = cros::mojom::EntryType::TYPE_INT32;
+    e->count = 1;
+    e->data = std::move(portrait_mode_value);
+    task.extra_metadata.push_back(std::move(e));
+  }
+
+  base::AutoLock lock(reprocess_tasks_lock_);
+
+  reprocess_task_queue_.push(std::move(task));
+}
+
+void CameraAppDeviceImpl::SetFpsRange(const gfx::Size& resolution,
+                                      const gfx::Range& fps_range,
+                                      SetFpsRangeCallback callback) {
+  const int entry_length = 2;
+
+  auto& static_metadata = camera_info_->static_camera_characteristics;
+  auto available_fps_range_entries = GetMetadataEntryAsSpan<int32_t>(
+      static_metadata, cros::mojom::CameraMetadataTag::
+                           ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
+  DCHECK(available_fps_range_entries.size() % entry_length == 0);
+
+  bool is_valid = false;
+  int min_fps = static_cast<int>(fps_range.GetMin());
+  int max_fps = static_cast<int>(fps_range.GetMax());
+  for (size_t i = 0; i < available_fps_range_entries.size();
+       i += entry_length) {
+    if (available_fps_range_entries[i] == min_fps &&
+        available_fps_range_entries[i + 1] == max_fps) {
+      is_valid = true;
+      break;
+    }
+  }
+
+  base::AutoLock lock(fps_ranges_lock_);
+
+  if (!is_valid) {
+    // If the input range is invalid, we should still clear the cache range so
+    // that it will fallback to use default fps range rather than the cache one.
+    auto it = resolution_fps_range_map_.find(resolution);
+    if (it != resolution_fps_range_map_.end()) {
+      resolution_fps_range_map_.erase(it);
+    }
+    std::move(callback).Run(false);
+    return;
+  }
+
+  resolution_fps_range_map_[resolution] = fps_range;
+  std::move(callback).Run(true);
+}
+
+}  // namespace media
diff --git a/media/capture/video/chromeos/camera_app_device_impl.h b/media/capture/video/chromeos/camera_app_device_impl.h
new file mode 100644
index 0000000..6c6bf7b
--- /dev/null
+++ b/media/capture/video/chromeos/camera_app_device_impl.h
@@ -0,0 +1,114 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_DEVICE_IMPL_H_
+#define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_DEVICE_IMPL_H_
+
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/containers/flat_set.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "media/capture/capture_export.h"
+#include "media/capture/mojom/image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_app.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/range/range.h"
+
+namespace media {
+
+struct ReprocessTask {
+ public:
+  ReprocessTask();
+  ReprocessTask(ReprocessTask&& other);
+  ~ReprocessTask();
+  cros::mojom::Effect effect;
+  cros::mojom::CameraAppDevice::SetReprocessOptionCallback callback;
+  std::vector<cros::mojom::CameraMetadataEntryPtr> extra_metadata;
+};
+
+using ReprocessTaskQueue = base::queue<ReprocessTask>;
+
+// TODO(shik): Get the keys from VendorTagOps by names instead (b/130774415).
+constexpr uint32_t kPortraitModeVendorKey = 0x80000000;
+constexpr uint32_t kPortraitModeSegmentationResultVendorKey = 0x80000001;
+constexpr int32_t kReprocessSuccess = 0;
+
+class CAPTURE_EXPORT CameraAppDeviceImpl : public cros::mojom::CameraAppDevice {
+ public:
+  struct SizeComparator {
+    bool operator()(const gfx::Size& size_1, const gfx::Size& size_2) const;
+  };
+
+  using GetFpsRangeCallback =
+      base::OnceCallback<void(base::Optional<gfx::Range>)>;
+
+  using ResolutionFpsRangeMap =
+      base::flat_map<gfx::Size, gfx::Range, SizeComparator>;
+
+  static int GetReprocessReturnCode(
+      cros::mojom::Effect effect,
+      const cros::mojom::CameraMetadataPtr* metadata);
+
+  static ReprocessTaskQueue GetSingleShotReprocessOptions(
+      media::mojom::ImageCapture::TakePhotoCallback take_photo_callback);
+
+  CameraAppDeviceImpl(const std::string& device_id,
+                      cros::mojom::CameraInfoPtr camera_info);
+  ~CameraAppDeviceImpl() override;
+
+  void BindReceiver(
+      mojo::PendingReceiver<cros::mojom::CameraAppDevice> receiver);
+
+  void ConsumeReprocessOptions(
+      media::mojom::ImageCapture::TakePhotoCallback take_photo_callback,
+      base::OnceCallback<void(ReprocessTaskQueue)> consumption_callback);
+
+  void GetFpsRange(const gfx::Size& resolution, GetFpsRangeCallback callback);
+
+  void SetReprocessResult(SetReprocessOptionCallback callback,
+                          const int32_t status,
+                          media::mojom::BlobPtr blob);
+
+  // cros::mojom::CameraAppDevice implementations.
+  void GetCameraInfo(GetCameraInfoCallback callback) override;
+
+  void SetReprocessOption(cros::mojom::Effect effect,
+                          SetReprocessOptionCallback callback) override;
+
+  void SetFpsRange(const gfx::Size& resolution,
+                   const gfx::Range& fps_range,
+                   SetFpsRangeCallback callback) override;
+
+ private:
+  std::string device_id_;
+
+  mojo::ReceiverSet<cros::mojom::CameraAppDevice> receivers_;
+
+  cros::mojom::CameraInfoPtr camera_info_;
+
+  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  base::Lock reprocess_tasks_lock_;
+
+  base::queue<ReprocessTask> reprocess_task_queue_;
+
+  base::Lock fps_ranges_lock_;
+
+  ResolutionFpsRangeMap resolution_fps_range_map_;
+
+  std::unique_ptr<base::WeakPtrFactory<CameraAppDeviceImpl>> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CameraAppDeviceImpl);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_DEVICE_IMPL_H_
diff --git a/media/capture/video/chromeos/camera_app_device_provider_impl.cc b/media/capture/video/chromeos/camera_app_device_provider_impl.cc
new file mode 100644
index 0000000..2a9f5168
--- /dev/null
+++ b/media/capture/video/chromeos/camera_app_device_provider_impl.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 "media/capture/video/chromeos/camera_app_device_provider_impl.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "media/base/bind_to_current_loop.h"
+
+namespace media {
+
+CameraAppDeviceProviderImpl::CameraAppDeviceProviderImpl(
+    mojo::PendingRemote<cros::mojom::CameraAppDeviceBridge> bridge,
+    DeviceIdMappingCallback mapping_callback)
+    : bridge_(std::move(bridge)),
+      mapping_callback_(std::move(mapping_callback)),
+      weak_ptr_factory_(this) {}
+
+CameraAppDeviceProviderImpl::~CameraAppDeviceProviderImpl() = default;
+
+void CameraAppDeviceProviderImpl::GetCameraAppDevice(
+    const std::string& source_id,
+    GetCameraAppDeviceCallback callback) {
+  mapping_callback_.Run(
+      source_id,
+      media::BindToCurrentLoop(base::BindOnce(
+          &CameraAppDeviceProviderImpl::GetCameraAppDeviceWithDeviceId,
+          weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
+}
+
+void CameraAppDeviceProviderImpl::GetCameraAppDeviceWithDeviceId(
+    GetCameraAppDeviceCallback callback,
+    const base::Optional<std::string>& device_id) {
+  if (!device_id.has_value()) {
+    std::move(callback).Run(
+        cros::mojom::GetCameraAppDeviceStatus::ERROR_INVALID_ID, {});
+    return;
+  }
+
+  bridge_->GetCameraAppDevice(*device_id, std::move(callback));
+}
+
+}  // namespace media
\ No newline at end of file
diff --git a/media/capture/video/chromeos/camera_app_device_provider_impl.h b/media/capture/video/chromeos/camera_app_device_provider_impl.h
new file mode 100644
index 0000000..cf2f932
--- /dev/null
+++ b/media/capture/video/chromeos/camera_app_device_provider_impl.h
@@ -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.
+
+#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_DEVICE_PROVIDER_IMPL_H_
+#define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_DEVICE_PROVIDER_IMPL_H_
+
+#include <string>
+
+#include "media/capture/capture_export.h"
+#include "media/capture/video/chromeos/mojom/camera_app.mojom.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+
+namespace media {
+
+class CAPTURE_EXPORT CameraAppDeviceProviderImpl
+    : public cros::mojom::CameraAppDeviceProvider {
+ public:
+  using WithRealIdCallback =
+      base::OnceCallback<void(const base::Optional<std::string>&)>;
+  using DeviceIdMappingCallback =
+      base::RepeatingCallback<void(const std::string&, WithRealIdCallback)>;
+
+  CameraAppDeviceProviderImpl(
+      mojo::PendingRemote<cros::mojom::CameraAppDeviceBridge> bridge,
+      DeviceIdMappingCallback mapping_callback);
+  ~CameraAppDeviceProviderImpl() override;
+
+  // cros::mojom::CameraAppDeviceProvider implementations.
+  void GetCameraAppDevice(const std::string& source_id,
+                          GetCameraAppDeviceCallback callback) override;
+
+ private:
+  void GetCameraAppDeviceWithDeviceId(
+      GetCameraAppDeviceCallback callback,
+      const base::Optional<std::string>& device_id);
+
+  mojo::Remote<cros::mojom::CameraAppDeviceBridge> bridge_;
+
+  DeviceIdMappingCallback mapping_callback_;
+
+  base::WeakPtrFactory<CameraAppDeviceProviderImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CameraAppDeviceProviderImpl);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_DEVICE_PROVIDER_IMPL_H_
\ No newline at end of file
diff --git a/media/capture/video/chromeos/camera_app_helper_impl.cc b/media/capture/video/chromeos/camera_app_helper_impl.cc
new file mode 100644
index 0000000..69168ab
--- /dev/null
+++ b/media/capture/video/chromeos/camera_app_helper_impl.cc
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/capture/video/chromeos/camera_app_helper_impl.h"
+
+namespace media {
+
+CameraAppHelperImpl::CameraAppHelperImpl(IntentCallback intent_callback)
+    : intent_callback_(std::move(intent_callback)) {}
+
+CameraAppHelperImpl::~CameraAppHelperImpl() = default;
+
+void CameraAppHelperImpl::OnIntentHandled(
+    uint32_t intent_id,
+    bool is_success,
+    const std::vector<uint8_t>& captured_data) {
+  intent_callback_.Run(intent_id, is_success, captured_data);
+}
+
+}  // namespace media
\ No newline at end of file
diff --git a/media/capture/video/chromeos/camera_app_helper_impl.h b/media/capture/video/chromeos/camera_app_helper_impl.h
new file mode 100644
index 0000000..2fd18f5
--- /dev/null
+++ b/media/capture/video/chromeos/camera_app_helper_impl.h
@@ -0,0 +1,38 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_HELPER_IMPL_H_
+#define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_HELPER_IMPL_H_
+
+#include <string>
+#include <vector>
+
+#include "media/capture/capture_export.h"
+#include "media/capture/video/chromeos/mojom/camera_app.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+
+namespace media {
+
+class CAPTURE_EXPORT CameraAppHelperImpl : public cros::mojom::CameraAppHelper {
+ public:
+  using IntentCallback = base::RepeatingCallback<
+      void(uint32_t, bool, const std::vector<uint8_t>&)>;
+
+  explicit CameraAppHelperImpl(IntentCallback intent_callback);
+  ~CameraAppHelperImpl() override;
+
+  // cros::mojom::CameraAppHelper implementations.
+  void OnIntentHandled(uint32_t intent_id,
+                       bool is_success,
+                       const std::vector<uint8_t>& captured_data) override;
+
+ private:
+  IntentCallback intent_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(CameraAppHelperImpl);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_APP_HELPER_IMPL_H_
\ No newline at end of file
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc
index 2144cf8..c375fe1 100644
--- a/media/capture/video/chromeos/camera_device_delegate.cc
+++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -24,7 +24,6 @@
 #include "media/capture/video/chromeos/camera_device_context.h"
 #include "media/capture/video/chromeos/camera_hal_delegate.h"
 #include "media/capture/video/chromeos/camera_metadata_utils.h"
-#include "media/capture/video/chromeos/reprocess_manager.h"
 #include "media/capture/video/chromeos/request_manager.h"
 
 namespace media {
@@ -162,11 +161,11 @@
     VideoCaptureDeviceDescriptor device_descriptor,
     scoped_refptr<CameraHalDelegate> camera_hal_delegate,
     scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner,
-    ReprocessManager* reprocess_manager)
+    CameraAppDeviceImpl* camera_app_device)
     : device_descriptor_(device_descriptor),
       camera_hal_delegate_(std::move(camera_hal_delegate)),
       ipc_task_runner_(std::move(ipc_task_runner)),
-      reprocess_manager_(reprocess_manager),
+      camera_app_device_(camera_app_device),
       weak_ptr_factory_(this) {}
 
 CameraDeviceDelegate::~CameraDeviceDelegate() = default;
@@ -221,8 +220,6 @@
     base::OnceClosure device_close_callback) {
   DCHECK(ipc_task_runner_->BelongsToCurrentThread());
 
-  reprocess_manager_->Flush(device_descriptor_.device_id);
-
   if (!device_context_ ||
       device_context_->GetState() == CameraDeviceContext::State::kStopped ||
       (device_context_->GetState() == CameraDeviceContext::State::kError &&
@@ -782,13 +779,16 @@
         FROM_HERE, "Failed to get default request settings");
     return;
   }
-  reprocess_manager_->GetFpsRange(
-      device_descriptor_.device_id,
-      chrome_capture_params_.requested_format.frame_size.width(),
-      chrome_capture_params_.requested_format.frame_size.height(),
-      media::BindToCurrentLoop(
-          base::BindOnce(&CameraDeviceDelegate::OnGotFpsRange, GetWeakPtr(),
-                         std::move(settings))));
+
+  if (camera_app_device_) {
+    camera_app_device_->GetFpsRange(
+        chrome_capture_params_.requested_format.frame_size,
+        media::BindToCurrentLoop(
+            base::BindOnce(&CameraDeviceDelegate::OnGotFpsRange, GetWeakPtr(),
+                           std::move(settings))));
+  } else {
+    OnGotFpsRange(std::move(settings), {});
+  }
 }
 
 void CameraDeviceDelegate::OnConstructedDefaultStillCaptureRequestSettings(
@@ -796,15 +796,21 @@
   DCHECK(ipc_task_runner_->BelongsToCurrentThread());
 
   while (!take_photo_callbacks_.empty()) {
-    reprocess_manager_->ConsumeReprocessOptions(
-        device_descriptor_.device_id,
-        base::BindOnce(
-            &TakePhotoCallbackBundle, std::move(take_photo_callbacks_.front()),
-            base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture,
-                           camera_3a_controller_->GetWeakPtr())),
-        media::BindToCurrentLoop(base::BindOnce(&RequestManager::TakePhoto,
-                                                request_manager_->GetWeakPtr(),
-                                                settings.Clone())));
+    auto take_photo_callback = base::BindOnce(
+        &TakePhotoCallbackBundle, std::move(take_photo_callbacks_.front()),
+        base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture,
+                       camera_3a_controller_->GetWeakPtr()));
+    if (camera_app_device_) {
+      camera_app_device_->ConsumeReprocessOptions(
+          std::move(take_photo_callback),
+          media::BindToCurrentLoop(base::BindOnce(
+              &RequestManager::TakePhoto, request_manager_->GetWeakPtr(),
+              settings.Clone())));
+    } else {
+      request_manager_->TakePhoto(
+          settings.Clone(), CameraAppDeviceImpl::GetSingleShotReprocessOptions(
+                                std::move(take_photo_callback)));
+    }
     take_photo_callbacks_.pop();
   }
 }
diff --git a/media/capture/video/chromeos/camera_device_delegate.h b/media/capture/video/chromeos/camera_device_delegate.h
index ee9a891..feef06b 100644
--- a/media/capture/video/chromeos/camera_device_delegate.h
+++ b/media/capture/video/chromeos/camera_device_delegate.h
@@ -21,9 +21,9 @@
 namespace media {
 
 class Camera3AController;
+class CameraAppDeviceImpl;
 class CameraDeviceContext;
 class CameraHalDelegate;
-class ReprocessManager;
 class RequestManager;
 
 enum class StreamType : uint64_t {
@@ -76,7 +76,7 @@
       VideoCaptureDeviceDescriptor device_descriptor,
       scoped_refptr<CameraHalDelegate> camera_hal_delegate,
       scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner,
-      ReprocessManager* reprocess_manager);
+      CameraAppDeviceImpl* camera_app_device);
 
   ~CameraDeviceDelegate();
 
@@ -203,7 +203,7 @@
 
   VideoCaptureDevice::SetPhotoOptionsCallback set_photo_option_callback_;
 
-  ReprocessManager* reprocess_manager_;  // weak
+  CameraAppDeviceImpl* camera_app_device_;  // Weak.
 
   base::WeakPtrFactory<CameraDeviceDelegate> weak_ptr_factory_;
 
diff --git a/media/capture/video/chromeos/camera_device_delegate_unittest.cc b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
index 4e0d4ce..8085aab5 100644
--- a/media/capture/video/chromeos/camera_device_delegate_unittest.cc
+++ b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
@@ -21,7 +21,6 @@
 #include "media/capture/video/chromeos/mock_camera_module.h"
 #include "media/capture/video/chromeos/mock_vendor_tag_ops.h"
 #include "media/capture/video/chromeos/mock_video_capture_client.h"
-#include "media/capture/video/chromeos/reprocess_manager.h"
 #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
 #include "media/capture/video/mock_gpu_memory_buffer_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -128,13 +127,11 @@
         new CameraHalDelegate(hal_delegate_thread_.task_runner());
     auto get_camera_info = base::BindRepeating(
         &CameraHalDelegate::GetCameraInfoFromDeviceId, camera_hal_delegate_);
-    reprocess_manager_ = std::make_unique<ReprocessManager>(get_camera_info);
     camera_hal_delegate_->SetCameraModule(
         mock_camera_module_.GetInterfacePtrInfo());
   }
 
   void TearDown() override {
-    reprocess_manager_.reset();
     camera_hal_delegate_->Reset();
     hal_delegate_thread_.Stop();
   }
@@ -146,9 +143,10 @@
     camera_hal_delegate_->GetDeviceDescriptors(&descriptors);
     ASSERT_EQ(descriptors.size(), 1u);
     device_delegate_thread_.Start();
+
     camera_device_delegate_ = std::make_unique<CameraDeviceDelegate>(
         descriptors[0], camera_hal_delegate_,
-        device_delegate_thread_.task_runner(), reprocess_manager_.get());
+        device_delegate_thread_.task_runner(), nullptr);
   }
 
   void GetNumberOfFakeCameras(
@@ -476,8 +474,6 @@
   mojo::Binding<cros::mojom::Camera3DeviceOps> mock_camera_device_binding_;
   cros::mojom::Camera3CallbackOpsPtr callback_ops_;
 
-  std::unique_ptr<ReprocessManager> reprocess_manager_;
-
   base::Thread device_delegate_thread_;
 
   std::unique_ptr<CameraDeviceContext> device_context_;
diff --git a/media/capture/video/chromeos/camera_hal_delegate.cc b/media/capture/video/chromeos/camera_hal_delegate.cc
index 6990532c..ed97f81 100644
--- a/media/capture/video/chromeos/camera_hal_delegate.cc
+++ b/media/capture/video/chromeos/camera_hal_delegate.cc
@@ -19,10 +19,10 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/system/system_monitor.h"
+#include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
 #include "media/capture/video/chromeos/camera_buffer_factory.h"
 #include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h"
 #include "media/capture/video/chromeos/camera_metadata_utils.h"
-#include "media/capture/video/chromeos/reprocess_manager.h"
 #include "media/capture/video/chromeos/video_capture_device_chromeos_halv3.h"
 
 namespace media {
@@ -129,21 +129,37 @@
 std::unique_ptr<VideoCaptureDevice> CameraHalDelegate::CreateDevice(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer,
     const VideoCaptureDeviceDescriptor& device_descriptor,
-    ReprocessManager* reprocess_manager) {
+    CameraAppDeviceBridgeImpl* camera_app_device_bridge) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  std::unique_ptr<VideoCaptureDevice> capture_device;
   if (!UpdateBuiltInCameraInfo()) {
-    return capture_device;
+    return nullptr;
   }
   int camera_id = GetCameraIdFromDeviceId(device_descriptor.device_id);
   if (camera_id == -1) {
     LOG(ERROR) << "Invalid camera device: " << device_descriptor.device_id;
-    return capture_device;
+    return nullptr;
   }
-  capture_device.reset(new VideoCaptureDeviceChromeOSHalv3(
-      std::move(task_runner_for_screen_observer), device_descriptor, this,
-      reprocess_manager));
-  return capture_device;
+
+  if (camera_app_device_bridge) {
+    auto* camera_app_device = camera_app_device_bridge->GetCameraAppDevice(
+        device_descriptor.device_id);
+    // Since the cleanup callback will be triggered when VideoCaptureDevice died
+    // and |camera_app_device_bridge| is actually owned by
+    // VideoCaptureServiceImpl, it should be safe to assume
+    // |camera_app_device_bridge| is still valid here.
+    auto cleanup_callback = base::BindOnce(
+        [](const std::string& device_id, CameraAppDeviceBridgeImpl* bridge) {
+          bridge->OnDeviceClosed(device_id);
+        },
+        device_descriptor.device_id, camera_app_device_bridge);
+    return std::make_unique<VideoCaptureDeviceChromeOSHalv3>(
+        std::move(task_runner_for_screen_observer), device_descriptor, this,
+        camera_app_device, std::move(cleanup_callback));
+  } else {
+    return std::make_unique<VideoCaptureDeviceChromeOSHalv3>(
+        std::move(task_runner_for_screen_observer), device_descriptor, this,
+        nullptr, base::DoNothing());
+  }
 }
 
 void CameraHalDelegate::GetSupportedFormats(
diff --git a/media/capture/video/chromeos/camera_hal_delegate.h b/media/capture/video/chromeos/camera_hal_delegate.h
index 3f02f7f..83795c3 100644
--- a/media/capture/video/chromeos/camera_hal_delegate.h
+++ b/media/capture/video/chromeos/camera_hal_delegate.h
@@ -24,8 +24,8 @@
 
 namespace media {
 
+class CameraAppDeviceBridgeImpl;
 class CameraBufferFactory;
-class ReprocessManager;
 
 // CameraHalDelegate is the component which does Mojo IPCs to the camera HAL
 // process on Chrome OS to access the module-level camera functionalities such
@@ -59,7 +59,7 @@
       scoped_refptr<base::SingleThreadTaskRunner>
           task_runner_for_screen_observer,
       const VideoCaptureDeviceDescriptor& device_descriptor,
-      ReprocessManager* reprocess_manager);
+      CameraAppDeviceBridgeImpl* app_device_bridge);
   void GetSupportedFormats(
       const VideoCaptureDeviceDescriptor& device_descriptor,
       VideoCaptureFormats* supported_formats);
diff --git a/media/capture/video/chromeos/cros_image_capture_impl.cc b/media/capture/video/chromeos/cros_image_capture_impl.cc
deleted file mode 100644
index e8f161f..0000000
--- a/media/capture/video/chromeos/cros_image_capture_impl.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/capture/video/chromeos/cros_image_capture_impl.h"
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/task/post_task.h"
-#include "media/base/bind_to_current_loop.h"
-
-namespace media {
-
-CrosImageCaptureImpl::CrosImageCaptureImpl(ReprocessManager* reprocess_manager)
-    : reprocess_manager_(reprocess_manager) {}
-
-CrosImageCaptureImpl::~CrosImageCaptureImpl() = default;
-
-void CrosImageCaptureImpl::GetCameraInfo(const std::string& device_id,
-                                         GetCameraInfoCallback callback) {
-  reprocess_manager_->GetCameraInfo(
-      device_id, media::BindToCurrentLoop(base::BindOnce(
-                     &CrosImageCaptureImpl::OnGotCameraInfo,
-                     base::Unretained(this), std::move(callback))));
-}
-
-void CrosImageCaptureImpl::SetReprocessOption(
-    const std::string& device_id,
-    cros::mojom::Effect effect,
-    SetReprocessOptionCallback callback) {
-  reprocess_manager_->SetReprocessOption(
-      device_id, effect, media::BindToCurrentLoop(std::move(callback)));
-}
-
-void CrosImageCaptureImpl::SetFpsRange(const std::string& device_id,
-                                       const uint32_t stream_width,
-                                       const uint32_t stream_height,
-                                       const int32_t min_fps,
-                                       const int32_t max_fps,
-                                       SetFpsRangeCallback callback) {
-  reprocess_manager_->SetFpsRange(
-      device_id, stream_width, stream_height, min_fps, max_fps,
-      media::BindToCurrentLoop(std::move(callback)));
-}
-
-void CrosImageCaptureImpl::OnGotCameraInfo(
-    GetCameraInfoCallback callback,
-    cros::mojom::CameraInfoPtr camera_info) {
-  std::move(callback).Run(std::move(camera_info));
-}
-
-void CrosImageCaptureImpl::OnIntentHandled(
-    uint32_t intent_id,
-    bool is_success,
-    const std::vector<uint8_t>& captured_data) {
-  NOTREACHED() << "Should be handled in RendererFacingCrosImageCapture";
-}
-
-}  // namespace media
diff --git a/media/capture/video/chromeos/cros_image_capture_impl.h b/media/capture/video/chromeos/cros_image_capture_impl.h
deleted file mode 100644
index 6c93866d..0000000
--- a/media/capture/video/chromeos/cros_image_capture_impl.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_CROS_IMAGE_CAPTURE_IMPL_H_
-#define MEDIA_CAPTURE_VIDEO_CHROMEOS_CROS_IMAGE_CAPTURE_IMPL_H_
-
-#include <string>
-
-#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
-#include "media/capture/video/chromeos/reprocess_manager.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-
-namespace media {
-
-class CrosImageCaptureImpl : public cros::mojom::CrosImageCapture {
- public:
-  explicit CrosImageCaptureImpl(ReprocessManager* reprocess_manager);
-
-  ~CrosImageCaptureImpl() override;
-
-  void BindRequest(cros::mojom::CrosImageCaptureRequest request);
-
-  // cros::mojom::CrosImageCapture implementations.
-
-  void GetCameraInfo(const std::string& device_id,
-                     GetCameraInfoCallback callback) override;
-
-  void SetReprocessOption(const std::string& device_id,
-                          cros::mojom::Effect effect,
-                          SetReprocessOptionCallback callback) override;
-
-  void SetFpsRange(const std::string& device_id,
-                   const uint32_t stream_width,
-                   const uint32_t stream_height,
-                   const int32_t min_fps,
-                   const int32_t max_fps,
-                   SetFpsRangeCallback callback) override;
-
-  void OnIntentHandled(uint32_t intent_id,
-                       bool is_success,
-                       const std::vector<uint8_t>& captured_data) override;
-
- private:
-  void OnGotCameraInfo(GetCameraInfoCallback callback,
-                       cros::mojom::CameraInfoPtr camera_info);
-
-  ReprocessManager* reprocess_manager_;  // weak
-
-  DISALLOW_COPY_AND_ASSIGN(CrosImageCaptureImpl);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_CAPTURE_VIDEO_CHROMEOS_CROS_IMAGE_CAPTURE_IMPL_H_
diff --git a/media/capture/video/chromeos/mojom/BUILD.gn b/media/capture/video/chromeos/mojom/BUILD.gn
index e19736e..f98d89e 100644
--- a/media/capture/video/chromeos/mojom/BUILD.gn
+++ b/media/capture/video/chromeos/mojom/BUILD.gn
@@ -7,16 +7,18 @@
 mojom("cros_camera") {
   sources = [
     "camera3.mojom",
+    "camera_app.mojom",
     "camera_common.mojom",
     "camera_metadata.mojom",
     "camera_metadata_tags.mojom",
     "cros_camera_service.mojom",
-    "cros_image_capture.mojom",
   ]
 
   deps = [
     "//components/chromeos_camera/common",
     "//media/capture/mojom:image_capture",
     "//media/mojo/mojom",
+    "//ui/gfx/geometry/mojom",
+    "//ui/gfx/range/mojom",
   ]
 }
diff --git a/media/capture/video/chromeos/mojom/camera_app.mojom b/media/capture/video/chromeos/mojom/camera_app.mojom
new file mode 100644
index 0000000..3484bde
--- /dev/null
+++ b/media/capture/video/chromeos/mojom/camera_app.mojom
@@ -0,0 +1,86 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module cros.mojom;
+
+import "media/capture/mojom/image_capture.mojom";
+import "media/capture/video/chromeos/mojom/camera_common.mojom";
+import "ui/gfx/geometry/mojom/geometry.mojom";
+import "ui/gfx/range/mojom/range.mojom";
+
+// Effect that recognized by Chrome OS.
+enum Effect {
+  NO_EFFECT = 0,
+  PORTRAIT_MODE = 1,
+};
+
+// Status code for getting camera app device.
+enum GetCameraAppDeviceStatus {
+  SUCCESS = 0,
+  ERROR_NON_V3 = 1,
+  ERROR_INVALID_ID = 2,
+};
+
+// Interface to let Chrome Camera App (Remote) get specific CameraAppDevice from
+// Chrome (Receiver).
+interface CameraAppDeviceProvider {
+  // Gets the interface to communicate with specific camera device given by
+  // |source_id|. If the |status| is not success, the |device| would be
+  // null.
+  GetCameraAppDevice(string source_id)
+      => (GetCameraAppDeviceStatus status,
+          pending_remote<CameraAppDevice> device);
+};
+
+// Interface for communication between Chrome Camera App (Remote) and Chrome
+// (Receiver).
+interface CameraAppHelper {
+  // Invoked when the Android intent from ARC++ is fulfilled or is failed.
+  // For the intent which expects to have result, it is fulfilled when the
+  // captured is done and is failed if the session ends without finishing the
+  // capture. For the intent which don't expect any result, it is fulfilled when
+  // the camera app is successfully launched and is failed when the camera fails
+  // to launch. |intent_id| should be the same id that was specified in the
+  // query when launching the camera app. |is_success| indicates the result
+  // status of the intent. The |captured_data| will be delivered to the handler
+  // as a byte array.
+  OnIntentHandled(uint32 intent_id, bool is_success,
+                  array<uint8> captured_data);
+};
+
+// Inner interface that used to communicate between browser process (Remote) and
+// the Video Capture service (Receiver).
+interface CameraAppDeviceBridge {
+  // Gets the interface to communicate with corresponding camera device given by
+  // |device_id|. Note that it only succeeds when running on Camera HAL v3
+  // stack. The |status| contains the result and the |device| interface
+  // is passed when it succeeds. Otherwise, the |device| would be null.
+  GetCameraAppDevice(string device_id)
+      => (GetCameraAppDeviceStatus status,
+          pending_remote<CameraAppDevice> device);
+};
+
+// Interface for communication between Chrome Camera App (Remote) and camera
+// device (Receiver).
+interface CameraAppDevice {
+  // Gets camera information |camera_info| which includes camera facing,
+  // characteristics, orientation, etc.
+  GetCameraInfo() => (CameraInfo camera_info);
+
+  // Sets reprocess option to bind with the coming take photo request. When this
+  // method is called, the reprocess option will be queued. All reprocess
+  // options in the queue will be consumed when ImageCapture::TakePhoto() is
+  // triggered and all the queued reprocess options will be bound
+  // to that take photo request.
+  SetReprocessOption(Effect effect)
+      => (int32 status, media.mojom.Blob? blob);
+
+  // Sets the fps range for upcoming configured camera stream.
+  // The caller sets the |fps_range| for target |resolution|.
+  // If the given fps range is valid and set successfully, |is_success| returns
+  // true. If the given fps range is invalid, the fps range which is cached
+  // previously will be cleared and |is_success| will return false.
+  SetFpsRange(gfx.mojom.Size resolution, gfx.mojom.Range fps_range)
+      => (bool is_success);
+};
diff --git a/media/capture/video/chromeos/mojom/cros_image_capture.mojom b/media/capture/video/chromeos/mojom/cros_image_capture.mojom
deleted file mode 100644
index 77043457..0000000
--- a/media/capture/video/chromeos/mojom/cros_image_capture.mojom
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module cros.mojom;
-
-import "media/capture/mojom/image_capture.mojom";
-import "media/capture/video/chromeos/mojom/camera_common.mojom";
-
-// Effect that recognized by Chrome OS.
-enum Effect {
-  NO_EFFECT = 0,
-  PORTRAIT_MODE = 1,
-};
-
-// Interface for Chrome OS specific Image Capture API which supports reprocess
-// mechanism. The |source_id| parameter in following methods might not be the
-// actual device id if it is called by renderer. It needs to be
-// translated to the actual video device id to be used in CrosImageCapture
-// implementation.
-interface CrosImageCapture {
-  // Gets camera information |camera_info| which includes camera facing,
-  // characteristics, orientation, etc. The |source_id| might need translation
-  // to be actual video device id. For invalid |source_id|, the returned
-  // |camera_info| would be empty.
-  GetCameraInfo(string source_id) => (CameraInfo? camera_info);
-
-  // Sets reprocess option to bind with the coming take photo request. When this
-  // method is called, the reprocess option will be queued. All reprocess
-  // options in the queue will be consumed when TakePhoto() method in Image
-  // Capture API is triggered and all the queued reprocess options will be bound
-  // to that take photo request. The |source_id| might need translation to be
-  // actual video device id.
-  // The result |status| would be set to 0 for success and the corresponding
-  // result will be put in |blob|. If it fails, the |status| indicates the error
-  // type and |blob| might be empty. For invalid |source_id|, it returns
-  // -EINVAL.
-  SetReprocessOption(string source_id, Effect effect)
-      => (int32 status, media.mojom.Blob? blob);
-
-  // Sets the fps range for upcoming configured camera stream.
-  // The |source_id| might need translation to be actual video device id.
-  // The |stream_width| and |stream_height| are the target stream resolution
-  // that the caller sets the fps range for.
-  // The |min_fps| and |max_fps| represent the target fps range.
-  // If the given fps range is valid and set successfully, |is_success| returns
-  // true. If the given fps range is invalid, the fps range which is cached
-  // previously will be cleared and |is_success| will return false.
-  SetFpsRange(string source_id, uint32 stream_width, uint32 stream_height,
-              int32 min_fps, int32 max_fps)
-      => (bool is_success);
-
-  // Invoked when the intent is fulfilled or is failed. For the intent which
-  // expects to have result, it is fulfilled when the captured is done and is
-  // failed if the session ends without finishing the capture. For the intent
-  // which don't expect any result, it is fulfilled when the camera app is
-  // successfully launched and is failed when the camera fails to launch.
-  // |intent_id| should be the same id that was specified in the query when
-  // launching the camera app. |is_success| indicates the result status of the
-  // intent. The |captured_data| will be delivered to the handler as a byte
-  // array.
-  OnIntentHandled(uint32 intent_id, bool is_success,
-                  array<uint8> captured_data);
-};
\ No newline at end of file
diff --git a/media/capture/video/chromeos/renderer_facing_cros_image_capture.cc b/media/capture/video/chromeos/renderer_facing_cros_image_capture.cc
deleted file mode 100644
index b6a3a94..0000000
--- a/media/capture/video/chromeos/renderer_facing_cros_image_capture.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/capture/video/chromeos/renderer_facing_cros_image_capture.h"
-
-#include <errno.h>
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/task/post_task.h"
-#include "media/base/bind_to_current_loop.h"
-#include "media/capture/mojom/image_capture.mojom.h"
-#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
-
-namespace media {
-
-RendererFacingCrosImageCapture::RendererFacingCrosImageCapture(
-    cros::mojom::CrosImageCapturePtr api_ptr,
-    DeviceIdMappingCallback mapping_callback,
-    IntentCallback intent_callback)
-    : cros_image_capture_(std::move(api_ptr)),
-      mapping_callback_(std::move(mapping_callback)),
-      intent_callback_(std::move(intent_callback)),
-      weak_ptr_factory_(this) {}
-
-RendererFacingCrosImageCapture::~RendererFacingCrosImageCapture() = default;
-
-void RendererFacingCrosImageCapture::GetCameraInfoWithRealId(
-    GetCameraInfoCallback callback,
-    const base::Optional<std::string>& device_id) {
-  if (!device_id.has_value()) {
-    std::move(callback).Run({});
-    return;
-  }
-  cros_image_capture_->GetCameraInfo(*device_id, std::move(callback));
-}
-
-void RendererFacingCrosImageCapture::SetReprocessOptionWithRealId(
-    cros::mojom::Effect effect,
-    SetReprocessOptionCallback callback,
-    const base::Optional<std::string>& device_id) {
-  if (!device_id.has_value()) {
-    std::move(callback).Run(-EINVAL, {});
-    return;
-  }
-  cros_image_capture_->SetReprocessOption(*device_id, effect,
-                                          std::move(callback));
-}
-
-void RendererFacingCrosImageCapture::SetFpsRangeWithRealId(
-    const uint32_t stream_width,
-    const uint32_t stream_height,
-    const int32_t min_frame_rate,
-    const int32_t max_frame_rate,
-    SetFpsRangeCallback callback,
-    const base::Optional<std::string>& device_id) {
-  if (!device_id.has_value()) {
-    std::move(callback).Run(false);
-    return;
-  }
-  cros_image_capture_->SetFpsRange(*device_id, stream_width, stream_height,
-                                   min_frame_rate, max_frame_rate,
-                                   std::move(callback));
-}
-
-void RendererFacingCrosImageCapture::GetCameraInfo(
-    const std::string& source_id,
-    GetCameraInfoCallback callback) {
-  mapping_callback_.Run(
-      source_id, media::BindToCurrentLoop(base::BindOnce(
-                     &RendererFacingCrosImageCapture::GetCameraInfoWithRealId,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
-}
-
-void RendererFacingCrosImageCapture::SetReprocessOption(
-    const std::string& source_id,
-    cros::mojom::Effect effect,
-    SetReprocessOptionCallback callback) {
-  mapping_callback_.Run(
-      source_id,
-      media::BindToCurrentLoop(base::BindOnce(
-          &RendererFacingCrosImageCapture::SetReprocessOptionWithRealId,
-          weak_ptr_factory_.GetWeakPtr(), effect, std::move(callback))));
-}
-
-void RendererFacingCrosImageCapture::SetFpsRange(const std::string& source_id,
-                                                 const uint32_t stream_width,
-                                                 const uint32_t stream_height,
-                                                 const int32_t min_frame_rate,
-                                                 const int32_t max_frame_rate,
-                                                 SetFpsRangeCallback callback) {
-  mapping_callback_.Run(
-      source_id,
-      media::BindToCurrentLoop(base::BindOnce(
-          &RendererFacingCrosImageCapture::SetFpsRangeWithRealId,
-          weak_ptr_factory_.GetWeakPtr(), stream_width, stream_height,
-          min_frame_rate, max_frame_rate, std::move(callback))));
-}
-
-void RendererFacingCrosImageCapture::OnIntentHandled(
-    uint32_t intent_id,
-    bool is_success,
-    const std::vector<uint8_t>& captured_data) {
-  intent_callback_.Run(intent_id, is_success, captured_data);
-}
-
-}  // namespace media
\ No newline at end of file
diff --git a/media/capture/video/chromeos/renderer_facing_cros_image_capture.h b/media/capture/video/chromeos/renderer_facing_cros_image_capture.h
deleted file mode 100644
index 60cf8a9..0000000
--- a/media/capture/video/chromeos/renderer_facing_cros_image_capture.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_RENDERER_FACING_CROS_IMAGE_CAPTURE_H_
-#define MEDIA_CAPTURE_VIDEO_CHROMEOS_RENDERER_FACING_CROS_IMAGE_CAPTURE_H_
-
-#include <string>
-
-#include "media/capture/capture_export.h"
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-
-namespace media {
-
-// Intermediate layer for communicating from renderer to CrosImageCapture
-// implementation. It will map the source id recognized by renderer to the
-// actual video device id.
-class CAPTURE_EXPORT RendererFacingCrosImageCapture
-    : public cros::mojom::CrosImageCapture {
- public:
-  using WithRealIdCallback =
-      base::OnceCallback<void(const base::Optional<std::string>&)>;
-  using DeviceIdMappingCallback =
-      base::RepeatingCallback<void(const std::string&, WithRealIdCallback)>;
-  using IntentCallback = base::RepeatingCallback<
-      void(uint32_t, bool, const std::vector<uint8_t>&)>;
-
-  // Create an intermediate layer between renderer to the actual
-  // CrosImageCapture implementation. This class should use |api_ptr| to
-  // communicate with the actual CrosImageCapture implementation and use
-  // |mapping_callback| to map the device id for every calls that inputs device
-  // id.
-  RendererFacingCrosImageCapture(cros::mojom::CrosImageCapturePtr api_ptr,
-                                 DeviceIdMappingCallback mapping_callback,
-                                 IntentCallback intent_callback);
-  ~RendererFacingCrosImageCapture() override;
-
-  void GetCameraInfoWithRealId(GetCameraInfoCallback callback,
-                               const base::Optional<std::string>& device_id);
-
-  void SetReprocessOptionWithRealId(
-      cros::mojom::Effect effect,
-      SetReprocessOptionCallback callback,
-      const base::Optional<std::string>& device_id);
-
-  void SetFpsRangeWithRealId(const uint32_t stream_width,
-                             const uint32_t stream_height,
-                             const int32_t min_frame_rate,
-                             const int32_t max_frame_rate,
-                             SetFpsRangeCallback callback,
-                             const base::Optional<std::string>& device_id);
-
-  // cros::mojom::CrosImageCapture implementations.
-  void GetCameraInfo(const std::string& source_id,
-                     GetCameraInfoCallback callback) override;
-  void SetReprocessOption(const std::string& source_id,
-                          cros::mojom::Effect effect,
-                          SetReprocessOptionCallback callback) override;
-  void SetFpsRange(const std::string& source_id,
-                   const uint32_t stream_width,
-                   const uint32_t stream_height,
-                   const int32_t min_frame_rate,
-                   const int32_t max_frame_rate,
-                   SetFpsRangeCallback callback) override;
-
-  void OnIntentHandled(uint32_t intent_id,
-                       bool is_success,
-                       const std::vector<uint8_t>& captured_data) override;
-
- private:
-  cros::mojom::CrosImageCapturePtr cros_image_capture_;
-
-  DeviceIdMappingCallback mapping_callback_;
-
-  IntentCallback intent_callback_;
-
-  base::WeakPtrFactory<RendererFacingCrosImageCapture> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(RendererFacingCrosImageCapture);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_CAPTURE_VIDEO_CHROMEOS_RENDERER_FACING_CROS_IMAGE_CAPTURE_H_
\ No newline at end of file
diff --git a/media/capture/video/chromeos/reprocess_manager.cc b/media/capture/video/chromeos/reprocess_manager.cc
deleted file mode 100644
index df045dd..0000000
--- a/media/capture/video/chromeos/reprocess_manager.cc
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/capture/video/chromeos/reprocess_manager.h"
-
-#include <functional>
-#include <utility>
-
-#include "media/capture/video/chromeos/camera_metadata_utils.h"
-
-namespace media {
-
-namespace {
-
-void OnStillCaptureDone(media::mojom::ImageCapture::TakePhotoCallback callback,
-                        int status,
-                        mojom::BlobPtr blob) {
-  std::move(callback).Run(std::move(blob));
-}
-
-}  // namespace
-
-ReprocessTask::ReprocessTask() = default;
-
-ReprocessTask::ReprocessTask(ReprocessTask&& other)
-    : effect(other.effect),
-      callback(std::move(other.callback)),
-      extra_metadata(std::move(other.extra_metadata)) {}
-
-ReprocessTask::~ReprocessTask() = default;
-
-// static
-int ReprocessManager::GetReprocessReturnCode(
-    cros::mojom::Effect effect,
-    const cros::mojom::CameraMetadataPtr* metadata) {
-  if (effect == cros::mojom::Effect::PORTRAIT_MODE) {
-    auto* portrait_mode_segmentation_result = GetMetadataEntry(
-        *metadata, static_cast<cros::mojom::CameraMetadataTag>(
-                       kPortraitModeSegmentationResultVendorKey));
-    CHECK(portrait_mode_segmentation_result);
-    return static_cast<int>((*portrait_mode_segmentation_result)->data[0]);
-  }
-  return kReprocessSuccess;
-}
-
-ReprocessManager::ReprocessManager(CameraInfoGetter get_camera_info)
-    : sequenced_task_runner_(base::CreateSequencedTaskRunner(
-          {base::ThreadPool(), base::TaskPriority::USER_VISIBLE})),
-      impl(std::make_unique<ReprocessManager::ReprocessManagerImpl>(
-          std::move(get_camera_info))) {}
-
-ReprocessManager::~ReprocessManager() {
-  sequenced_task_runner_->DeleteSoon(FROM_HERE, std::move(impl));
-}
-
-void ReprocessManager::SetReprocessOption(
-    const std::string& device_id,
-    cros::mojom::Effect effect,
-    cros::mojom::CrosImageCapture::SetReprocessOptionCallback
-        reprocess_result_callback) {
-  sequenced_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &ReprocessManager::ReprocessManagerImpl::SetReprocessOption,
-          base::Unretained(impl.get()), device_id, effect,
-          std::move(reprocess_result_callback)));
-}
-
-void ReprocessManager::ConsumeReprocessOptions(
-    const std::string& device_id,
-    media::mojom::ImageCapture::TakePhotoCallback take_photo_callback,
-    base::OnceCallback<void(ReprocessTaskQueue)> consumption_callback) {
-  sequenced_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &ReprocessManager::ReprocessManagerImpl::ConsumeReprocessOptions,
-          base::Unretained(impl.get()), device_id,
-          std::move(take_photo_callback), std::move(consumption_callback)));
-}
-
-void ReprocessManager::Flush(const std::string& device_id) {
-  sequenced_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&ReprocessManager::ReprocessManagerImpl::Flush,
-                                base::Unretained(impl.get()), device_id));
-}
-
-void ReprocessManager::GetCameraInfo(const std::string& device_id,
-                                     GetCameraInfoCallback callback) {
-  sequenced_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ReprocessManager::ReprocessManagerImpl::GetCameraInfo,
-                     base::Unretained(impl.get()), device_id,
-                     std::move(callback)));
-}
-
-void ReprocessManager::SetFpsRange(
-    const std::string& device_id,
-    const uint32_t stream_width,
-    const uint32_t stream_height,
-    const int32_t min_fps,
-    const int32_t max_fps,
-    cros::mojom::CrosImageCapture::SetFpsRangeCallback callback) {
-  sequenced_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ReprocessManager::ReprocessManagerImpl::SetFpsRange,
-                     base::Unretained(impl.get()), device_id, stream_width,
-                     stream_height, min_fps, max_fps, std::move(callback)));
-}
-
-void ReprocessManager::GetFpsRange(const std::string& device_id,
-                                   const uint32_t stream_width,
-                                   const uint32_t stream_height,
-                                   GetFpsRangeCallback callback) {
-  sequenced_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ReprocessManager::ReprocessManagerImpl::GetFpsRange,
-                     base::Unretained(impl.get()), device_id, stream_width,
-                     stream_height, std::move(callback)));
-}
-
-ReprocessManager::ReprocessManagerImpl::ReprocessManagerImpl(
-    CameraInfoGetter get_camera_info)
-    : get_camera_info_(std::move(get_camera_info)) {}
-
-ReprocessManager::ReprocessManagerImpl::~ReprocessManagerImpl() = default;
-
-void ReprocessManager::ReprocessManagerImpl::SetReprocessOption(
-    const std::string& device_id,
-    cros::mojom::Effect effect,
-    cros::mojom::CrosImageCapture::SetReprocessOptionCallback
-        reprocess_result_callback) {
-  ReprocessTask task;
-  task.effect = effect;
-  task.callback = std::move(reprocess_result_callback);
-
-  if (effect == cros::mojom::Effect::PORTRAIT_MODE) {
-    std::vector<uint8_t> portrait_mode_value(sizeof(int32_t));
-    *reinterpret_cast<int32_t*>(portrait_mode_value.data()) = 1;
-    cros::mojom::CameraMetadataEntryPtr e =
-        cros::mojom::CameraMetadataEntry::New();
-    e->tag =
-        static_cast<cros::mojom::CameraMetadataTag>(kPortraitModeVendorKey);
-    e->type = cros::mojom::EntryType::TYPE_INT32;
-    e->count = 1;
-    e->data = std::move(portrait_mode_value);
-    task.extra_metadata.push_back(std::move(e));
-  }
-
-  reprocess_task_queue_map_[device_id].push(std::move(task));
-}
-
-void ReprocessManager::ReprocessManagerImpl::ConsumeReprocessOptions(
-    const std::string& device_id,
-    media::mojom::ImageCapture::TakePhotoCallback take_photo_callback,
-    base::OnceCallback<void(ReprocessTaskQueue)> consumption_callback) {
-  ReprocessTaskQueue result_task_queue;
-
-  ReprocessTask still_capture_task;
-  still_capture_task.effect = cros::mojom::Effect::NO_EFFECT;
-  still_capture_task.callback =
-      base::BindOnce(&OnStillCaptureDone, std::move(take_photo_callback));
-  result_task_queue.push(std::move(still_capture_task));
-
-  auto& task_queue = reprocess_task_queue_map_[device_id];
-  while (!task_queue.empty()) {
-    result_task_queue.push(std::move(task_queue.front()));
-    task_queue.pop();
-  }
-  std::move(consumption_callback).Run(std::move(result_task_queue));
-}
-
-void ReprocessManager::ReprocessManagerImpl::Flush(
-    const std::string& device_id) {
-  auto empty_queue = ReprocessTaskQueue();
-  reprocess_task_queue_map_[device_id].swap(empty_queue);
-
-  auto empty_map = ResolutionFpsRangeMap();
-  resolution_fps_range_map_[device_id].swap(empty_map);
-}
-
-void ReprocessManager::ReprocessManagerImpl::GetCameraInfo(
-    const std::string& device_id,
-    GetCameraInfoCallback callback) {
-  std::move(callback).Run(get_camera_info_.Run(device_id));
-}
-
-void ReprocessManager::ReprocessManagerImpl::SetFpsRange(
-    const std::string& device_id,
-    const uint32_t stream_width,
-    const uint32_t stream_height,
-    const int32_t min_fps,
-    const int32_t max_fps,
-    cros::mojom::CrosImageCapture::SetFpsRangeCallback callback) {
-  const int entry_length = 2;
-
-  auto camera_info = get_camera_info_.Run(device_id);
-  auto& static_metadata = camera_info->static_camera_characteristics;
-  auto available_fps_range_entries = GetMetadataEntryAsSpan<int32_t>(
-      static_metadata, cros::mojom::CameraMetadataTag::
-                           ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
-  CHECK(available_fps_range_entries.size() % entry_length == 0);
-
-  bool is_valid = false;
-  for (size_t i = 0; i < available_fps_range_entries.size();
-       i += entry_length) {
-    if (available_fps_range_entries[i] == min_fps &&
-        available_fps_range_entries[i + 1] == max_fps) {
-      is_valid = true;
-      break;
-    }
-  }
-
-  auto resolution = gfx::Size(stream_width, stream_height);
-  auto& fps_map = resolution_fps_range_map_[device_id];
-  if (!is_valid) {
-    // If the input range is invalid, we should still clear the cache range so
-    // that it will fallback to use default fps range rather than the cache one.
-    auto it = fps_map.find(resolution);
-    if (it != fps_map.end()) {
-      fps_map.erase(it);
-    }
-    std::move(callback).Run(false);
-    return;
-  }
-
-  auto fps_range = gfx::Range(min_fps, max_fps);
-  fps_map[resolution] = fps_range;
-  std::move(callback).Run(true);
-}
-
-void ReprocessManager::ReprocessManagerImpl::GetFpsRange(
-    const std::string& device_id,
-    const uint32_t stream_width,
-    const uint32_t stream_height,
-    GetFpsRangeCallback callback) {
-  if (resolution_fps_range_map_.find(device_id) ==
-      resolution_fps_range_map_.end()) {
-    std::move(callback).Run({});
-    return;
-  }
-
-  auto resolution = gfx::Size(stream_width, stream_height);
-  auto& fps_map = resolution_fps_range_map_[device_id];
-  if (fps_map.find(resolution) == fps_map.end()) {
-    std::move(callback).Run({});
-    return;
-  }
-
-  std::move(callback).Run(fps_map[resolution]);
-}
-
-bool ReprocessManager::ReprocessManagerImpl::SizeComparator::operator()(
-    const gfx::Size size_1,
-    const gfx::Size size_2) const {
-  return size_1.width() < size_2.width() || (size_1.width() == size_2.width() &&
-                                             size_1.height() < size_2.height());
-}
-
-}  // namespace media
diff --git a/media/capture/video/chromeos/reprocess_manager.h b/media/capture/video/chromeos/reprocess_manager.h
deleted file mode 100644
index 831ee69..0000000
--- a/media/capture/video/chromeos/reprocess_manager.h
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_REPROCESS_MANAGER_H_
-#define MEDIA_CAPTURE_VIDEO_CHROMEOS_REPROCESS_MANAGER_H_
-
-#include <queue>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/containers/flat_set.h"
-#include "base/sequenced_task_runner.h"
-#include "base/task/post_task.h"
-#include "media/capture/capture_export.h"
-#include "media/capture/mojom/image_capture.mojom.h"
-#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
-#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/range/range.h"
-
-namespace media {
-
-struct ReprocessTask {
- public:
-  ReprocessTask();
-  ReprocessTask(ReprocessTask&& other);
-  ~ReprocessTask();
-  cros::mojom::Effect effect;
-  cros::mojom::CrosImageCapture::SetReprocessOptionCallback callback;
-  std::vector<cros::mojom::CameraMetadataEntryPtr> extra_metadata;
-};
-
-using ReprocessTaskQueue = base::queue<ReprocessTask>;
-
-// TODO(shik): Get the keys from VendorTagOps by names instead (b/130774415).
-constexpr uint32_t kPortraitModeVendorKey = 0x80000000;
-constexpr uint32_t kPortraitModeSegmentationResultVendorKey = 0x80000001;
-constexpr int32_t kReprocessSuccess = 0;
-
-// ReprocessManager is used to communicate between the reprocess requester and
-// the consumer. When reprocess is requested, the reprocess information will be
-// wrapped as a ReprocessTask and stored in the queue. When consumption, all
-// ReprocessTask in the queue will be dumped and a default NO_EFFECT task will
-// be added on the top of the result queue. Note that all calls will be
-// sequentialize to a single sequence.
-class CAPTURE_EXPORT ReprocessManager {
- public:
-  using CameraInfoGetter = base::RepeatingCallback<cros::mojom::CameraInfoPtr(
-      const std::string& device_id)>;
-  using GetCameraInfoCallback =
-      base::OnceCallback<void(cros::mojom::CameraInfoPtr camera_info)>;
-  using GetFpsRangeCallback =
-      base::OnceCallback<void(base::Optional<gfx::Range>)>;
-
-  class ReprocessManagerImpl {
-   public:
-    struct SizeComparator {
-      bool operator()(const gfx::Size size_1, const gfx::Size size_2) const;
-    };
-
-    using ResolutionFpsRangeMap =
-        base::flat_map<gfx::Size, gfx::Range, SizeComparator>;
-
-    ReprocessManagerImpl(CameraInfoGetter get_camera_info);
-    ~ReprocessManagerImpl();
-
-    void SetReprocessOption(
-        const std::string& device_id,
-        cros::mojom::Effect effect,
-        cros::mojom::CrosImageCapture::SetReprocessOptionCallback
-            reprocess_result_callback);
-
-    void ConsumeReprocessOptions(
-        const std::string& device_id,
-        media::mojom::ImageCapture::TakePhotoCallback take_photo_callback,
-        base::OnceCallback<void(ReprocessTaskQueue)> consumption_callback);
-
-    void Flush(const std::string& device_id);
-
-    void GetCameraInfo(const std::string& device_id,
-                       GetCameraInfoCallback callback);
-
-    void SetFpsRange(
-        const std::string& device_id,
-        const uint32_t stream_width,
-        const uint32_t stream_height,
-        const int32_t min_fps,
-        const int32_t max_fps,
-        cros::mojom::CrosImageCapture::SetFpsRangeCallback callback);
-
-    void GetFpsRange(const std::string& device_id,
-                     const uint32_t stream_width,
-                     const uint32_t stream_height,
-                     GetFpsRangeCallback callback);
-
-   private:
-    base::flat_map<std::string, base::queue<ReprocessTask>>
-        reprocess_task_queue_map_;
-    base::flat_map<std::string, ResolutionFpsRangeMap>
-        resolution_fps_range_map_;
-
-    CameraInfoGetter get_camera_info_;
-
-    DISALLOW_COPY_AND_ASSIGN(ReprocessManagerImpl);
-  };
-
-  static int GetReprocessReturnCode(
-      cros::mojom::Effect effect,
-      const cros::mojom::CameraMetadataPtr* metadata);
-  ReprocessManager(CameraInfoGetter callback);
-  ~ReprocessManager();
-
-  // Sets the reprocess option for given device id and effect. Each reprocess
-  // option has a corressponding callback.
-  void SetReprocessOption(
-      const std::string& device_id,
-      cros::mojom::Effect effect,
-      cros::mojom::CrosImageCapture::SetReprocessOptionCallback
-          reprocess_result_callback);
-
-  // Consumes all ReprocessTasks in the queue. A default NO_EFFECT task will be
-  // added on the top of the result queue.
-  void ConsumeReprocessOptions(
-      const std::string& device_id,
-      media::mojom::ImageCapture::TakePhotoCallback take_photo_callback,
-      base::OnceCallback<void(ReprocessTaskQueue)> consumption_callback);
-
-  // Clears all temporary queues and maps that is used for given device id.
-  void Flush(const std::string& device_id);
-
-  // Gets camera information for current active device.
-  void GetCameraInfo(const std::string& device_id,
-                     GetCameraInfoCallback callback);
-
-  // Sets fps range for given device.
-  void SetFpsRange(const std::string& device_id,
-                   const uint32_t stream_width,
-                   const uint32_t stream_height,
-                   const int32_t min_fps,
-                   const int32_t max_fps,
-                   cros::mojom::CrosImageCapture::SetFpsRangeCallback callback);
-
-  // Gets fps range for given device and resolution.
-  void GetFpsRange(const std::string& device_id,
-                   const uint32_t stream_width,
-                   const uint32_t stream_height,
-                   GetFpsRangeCallback callback);
-
- private:
-  scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
-  std::unique_ptr<ReprocessManagerImpl> impl;
-
-  DISALLOW_COPY_AND_ASSIGN(ReprocessManager);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_CAPTURE_VIDEO_CHROMEOS_REPROCESS_MANAGER_H_
diff --git a/media/capture/video/chromeos/request_manager.cc b/media/capture/video/chromeos/request_manager.cc
index 1f05655..2926262 100644
--- a/media/capture/video/chromeos/request_manager.cc
+++ b/media/capture/video/chromeos/request_manager.cc
@@ -20,7 +20,6 @@
 #include "media/capture/video/chromeos/camera_buffer_factory.h"
 #include "media/capture/video/chromeos/camera_device_context.h"
 #include "media/capture/video/chromeos/camera_metadata_utils.h"
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #include "mojo/public/cpp/platform/platform_handle.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 
@@ -877,7 +876,7 @@
   if (blob) {
     int task_status = kReprocessSuccess;
     if (stream_buffer_manager_->IsReprocessSupported()) {
-      task_status = ReprocessManager::GetReprocessReturnCode(
+      task_status = CameraAppDeviceImpl::GetReprocessReturnCode(
           pending_result.reprocess_effect, &pending_result.metadata);
     }
     std::move(pending_result.still_capture_callback)
diff --git a/media/capture/video/chromeos/request_manager.h b/media/capture/video/chromeos/request_manager.h
index b632df7..59bb8bab 100644
--- a/media/capture/video/chromeos/request_manager.h
+++ b/media/capture/video/chromeos/request_manager.h
@@ -15,9 +15,9 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "media/capture/mojom/image_capture.mojom.h"
+#include "media/capture/video/chromeos/camera_app_device_impl.h"
 #include "media/capture/video/chromeos/camera_device_delegate.h"
 #include "media/capture/video/chromeos/mojom/camera3.mojom.h"
-#include "media/capture/video/chromeos/reprocess_manager.h"
 #include "media/capture/video/chromeos/request_builder.h"
 #include "media/capture/video/chromeos/stream_buffer_manager.h"
 #include "media/capture/video_capture_types.h"
diff --git a/media/capture/video/chromeos/request_manager_unittest.cc b/media/capture/video/chromeos/request_manager_unittest.cc
index 1e6fb82..560e3ce 100644
--- a/media/capture/video/chromeos/request_manager_unittest.cc
+++ b/media/capture/video/chromeos/request_manager_unittest.cc
@@ -19,7 +19,6 @@
 #include "media/capture/video/chromeos/camera_device_context.h"
 #include "media/capture/video/chromeos/camera_device_delegate.h"
 #include "media/capture/video/chromeos/mock_video_capture_client.h"
-#include "media/capture/video/chromeos/reprocess_manager.h"
 #include "media/capture/video/chromeos/stream_buffer_manager.h"
 #include "media/capture/video/mock_gpu_memory_buffer_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
index 12ba25d..3bb86857 100644
--- a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
+++ b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
@@ -19,7 +19,6 @@
 #include "media/capture/video/chromeos/camera_device_context.h"
 #include "media/capture/video/chromeos/camera_device_delegate.h"
 #include "media/capture/video/chromeos/camera_hal_delegate.h"
-#include "media/capture/video/chromeos/reprocess_manager.h"
 #include "ui/display/display.h"
 #include "ui/display/display_observer.h"
 #include "ui/display/screen.h"
@@ -105,7 +104,8 @@
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
     const VideoCaptureDeviceDescriptor& device_descriptor,
     scoped_refptr<CameraHalDelegate> camera_hal_delegate,
-    ReprocessManager* reprocess_manager)
+    CameraAppDeviceImpl* camera_app_device,
+    base::OnceClosure cleanup_callback)
     : device_descriptor_(device_descriptor),
       camera_hal_delegate_(std::move(camera_hal_delegate)),
       capture_task_runner_(base::ThreadTaskRunnerHandle::Get()),
@@ -119,7 +119,8 @@
       rotates_with_device_(lens_facing_ !=
                            VideoFacingMode::MEDIA_VIDEO_FACING_NONE),
       rotation_(0),
-      reprocess_manager_(reprocess_manager),
+      camera_app_device_(camera_app_device),
+      cleanup_callback_(std::move(cleanup_callback)),
       power_manager_client_proxy_(
           base::MakeRefCounted<PowerManagerClientProxy>()),
       weak_ptr_factory_(this) {
@@ -133,6 +134,7 @@
   DCHECK(!camera_device_ipc_thread_.IsRunning());
   screen_observer_delegate_->RemoveObserver();
   power_manager_client_proxy_->Shutdown();
+  std::move(cleanup_callback_).Run();
 }
 
 // VideoCaptureDevice implementation.
@@ -152,9 +154,10 @@
   }
   capture_params_ = params;
   device_context_ = std::make_unique<CameraDeviceContext>(std::move(client));
+
   camera_device_delegate_ = std::make_unique<CameraDeviceDelegate>(
       device_descriptor_, camera_hal_delegate_,
-      camera_device_ipc_thread_.task_runner(), reprocess_manager_);
+      camera_device_ipc_thread_.task_runner(), camera_app_device_);
   OpenDevice();
 }
 
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.h b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.h
index e0214aa..79885bc1 100644
--- a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.h
+++ b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.h
@@ -24,10 +24,10 @@
 
 namespace media {
 
+class CameraAppDeviceImpl;
 class CameraHalDelegate;
 class CameraDeviceContext;
 class CameraDeviceDelegate;
-class ReprocessManager;
 
 // Implementation of VideoCaptureDevice for ChromeOS with CrOS camera HALv3.
 class CAPTURE_EXPORT VideoCaptureDeviceChromeOSHalv3 final
@@ -38,7 +38,8 @@
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
       const VideoCaptureDeviceDescriptor& device_descriptor,
       scoped_refptr<CameraHalDelegate> camera_hal_delegate,
-      ReprocessManager* reprocess_manager);
+      CameraAppDeviceImpl* camera_app_device,
+      base::OnceClosure cleanup_callback);
 
   ~VideoCaptureDeviceChromeOSHalv3() final;
 
@@ -95,7 +96,9 @@
   const bool rotates_with_device_;
   int rotation_;
 
-  ReprocessManager* reprocess_manager_;  // weak
+  CameraAppDeviceImpl* camera_app_device_;  // Weak.
+
+  base::OnceClosure cleanup_callback_;
 
   scoped_refptr<PowerManagerClientProxy> power_manager_client_proxy_;
 
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc
index 6a4fc14..c808420 100644
--- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc
+++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc
@@ -8,9 +8,8 @@
 
 #include "base/memory/ptr_util.h"
 #include "media/base/bind_to_current_loop.h"
+#include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
 #include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h"
-#include "media/capture/video/chromeos/cros_image_capture_impl.h"
-#include "media/capture/video/chromeos/reprocess_manager.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
 namespace media {
@@ -22,19 +21,18 @@
 }  // namespace
 
 VideoCaptureDeviceFactoryChromeOS::VideoCaptureDeviceFactoryChromeOS(
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer)
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer,
+    CameraAppDeviceBridgeImpl* camera_app_device_bridge)
     : task_runner_for_screen_observer_(task_runner_for_screen_observer),
       camera_hal_ipc_thread_("CameraHalIpcThread"),
+      camera_app_device_bridge_(camera_app_device_bridge),
       initialized_(Init()),
-      weak_ptr_factory_(this) {
-  auto get_camera_info =
-      base::BindRepeating(&VideoCaptureDeviceFactoryChromeOS::GetCameraInfo,
-                          base::Unretained(this));
-  reprocess_manager_ =
-      std::make_unique<ReprocessManager>(std::move(get_camera_info));
-}
+      weak_ptr_factory_(this) {}
 
 VideoCaptureDeviceFactoryChromeOS::~VideoCaptureDeviceFactoryChromeOS() {
+  if (camera_app_device_bridge_) {
+    camera_app_device_bridge_->UnsetCameraInfoGetter();
+  }
   camera_hal_delegate_->Reset();
   camera_hal_ipc_thread_.Stop();
 }
@@ -48,7 +46,7 @@
   }
   return camera_hal_delegate_->CreateDevice(task_runner_for_screen_observer_,
                                             device_descriptor,
-                                            reprocess_manager_.get());
+                                            camera_app_device_bridge_);
 }
 
 void VideoCaptureDeviceFactoryChromeOS::GetSupportedFormats(
@@ -94,22 +92,20 @@
   camera_hal_delegate_ =
       new CameraHalDelegate(camera_hal_ipc_thread_.task_runner());
   camera_hal_delegate_->RegisterCameraClient();
+
+  // Since the |camera_hal_delegate_| is initialized on the constructor of this
+  // object and is destroyed after |camera_app_device_bridge_| unsetting its
+  // reference, it is safe to use base::Unretained() here.
+  if (camera_app_device_bridge_) {
+    camera_app_device_bridge_->SetCameraInfoGetter(
+        base::BindRepeating(&CameraHalDelegate::GetCameraInfoFromDeviceId,
+                            base::Unretained(camera_hal_delegate_.get())));
+  }
   return true;
 }
 
-cros::mojom::CameraInfoPtr VideoCaptureDeviceFactoryChromeOS::GetCameraInfo(
-    const std::string& device_id) {
-  if (!initialized_) {
-    return {};
-  }
-  return camera_hal_delegate_->GetCameraInfoFromDeviceId(device_id);
-}
-
-void VideoCaptureDeviceFactoryChromeOS::BindCrosImageCaptureRequest(
-    cros::mojom::CrosImageCaptureRequest request) {
-  mojo::MakeStrongBinding(
-      std::make_unique<CrosImageCaptureImpl>(reprocess_manager_.get()),
-      std::move(request));
+bool VideoCaptureDeviceFactoryChromeOS::IsSupportedCameraAppDeviceBridge() {
+  return true;
 }
 
 }  // namespace media
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.h b/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
index d4766db..591bda1 100644
--- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
+++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
@@ -11,22 +11,22 @@
 #include "base/single_thread_task_runner.h"
 #include "components/chromeos_camera/common/mjpeg_decode_accelerator.mojom.h"
 #include "media/capture/video/chromeos/camera_hal_delegate.h"
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #include "media/capture/video/video_capture_device_factory.h"
 
 namespace media {
 
+class CameraAppDeviceBridgeImpl;
+
 using MojoMjpegDecodeAcceleratorFactoryCB = base::RepeatingCallback<void(
     chromeos_camera::mojom::MjpegDecodeAcceleratorRequest)>;
 
-class ReprocessManager;
-
 class CAPTURE_EXPORT VideoCaptureDeviceFactoryChromeOS final
     : public VideoCaptureDeviceFactory {
  public:
   explicit VideoCaptureDeviceFactoryChromeOS(
       scoped_refptr<base::SingleThreadTaskRunner>
-          task_runner_for_screen_observer);
+          task_runner_for_screen_observer,
+      CameraAppDeviceBridgeImpl* camera_app_device_bridge);
 
   ~VideoCaptureDeviceFactoryChromeOS() override;
 
@@ -39,21 +39,16 @@
   void GetDeviceDescriptors(
       VideoCaptureDeviceDescriptors* device_descriptors) final;
 
+  bool IsSupportedCameraAppDeviceBridge() override;
+
   static gpu::GpuMemoryBufferManager* GetBufferManager();
   static void SetGpuBufferManager(gpu::GpuMemoryBufferManager* buffer_manager);
 
-  void BindCrosImageCaptureRequest(
-      cros::mojom::CrosImageCaptureRequest request);
-
  private:
   // Initializes the factory. The factory is functional only after this call
   // succeeds.
   bool Init();
 
-  // Gets camera info for the given |device_id|. Returns null CameraInfoPtr on
-  // error.
-  cros::mojom::CameraInfoPtr GetCameraInfo(const std::string& device_id);
-
   const scoped_refptr<base::SingleThreadTaskRunner>
       task_runner_for_screen_observer_;
 
@@ -67,7 +62,7 @@
   // |camera_hal_ipc_thread_|.
   scoped_refptr<CameraHalDelegate> camera_hal_delegate_;
 
-  std::unique_ptr<ReprocessManager> reprocess_manager_;
+  CameraAppDeviceBridgeImpl* camera_app_device_bridge_;  // Weak.
 
   bool initialized_;
 
diff --git a/media/capture/video/create_video_capture_device_factory.cc b/media/capture/video/create_video_capture_device_factory.cc
index 9e4bcfc..18f519a 100644
--- a/media/capture/video/create_video_capture_device_factory.cc
+++ b/media/capture/video/create_video_capture_device_factory.cc
@@ -13,6 +13,7 @@
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
 #include "media/capture/video/linux/video_capture_device_factory_linux.h"
 #elif defined(OS_CHROMEOS)
+#include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
 #include "media/capture/video/chromeos/public/cros_features.h"
 #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
 #include "media/capture/video/linux/video_capture_device_factory_linux.h"
@@ -30,44 +31,9 @@
 
 namespace {
 
+// Returns null if the corresponding switch is off.
 std::unique_ptr<VideoCaptureDeviceFactory>
-CreatePlatformSpecificVideoCaptureDeviceFactory(
-    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-  return std::make_unique<VideoCaptureDeviceFactoryLinux>(ui_task_runner);
-#elif defined(OS_CHROMEOS)
-  // On Chrome OS we have to support two use cases:
-  //
-  // 1. For devices that have the camera HAL v3 service running on Chrome OS,
-  //    we use the HAL v3 capture device which VideoCaptureDeviceFactoryChromeOS
-  //    provides.
-  // 2. Existing devices that use UVC cameras need to use the V4L2 capture
-  //    device which VideoCaptureDeviceFacotoryLinux provides; there are also
-  //    some special devices that may never be able to implement a camera HAL
-  //    v3.
-  if (ShouldUseCrosCameraService()) {
-    return std::make_unique<VideoCaptureDeviceFactoryChromeOS>(ui_task_runner);
-  } else {
-    return std::make_unique<VideoCaptureDeviceFactoryLinux>(ui_task_runner);
-  }
-#elif defined(OS_WIN)
-  return std::make_unique<VideoCaptureDeviceFactoryWin>();
-#elif defined(OS_MACOSX)
-  return std::make_unique<VideoCaptureDeviceFactoryMac>();
-#elif defined(OS_ANDROID)
-  return std::make_unique<VideoCaptureDeviceFactoryAndroid>();
-#elif defined(OS_FUCHSIA)
-  return std::make_unique<VideoCaptureDeviceFactoryFuchsia>();
-#else
-  NOTIMPLEMENTED();
-  return nullptr;
-#endif
-}
-
-}  // anonymous namespace
-
-std::unique_ptr<VideoCaptureDeviceFactory> CreateVideoCaptureDeviceFactory(
-    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
+CreateFakeVideoCaptureDeviceFactory() {
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
   // Use a Fake or File Video Device Factory if the command line flags are
@@ -86,10 +52,82 @@
       return std::move(result);
     }
   } else {
+    return nullptr;
+  }
+}
+
+#if defined(OS_CHROMEOS)
+std::unique_ptr<VideoCaptureDeviceFactory>
+CreateChromeOSVideoCaptureDeviceFactory(
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+    media::CameraAppDeviceBridgeImpl* camera_app_device_bridge) {
+  // On Chrome OS we have to support two use cases:
+  //
+  // 1. For devices that have the camera HAL v3 service running on Chrome OS,
+  //    we use the HAL v3 capture device which VideoCaptureDeviceFactoryChromeOS
+  //    provides.
+  // 2. Existing devices that use UVC cameras need to use the V4L2 capture
+  //    device which VideoCaptureDeviceFacotoryLinux provides; there are also
+  //    some special devices that may never be able to implement a camera HAL
+  //    v3.
+  if (ShouldUseCrosCameraService()) {
+    return std::make_unique<VideoCaptureDeviceFactoryChromeOS>(
+        ui_task_runner, camera_app_device_bridge);
+  } else {
+    return std::make_unique<VideoCaptureDeviceFactoryLinux>(ui_task_runner);
+  }
+}
+#endif  // defined(OS_CHROMEOS)
+
+std::unique_ptr<VideoCaptureDeviceFactory>
+CreatePlatformSpecificVideoCaptureDeviceFactory(
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  return std::make_unique<VideoCaptureDeviceFactoryLinux>(ui_task_runner);
+#elif defined(OS_CHROMEOS)
+  return CreateChromeOSVideoCaptureDeviceFactory(ui_task_runner, {});
+#elif defined(OS_WIN)
+  return std::make_unique<VideoCaptureDeviceFactoryWin>();
+#elif defined(OS_MACOSX)
+  return std::make_unique<VideoCaptureDeviceFactoryMac>();
+#elif defined(OS_ANDROID)
+  return std::make_unique<VideoCaptureDeviceFactoryAndroid>();
+#elif defined(OS_FUCHSIA)
+  return std::make_unique<VideoCaptureDeviceFactoryFuchsia>();
+#else
+  NOTIMPLEMENTED();
+  return nullptr;
+#endif
+}
+
+}  // anonymous namespace
+
+std::unique_ptr<VideoCaptureDeviceFactory> CreateVideoCaptureDeviceFactory(
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
+  auto fake_device_factory = CreateFakeVideoCaptureDeviceFactory();
+  if (fake_device_factory) {
+    return fake_device_factory;
+  } else {
     // |ui_task_runner| is needed for the Linux ChromeOS factory to retrieve
     // screen rotations.
     return CreatePlatformSpecificVideoCaptureDeviceFactory(ui_task_runner);
   }
 }
 
+#if defined(OS_CHROMEOS)
+std::unique_ptr<VideoCaptureDeviceFactory> CreateVideoCaptureDeviceFactory(
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+    media::CameraAppDeviceBridgeImpl* camera_app_device_bridge) {
+  auto fake_device_factory = CreateFakeVideoCaptureDeviceFactory();
+  if (fake_device_factory) {
+    return fake_device_factory;
+  } else {
+    // |ui_task_runner| is needed for the Linux ChromeOS factory to retrieve
+    // screen rotations.
+    return CreateChromeOSVideoCaptureDeviceFactory(ui_task_runner,
+                                                   camera_app_device_bridge);
+  }
+}
+#endif  // defined(OS_CHROMEOS)
+
 }  // namespace media
diff --git a/media/capture/video/create_video_capture_device_factory.h b/media/capture/video/create_video_capture_device_factory.h
index 7199bf8..b2450fa 100644
--- a/media/capture/video/create_video_capture_device_factory.h
+++ b/media/capture/video/create_video_capture_device_factory.h
@@ -13,10 +13,19 @@
 
 namespace media {
 
+class CameraAppDeviceBridgeImpl;
+
 std::unique_ptr<VideoCaptureDeviceFactory> CAPTURE_EXPORT
 CreateVideoCaptureDeviceFactory(
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
 
+#if defined(OS_CHROMEOS)
+std::unique_ptr<VideoCaptureDeviceFactory> CAPTURE_EXPORT
+CreateVideoCaptureDeviceFactory(
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+    media::CameraAppDeviceBridgeImpl* camera_app_device_bridge);
+#endif  // defined(OS_CHROMEOS)
+
 }  // namespace media
 
 #endif  // MEDIA_CAPTURE_VIDEO_CREATE_VIDEO_CAPTURE_DEVICE_FACTORY_H_
diff --git a/media/capture/video/video_capture_device_factory.cc b/media/capture/video/video_capture_device_factory.cc
index 4d903b6..0170051 100644
--- a/media/capture/video/video_capture_device_factory.cc
+++ b/media/capture/video/video_capture_device_factory.cc
@@ -26,4 +26,10 @@
   NOTIMPLEMENTED();
 }
 
+#if defined(OS_CHROMEOS)
+bool VideoCaptureDeviceFactory::IsSupportedCameraAppDeviceBridge() {
+  return false;
+}
+#endif  // defined(OS_CHROMEOS)
+
 }  // namespace media
diff --git a/media/capture/video/video_capture_device_factory.h b/media/capture/video/video_capture_device_factory.h
index 57e8c87c..c1e17c7 100644
--- a/media/capture/video/video_capture_device_factory.h
+++ b/media/capture/video/video_capture_device_factory.h
@@ -59,6 +59,10 @@
       std::unique_ptr<VideoCaptureDeviceDescriptors> device_descriptors,
       DeviceDescriptorsCallback result_callback);
 
+#if defined(OS_CHROMEOS)
+  virtual bool IsSupportedCameraAppDeviceBridge();
+#endif  // defined(OS_CHROMEOS)
+
  protected:
   base::ThreadChecker thread_checker_;
 
diff --git a/media/capture/video/video_capture_system.h b/media/capture/video/video_capture_system.h
index 90078fbe..016b8e2 100644
--- a/media/capture/video/video_capture_system.h
+++ b/media/capture/video/video_capture_system.h
@@ -8,10 +8,6 @@
 #include "media/capture/video/video_capture_device_factory.h"
 #include "media/capture/video/video_capture_device_info.h"
 
-#if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
-#endif  // defined(OS_CHROMEOS)
-
 namespace media {
 
 // GetDeviceInfosAsync() should be called at least once before calling
@@ -33,12 +29,6 @@
   // wrong.
   virtual std::unique_ptr<VideoCaptureDevice> CreateDevice(
       const std::string& device_id) = 0;
-
-#if defined(OS_CHROMEOS)
-  // Pass the mojo request to bind with DeviceFactory for Chrome OS.
-  virtual void BindCrosImageCaptureRequest(
-      cros::mojom::CrosImageCaptureRequest request) = 0;
-#endif  // defined(OS_CHROMEOS)
 };
 
 }  // namespace media
diff --git a/media/capture/video/video_capture_system_impl.cc b/media/capture/video/video_capture_system_impl.cc
index a0e69a9b..aef3390 100644
--- a/media/capture/video/video_capture_system_impl.cc
+++ b/media/capture/video/video_capture_system_impl.cc
@@ -11,13 +11,6 @@
 #include "build/build_config.h"
 #include "media/base/bind_to_current_loop.h"
 
-#if defined(OS_CHROMEOS)
-#include "base/command_line.h"
-#include "media/base/media_switches.h"
-#include "media/capture/video/chromeos/public/cros_features.h"
-#include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
-#endif  // defined(OS_CHROMEOS)
-
 namespace {
 
 // Compares two VideoCaptureFormat by checking smallest frame_size area, then
@@ -165,18 +158,4 @@
   ProcessDeviceInfoRequest();
 }
 
-#if defined(OS_CHROMEOS)
-void VideoCaptureSystemImpl::BindCrosImageCaptureRequest(
-    cros::mojom::CrosImageCaptureRequest request) {
-  CHECK(factory_);
-
-  if (media::ShouldUseCrosCameraService() &&
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kUseFakeDeviceForMediaStream)) {
-    static_cast<VideoCaptureDeviceFactoryChromeOS*>(factory_.get())
-        ->BindCrosImageCaptureRequest(std::move(request));
-  }
-}
-#endif  // defined(OS_CHROMEOS)
-
 }  // namespace media
diff --git a/media/capture/video/video_capture_system_impl.h b/media/capture/video/video_capture_system_impl.h
index 198b6db..581979a 100644
--- a/media/capture/video/video_capture_system_impl.h
+++ b/media/capture/video/video_capture_system_impl.h
@@ -7,10 +7,6 @@
 
 #include "media/capture/video/video_capture_system.h"
 
-#if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
-#endif  // defined(OS_CHROMEOS)
-
 namespace media {
 
 // Layer on top of VideoCaptureDeviceFactory that translates device descriptors
@@ -26,11 +22,6 @@
   std::unique_ptr<VideoCaptureDevice> CreateDevice(
       const std::string& device_id) override;
 
-#if defined(OS_CHROMEOS)
-  void BindCrosImageCaptureRequest(
-      cros::mojom::CrosImageCaptureRequest request) override;
-#endif  // defined(OS_CHROMEOS)
-
  private:
   using DeviceEnumQueue = std::list<DeviceInfoCallback>;
 
diff --git a/media/gpu/linux/mailbox_video_frame_converter.cc b/media/gpu/linux/mailbox_video_frame_converter.cc
index 57d7ce90..2991e95 100644
--- a/media/gpu/linux/mailbox_video_frame_converter.cc
+++ b/media/gpu/linux/mailbox_video_frame_converter.cc
@@ -181,6 +181,7 @@
   };
 #if defined(USE_OZONE)
   gfx::GpuMemoryBufferHandle handle = CreateGpuMemoryBufferHandle(origin_frame);
+  DCHECK(!handle.is_null());
   pixmap = ui::OzonePlatform::GetInstance()
                ->GetSurfaceFactoryOzone()
                ->CreateNativePixmapFromHandle(
diff --git a/media/gpu/linux/platform_video_frame_utils.cc b/media/gpu/linux/platform_video_frame_utils.cc
index c51c66b..e99a5ca 100644
--- a/media/gpu/linux/platform_video_frame_utils.cc
+++ b/media/gpu/linux/platform_video_frame_utils.cc
@@ -147,10 +147,7 @@
   // Create a native pixmap from the frame's memory buffer handle.
   gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle =
       CreateGpuMemoryBufferHandle(video_frame);
-  if (gpu_memory_buffer_handle.is_null()) {
-    VLOGF(1) << "Failed to create GPU memory handle from video frame";
-    return nullptr;
-  }
+  DCHECK(!gpu_memory_buffer_handle.is_null());
 
   auto buffer_format =
       VideoPixelFormatToGfxBufferFormat(video_frame->layout().format());
diff --git a/media/gpu/test/texture_ref.cc b/media/gpu/test/texture_ref.cc
index da060e50..9311f057 100644
--- a/media/gpu/test/texture_ref.cc
+++ b/media/gpu/test/texture_ref.cc
@@ -60,7 +60,9 @@
 
 gfx::GpuMemoryBufferHandle TextureRef::ExportGpuMemoryBufferHandle() const {
 #if defined(OS_CHROMEOS)
-  return CreateGpuMemoryBufferHandle(frame_.get());
+  auto handle = CreateGpuMemoryBufferHandle(frame_.get());
+  DCHECK(!handle.is_null());
+  return handle;
 #else
   return gfx::GpuMemoryBufferHandle();
 #endif
diff --git a/media/gpu/test/video_player/test_vda_video_decoder.cc b/media/gpu/test/video_player/test_vda_video_decoder.cc
index 1a3daad..abc8e9d 100644
--- a/media/gpu/test/video_player/test_vda_video_decoder.cc
+++ b/media/gpu/test/video_player/test_vda_video_decoder.cc
@@ -227,6 +227,7 @@
         gfx::GpuMemoryBufferHandle handle;
 #if BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
         handle = CreateGpuMemoryBufferHandle(video_frame.get());
+        DCHECK(!handle.is_null());
 #else
         NOTREACHED();
 #endif
diff --git a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
index 7c8b6c9..d109b73 100644
--- a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
@@ -1499,10 +1499,7 @@
   size_t idx = 0;
 
   auto output_gmb_handle = CreateGpuMemoryBufferHandle(output_frame.get());
-  if (output_gmb_handle.is_null()) {
-    VLOGF(1) << "Failed to create GpuMemoryBufferHandle";
-    return 0;
-  }
+  DCHECK(!output_gmb_handle.is_null());
   auto output_gmb_buffer =
       gpu_memory_buffer_support_->CreateGpuMemoryBufferImplFromHandle(
           std::move(output_gmb_handle), output_frame->coded_size(),
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index e725381..e251d19 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -532,18 +532,32 @@
   DCHECK_GT(num_pictures, 0u);
   DCHECK(!pic_size.IsEmpty());
 
-  // Since VdaVideoDeecoder doesn't allocate PictureBuffer with size adjusted by
+  // Since VdaVideoDecoder doesn't allocate PictureBuffer with size adjusted by
   // itself, we have to adjust here.
   struct v4l2_format format;
   memset(&format, 0, sizeof(format));
-  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-  format.fmt.pix_mp.pixelformat = output_format_fourcc_;
+  format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+
+  if (device_->Ioctl(VIDIOC_G_FMT, &format) != 0) {
+    VPLOGF(1) << "Failed getting OUTPUT format";
+    NOTIFY_ERROR(PLATFORM_FAILURE);
+    return false;
+  }
+
   format.fmt.pix_mp.width = pic_size.width();
   format.fmt.pix_mp.height = pic_size.height();
-  format.fmt.pix_mp.num_planes = output_planes_count_;
 
   if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0) {
-    VPLOGF(1) << "Failed setting format to: " << output_format_fourcc_;
+    VPLOGF(1) << "Failed setting OUTPUT format to: " << input_format_fourcc_;
+    NOTIFY_ERROR(PLATFORM_FAILURE);
+    return false;
+  }
+
+  // Get the coded size from the CAPTURE queue
+  memset(&format, 0, sizeof(format));
+  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+  if (device_->Ioctl(VIDIOC_G_FMT, &format) != 0) {
+    VPLOGF(1) << "Failed getting CAPTURE format";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return false;
   }
diff --git a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
index cde410ee..ecdb3bb 100644
--- a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
@@ -142,11 +142,7 @@
   // Construct GBM Handle from VideoFrame.
   gfx::GpuMemoryBufferHandle input_gmb_handle =
       CreateGpuMemoryBufferHandle(input_frame.get());
-  if (input_gmb_handle.is_null()) {
-    VLOGF(1) << "Failed to create input gmb handle";
-    notify_error_cb_.Run(task_id, PLATFORM_FAILURE);
-    return;
-  }
+  DCHECK(!input_gmb_handle.is_null());
 
   // Create pixmap for input handle and create VA surface.
   auto num_planes_input = VideoFrame::NumPlanes(input_frame->format());
@@ -229,11 +225,7 @@
   // size is the 2D image size, we should use (buffer_size, 1) as the R8 gmb's
   // size, where buffer_size can be obtained from the first plane's size.
   auto output_gmb_handle = CreateGpuMemoryBufferHandle(output_frame.get());
-  if (output_gmb_handle.is_null()) {
-    VLOGF(1) << "Failed to create GpuMemoryBufferHandle";
-    notify_error_cb_.Run(task_id, PLATFORM_FAILURE);
-    return;
-  }
+  DCHECK(!output_gmb_handle.is_null());
   const gfx::Size output_gmb_buffer_size(
       base::checked_cast<int32_t>(output_frame->layout().planes()[0].size), 1);
   auto output_gmb_buffer =
diff --git a/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc b/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc
index 16766ba..b68e42c 100644
--- a/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc
@@ -265,10 +265,11 @@
       VLOGF(1) << "Unsupported format: " << video_frame->format();
       return false;
     }
+    auto gmb_handle = CreateGpuMemoryBufferHandle(video_frame.get());
+    DCHECK(!gmb_handle.is_null());
     std::unique_ptr<gpu::GpuMemoryBufferImpl> gmb =
         gpu_memory_buffer_support_->CreateGpuMemoryBufferImplFromHandle(
-            CreateGpuMemoryBufferHandle(video_frame.get()),
-            video_frame->coded_size(), *gfx_format,
+            std::move(gmb_handle), video_frame->coded_size(), *gfx_format,
             gfx::BufferUsage::SCANOUT_CPU_READ_WRITE, base::DoNothing());
     if (!gmb) {
       VLOGF(1) << "Failed to create GPU memory buffer";
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
index 122bfb1..ed2dea0 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
@@ -555,11 +555,7 @@
         PictureBuffer(kDummyPictureBufferId, frame->coded_size()));
     gfx::GpuMemoryBufferHandle gmb_handle =
         CreateGpuMemoryBufferHandle(frame.get());
-    if (gmb_handle.is_null()) {
-      NOTIFY_ERROR(kPlatformFailureError,
-                   "Failed to create GMB handle from video frame");
-      return nullptr;
-    }
+    DCHECK(!gmb_handle.is_null());
 
     auto buffer_format = VideoPixelFormatToGfxBufferFormat(frame->format());
     if (!buffer_format) {
diff --git a/net/base/load_flags_list.h b/net/base/load_flags_list.h
index 14684e06..ed457067 100644
--- a/net/base/load_flags_list.h
+++ b/net/base/load_flags_list.h
@@ -105,3 +105,15 @@
 // does not complete in 60 seconds, the cache treat the stale resource as
 // invalid, as it did not specify stale-while-revalidate.
 LOAD_FLAG(SUPPORT_ASYNC_REVALIDATION, 1 << 17)
+
+// Indicates that a prefetch request's cached response should be restricted in
+// in terms of reuse. The cached response can only be reused by requests with
+// the LOAD_CAN_USE_RESTRICTED_PREFETCH load flag.
+LOAD_FLAG(RESTRICTED_PREFETCH, 1 << 18)
+
+// This flag must be set on requests that are allowed to reuse cache entries
+// that are marked as RESTRICTED_PREFETCH. Requests without this flag cannot
+// reuse restricted prefetch responses in the cache. Restricted response reuse
+// is considered privileged, and therefore this flag must only be set from a
+// trusted process.
+LOAD_FLAG(CAN_USE_RESTRICTED_PREFETCH, 1 << 19)
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 4db51d8..955e0e82 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -1513,6 +1513,20 @@
     }
   }
 
+  if (response_.restricted_prefetch &&
+      !(request_->load_flags & LOAD_CAN_USE_RESTRICTED_PREFETCH)) {
+    TransitionToState(STATE_SEND_REQUEST);
+    return OK;
+  }
+
+  // When a restricted prefetch is reused, we lift its reuse restriction. This
+  // is done by DoCacheToggleUnusedSincePrefetch(), because when a restricted
+  // prefetch is reused, |unused_since_prefetch| must be set as well.
+  bool restricted_prefetch_reuse =
+      response_.restricted_prefetch &&
+      request_->load_flags & LOAD_CAN_USE_RESTRICTED_PREFETCH;
+  DCHECK(!restricted_prefetch_reuse || response_.unused_since_prefetch);
+
   if (response_.unused_since_prefetch !=
       !!(request_->load_flags & LOAD_PREFETCH)) {
     // Either this is the first use of an entry since it was prefetched XOR
@@ -1530,7 +1544,14 @@
   TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheToggleUnusedSincePrefetch");
   // Write back the toggled value for the next use of this entry.
   response_.unused_since_prefetch = !response_.unused_since_prefetch;
-
+  // TODO(crbug.com/939317): Instead of toggling |unused_since_prefetch| and
+  // |restricted_prefetch| here, writing them to the cache, and untoggling for
+  // the current transaction, we should instead make a copy of |response_| with
+  // the modified properties to write to disk, and use that here.
+  if (response_.restricted_prefetch &&
+      request_->load_flags & LOAD_CAN_USE_RESTRICTED_PREFETCH) {
+    response_.restricted_prefetch = false;
+  }
   // TODO(jkarlin): If DoUpdateCachedResponse is also called for this
   // transaction then metadata will be written to cache twice. If prefetching
   // becomes more common, consider combining the writes.
@@ -1707,6 +1728,7 @@
   response_.network_accessed = response->network_accessed;
   response_.was_fetched_via_proxy = response->was_fetched_via_proxy;
   response_.proxy_server = response->proxy_server;
+  response_.restricted_prefetch = response->restricted_prefetch;
 
   // Do not record requests that have network errors or restarts.
   UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
@@ -1845,6 +1867,7 @@
   response_.request_time = new_response_->request_time;
   response_.network_accessed = new_response_->network_accessed;
   response_.unused_since_prefetch = new_response_->unused_since_prefetch;
+  response_.restricted_prefetch = new_response_->restricted_prefetch;
   response_.ssl_info = new_response_->ssl_info;
   if (new_response_->vary_data.is_valid()) {
     response_.vary_data = new_response_->vary_data;
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 8d4f37b..c41fe4af 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -1420,6 +1420,92 @@
   EXPECT_TRUE(response_info.was_cached);
 }
 
+// Tests that requests made with the LOAD_RESTRICTED_PREFETCH load flag result
+// in HttpResponseInfo entries with the |restricted_prefetch| flag set. Also
+// tests that responses with |restricted_prefetch| flag set can only be used by
+// requests that have the LOAD_CAN_USE_RESTRICTED_PREFETCH load flag.
+TEST_F(HttpCacheTest, SimpleGET_RestrictedPrefetchIsRestrictedUntilReuse) {
+  MockHttpCache cache;
+  HttpResponseInfo response_info;
+
+  // A normal load does not have |restricted_prefetch| set.
+  RunTransactionTestWithResponseInfoAndGetTiming(
+      cache.http_cache(), kTypicalGET_Transaction, &response_info,
+      BoundTestNetLog().bound(), nullptr);
+  EXPECT_FALSE(response_info.restricted_prefetch);
+  EXPECT_FALSE(response_info.was_cached);
+  EXPECT_TRUE(response_info.network_accessed);
+
+  // A restricted prefetch is marked as |restricted_prefetch|.
+  MockTransaction prefetch_transaction(kSimpleGET_Transaction);
+  prefetch_transaction.load_flags |= LOAD_PREFETCH;
+  prefetch_transaction.load_flags |= LOAD_RESTRICTED_PREFETCH;
+  RunTransactionTestWithResponseInfoAndGetTiming(
+      cache.http_cache(), prefetch_transaction, &response_info,
+      BoundTestNetLog().bound(), nullptr);
+  EXPECT_TRUE(response_info.restricted_prefetch);
+  EXPECT_FALSE(response_info.was_cached);
+  EXPECT_TRUE(response_info.network_accessed);
+
+  // Requests that are marked as able to reuse restricted prefetches can do so
+  // correctly. Once it is reused, it is no longer considered as or marked
+  // restricted.
+  MockTransaction can_use_restricted_prefetch_transaction(
+      kSimpleGET_Transaction);
+  can_use_restricted_prefetch_transaction.load_flags |=
+      LOAD_CAN_USE_RESTRICTED_PREFETCH;
+  RunTransactionTestWithResponseInfoAndGetTiming(
+      cache.http_cache(), can_use_restricted_prefetch_transaction,
+      &response_info, BoundTestNetLog().bound(), nullptr);
+  EXPECT_FALSE(response_info.restricted_prefetch);
+  EXPECT_TRUE(response_info.was_cached);
+  EXPECT_FALSE(response_info.network_accessed);
+
+  // Later reuse is still no longer marked restricted.
+  RunTransactionTestWithResponseInfoAndGetTiming(
+      cache.http_cache(), kSimpleGET_Transaction, &response_info,
+      BoundTestNetLog().bound(), nullptr);
+  EXPECT_FALSE(response_info.restricted_prefetch);
+  EXPECT_TRUE(response_info.was_cached);
+  EXPECT_FALSE(response_info.network_accessed);
+}
+
+TEST_F(HttpCacheTest, SimpleGET_RestrictedPrefetchReuseIsLimited) {
+  MockHttpCache cache;
+  HttpResponseInfo response_info;
+
+  // A restricted prefetch is marked as |restricted_prefetch|.
+  MockTransaction prefetch_transaction(kSimpleGET_Transaction);
+  prefetch_transaction.load_flags |= LOAD_PREFETCH;
+  prefetch_transaction.load_flags |= LOAD_RESTRICTED_PREFETCH;
+  RunTransactionTestWithResponseInfoAndGetTiming(
+      cache.http_cache(), prefetch_transaction, &response_info,
+      BoundTestNetLog().bound(), nullptr);
+  EXPECT_TRUE(response_info.restricted_prefetch);
+  EXPECT_FALSE(response_info.was_cached);
+  EXPECT_TRUE(response_info.network_accessed);
+
+  // Requests that cannot reuse restricted prefetches fail to do so. The network
+  // is accessed and the resulting response is not marked as
+  // |restricted_prefetch|.
+  RunTransactionTestWithResponseInfoAndGetTiming(
+      cache.http_cache(), kSimpleGET_Transaction, &response_info,
+      BoundTestNetLog().bound(), nullptr);
+  EXPECT_FALSE(response_info.restricted_prefetch);
+  EXPECT_FALSE(response_info.was_cached);
+  EXPECT_TRUE(response_info.network_accessed);
+
+  // Future requests that are not marked as able to reuse restricted prefetches
+  // can use the entry in the cache now, since it has been evicted in favor of
+  // an unrestricted one.
+  RunTransactionTestWithResponseInfoAndGetTiming(
+      cache.http_cache(), kSimpleGET_Transaction, &response_info,
+      BoundTestNetLog().bound(), nullptr);
+  EXPECT_FALSE(response_info.restricted_prefetch);
+  EXPECT_TRUE(response_info.was_cached);
+  EXPECT_FALSE(response_info.network_accessed);
+}
+
 static void PreserveRequestHeaders_Handler(const HttpRequestInfo* request,
                                            std::string* response_status,
                                            std::string* response_headers,
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index be26b28..70a7dcb 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -193,8 +193,14 @@
     can_send_early_data_ = true;
   }
 
-  if (request_->load_flags & LOAD_PREFETCH)
+  if (request_->load_flags & LOAD_PREFETCH) {
     response_.unused_since_prefetch = true;
+  }
+
+  if (request_->load_flags & LOAD_RESTRICTED_PREFETCH) {
+    DCHECK(response_.unused_since_prefetch);
+    response_.restricted_prefetch = true;
+  }
 
   next_state_ = STATE_NOTIFY_BEFORE_CREATE_STREAM;
   int rv = DoLoop(OK);
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index 0b9844e9..d03f76da 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -110,6 +110,10 @@
   // This bit is set if the response has a peer signature algorithm.
   RESPONSE_INFO_HAS_PEER_SIGNATURE_ALGORITHM = 1 << 25,
 
+  // This bit is set if the response is a prefetch whose reuse should be
+  // restricted in some way.
+  RESPONSE_INFO_RESTRICTED_PREFETCH = 1 << 26,
+
   // TODO(darin): Add other bits to indicate alternate request methods.
   // For now, we don't support storing those.
 };
@@ -124,6 +128,7 @@
       was_fetched_via_proxy(false),
       did_use_http_auth(false),
       unused_since_prefetch(false),
+      restricted_prefetch(false),
       async_revalidation_requested(false),
       connection_info(CONNECTION_INFO_UNKNOWN) {}
 
@@ -287,6 +292,8 @@
 
   unused_since_prefetch = (flags & RESPONSE_INFO_UNUSED_SINCE_PREFETCH) != 0;
 
+  restricted_prefetch = (flags & RESPONSE_INFO_RESTRICTED_PREFETCH) != 0;
+
   ssl_info.pkp_bypassed = (flags & RESPONSE_INFO_PKP_BYPASSED) != 0;
 
   // Read peer_signature_algorithm.
@@ -336,6 +343,8 @@
     flags |= RESPONSE_INFO_USE_HTTP_AUTHENTICATION;
   if (unused_since_prefetch)
     flags |= RESPONSE_INFO_UNUSED_SINCE_PREFETCH;
+  if (restricted_prefetch)
+    flags |= RESPONSE_INFO_RESTRICTED_PREFETCH;
   if (ssl_info.pkp_bypassed)
     flags |= RESPONSE_INFO_PKP_BYPASSED;
   if (!stale_revalidate_timeout.is_null())
diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h
index 1f75fe4..ff80d89 100644
--- a/net/http/http_response_info.h
+++ b/net/http/http_response_info.h
@@ -157,6 +157,11 @@
   // used since.
   bool unused_since_prefetch;
 
+  // True if the response is a prefetch whose reuse is "restricted". This means
+  // it can only be reused from the cache by requests that are marked as able to
+  // use restricted prefetches.
+  bool restricted_prefetch;
+
   // True if this resource is stale and needs async revalidation.
   // This value is not persisted by Persist(); it is only ever set when the
   // response is retrieved from the cache.
diff --git a/net/http/http_transaction_test_util.cc b/net/http/http_transaction_test_util.cc
index 28b65dd1..930853f 100644
--- a/net/http/http_transaction_test_util.cc
+++ b/net/http/http_transaction_test_util.cc
@@ -501,6 +501,11 @@
   if (request_->load_flags & LOAD_PREFETCH)
     response_.unused_since_prefetch = true;
 
+  if (request_->load_flags & LOAD_RESTRICTED_PREFETCH) {
+    DCHECK(response_.unused_since_prefetch);
+    response_.restricted_prefetch = true;
+  }
+
   // Pause and resume.
   if (!before_network_start_callback_.is_null()) {
     bool defer = false;
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 61e29e3..cc86de2 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -353,7 +353,8 @@
     { "name": "crosbug.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
     { "name": "crrev.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
     { "name": "firebaseio.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
-    { "name": "g.co", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
+    { "name": "g.co", "policy": "google", "mode": "force-https", "pins": "google" },
+    { "name": "www.g.co", "policy": "google", "mode": "force-https", "pins": "google" },
     { "name": "g4w.co", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
     { "name": "gmail.com", "policy": "google", "mode": "force-https", "pins": "google" },
     { "name": "goo.gl", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index 2533c30..dc4e86d 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -2646,6 +2646,10 @@
   EXPECT_TRUE(
       state.GetStaticDomainState("www.googlemail.com", &sts_state, &pkp_state));
 
+  // fi.g.co should not force HTTPS because there are still HTTP-only services
+  // on it.
+  EXPECT_FALSE(StaticShouldRedirect("fi.g.co"));
+
   // Other hosts:
 
   EXPECT_TRUE(StaticShouldRedirect("aladdinschools.appspot.com"));
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index 7ca16c3..81f1ca0 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -151,6 +151,21 @@
     return false;
   }
 
+  // Reject request if the restricted prefetch load flag is set but the
+  // request's NetworkIsolationKey is not present. This is because the
+  // restricted prefetch flag is only used when the browser sets the request's
+  // NetworkIsolationKey to correctly cache-partition the resource.
+  bool request_network_isolation_key_present =
+      request.trusted_params &&
+      !request.trusted_params->network_isolation_key.IsEmpty();
+  if (request.load_flags & net::LOAD_RESTRICTED_PREFETCH &&
+      !request_network_isolation_key_present) {
+    mojo::ReportBadMessage(
+        "CorsURLLoaderFactory: Request with LOAD_RESTRICTED_PREFETCH flag is "
+        "not trusted");
+    return false;
+  }
+
   // Ensure that renderer requests are covered either by CORS or CORB.
   if (process_id_ != mojom::kBrowserProcessId) {
     switch (request.mode) {
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index 6bc0af7..1c9bbba 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -1826,6 +1826,74 @@
   }
 }
 
+// Test that when a request has LOAD_RESTRICTED_PREFETCH and a
+// NetworkIsolationKey, CorsURLLoaderFactory does not reject the request.
+TEST_F(CorsURLLoaderTest, RestrictedPrefetchSucceedsWithNIK) {
+  ResetFactory(base::nullopt, kRendererProcessId, true);
+
+  BadMessageTestHelper bad_message_helper;
+
+  ResourceRequest request;
+  request.mode = mojom::RequestMode::kCors;
+  request.credentials_mode = mojom::CredentialsMode::kOmit;
+  request.method = net::HttpRequestHeaders::kGetMethod;
+  request.url = GURL("http://other.com/foo.png");
+  request.request_initiator = url::Origin::Create(GURL("http://example.com"));
+  request.load_flags |= net::LOAD_RESTRICTED_PREFETCH;
+  request.trusted_params = ResourceRequest::TrustedParams();
+
+  // Fill up the |trusted_params| NetworkIsolationKey member.
+  url::Origin request_origin = url::Origin::Create(request.url);
+  request.trusted_params->network_isolation_key =
+      net::NetworkIsolationKey(request_origin, request_origin);
+
+  CreateLoaderAndStart(request);
+
+  NotifyLoaderClientOnReceiveResponse(
+      {"Access-Control-Allow-Origin: http://example.com"});
+  NotifyLoaderClientOnComplete(net::OK);
+
+  RunUntilComplete();
+
+  EXPECT_TRUE(IsNetworkLoaderStarted());
+  EXPECT_TRUE(client().has_received_response());
+  EXPECT_TRUE(client().has_received_completion());
+  EXPECT_EQ(net::OK, client().completion_status().error_code);
+  EXPECT_TRUE(GetRequest().headers.HasHeader(net::HttpRequestHeaders::kOrigin));
+}
+
+// Test that when a request has LOAD_RESTRICTED_PREFETCH but no
+// NetworkIsolationKey, CorsURLLoaderFactory rejects the request. This is
+// because the LOAD_RESTRICTED_PREFETCH flag must only appear on requests that
+// make use of their TrustedParams' |network_isolation_key|.
+TEST_F(CorsURLLoaderTest, RestrictedPrefetchFailsWithoutNIK) {
+  ResetFactory(base::nullopt, kRendererProcessId, true);
+
+  BadMessageTestHelper bad_message_helper;
+
+  ResourceRequest request;
+  request.mode = mojom::RequestMode::kCors;
+  request.credentials_mode = mojom::CredentialsMode::kOmit;
+  request.method = net::HttpRequestHeaders::kGetMethod;
+  request.url = GURL("http://other.com/foo.png");
+  request.request_initiator = url::Origin::Create(GURL("http://example.com"));
+  request.load_flags |= net::LOAD_RESTRICTED_PREFETCH;
+  request.trusted_params = ResourceRequest::TrustedParams();
+
+  CreateLoaderAndStart(request);
+
+  RunUntilComplete();
+  EXPECT_FALSE(IsNetworkLoaderStarted());
+  EXPECT_FALSE(client().has_received_redirect());
+  EXPECT_FALSE(client().has_received_response());
+  EXPECT_TRUE(client().has_received_completion());
+  EXPECT_EQ(net::ERR_INVALID_ARGUMENT, client().completion_status().error_code);
+  EXPECT_THAT(
+      bad_message_helper.bad_message_reports(),
+      ::testing::ElementsAre("CorsURLLoaderFactory: Request with "
+                             "LOAD_RESTRICTED_PREFETCH flag is not trusted"));
+}
+
 }  // namespace
 
 }  // namespace cors
diff --git a/services/network/cors/preflight_controller.h b/services/network/cors/preflight_controller.h
index c58251a..25b4646 100644
--- a/services/network/cors/preflight_controller.h
+++ b/services/network/cors/preflight_controller.h
@@ -25,6 +25,8 @@
 
 namespace network {
 
+struct ResourceResponseHead;
+
 namespace cors {
 
 // A class to manage CORS-preflight, making a CORS-preflight request, checking
diff --git a/services/network/public/cpp/DEPS b/services/network/public/cpp/DEPS
index 0cab4fa..fd78583 100644
--- a/services/network/public/cpp/DEPS
+++ b/services/network/public/cpp/DEPS
@@ -15,6 +15,7 @@
     # rather than to store user preferences.
     "+components/prefs",
     "+services/network",
+    "+services/proxy_resolver/public/cpp",
     "+services/proxy_resolver/public/mojom",
   ],
 }
diff --git a/services/network/public/cpp/load_timing_info.typemap b/services/network/public/cpp/load_timing_info.typemap
new file mode 100644
index 0000000..c2636ee
--- /dev/null
+++ b/services/network/public/cpp/load_timing_info.typemap
@@ -0,0 +1,15 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//services/network/public/mojom/load_timing_info.mojom"
+public_headers = [ "//net/base/load_timing_info.h" ]
+traits_headers =
+    [ "//services/network/public/cpp/load_timing_info_mojom_traits.h" ]
+sources = [
+  "//services/network/public/cpp/load_timing_info_mojom_traits.cc",
+]
+type_mappings = [
+  "network.mojom.LoadTimingInfo=net::LoadTimingInfo",
+  "network.mojom.LoadTimingInfoConnectTiming=net::LoadTimingInfo::ConnectTiming",
+]
diff --git a/content/public/common/load_timing_info_mojom_traits.cc b/services/network/public/cpp/load_timing_info_mojom_traits.cc
similarity index 81%
rename from content/public/common/load_timing_info_mojom_traits.cc
rename to services/network/public/cpp/load_timing_info_mojom_traits.cc
index 27820b4..1bcce28 100644
--- a/content/public/common/load_timing_info_mojom_traits.cc
+++ b/services/network/public/cpp/load_timing_info_mojom_traits.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/public/common/load_timing_info_mojom_traits.h"
+#include "services/network/public/cpp/load_timing_info_mojom_traits.h"
 
 #include "mojo/public/cpp/base/time_mojom_traits.h"
 
 namespace mojo {
 
 // static
-bool StructTraits<content::mojom::LoadTimingInfoConnectTimingDataView,
+bool StructTraits<network::mojom::LoadTimingInfoConnectTimingDataView,
                   net::LoadTimingInfo::ConnectTiming>::
-    Read(content::mojom::LoadTimingInfoConnectTimingDataView data,
+    Read(network::mojom::LoadTimingInfoConnectTimingDataView data,
          net::LoadTimingInfo::ConnectTiming* out) {
   return data.ReadDnsStart(&out->dns_start) && data.ReadDnsEnd(&out->dns_end) &&
          data.ReadConnectStart(&out->connect_start) &&
@@ -20,8 +20,8 @@
 }
 
 // static
-bool StructTraits<content::mojom::LoadTimingInfoDataView, net::LoadTimingInfo>::
-    Read(content::mojom::LoadTimingInfoDataView data,
+bool StructTraits<network::mojom::LoadTimingInfoDataView, net::LoadTimingInfo>::
+    Read(network::mojom::LoadTimingInfoDataView data,
          net::LoadTimingInfo* out) {
   out->socket_reused = data.socket_reused();
   out->socket_log_id = data.socket_log_id();
diff --git a/content/public/common/load_timing_info_mojom_traits.h b/services/network/public/cpp/load_timing_info_mojom_traits.h
similarity index 83%
rename from content/public/common/load_timing_info_mojom_traits.h
rename to services/network/public/cpp/load_timing_info_mojom_traits.h
index 8cf36d61..994e8fd4 100644
--- a/content/public/common/load_timing_info_mojom_traits.h
+++ b/services/network/public/cpp/load_timing_info_mojom_traits.h
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_PUBLIC_COMMON_LOAD_TIMING_INFO_MOJOM_TRAITS_H_
-#define CONTENT_PUBLIC_COMMON_LOAD_TIMING_INFO_MOJOM_TRAITS_H_
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_LOAD_TIMING_INFO_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_LOAD_TIMING_INFO_MOJOM_TRAITS_H_
 
-#include "content/public/common/load_timing_info.mojom.h"
 #include "mojo/public/cpp/bindings/struct_traits.h"
 #include "net/base/load_timing_info.h"
+#include "services/network/public/mojom/load_timing_info.mojom.h"
 
 namespace mojo {
 
 template <>
-struct StructTraits<content::mojom::LoadTimingInfoConnectTimingDataView,
+struct StructTraits<network::mojom::LoadTimingInfoConnectTimingDataView,
                     net::LoadTimingInfo::ConnectTiming> {
   static base::TimeTicks dns_start(
       const net::LoadTimingInfo::ConnectTiming& obj) {
@@ -44,12 +44,12 @@
     return obj.ssl_end;
   }
 
-  static bool Read(content::mojom::LoadTimingInfoConnectTimingDataView obj,
+  static bool Read(network::mojom::LoadTimingInfoConnectTimingDataView obj,
                    net::LoadTimingInfo::ConnectTiming* output);
 };
 
 template <>
-struct StructTraits<content::mojom::LoadTimingInfoDataView,
+struct StructTraits<network::mojom::LoadTimingInfoDataView,
                     net::LoadTimingInfo> {
   static bool socket_reused(const net::LoadTimingInfo& obj) {
     return obj.socket_reused;
@@ -104,10 +104,10 @@
     return obj.push_end;
   }
 
-  static bool Read(content::mojom::LoadTimingInfoDataView obj,
+  static bool Read(network::mojom::LoadTimingInfoDataView obj,
                    net::LoadTimingInfo* output);
 };
 
 }  // namespace mojo
 
-#endif  // CONTENT_PUBLIC_COMMON_LOAD_TIMING_INFO_MOJOM_TRAITS_H_
+#endif  // SERVICES_NETWORK_PUBLIC_CPP_LOAD_TIMING_INFO_MOJOM_TRAITS_H_
diff --git a/services/network/public/cpp/network_ipc_param_traits.h b/services/network/public/cpp/network_ipc_param_traits.h
index 72c5b46..798c206 100644
--- a/services/network/public/cpp/network_ipc_param_traits.h
+++ b/services/network/public/cpp/network_ipc_param_traits.h
@@ -27,9 +27,8 @@
 #include "net/ssl/ssl_info.h"
 #include "net/url_request/redirect_info.h"
 #include "services/network/public/cpp/net_ipc_param_traits.h"
+#include "services/network/public/cpp/origin_policy.h"
 #include "services/network/public/cpp/resource_request_body.h"
-#include "services/network/public/cpp/resource_response.h"
-#include "services/network/public/cpp/resource_response_info.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
 #include "services/network/public/mojom/cors.mojom-shared.h"
 #include "services/network/public/mojom/fetch_api.mojom-shared.h"
@@ -135,50 +134,6 @@
   IPC_STRUCT_TRAITS_MEMBER(proxy_server)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(network::ResourceResponseInfo)
-  IPC_STRUCT_TRAITS_MEMBER(request_time)
-  IPC_STRUCT_TRAITS_MEMBER(response_time)
-  IPC_STRUCT_TRAITS_MEMBER(headers)
-  IPC_STRUCT_TRAITS_MEMBER(mime_type)
-  IPC_STRUCT_TRAITS_MEMBER(charset)
-  IPC_STRUCT_TRAITS_MEMBER(ct_policy_compliance)
-  IPC_STRUCT_TRAITS_MEMBER(content_length)
-  IPC_STRUCT_TRAITS_MEMBER(network_accessed)
-  IPC_STRUCT_TRAITS_MEMBER(encoded_data_length)
-  IPC_STRUCT_TRAITS_MEMBER(encoded_body_length)
-  IPC_STRUCT_TRAITS_MEMBER(appcache_id)
-  IPC_STRUCT_TRAITS_MEMBER(appcache_manifest_url)
-  IPC_STRUCT_TRAITS_MEMBER(load_timing)
-  IPC_STRUCT_TRAITS_MEMBER(raw_request_response_info)
-  IPC_STRUCT_TRAITS_MEMBER(was_fetched_via_spdy)
-  IPC_STRUCT_TRAITS_MEMBER(was_alpn_negotiated)
-  IPC_STRUCT_TRAITS_MEMBER(was_alternate_protocol_available)
-  IPC_STRUCT_TRAITS_MEMBER(connection_info)
-  IPC_STRUCT_TRAITS_MEMBER(alpn_negotiated_protocol)
-  IPC_STRUCT_TRAITS_MEMBER(remote_endpoint)
-  IPC_STRUCT_TRAITS_MEMBER(was_fetched_via_cache)
-  IPC_STRUCT_TRAITS_MEMBER(proxy_server)
-  IPC_STRUCT_TRAITS_MEMBER(was_fetched_via_service_worker)
-  IPC_STRUCT_TRAITS_MEMBER(was_fallback_required_by_service_worker)
-  IPC_STRUCT_TRAITS_MEMBER(url_list_via_service_worker)
-  IPC_STRUCT_TRAITS_MEMBER(response_type)
-  IPC_STRUCT_TRAITS_MEMBER(service_worker_start_time)
-  IPC_STRUCT_TRAITS_MEMBER(service_worker_ready_time)
-  IPC_STRUCT_TRAITS_MEMBER(is_in_cache_storage)
-  IPC_STRUCT_TRAITS_MEMBER(cache_storage_cache_name)
-  IPC_STRUCT_TRAITS_MEMBER(did_service_worker_navigation_preload)
-  IPC_STRUCT_TRAITS_MEMBER(effective_connection_type)
-  IPC_STRUCT_TRAITS_MEMBER(cert_status)
-  IPC_STRUCT_TRAITS_MEMBER(ssl_info)
-  IPC_STRUCT_TRAITS_MEMBER(cors_exposed_header_names)
-  IPC_STRUCT_TRAITS_MEMBER(async_revalidation_requested)
-  IPC_STRUCT_TRAITS_MEMBER(did_mime_sniff)
-  IPC_STRUCT_TRAITS_MEMBER(is_signed_exchange_inner_response)
-  IPC_STRUCT_TRAITS_MEMBER(was_in_prefetch_cache)
-  IPC_STRUCT_TRAITS_MEMBER(is_legacy_tls_version)
-  IPC_STRUCT_TRAITS_MEMBER(auth_challenge_info)
-IPC_STRUCT_TRAITS_END()
-
 IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::FetchResponseType,
                           network::mojom::FetchResponseType::kMaxValue)
 
@@ -197,11 +152,4 @@
   IPC_STRUCT_TRAITS_MEMBER(contents)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(network::ResourceResponseHead)
-  IPC_STRUCT_TRAITS_PARENT(network::ResourceResponseInfo)
-  IPC_STRUCT_TRAITS_MEMBER(request_start)
-  IPC_STRUCT_TRAITS_MEMBER(response_start)
-  IPC_STRUCT_TRAITS_MEMBER(origin_policy)
-IPC_STRUCT_TRAITS_END()
-
 #endif  // SERVICES_NETWORK_PUBLIC_CPP_NETWORK_IPC_PARAM_TRAITS_H_
diff --git a/services/network/public/cpp/network_types.typemap b/services/network/public/cpp/network_types.typemap
index 0f4ba2f..985ffd4 100644
--- a/services/network/public/cpp/network_types.typemap
+++ b/services/network/public/cpp/network_types.typemap
@@ -6,10 +6,17 @@
 public_deps = [
   "//net",
 ]
-public_headers = [ "//net/nqe/effective_connection_type.h" ]
+public_headers = [
+  "//net/cert/ct_policy_status.h",
+  "//net/http/http_response_info.h",
+  "//net/nqe/effective_connection_type.h",
+]
 traits_headers = [ "//services/network/public/cpp/network_ipc_param_traits.h" ]
 deps = [
   "//services/network/public/cpp:cpp_base",
 ]
-type_mappings =
-    [ "network.mojom.EffectiveConnectionType=net::EffectiveConnectionType" ]
+type_mappings = [
+  "network.mojom.ConnectionInfo=net::HttpResponseInfo::ConnectionInfo",
+  "network.mojom.CTPolicyCompliance=net::ct::CTPolicyCompliance",
+  "network.mojom.EffectiveConnectionType=net::EffectiveConnectionType",
+]
diff --git a/services/network/public/cpp/simple_url_loader.h b/services/network/public/cpp/simple_url_loader.h
index f81788d..d550e73 100644
--- a/services/network/public/cpp/simple_url_loader.h
+++ b/services/network/public/cpp/simple_url_loader.h
@@ -15,6 +15,7 @@
 #include "base/callback_forward.h"
 #include "base/component_export.h"
 #include "base/macros.h"
+#include "services/network/public/cpp/resource_response.h"
 
 class GURL;
 
@@ -35,7 +36,6 @@
 
 namespace network {
 struct ResourceRequest;
-struct ResourceResponseHead;
 namespace mojom {
 class URLLoaderFactory;
 }
diff --git a/services/network/public/cpp/typemaps.gni b/services/network/public/cpp/typemaps.gni
index 9317ce41..2840b16 100644
--- a/services/network/public/cpp/typemaps.gni
+++ b/services/network/public/cpp/typemaps.gni
@@ -15,6 +15,7 @@
   "//services/network/public/cpp/host_resolver.typemap",
   "//services/network/public/cpp/ip_address.typemap",
   "//services/network/public/cpp/ip_endpoint.typemap",
+  "//services/network/public/cpp/load_timing_info.typemap",
   "//services/network/public/cpp/mutable_network_traffic_annotation_tag.typemap",
   "//services/network/public/cpp/mutable_partial_network_traffic_annotation_tag.typemap",
   "//services/network/public/cpp/net_log.typemap",
@@ -26,8 +27,8 @@
   "//services/network/public/cpp/p2p.typemap",
   "//services/network/public/cpp/proxy_config.typemap",
   "//services/network/public/cpp/proxy_config_with_annotation.typemap",
+  "//services/network/public/cpp/url_response_head.typemap",
   "//services/network/public/cpp/url_loader_completion_status.typemap",
   "//services/network/public/cpp/url_request.typemap",
   "//services/network/public/cpp/url_request_redirect_info.typemap",
-  "//services/network/public/cpp/url_response_head.typemap",
 ]
diff --git a/services/network/public/cpp/url_response_head.typemap b/services/network/public/cpp/url_response_head.typemap
index dda595a..2c1b42c 100644
--- a/services/network/public/cpp/url_response_head.typemap
+++ b/services/network/public/cpp/url_response_head.typemap
@@ -4,7 +4,11 @@
 
 mojom = "//services/network/public/mojom/url_loader.mojom"
 public_headers = [ "//services/network/public/cpp/resource_response.h" ]
-traits_headers = [ "//services/network/public/cpp/network_ipc_param_traits.h" ]
+traits_headers =
+    [ "//services/network/public/cpp/url_response_head_mojom_traits.h" ]
+sources = [
+  "//services/network/public/cpp/url_response_head_mojom_traits.cc",
+]
 public_deps = [
   "//services/network/public/cpp:cpp_base",
 ]
diff --git a/services/network/public/cpp/url_response_head_mojom_traits.cc b/services/network/public/cpp/url_response_head_mojom_traits.cc
new file mode 100644
index 0000000..3c406026
--- /dev/null
+++ b/services/network/public/cpp/url_response_head_mojom_traits.cc
@@ -0,0 +1,102 @@
+// 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 "services/network/public/cpp/url_response_head_mojom_traits.h"
+
+#include "mojo/public/cpp/base/time_mojom_traits.h"
+#include "services/network/public/cpp/ip_endpoint_mojom_traits.h"
+#include "services/network/public/cpp/load_timing_info_mojom_traits.h"
+#include "services/network/public/cpp/network_ipc_param_traits.h"
+#include "services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h"
+#include "url/mojom/url_gurl_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<network::mojom::URLResponseHead::DataView,
+                  network::ResourceResponseHead>::
+    Read(network::mojom::URLResponseHead::DataView input,
+         network::ResourceResponseHead* output) {
+  bool success = true;
+
+  if (!input.ReadRequestTime(&output->request_time))
+    success = false;
+  if (!input.ReadResponseTime(&output->response_time))
+    success = false;
+  if (!input.ReadHeaders(&output->headers))
+    success = false;
+  if (!input.ReadMimeType(&output->mime_type))
+    success = false;
+  if (!input.ReadCharset(&output->charset))
+    success = false;
+  if (!input.ReadCtPolicyCompliance(&output->ct_policy_compliance))
+    success = false;
+  output->content_length = input.content_length();
+  output->encoded_data_length = input.encoded_data_length();
+  output->encoded_body_length = input.encoded_body_length();
+  output->network_accessed = input.network_accessed();
+  output->appcache_id = input.appcache_id();
+  if (!input.ReadAppcacheManifestUrl(&output->appcache_manifest_url))
+    success = false;
+  if (!input.ReadLoadTiming(&output->load_timing))
+    success = false;
+  if (!input.ReadRawRequestResponseInfo(&output->raw_request_response_info))
+    success = false;
+  output->was_fetched_via_spdy = input.was_fetched_via_spdy();
+  output->was_alpn_negotiated = input.was_alpn_negotiated();
+  output->was_alternate_protocol_available =
+      input.was_alternate_protocol_available();
+  if (!input.ReadConnectionInfo(&output->connection_info))
+    success = false;
+  if (!input.ReadAlpnNegotiatedProtocol(&output->alpn_negotiated_protocol))
+    success = false;
+  if (!input.ReadRemoteEndpoint(&output->remote_endpoint))
+    success = false;
+  output->was_fetched_via_cache = input.was_fetched_via_cache();
+  if (!input.ReadProxyServer(&output->proxy_server))
+    success = false;
+  output->was_fetched_via_service_worker =
+      input.was_fetched_via_service_worker();
+  output->was_fallback_required_by_service_worker =
+      input.was_fallback_required_by_service_worker();
+  if (!input.ReadUrlListViaServiceWorker(&output->url_list_via_service_worker))
+    success = false;
+  if (!input.ReadResponseType(&output->response_type))
+    success = false;
+  if (!input.ReadServiceWorkerStartTime(&output->service_worker_start_time))
+    success = false;
+  if (!input.ReadServiceWorkerReadyTime(&output->service_worker_ready_time))
+    success = false;
+  output->is_in_cache_storage = input.is_in_cache_storage();
+  if (!input.ReadCacheStorageCacheName(&output->cache_storage_cache_name))
+    success = false;
+  if (!input.ReadEffectiveConnectionType(&output->effective_connection_type))
+    success = false;
+  output->cert_status = input.cert_status();
+  if (!input.ReadSslInfo(&output->ssl_info))
+    success = false;
+  if (!input.ReadCorsExposedHeaderNames(&output->cors_exposed_header_names))
+    success = false;
+  output->did_service_worker_navigation_preload =
+      input.did_service_worker_navigation_preload();
+  output->should_report_corb_blocking = input.should_report_corb_blocking();
+  output->async_revalidation_requested = input.async_revalidation_requested();
+  output->did_mime_sniff = input.did_mime_sniff();
+  output->is_signed_exchange_inner_response =
+      input.is_signed_exchange_inner_response();
+  output->was_in_prefetch_cache = input.was_in_prefetch_cache();
+  output->intercepted_by_plugin = input.intercepted_by_plugin();
+  output->is_legacy_tls_version = input.is_legacy_tls_version();
+  if (!input.ReadAuthChallengeInfo(&output->auth_challenge_info))
+    success = false;
+  if (!input.ReadRequestStart(&output->request_start))
+    success = false;
+  if (!input.ReadResponseStart(&output->response_start))
+    success = false;
+  if (!input.ReadOriginPolicy(&output->origin_policy))
+    success = false;
+  return success;
+}
+
+}  // namespace mojo
diff --git a/services/network/public/cpp/url_response_head_mojom_traits.h b/services/network/public/cpp/url_response_head_mojom_traits.h
new file mode 100644
index 0000000..b92c446
--- /dev/null
+++ b/services/network/public/cpp/url_response_head_mojom_traits.h
@@ -0,0 +1,248 @@
+// 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 SERVICES_NETWORK_PUBLIC_CPP_URL_RESPONSE_HEAD_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_URL_RESPONSE_HEAD_MOJOM_TRAITS_H_
+
+#include "services/network/public/cpp/http_raw_request_response_info.h"
+#include "services/network/public/cpp/origin_policy.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/mojom/fetch_api.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<network::mojom::URLResponseHeadDataView,
+                    network::ResourceResponseHead> {
+  static const base::Time& request_time(
+      const network::ResourceResponseHead& input) {
+    return input.request_time;
+  }
+
+  static const base::Time& response_time(
+      const network::ResourceResponseHead& input) {
+    return input.response_time;
+  }
+
+  static scoped_refptr<net::HttpResponseHeaders> headers(
+      const network::ResourceResponseHead& input) {
+    return input.headers;
+  }
+
+  static const std::string& mime_type(
+      const network::ResourceResponseHead& input) {
+    return input.mime_type;
+  }
+
+  static const std::string& charset(
+      const network::ResourceResponseHead& input) {
+    return input.charset;
+  }
+
+  static net::ct::CTPolicyCompliance ct_policy_compliance(
+      const network::ResourceResponseHead& input) {
+    return input.ct_policy_compliance;
+  }
+
+  static int64_t content_length(const network::ResourceResponseHead& input) {
+    return input.content_length;
+  }
+
+  static int64_t encoded_data_length(
+      const network::ResourceResponseHead& input) {
+    return input.encoded_data_length;
+  }
+
+  static int64_t encoded_body_length(
+      const network::ResourceResponseHead& input) {
+    return input.encoded_body_length;
+  }
+
+  static bool network_accessed(const network::ResourceResponseHead& input) {
+    return input.network_accessed;
+  }
+
+  static int64_t appcache_id(const network::ResourceResponseHead& input) {
+    return input.appcache_id;
+  }
+
+  static const GURL& appcache_manifest_url(
+      const network::ResourceResponseHead& input) {
+    return input.appcache_manifest_url;
+  }
+
+  static const net::LoadTimingInfo& load_timing(
+      const network::ResourceResponseHead& input) {
+    return input.load_timing;
+  }
+
+  static scoped_refptr<network::HttpRawRequestResponseInfo>
+  raw_request_response_info(const network::ResourceResponseHead& input) {
+    return input.raw_request_response_info;
+  }
+
+  static bool was_fetched_via_spdy(const network::ResourceResponseHead& input) {
+    return input.was_fetched_via_spdy;
+  }
+
+  static bool was_alpn_negotiated(const network::ResourceResponseHead& input) {
+    return input.was_alpn_negotiated;
+  }
+
+  static bool was_alternate_protocol_available(
+      const network::ResourceResponseHead& input) {
+    return input.was_alternate_protocol_available;
+  }
+
+  static net::HttpResponseInfo::ConnectionInfo connection_info(
+      const network::ResourceResponseHead& input) {
+    return input.connection_info;
+  }
+
+  static const std::string& alpn_negotiated_protocol(
+      const network::ResourceResponseHead& input) {
+    return input.alpn_negotiated_protocol;
+  }
+
+  static const net::IPEndPoint& remote_endpoint(
+      const network::ResourceResponseHead& input) {
+    return input.remote_endpoint;
+  }
+
+  static bool was_fetched_via_cache(
+      const network::ResourceResponseHead& input) {
+    return input.was_fetched_via_cache;
+  }
+
+  static const net::ProxyServer& proxy_server(
+      const network::ResourceResponseHead& input) {
+    return input.proxy_server;
+  }
+
+  static bool was_fetched_via_service_worker(
+      const network::ResourceResponseHead& input) {
+    return input.was_fetched_via_service_worker;
+  }
+
+  static bool was_fallback_required_by_service_worker(
+      const network::ResourceResponseHead& input) {
+    return input.was_fallback_required_by_service_worker;
+  }
+
+  static const std::vector<GURL>& url_list_via_service_worker(
+      const network::ResourceResponseHead& input) {
+    return input.url_list_via_service_worker;
+  }
+
+  static network::mojom::FetchResponseType response_type(
+      const network::ResourceResponseHead& input) {
+    return input.response_type;
+  }
+
+  static const base::TimeTicks& service_worker_start_time(
+      const network::ResourceResponseHead& input) {
+    return input.service_worker_start_time;
+  }
+
+  static const base::TimeTicks& service_worker_ready_time(
+      const network::ResourceResponseHead& input) {
+    return input.service_worker_ready_time;
+  }
+
+  static bool is_in_cache_storage(const network::ResourceResponseHead& input) {
+    return input.is_in_cache_storage;
+  }
+
+  static const std::string& cache_storage_cache_name(
+      const network::ResourceResponseHead& input) {
+    return input.cache_storage_cache_name;
+  }
+
+  static net::EffectiveConnectionType effective_connection_type(
+      const network::ResourceResponseHead& input) {
+    return input.effective_connection_type;
+  }
+
+  static net::CertStatus cert_status(
+      const network::ResourceResponseHead& input) {
+    return input.cert_status;
+  }
+
+  static const base::Optional<net::SSLInfo>& ssl_info(
+      const network::ResourceResponseHead& input) {
+    return input.ssl_info;
+  }
+
+  static const std::vector<std::string>& cors_exposed_header_names(
+      const network::ResourceResponseHead& input) {
+    return input.cors_exposed_header_names;
+  }
+
+  static bool did_service_worker_navigation_preload(
+      const network::ResourceResponseHead& input) {
+    return input.did_service_worker_navigation_preload;
+  }
+
+  static bool should_report_corb_blocking(
+      const network::ResourceResponseHead& input) {
+    return input.should_report_corb_blocking;
+  }
+
+  static bool async_revalidation_requested(
+      const network::ResourceResponseHead& input) {
+    return input.async_revalidation_requested;
+  }
+
+  static bool did_mime_sniff(const network::ResourceResponseHead& input) {
+    return input.did_mime_sniff;
+  }
+
+  static bool is_signed_exchange_inner_response(
+      const network::ResourceResponseHead& input) {
+    return input.is_signed_exchange_inner_response;
+  }
+
+  static bool was_in_prefetch_cache(
+      const network::ResourceResponseHead& input) {
+    return input.was_in_prefetch_cache;
+  }
+
+  static bool intercepted_by_plugin(
+      const network::ResourceResponseHead& input) {
+    return input.intercepted_by_plugin;
+  }
+
+  static bool is_legacy_tls_version(
+      const network::ResourceResponseHead& input) {
+    return input.is_legacy_tls_version;
+  }
+
+  static const base::Optional<net::AuthChallengeInfo>& auth_challenge_info(
+      const network::ResourceResponseHead& input) {
+    return input.auth_challenge_info;
+  }
+
+  static const base::TimeTicks& request_start(
+      const network::ResourceResponseHead& input) {
+    return input.request_start;
+  }
+
+  static const base::TimeTicks& response_start(
+      const network::ResourceResponseHead& input) {
+    return input.response_start;
+  }
+
+  static const base::Optional<network::OriginPolicy>& origin_policy(
+      const network::ResourceResponseHead& input) {
+    return input.origin_policy;
+  }
+
+  static bool Read(network::mojom::URLResponseHead::DataView input,
+                   network::ResourceResponseHead* output);
+};
+
+}  // namespace mojo
+
+#endif  // SERVICES_NETWORK_PUBLIC_CPP_URL_RESPONSE_HEAD_MOJOM_TRAITS_H_
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index 0c705f73..f65689b 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -83,6 +83,7 @@
     "http_raw_headers.mojom",
     "http_request_headers.mojom",
     "ip_address_space.mojom",
+    "load_timing_info.mojom",
     "mdns_responder.mojom",
     "net_log.mojom",
     "network_change_manager.mojom",
@@ -108,6 +109,7 @@
     "udp_socket.mojom",
     "url_loader.mojom",
     "url_loader_factory.mojom",
+    "url_response_head.mojom",
   ]
 
   public_deps = [
diff --git a/content/public/common/load_timing_info.mojom b/services/network/public/mojom/load_timing_info.mojom
similarity index 97%
rename from content/public/common/load_timing_info.mojom
rename to services/network/public/mojom/load_timing_info.mojom
index 51824f1a..7fe76f6 100644
--- a/content/public/common/load_timing_info.mojom
+++ b/services/network/public/mojom/load_timing_info.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module content.mojom;
+module network.mojom;
 
 import "mojo/public/mojom/base/time.mojom";
 
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index 7d7ed66..c6baa591 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -20,6 +20,7 @@
 import "services/network/public/mojom/network_interface.mojom";
 import "services/network/public/mojom/network_param.mojom";
 import "services/network/public/mojom/network_quality_estimator_manager.mojom";
+import "services/network/public/mojom/url_response_head.mojom";
 import "services/network/public/mojom/url_loader.mojom";
 import "services/network/public/mojom/url_loader_factory.mojom";
 import "url/mojom/origin.mojom";
diff --git a/services/network/public/mojom/network_types.mojom b/services/network/public/mojom/network_types.mojom
index d3adda5d..a95db5c 100644
--- a/services/network/public/mojom/network_types.mojom
+++ b/services/network/public/mojom/network_types.mojom
@@ -9,5 +9,11 @@
 // proper mojom definitions.
 
 [Native]
+enum ConnectionInfo;
+
+[Native]
 enum EffectiveConnectionType;
 
+[Native]
+enum CTPolicyCompliance;
+
diff --git a/services/network/public/mojom/url_loader.mojom b/services/network/public/mojom/url_loader.mojom
index d839a35..a10606a 100644
--- a/services/network/public/mojom/url_loader.mojom
+++ b/services/network/public/mojom/url_loader.mojom
@@ -16,13 +16,11 @@
 import "services/network/public/mojom/http_request_headers.mojom";
 import "services/network/public/mojom/network_isolation_key.mojom";
 import "services/network/public/mojom/network_param.mojom";
+import "services/network/public/mojom/url_response_head.mojom";
 import "url/mojom/origin.mojom";
 import "url/mojom/url.mojom";
 
 [Native]
-struct URLResponseHead;
-
-[Native]
 struct URLRequestRedirectInfo;
 
 [Native]
diff --git a/services/network/public/mojom/url_response_head.mojom b/services/network/public/mojom/url_response_head.mojom
new file mode 100644
index 0000000..9111a929
--- /dev/null
+++ b/services/network/public/mojom/url_response_head.mojom
@@ -0,0 +1,206 @@
+// 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 network.mojom;
+
+import "mojo/public/mojom/base/time.mojom";
+import "services/network/public/mojom/fetch_api.mojom";
+import "services/network/public/mojom/ip_endpoint.mojom";
+import "services/network/public/mojom/load_timing_info.mojom";
+import "services/network/public/mojom/network_param.mojom";
+import "services/network/public/mojom/network_types.mojom";
+import "services/network/public/mojom/origin_policy_manager.mojom";
+import "services/proxy_resolver/public/mojom/proxy_resolver.mojom";
+import "url/mojom/url.mojom";
+
+[Native]
+struct HttpRawRequestResponseInfo;
+
+struct URLResponseHead {
+  // The time at which the request was made that resulted in this response.
+  // For cached responses, this time could be "far" in the past.
+  mojo_base.mojom.Time request_time;
+
+  // The time at which the response headers were received.  For cached
+  // responses, this time could be "far" in the past.
+  mojo_base.mojom.Time response_time;
+
+  // The response headers or NULL if the URL type does not support headers.
+  HttpResponseHeaders headers;
+
+  // The mime type of the response.  This may be a derived value.
+  string mime_type;
+
+  // The character encoding of the response or none if not applicable to the
+  // response's mime type.  This may be a derived value.
+  string charset;
+
+  // The resource's compliance with the Certificate Transparency policy.
+  CTPolicyCompliance ct_policy_compliance;
+
+  // Content length if available. -1 if not available
+  int64 content_length = -1;
+
+  // Length of the encoded data transferred over the network. In case there is
+  // no data, contains -1.
+  int64 encoded_data_length = -1;
+
+  // Length of the response body data before decompression. -1 unless the body
+  // has been read to the end.
+  int64 encoded_body_length = -1;
+
+  // True if the request accessed the network in the process of retrieving data.
+  bool network_accessed = false;
+
+  // The appcache this response was loaded from, or kAppCacheNoCacheId.
+  // TODO(rdsmith): Remove conceptual dependence on appcache.
+  int64 appcache_id;
+
+  // The manifest url of the appcache this response was loaded from.
+  // Note: this value is only populated for main resource requests.
+  url.mojom.Url appcache_manifest_url;
+
+  // Detailed timing information used by the WebTiming, HAR and Developer
+  // Tools.  Includes socket ID and socket reuse information.
+  LoadTimingInfo load_timing;
+
+  // Actual request and response headers, as obtained from the network stack.
+  // Only present if the renderer set report_raw_headers to true and had the
+  // CanReadRawCookies permission.
+  HttpRawRequestResponseInfo raw_request_response_info;
+
+  // True if the response was delivered using SPDY.
+  bool was_fetched_via_spdy = false;
+
+  // True if the response was delivered after NPN is negotiated.
+  bool was_alpn_negotiated;
+
+  // True if response could use alternate protocol. However, browser will
+  // ignore the alternate protocol when spdy is not enabled on browser side.
+  bool was_alternate_protocol_available = false;
+
+  // Information about the type of connection used to fetch this response.
+  ConnectionInfo connection_info;
+
+  // ALPN protocol negotiated with the server.
+  string alpn_negotiated_protocol;
+
+  // Remote address of the socket which fetched this resource.
+  IPEndPoint remote_endpoint;
+
+  // True if the response came from cache.
+  bool was_fetched_via_cache = false;
+
+  // The proxy server used for this request, if any.
+  proxy_resolver.mojom.ProxyServer proxy_server;
+
+  // True if a service worker responded to the request. If the service worker
+  // received a fetch event and did not call respondWith(), or was bypassed due
+  // to absence of a fetch event handler, this function typically returns false
+  // but returns true if "fallback to renderer" was required (however in this
+  // case the response is not an actual resource and the request will be
+  // reissued by the renderer).
+  bool was_fetched_via_service_worker = false;
+
+  // True when a request whose mode is |CORS| or |CORS-with-forced-preflight|
+  // is sent to a ServiceWorker but FetchEvent.respondWith is not called. So the
+  // renderer has to resend the request with skip service worker flag
+  // considering the CORS preflight logic.
+  bool was_fallback_required_by_service_worker;
+
+  // The URL list of the Response object the service worker passed to
+  // respondWith() to create this response. For example, if the service worker
+  // calls respondWith(fetch('http://example.com/a')) and http://example.com/a
+  // redirects to http://example.net/b which redirects to http://example.org/c,
+  // the URL list is the vector <"http://example.com/a", "http://example.net/b",
+  // "http://example.org/c">. This is empty if the response was programmatically
+  // generated as in respondWith(new Response()). It is also empty if a service
+  // worker did not respond to the request or did not call respondWith().
+  array<url.mojom.Url> url_list_via_service_worker;
+
+  // https://fetch.spec.whatwg.org/#concept-response-type
+  FetchResponseType response_type;
+
+  // The time immediately before starting ServiceWorker. If the response is not
+  // provided by the ServiceWorker, kept empty.
+  // TODO(ksakamoto): Move this to net::LoadTimingInfo.
+  mojo_base.mojom.TimeTicks service_worker_start_time;
+
+  // The time immediately before dispatching fetch event in ServiceWorker.
+  // If the response is not provided by the ServiceWorker, kept empty.
+  // TODO(ksakamoto): Move this to net::LoadTimingInfo.
+  mojo_base.mojom.TimeTicks service_worker_ready_time;
+
+  // True when the response is served from the CacheStorage via the
+  // ServiceWorker.
+  bool is_in_cache_storage = false;
+
+  // The cache name of the CacheStorage from where the response is served via
+  // the ServiceWorker. Empty if the response isn't from the CacheStorage.
+  string cache_storage_cache_name;
+
+  // Effective connection type when the resource was fetched. This is populated
+  // only for responses that correspond to main frame requests.
+  EffectiveConnectionType effective_connection_type;
+
+  // Bitmask of status info of the SSL certificate. See cert_status_flags.h for
+  // values.
+  uint32 cert_status = 0;
+
+  // Only provided if kURLLoadOptionsSendSSLInfoWithResponse was specified to
+  // the URLLoaderFactory::CreateLoaderAndStart option or
+  // if ResourceRequest::report_raw_headers is set. When set via
+  // |report_raw_headers|, the SSLInfo is not guaranteed to be fully populated
+  // and may only contain certain fields of interest (namely, connection
+  // parameters and certificate information).
+  SSLInfo? ssl_info;
+
+  // In case this is a CORS response fetched by a ServiceWorker, this is the
+  // set of headers that should be exposed.
+  array<string> cors_exposed_header_names;
+
+  // True if service worker navigation preload was performed due to the request
+  // for this response.
+  bool did_service_worker_navigation_preload = false;
+
+  // Is used to report that a cross-origin response was blocked by Cross-Origin
+  // Read Blocking (CORB) from entering renderer. Corresponding message will be
+  // generated in devtools console if this flag is set to true.
+  bool should_report_corb_blocking = false;
+
+  // True if this resource is stale and needs async revalidation. Will only
+  // possibly be set if the load_flags indicated SUPPORT_ASYNC_REVALIDATION.
+  bool async_revalidation_requested = false;
+
+  // True if mime sniffing has been done. In that case, we don't need to do
+  // mime sniffing anymore.
+  bool did_mime_sniff = false;
+
+  // True if the response is an inner response of a signed exchange.
+  bool is_signed_exchange_inner_response = false;
+
+  // True if this resource is served from the prefetch cache.
+  bool was_in_prefetch_cache = false;
+
+  // True if the response was intercepted by a plugin.
+  bool intercepted_by_plugin = false;
+
+  // True if the response was sent over TLS 1.0 or 1.1, which are deprecated and
+  // will be removed in the future.
+  bool is_legacy_tls_version = false;
+
+  // If the request received an authentication challenge, the challenge info is
+  // recorded here.
+  AuthChallengeInfo? auth_challenge_info;
+
+  // TimeTicks::Now() when the browser received the request from the renderer.
+  mojo_base.mojom.TimeTicks request_start;
+
+  // TimeTicks::Now() when the browser sent the response to the renderer.
+  mojo_base.mojom.TimeTicks response_start;
+
+  // Origin Policy associated with this response or nullptr if not applicable.
+  // Spec: https://wicg.github.io/origin-policy/
+  OriginPolicy? origin_policy;
+};
diff --git a/services/network/websocket.cc b/services/network/websocket.cc
index 11dcfc36..1ab2007 100644
--- a/services/network/websocket.cc
+++ b/services/network/websocket.cc
@@ -34,6 +34,7 @@
 #include "net/websockets/websocket_frame.h"  // for WebSocketFrameHeader::OpCode
 #include "net/websockets/websocket_handshake_request_info.h"
 #include "net/websockets/websocket_handshake_response_info.h"
+#include "services/network/websocket_factory.h"
 
 namespace network {
 namespace {
@@ -134,8 +135,6 @@
     net::URLRequest* url_request) {
   url_request->SetUserData(WebSocket::kUserDataKey,
                            std::make_unique<UnownedPointer>(impl_));
-  impl_->delegate_->OnCreateURLRequest(impl_->child_id_, impl_->frame_id_,
-                                       url_request);
 }
 
 void WebSocket::WebSocketEventHandler::OnAddChannelResponse(
@@ -260,11 +259,9 @@
 
 void WebSocket::WebSocketEventHandler::OnStartOpeningHandshake(
     std::unique_ptr<net::WebSocketHandshakeRequestInfo> request) {
-  bool can_read_raw_cookies = impl_->delegate_->CanReadRawCookies(request->url);
-
   DVLOG(3) << "WebSocketEventHandler::OnStartOpeningHandshake @"
            << reinterpret_cast<void*>(this)
-           << " can_read_raw_cookies =" << can_read_raw_cookies;
+           << " can_read_raw_cookies =" << impl_->has_raw_headers_access_;
 
   mojom::WebSocketHandshakeRequestPtr request_to_pass(
       mojom::WebSocketHandshakeRequest::New());
@@ -273,7 +270,7 @@
       "GET %s HTTP/1.1\r\n", request_to_pass->url.spec().c_str());
   net::HttpRequestHeaders::Iterator it(request->headers);
   while (it.GetNext()) {
-    if (!can_read_raw_cookies &&
+    if (!impl_->has_raw_headers_access_ &&
         base::EqualsCaseInsensitiveASCII(it.name(),
                                          net::HttpRequestHeaders::kCookie)) {
       continue;
@@ -294,11 +291,9 @@
 
 void WebSocket::WebSocketEventHandler::OnFinishOpeningHandshake(
     std::unique_ptr<net::WebSocketHandshakeResponseInfo> response) {
-  bool can_read_raw_cookies =
-      impl_->delegate_->CanReadRawCookies(response->url);
   DVLOG(3) << "WebSocketEventHandler::OnFinishOpeningHandshake "
            << reinterpret_cast<void*>(this)
-           << " CanReadRawCookies=" << can_read_raw_cookies;
+           << " CanReadRawCookies=" << impl_->has_raw_headers_access_;
 
   mojom::WebSocketHandshakeResponsePtr response_to_pass(
       mojom::WebSocketHandshakeResponse::New());
@@ -312,7 +307,7 @@
   std::string headers_text =
       base::StrCat({response->headers->GetStatusLine(), "\r\n"});
   while (response->headers->EnumerateHeaderLines(&iter, &name, &value)) {
-    if (can_read_raw_cookies ||
+    if (impl_->has_raw_headers_access_ ||
         !net::HttpResponseHeaders::IsCookieResponseHeader(name)) {
       // We drop cookie-related headers such as "set-cookie" when the
       // renderer doesn't have access.
@@ -335,9 +330,11 @@
   DVLOG(3) << "WebSocketEventHandler::OnSSLCertificateError"
            << reinterpret_cast<void*>(this) << " url=" << url.spec()
            << " cert_status=" << ssl_info.cert_status << " fatal=" << fatal;
-  impl_->delegate_->OnSSLCertificateError(std::move(callbacks), url,
-                                          impl_->child_id_, impl_->frame_id_,
-                                          net_error, ssl_info, fatal);
+  impl_->factory_->OnSSLCertificateError(
+      base::BindOnce(&WebSocket::OnSSLCertificateErrorResponse,
+                     impl_->weak_ptr_factory_.GetWeakPtr(),
+                     std::move(callbacks), ssl_info),
+      url, impl_->child_id_, impl_->frame_id_, net_error, ssl_info, fatal);
 }
 
 int WebSocket::WebSocketEventHandler::OnAuthRequired(
@@ -362,7 +359,7 @@
 }
 
 WebSocket::WebSocket(
-    std::unique_ptr<Delegate> delegate,
+    WebSocketFactory* factory,
     const GURL& url,
     const std::vector<std::string>& requested_protocols,
     const GURL& site_for_cookies,
@@ -371,12 +368,13 @@
     int32_t frame_id,
     const url::Origin& origin,
     uint32_t options,
+    HasRawHeadersAccess has_raw_headers_access,
     mojom::WebSocketHandshakeClientPtr handshake_client,
     mojom::AuthenticationHandlerPtr auth_handler,
     mojom::TrustedHeaderClientPtr header_client,
     WebSocketThrottler::PendingConnection pending_connection_tracker,
     base::TimeDelta delay)
-    : delegate_(std::move(delegate)),
+    : factory_(factory),
       binding_(this),
       handshake_client_(std::move(handshake_client)),
       auth_handler_(std::move(auth_handler)),
@@ -387,6 +385,7 @@
       child_id_(child_id),
       frame_id_(frame_id),
       origin_(std::move(origin)),
+      has_raw_headers_access_(has_raw_headers_access),
       writable_watcher_(FROM_HERE,
                         mojo::SimpleWatcher::ArmingPolicy::MANUAL,
                         base::ThreadTaskRunnerHandle::Get()) {
@@ -418,18 +417,16 @@
              std::move(additional_headers));
 }
 
-WebSocket::~WebSocket() {}
-
-// static
-const void* const WebSocket::kUserDataKey = &WebSocket::kUserDataKey;
-
-void WebSocket::GoAway() {
+WebSocket::~WebSocket() {
   if (channel_ && handshake_succeeded_) {
     StartClosingHandshake(static_cast<uint16_t>(net::kWebSocketErrorGoingAway),
                           "");
   }
 }
 
+// static
+const void* const WebSocket::kUserDataKey = &WebSocket::kUserDataKey;
+
 void WebSocket::SendFrame(bool fin,
                           mojom::WebSocketMessageType type,
                           const std::vector<uint8_t>& data) {
@@ -531,7 +528,7 @@
 void WebSocket::OnConnectionError() {
   DVLOG(3) << "WebSocket::OnConnectionError @" << reinterpret_cast<void*>(this);
 
-  delegate_->OnLostConnectionToClient(this);
+  factory_->Remove(this);
 }
 
 void WebSocket::AddChannel(
@@ -549,7 +546,7 @@
   std::unique_ptr<net::WebSocketEventInterface> event_interface(
       new WebSocketEventHandler(this));
   channel_.reset(new net::WebSocketChannel(std::move(event_interface),
-                                           delegate_->GetURLRequestContext()));
+                                           factory_->GetURLRequestContext()));
 
   net::HttpRequestHeaders headers_to_pass;
   for (const auto& header : additional_headers) {
@@ -626,6 +623,18 @@
   return true;
 }
 
+void WebSocket::OnSSLCertificateErrorResponse(
+    std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks,
+    const net::SSLInfo& ssl_info,
+    int net_error) {
+  if (net_error == net::OK) {
+    callbacks->ContinueSSLRequest();
+    return;
+  }
+
+  callbacks->CancelSSLRequest(net_error, &ssl_info);
+}
+
 void WebSocket::OnAuthRequiredComplete(
     base::OnceCallback<void(const net::AuthCredentials*)> callback,
     const base::Optional<net::AuthCredentials>& credentials) {
diff --git a/services/network/websocket.h b/services/network/websocket.h
index 246bb61..24b6dad 100644
--- a/services/network/websocket.h
+++ b/services/network/websocket.h
@@ -16,6 +16,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "base/util/type_safety/strong_alias.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "net/websockets/websocket_event_interface.h"
 #include "services/network/public/mojom/network_context.mojom.h"
@@ -26,45 +27,21 @@
 class GURL;
 
 namespace net {
-class URLRequestContext;
-class WebSocketChannel;
 class SSLInfo;
+class WebSocketChannel;
 }  // namespace net
 
 namespace network {
 
+class WebSocketFactory;
+
 // Host of net::WebSocketChannel.
 class COMPONENT_EXPORT(NETWORK_SERVICE) WebSocket : public mojom::WebSocket {
  public:
-  class Delegate {
-   public:
-    enum class BadMessageReason {
-      kUnexpectedAddChannelRequest,
-      kUnexpectedSendFrame,
-    };
-    virtual ~Delegate() {}
+  using HasRawHeadersAccess =
+      util::StrongAlias<class HasRawHeadersAccessTag, bool>;
 
-    virtual net::URLRequestContext* GetURLRequestContext() = 0;
-    // This function may delete |impl|.
-    virtual void OnLostConnectionToClient(WebSocket* impl) = 0;
-    virtual void OnSSLCertificateError(
-        std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks>
-            callbacks,
-        const GURL& url,
-        int child_id,
-        int frame_id,
-        int net_error,
-        const net::SSLInfo& ssl_info,
-        bool fatal) = 0;
-    // This function may delete |impl|.
-    virtual void ReportBadMessage(BadMessageReason reason, WebSocket* impl) = 0;
-    virtual bool CanReadRawCookies(const GURL& url) = 0;
-    virtual void OnCreateURLRequest(int child_id,
-                                    int frame_id,
-                                    net::URLRequest* request) = 0;
-  };
-
-  WebSocket(std::unique_ptr<Delegate> delegate,
+  WebSocket(WebSocketFactory* factory,
             const GURL& url,
             const std::vector<std::string>& requested_protocols,
             const GURL& site_for_cookies,
@@ -73,6 +50,7 @@
             int32_t render_frame_id,
             const url::Origin& origin,
             uint32_t options,
+            HasRawHeadersAccess has_raw_cookie_access,
             mojom::WebSocketHandshakeClientPtr handshake_client,
             mojom::AuthenticationHandlerPtr auth_handler,
             mojom::TrustedHeaderClientPtr header_client,
@@ -80,10 +58,6 @@
             base::TimeDelta delay);
   ~WebSocket() override;
 
-  // The renderer process is going away.
-  // This function is virtual for testing.
-  virtual void GoAway();
-
   // mojom::WebSocket methods:
   void SendFrame(bool fin,
                  mojom::WebSocketMessageType type,
@@ -138,6 +112,11 @@
                   const std::vector<std::string>& requested_protocols,
                   const GURL& site_for_cookies,
                   std::vector<mojom::HttpHeaderPtr> additional_headers);
+  void OnSSLCertificateErrorResponse(
+      std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks>
+          callbacks,
+      const net::SSLInfo& ssl_info,
+      int net_error);
   void OnAuthRequiredComplete(
       base::OnceCallback<void(const net::AuthCredentials*)> callback,
       const base::Optional<net::AuthCredentials>& credential);
@@ -162,7 +141,8 @@
   // Returns false if mojo error occurs.
   bool SendDataFrame(DataFrame*);
 
-  std::unique_ptr<Delegate> delegate_;
+  // |factory_| owns |this|.
+  WebSocketFactory* const factory_;
   mojo::Binding<mojom::WebSocket> binding_;
 
   mojom::WebSocketHandshakeClientPtr handshake_client_;
@@ -189,6 +169,7 @@
   // handshake_succeeded_ is used by WebSocketManager to manage counters for
   // per-renderer WebSocket throttling.
   bool handshake_succeeded_ = false;
+  const HasRawHeadersAccess has_raw_headers_access_;
 
   // Datapipe fields to receive.
   mojo::ScopedDataPipeProducerHandle writable_;
diff --git a/services/network/websocket_factory.cc b/services/network/websocket_factory.cc
index d6ef78a..20bda71 100644
--- a/services/network/websocket_factory.cc
+++ b/services/network/websocket_factory.cc
@@ -5,7 +5,6 @@
 #include "services/network/websocket_factory.h"
 
 #include "base/bind.h"
-#include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/url_util.h"
 #include "services/network/network_context.h"
@@ -17,75 +16,6 @@
 
 namespace network {
 
-class WebSocketFactory::Delegate final : public WebSocket::Delegate {
- public:
-  Delegate(WebSocketFactory* factory, int32_t process_id)
-      : factory_(factory), process_id_(process_id) {}
-  ~Delegate() override {}
-
-  net::URLRequestContext* GetURLRequestContext() override {
-    return factory_->context_->url_request_context();
-  }
-
-  void OnLostConnectionToClient(WebSocket* impl) override {
-    factory_->OnLostConnectionToClient(impl);
-  }
-
-  void OnSSLCertificateError(
-      std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks>
-          callbacks,
-      const GURL& url,
-      int process_id,
-      int render_frame_id,
-      int net_error,
-      const net::SSLInfo& ssl_info,
-      bool fatal) override {
-    DCHECK(!callbacks_);
-    callbacks_ = std::move(callbacks);
-
-    NetworkService* network_service = factory_->context_->network_service();
-    network_service->client()->OnSSLCertificateError(
-        process_id, render_frame_id, url, net_error, ssl_info, fatal,
-        base::BindRepeating(&Delegate::OnSSLCertificateErrorResponse,
-                            weak_factory_.GetWeakPtr(), ssl_info));
-  }
-
-  void ReportBadMessage(BadMessageReason reason, WebSocket* impl) override {
-    OnLostConnectionToClient(impl);
-  }
-
-  bool CanReadRawCookies(const GURL& url) override {
-    DCHECK(url.SchemeIsWSOrWSS());
-    GURL url_to_check = net::ChangeWebSocketSchemeToHttpScheme(url);
-    return factory_->context_->network_service()->HasRawHeadersAccess(
-        process_id_, url_to_check);
-  }
-
-  void OnCreateURLRequest(int child_id,
-                          int frame_id,
-                          net::URLRequest* request) override {}
-
- private:
-  void OnSSLCertificateErrorResponse(const net::SSLInfo& ssl_info,
-                                     int net_error) {
-    if (net_error == net::OK) {
-      callbacks_->ContinueSSLRequest();
-      return;
-    }
-
-    callbacks_->CancelSSLRequest(net_error, &ssl_info);
-  }
-
-  // |factory_| outlives this object.
-  WebSocketFactory* const factory_;
-  const int process_id_;
-  std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks_;
-
-  base::WeakPtrFactory<Delegate> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(Delegate);
-};
-
 WebSocketFactory::WebSocketFactory(NetworkContext* context)
     : context_(context) {}
 
@@ -110,19 +40,39 @@
         "Error in connection establishment: net::ERR_INSUFFICIENT_RESOURCES");
     return;
   }
+  WebSocket::HasRawHeadersAccess has_raw_headers_access(
+      context_->network_service()->HasRawHeadersAccess(
+          process_id, net::ChangeWebSocketSchemeToHttpScheme(url)));
   connections_.insert(std::make_unique<WebSocket>(
-      std::make_unique<Delegate>(this, process_id), url, requested_protocols,
-      site_for_cookies, std::move(additional_headers), process_id,
-      render_frame_id, origin, options, std::move(handshake_client),
+      this, url, requested_protocols, site_for_cookies,
+      std::move(additional_headers), process_id, render_frame_id, origin,
+      options, has_raw_headers_access, std::move(handshake_client),
       std::move(auth_handler), std::move(header_client),
       throttler_.IssuePendingConnectionTracker(process_id),
       throttler_.CalculateDelay(process_id)));
 }
 
-void WebSocketFactory::OnLostConnectionToClient(WebSocket* impl) {
+net::URLRequestContext* WebSocketFactory::GetURLRequestContext() {
+  return context_->url_request_context();
+}
+
+void WebSocketFactory::OnSSLCertificateError(
+    base::OnceCallback<void(int)> callback,
+    const GURL& url,
+    int process_id,
+    int render_frame_id,
+    int net_error,
+    const net::SSLInfo& ssl_info,
+    bool fatal) {
+  NetworkService* network_service = context_->network_service();
+  network_service->client()->OnSSLCertificateError(process_id, render_frame_id,
+                                                   url, net_error, ssl_info,
+                                                   fatal, std::move(callback));
+}
+
+void WebSocketFactory::Remove(WebSocket* impl) {
   auto it = connections_.find(impl);
   DCHECK(it != connections_.end());
-  impl->GoAway();
   connections_.erase(it);
 }
 
diff --git a/services/network/websocket_factory.h b/services/network/websocket_factory.h
index ab0c36b..d9a81f6f 100644
--- a/services/network/websocket_factory.h
+++ b/services/network/websocket_factory.h
@@ -5,15 +5,24 @@
 #ifndef SERVICES_NETWORK_WEBSOCKET_FACTORY_H_
 #define SERVICES_NETWORK_WEBSOCKET_FACTORY_H_
 
+#include <set>
 #include <vector>
 
+#include "base/callback_forward.h"
 #include "base/containers/unique_ptr_adapters.h"
+#include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/websocket.mojom.h"
 #include "services/network/websocket.h"
 #include "services/network/websocket_throttler.h"
 
+class GURL;
+
+namespace net {
+class SSLInfo;
+}  // namespace net
+
 namespace url {
 class Origin;
 }  // namespace url
@@ -21,6 +30,7 @@
 namespace network {
 
 class NetworkContext;
+class WebSocket;
 
 class WebSocketFactory final {
  public:
@@ -39,11 +49,22 @@
                        mojom::AuthenticationHandlerPtr auth_handler,
                        mojom::TrustedHeaderClientPtr header_client);
 
+  // Returns a URLRequestContext associated with this factory.
+  net::URLRequestContext* GetURLRequestContext();
+
+  // Called when a WebSocket sees a SSL certificate error.
+  void OnSSLCertificateError(base::OnceCallback<void(int)> callback,
+                             const GURL& url,
+                             int process_id,
+                             int render_frame_id,
+                             int net_error,
+                             const net::SSLInfo& ssl_info,
+                             bool fatal);
+
+  // Removes and deletes |impl|.
+  void Remove(WebSocket* impl);
+
  private:
-  class Delegate;
-
-  void OnLostConnectionToClient(WebSocket* impl);
-
   // The connections held by this factory.
   std::set<std::unique_ptr<WebSocket>, base::UniquePtrComparator> connections_;
 
diff --git a/services/video_capture/device_factory.h b/services/video_capture/device_factory.h
index bc410f6f..0470764 100644
--- a/services/video_capture/device_factory.h
+++ b/services/video_capture/device_factory.h
@@ -7,18 +7,10 @@
 
 #include "services/video_capture/public/mojom/device_factory.mojom.h"
 
-#if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
-#endif  // defined(OS_CHROMEOS)
-
 namespace video_capture {
 
 class DeviceFactory : public mojom::DeviceFactory {
  public:
-#if defined(OS_CHROMEOS)
-  virtual void BindCrosImageCaptureRequest(
-      cros::mojom::CrosImageCaptureRequest request) = 0;
-#endif  // defined(OS_CHROMEOS)
 };
 
 }  // namespace video_capture
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.cc b/services/video_capture/device_factory_media_to_mojo_adapter.cc
index b017d2a..403d509 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.cc
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.cc
@@ -202,13 +202,4 @@
   active_devices_by_id_.erase(device_id);
 }
 
-#if defined(OS_CHROMEOS)
-void DeviceFactoryMediaToMojoAdapter::BindCrosImageCaptureRequest(
-    cros::mojom::CrosImageCaptureRequest request) {
-  CHECK(capture_system_);
-
-  capture_system_->BindCrosImageCaptureRequest(std::move(request));
-}
-#endif  // defined(OS_CHROMEOS)
-
 }  // namespace video_capture
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.h b/services/video_capture/device_factory_media_to_mojo_adapter.h
index 2b9157e..6c3496c 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.h
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.h
@@ -14,7 +14,6 @@
 #include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
 
 #if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
 #endif  // defined(OS_CHROMEOS)
 
@@ -55,12 +54,6 @@
   void RegisterVirtualDevicesChangedObserver(
       mojom::DevicesChangedObserverPtr observer,
       bool raise_event_if_virtual_devices_already_present) override;
-
-#if defined(OS_CHROMEOS)
-  void BindCrosImageCaptureRequest(
-      cros::mojom::CrosImageCaptureRequest request) override;
-#endif  // defined(OS_CHROMEOS)
-
  private:
   struct ActiveDeviceEntry {
     ActiveDeviceEntry();
diff --git a/services/video_capture/public/cpp/mock_video_capture_service.h b/services/video_capture/public/cpp/mock_video_capture_service.h
index da63ced..a611ab0 100644
--- a/services/video_capture/public/cpp/mock_video_capture_service.h
+++ b/services/video_capture/public/cpp/mock_video_capture_service.h
@@ -30,8 +30,8 @@
       DoInjectGpuDependencies,
       void(video_capture::mojom::AcceleratorFactoryPtr& accelerator_factory));
 
-  void BindCrosImageCapture(
-      mojo::PendingReceiver<cros::mojom::CrosImageCapture>) override {}
+  void ConnectToCameraAppDeviceBridge(
+      mojo::PendingReceiver<cros::mojom::CameraAppDeviceBridge>) override {}
 #endif  // defined(OS_CHROMEOS
 
   void BindControlsForTesting(
diff --git a/services/video_capture/public/mojom/video_capture_service.mojom b/services/video_capture/public/mojom/video_capture_service.mojom
index 5b4cc56..8cc7a56 100644
--- a/services/video_capture/public/mojom/video_capture_service.mojom
+++ b/services/video_capture/public/mojom/video_capture_service.mojom
@@ -11,7 +11,7 @@
 import "services/video_capture/public/mojom/video_source_provider.mojom";
 
 [EnableIf=is_chromeos]
-import "media/capture/video/chromeos/mojom/cros_image_capture.mojom";
+import "media/capture/video/chromeos/mojom/camera_app.mojom";
 
 [EnableIf=is_chromeos]
 interface AcceleratorFactory {
@@ -33,9 +33,10 @@
   [EnableIf=is_chromeos]
   InjectGpuDependencies(AcceleratorFactory accelerator_factory);
 
-  // Binds a Chrome OS camera capture interface.
+  // Binds a bridge for Chrome OS camera app and device.
   [EnableIf=is_chromeos]
-  BindCrosImageCapture(pending_receiver<cros.mojom.CrosImageCapture> receiver);
+  ConnectToCameraAppDeviceBridge(
+      pending_receiver<cros.mojom.CameraAppDeviceBridge> receiver);
 
   // Legacy API. Supports one client per device.
   ConnectToDeviceFactory(DeviceFactory& request);
diff --git a/services/video_capture/video_capture_service_impl.cc b/services/video_capture/video_capture_service_impl.cc
index 2d9531a9..57e0dd2 100644
--- a/services/video_capture/video_capture_service_impl.cc
+++ b/services/video_capture/video_capture_service_impl.cc
@@ -94,6 +94,11 @@
 VideoCaptureServiceImpl::~VideoCaptureServiceImpl() {
   factory_bindings_.CloseAllBindings();
   device_factory_.reset();
+
+#if defined(OS_CHROMEOS)
+  camera_app_device_bridge_.reset();
+#endif  // defined (OS_CHROMEOS)
+
   if (gpu_dependencies_context_) {
     gpu_dependencies_context_->GetTaskRunner()->DeleteSoon(
         FROM_HERE, std::move(gpu_dependencies_context_));
@@ -110,10 +115,10 @@
                                 accelerator_factory.PassInterface()));
 }
 
-void VideoCaptureServiceImpl::BindCrosImageCapture(
-    mojo::PendingReceiver<cros::mojom::CrosImageCapture> receiver) {
-  CHECK(device_factory_);
-  device_factory_->BindCrosImageCaptureRequest(std::move(receiver));
+void VideoCaptureServiceImpl::ConnectToCameraAppDeviceBridge(
+    mojo::PendingReceiver<cros::mojom::CameraAppDeviceBridge> receiver) {
+  DCHECK(camera_app_device_bridge_);
+  camera_app_device_bridge_->BindReceiver(std::move(receiver));
 }
 #endif  // defined(OS_CHROMEOS)
 
@@ -156,9 +161,18 @@
   // The task runner passed to CreateFactory is used for things that need to
   // happen on a "UI thread equivalent", e.g. obtaining screen rotation on
   // Chrome OS.
+#if defined(OS_CHROMEOS)
+  camera_app_device_bridge_ =
+      std::make_unique<media::CameraAppDeviceBridgeImpl>();
+  std::unique_ptr<media::VideoCaptureDeviceFactory> media_device_factory =
+      media::CreateVideoCaptureDeviceFactory(ui_task_runner_,
+                                             camera_app_device_bridge_.get());
+  camera_app_device_bridge_->SetIsSupported(
+      media_device_factory->IsSupportedCameraAppDeviceBridge());
+#else
   std::unique_ptr<media::VideoCaptureDeviceFactory> media_device_factory =
       media::CreateVideoCaptureDeviceFactory(ui_task_runner_);
-  DCHECK(media_device_factory);
+#endif  // defined(OS_CHROMEOS)
 
   auto video_capture_system = std::make_unique<media::VideoCaptureSystemImpl>(
       std::move(media_device_factory));
diff --git a/services/video_capture/video_capture_service_impl.h b/services/video_capture/video_capture_service_impl.h
index ef83ff1..b6310030 100644
--- a/services/video_capture/video_capture_service_impl.h
+++ b/services/video_capture/video_capture_service_impl.h
@@ -16,7 +16,8 @@
 #include "services/video_capture/public/mojom/video_capture_service.mojom.h"
 
 #if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
+#include "media/capture/video/chromeos/mojom/camera_app.mojom.h"
 #endif  // defined(OS_CHROMEOS)
 
 namespace video_capture {
@@ -35,8 +36,9 @@
 #if defined(OS_CHROMEOS)
   void InjectGpuDependencies(
       mojom::AcceleratorFactoryPtr accelerator_factory) override;
-  void BindCrosImageCapture(
-      mojo::PendingReceiver<cros::mojom::CrosImageCapture> receiver) override;
+  void ConnectToCameraAppDeviceBridge(
+      mojo::PendingReceiver<cros::mojom::CameraAppDeviceBridge> receiver)
+      override;
 #endif  // defined(OS_CHROMEOS)
   void ConnectToDeviceFactory(mojom::DeviceFactoryRequest request) override;
   void ConnectToVideoSourceProvider(
@@ -59,6 +61,11 @@
   std::unique_ptr<VideoSourceProviderImpl> video_source_provider_;
   std::unique_ptr<GpuDependenciesContext> gpu_dependencies_context_;
 
+#if defined(OS_CHROMEOS)
+  // Bridge for Chrome OS camera app and camera devices.
+  std::unique_ptr<media::CameraAppDeviceBridgeImpl> camera_app_device_bridge_;
+#endif  // defined(OS_CHROMEOS)
+
   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(VideoCaptureServiceImpl);
diff --git a/services/video_capture/virtual_device_enabled_device_factory.cc b/services/video_capture/virtual_device_enabled_device_factory.cc
index 6e3de4d..424989d 100644
--- a/services/video_capture/virtual_device_enabled_device_factory.cc
+++ b/services/video_capture/virtual_device_enabled_device_factory.cc
@@ -243,13 +243,4 @@
   devices_changed_observers_.erase(iter);
 }
 
-#if defined(OS_CHROMEOS)
-void VirtualDeviceEnabledDeviceFactory::BindCrosImageCaptureRequest(
-    cros::mojom::CrosImageCaptureRequest request) {
-  CHECK(device_factory_);
-
-  device_factory_->BindCrosImageCaptureRequest(std::move(request));
-}
-#endif  // defined(OS_CHROMEOS)
-
 }  // namespace video_capture
diff --git a/services/video_capture/virtual_device_enabled_device_factory.h b/services/video_capture/virtual_device_enabled_device_factory.h
index 583e4b4f..b206866 100644
--- a/services/video_capture/virtual_device_enabled_device_factory.h
+++ b/services/video_capture/virtual_device_enabled_device_factory.h
@@ -14,10 +14,6 @@
 #include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
 #include "services/video_capture/public/mojom/virtual_device.mojom.h"
 
-#if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
-#endif  // defined(OS_CHROMEOS)
-
 namespace video_capture {
 
 // Decorator that adds support for virtual devices to a given DeviceFactory.
@@ -43,12 +39,6 @@
   void RegisterVirtualDevicesChangedObserver(
       mojom::DevicesChangedObserverPtr observer,
       bool raise_event_if_virtual_devices_already_present) override;
-
-#if defined(OS_CHROMEOS)
-  void BindCrosImageCaptureRequest(
-      cros::mojom::CrosImageCaptureRequest request) override;
-#endif  // defined(OS_CHROMEOS)
-
  private:
   class VirtualDeviceEntry;
 
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index ee7556f..c080d2d 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -31660,6 +31660,644 @@
       }
     ]
   },
+  "Win10 FYI x86 Release (NVIDIA)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "angle_unittests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--enable-gpu",
+          "--test-launcher-bot-mode",
+          "--test-launcher-jobs=1",
+          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "tab_capture_end2end_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "browser_tests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=validating"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_tests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=passthrough"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gl_tests_passthrough",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_tests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_unittests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--use-angle=d3d11",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d11_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "video_decode_accelerator_unittest",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "--ignore-runtime-requirements=*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "xr_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "xr_browser_tests",
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "context_lost",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "context_lost_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "depth_capture",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "depth_capture_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "gpu_process",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "gpu_process_launch_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "hardware_accelerated_feature_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "info_collection",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--expected-vendor-id",
+          "10de",
+          "--expected-device-id",
+          "1cb3"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "info_collection_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "maps",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "maps_pixel_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "pixel_skia_gold_test",
+        "precommit_args": [
+          "--review-patch-issue",
+          "${patch_issue}",
+          "--review-patch-set",
+          "${patch_set}",
+          "--buildbucket-build-id",
+          "${buildbucket_build_id}"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "screenshot_sync",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "screenshot_sync_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "trace_test",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "trace_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "nvidia-quadro-p400-win10-stable",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "shards": 2
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-trigger-configs",
+            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
+        }
+      }
+    ]
+  },
   "Win7 ANGLE Tryserver (AMD)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 79786c6..dab914b 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -669,7 +669,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -693,7 +693,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -717,7 +717,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -741,7 +741,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -765,7 +765,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -789,7 +789,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -813,7 +813,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -837,7 +837,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -1336,7 +1336,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -1360,7 +1360,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -1384,7 +1384,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -1408,7 +1408,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -1432,7 +1432,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -1456,7 +1456,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
@@ -1480,7 +1480,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-14.04",
+              "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
           ],
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index fd49daf..54567a3 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -3156,6 +3156,19 @@
         },
         'use_multi_dimension_trigger_script': True,
       },
+      'Win10 FYI x86 Release (NVIDIA)': {
+        'browser_config': 'release',
+        'os_type': 'win',
+        'mixins': [
+          'win10_nvidia_quadro_p400_stable',
+        ],
+        'test_suites': {
+          'gtest_tests': 'gpu_win_gtests',
+          'gpu_telemetry_tests': 'gpu_common_win_and_linux_telemetry_tests',
+        },
+        # We keep this value enabled to provide minimal regression testing.
+        'use_multi_dimension_trigger_script': True,
+      },
       # This tryserver doesn't actually exist; it's a separate
       # configuration from the Win AMD bot on this waterfall because we
       # don't have enough tryserver capacity to run all the tests from
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 6ff43dc..5ca48b6 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -103,6 +103,11 @@
     "OffMainThreadDedicatedWorkerScriptFetch",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Start service workers on the IO thread.
+// https://crbug.com/692909
+const base::Feature kOffMainThreadServiceWorkerStartup{
+    "OffMainThreadServiceWorkerStartup", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enable browser-initiated dedicated worker script loading
 // (PlzDedicatedWorker). https://crbug.com/906991
 const base::Feature kPlzDedicatedWorker{"PlzDedicatedWorker",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index d41308b7..68274e28 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -36,6 +36,8 @@
 BLINK_COMMON_EXPORT extern const base::Feature kNavigationPredictor;
 BLINK_COMMON_EXPORT extern const base::Feature
     kOffMainThreadDedicatedWorkerScriptFetch;
+BLINK_COMMON_EXPORT extern const base::Feature
+    kOffMainThreadServiceWorkerStartup;
 BLINK_COMMON_EXPORT extern const base::Feature kPlzDedicatedWorker;
 BLINK_COMMON_EXPORT extern const base::Feature kPortals;
 BLINK_COMMON_EXPORT extern const base::Feature
diff --git a/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom b/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom
index f99665e..89929f7 100644
--- a/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom
+++ b/third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom
@@ -4,6 +4,7 @@
 
 module blink.mojom;
 
+import "services/network/public/mojom/url_response_head.mojom";
 import "services/network/public/mojom/url_loader.mojom";
 
 // NetworkService (PlzWorker):
diff --git a/third_party/blink/public/web/web_embedded_worker.h b/third_party/blink/public/web/web_embedded_worker.h
index 8d0f16b4..1998934 100644
--- a/third_party/blink/public/web/web_embedded_worker.h
+++ b/third_party/blink/public/web/web_embedded_worker.h
@@ -72,7 +72,9 @@
   virtual ~WebEmbeddedWorker() = default;
 
   // Starts and terminates WorkerThread and WorkerGlobalScope.
-  virtual void StartWorkerContext(const WebEmbeddedWorkerStartData&) = 0;
+  virtual void StartWorkerContext(const WebEmbeddedWorkerStartData&,
+                                  scoped_refptr<base::SingleThreadTaskRunner>
+                                      initiator_thread_task_runner) = 0;
   virtual void TerminateWorkerContext() = 0;
 
   // Resumes starting a worker startup that was paused via
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py b/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py
index ab7fcad..12ba24d 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/__init__.py
@@ -19,7 +19,8 @@
         # //tools/idl_parser
         os.path.join(root_dir, 'tools'),
         # //third_party/blink/renderer/build/scripts/blinkbuild
-        os.path.join(this_dir, '..', '..', '..', 'build', 'scripts'),
+        os.path.join(root_dir, 'third_party', 'blink', 'renderer', 'build',
+                     'scripts'),
     ] + sys.path
 
 
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
index a63a25a..4b40781 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
@@ -279,14 +279,23 @@
                 key_pieces.append('type null')  # something unique
             return '|'.join(key_pieces)
 
-        grouped_unions = {}  # {unique key: list of union types, ...}
+        grouped_unions = {}  # {unique key: list of union types}
         for union_type in all_union_types:
             key = unique_key(union_type)
             grouped_unions.setdefault(key, []).append(union_type)
 
+        grouped_typedefs = {}  # {unique key: list of typedefs to the union}
+        all_typedefs = self._db.find_by_kind(DatabaseBody.Kind.TYPEDEF)
+        for typedef in all_typedefs.itervalues():
+            if not typedef.idl_type.is_union:
+                continue
+            key = unique_key(typedef.idl_type)
+            grouped_typedefs.setdefault(key, []).append(typedef)
+
         for key, union_types in grouped_unions.iteritems():
             self._db.register(
                 DatabaseBody.Kind.UNION,
                 Union(
                     Identifier(key),  # dummy identifier
-                    union_types))
+                    union_types=union_types,
+                    typedef_backrefs=grouped_typedefs.get(key, [])))
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/union.py b/third_party/blink/renderer/bindings/scripts/web_idl/union.py
index b25a69a..e4e2ab3 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/union.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/union.py
@@ -7,6 +7,7 @@
 from .composition_parts import WithDebugInfo
 from .composition_parts import WithIdentifier
 from .idl_type import IdlType
+from .typedef import Typedef
 
 
 class Union(WithIdentifier, WithCodeGeneratorInfo, WithComponent,
@@ -29,18 +30,23 @@
     expected to define an implementation class for each Union instance.
     """
 
-    def __init__(self, identifier, union_types):
+    def __init__(self, identifier, union_types, typedef_backrefs):
         """
         Args:
             union_types: Union types of which this object consists.  All types
                 in |union_types| must have the same flattened_member_types and
                 the same value of does_include_nullable_type.
+            typedef_backrefs: Typedef instances whose typedef'ed type is this
+                union.
         """
         assert isinstance(union_types, (list, tuple))
         assert len(union_types) > 0
         assert all(
             isinstance(union_type, IdlType) and union_type.is_union
             for union_type in union_types)
+        assert isinstance(typedef_backrefs, (list, tuple))
+        assert all(
+            isinstance(typedef, Typedef) for typedef in typedef_backrefs)
 
         flattened_members = union_types[0].flattened_member_types
         does_include_nullable_type = union_types[0].does_include_nullable_type
@@ -84,6 +90,7 @@
         self._nullable_members = tuple(sorted(nullable_members, key=sort_key))
         self._typedef_members = tuple(sorted(typedef_members, key=sort_key))
         self._union_members = tuple(sorted(union_members, key=sort_key))
+        self._typedef_backrefs = tuple(typedef_backrefs)
 
     @property
     def flattened_member_types(self):
@@ -137,3 +144,10 @@
         IdlType(B or C).
         """
         return self._union_members
+
+    @property
+    def aliasing_typedefs(self):
+        """
+        Returns a list of typedefs which are aliases to this union type.
+        """
+        return self._typedef_backrefs
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.cc b/third_party/blink/renderer/core/css/css_math_expression_node.cc
index fe085d23..f2c348c 100644
--- a/third_party/blink/renderer/core/css/css_math_expression_node.cc
+++ b/third_party/blink/renderer/core/css/css_math_expression_node.cc
@@ -916,18 +916,22 @@
       return nullptr;
 
     CSSMathExpressionVariadicOperation::Operands operands;
+    bool last_token_is_comma = false;
     while (!tokens.AtEnd()) {
       tokens.ConsumeWhitespace();
       CSSMathExpressionNode* operand = ParseValueExpression(tokens, depth);
       if (!operand)
         return nullptr;
 
+      last_token_is_comma = false;
       operands.push_back(operand);
+
       if (!css_property_parser_helpers::ConsumeCommaIncludingWhitespace(tokens))
         break;
+      last_token_is_comma = true;
     }
 
-    if (operands.IsEmpty() || !tokens.AtEnd())
+    if (operands.IsEmpty() || !tokens.AtEnd() || last_token_is_comma)
       return nullptr;
 
     return CSSMathExpressionVariadicOperation::Create(std::move(operands), op);
diff --git a/third_party/blink/renderer/core/css/css_primitive_value.h b/third_party/blink/renderer/core/css/css_primitive_value.h
index 8185d59..ea1ac04 100644
--- a/third_party/blink/renderer/core/css/css_primitive_value.h
+++ b/third_party/blink/renderer/core/css/css_primitive_value.h
@@ -291,7 +291,8 @@
     const CSSToLengthConversionData&) const;
 
 template <>
-float CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
+CORE_EXPORT float CSSPrimitiveValue::ComputeLength(
+    const CSSToLengthConversionData&) const;
 
 template <>
 double CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
diff --git a/third_party/blink/renderer/core/css/parser/sizes_calc_parser.cc b/third_party/blink/renderer/core/css/parser/sizes_calc_parser.cc
index cfcc796..ca6f4f2 100644
--- a/third_party/blink/renderer/core/css/parser/sizes_calc_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/sizes_calc_parser.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/renderer/core/css/media_values.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_token.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -63,6 +64,65 @@
   return true;
 }
 
+bool SizesCalcParser::HandleRightParenthesis(Vector<CSSParserToken>& stack) {
+  // If the token is a right parenthesis:
+  // Until the token at the top of the stack is a left parenthesis or a
+  // function, pop operators off the stack onto the output queue.
+  // Also count the number of commas to get the number of function
+  // parameters if this right parenthesis closes a function.
+  wtf_size_t comma_count = 0;
+  while (!stack.IsEmpty() && stack.back().GetType() != kLeftParenthesisToken &&
+         stack.back().GetType() != kFunctionToken) {
+    if (stack.back().GetType() == kCommaToken)
+      ++comma_count;
+    else
+      AppendOperator(stack.back());
+    stack.pop_back();
+  }
+  // If the stack runs out without finding a left parenthesis, then there
+  // are mismatched parentheses.
+  if (stack.IsEmpty())
+    return false;
+
+  CSSParserToken left_side = stack.back();
+  stack.pop_back();
+
+  if (left_side.GetType() == kLeftParenthesisToken ||
+      left_side.FunctionId() == CSSValueID::kCalc) {
+    // There should be exactly one calculation within calc() or parentheses.
+    return !comma_count;
+  }
+
+  // Break variadic min/max() into binary operations to fit in the reverse
+  // polish notation.
+  CSSMathOperator op = left_side.FunctionId() == CSSValueID::kMin
+                           ? CSSMathOperator::kMin
+                           : CSSMathOperator::kMax;
+  for (wtf_size_t i = 0; i < comma_count; ++i)
+    value_list_.emplace_back(op);
+  return true;
+}
+
+bool SizesCalcParser::HandleComma(Vector<CSSParserToken>& stack,
+                                  const CSSParserToken& token) {
+  if (!RuntimeEnabledFeatures::CSSComparisonFunctionsEnabled())
+    return false;
+  // Treat comma as a binary right-associative operation for now, so that
+  // when reaching the right parenthesis of the function, we can get the
+  // number of parameters by counting the number of commas.
+  while (!stack.IsEmpty() && stack.back().GetType() != kFunctionToken &&
+         stack.back().GetType() != kLeftParenthesisToken &&
+         stack.back().GetType() != kCommaToken) {
+    AppendOperator(stack.back());
+    stack.pop_back();
+  }
+  // Commas are allowed as function parameter separators only
+  if (stack.IsEmpty() || stack.back().GetType() == kLeftParenthesisToken)
+    return false;
+  stack.push_back(token);
+  return true;
+}
+
 void SizesCalcParser::AppendNumber(const CSSParserToken& token) {
   SizesCalcValue value;
   value.value = token.NumericValue();
@@ -82,9 +142,7 @@
 }
 
 void SizesCalcParser::AppendOperator(const CSSParserToken& token) {
-  SizesCalcValue value;
-  value.operation = ParseCSSArithmeticOperator(token);
-  value_list_.push_back(value);
+  value_list_.emplace_back(ParseCSSArithmeticOperator(token));
 }
 
 bool SizesCalcParser::CalcToReversePolishNotation(CSSParserTokenRange range) {
@@ -109,6 +167,14 @@
           return false;
         break;
       case kFunctionToken:
+        if (RuntimeEnabledFeatures::CSSComparisonFunctionsEnabled()) {
+          if (token.FunctionId() == CSSValueID::kMin ||
+              token.FunctionId() == CSSValueID::kMax) {
+            // TODO(crbug.com/825895): Add clamp() when min/max are done.
+            stack.push_back(token);
+            break;
+          }
+        }
         if (token.FunctionId() != CSSValueID::kCalc)
           return false;
         // "calc(" is the same as "("
@@ -118,22 +184,12 @@
         stack.push_back(token);
         break;
       case kRightParenthesisToken:
-        // If the token is a right parenthesis:
-        // Until the token at the top of the stack is a left parenthesis, pop
-        // operators off the stack onto the output queue.
-        while (!stack.IsEmpty() &&
-               stack.back().GetType() != kLeftParenthesisToken &&
-               stack.back().GetType() != kFunctionToken) {
-          AppendOperator(stack.back());
-          stack.pop_back();
-        }
-        // If the stack runs out without finding a left parenthesis, then there
-        // are mismatched parentheses.
-        if (stack.IsEmpty())
+        if (!HandleRightParenthesis(stack))
           return false;
-        // Pop the left parenthesis from the stack, but not onto the output
-        // queue.
-        stack.pop_back();
+        break;
+      case kCommaToken:
+        if (!HandleComma(stack, token))
+          return false;
         break;
       case kWhitespaceToken:
       case kEOFToken:
@@ -156,7 +212,6 @@
       case kColumnToken:
       case kUnicodeRangeToken:
       case kIdentToken:
-      case kCommaToken:
       case kColonToken:
       case kSemicolonToken:
       case kLeftBraceToken:
@@ -221,6 +276,20 @@
       stack.push_back(SizesCalcValue(left_operand.value / right_operand.value,
                                      left_operand.is_length));
       break;
+    case CSSMathOperator::kMin:
+      if (right_operand.is_length != left_operand.is_length)
+        return false;
+      is_length = (right_operand.is_length && left_operand.is_length);
+      stack.push_back(SizesCalcValue(
+          std::min(left_operand.value, right_operand.value), is_length));
+      break;
+    case CSSMathOperator::kMax:
+      if (right_operand.is_length != left_operand.is_length)
+        return false;
+      is_length = (right_operand.is_length && left_operand.is_length);
+      stack.push_back(SizesCalcValue(
+          std::max(left_operand.value, right_operand.value), is_length));
+      break;
     default:
       return false;
   }
diff --git a/third_party/blink/renderer/core/css/parser/sizes_calc_parser.h b/third_party/blink/renderer/core/css/parser/sizes_calc_parser.h
index fa3b96f..b5ca960 100644
--- a/third_party/blink/renderer/core/css/parser/sizes_calc_parser.h
+++ b/third_party/blink/renderer/core/css/parser/sizes_calc_parser.h
@@ -5,6 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_SIZES_CALC_PARSER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_SIZES_CALC_PARSER_H_
 
+// TODO(crbug.com/825895): Rename the file and classes from "calc" to "math"
+
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/css_math_operator.h"
 #include "third_party/blink/renderer/core/css/media_values.h"
@@ -24,6 +26,8 @@
 
   SizesCalcValue(double numeric_value, bool length)
       : value(numeric_value), is_length(length) {}
+
+  explicit SizesCalcValue(CSSMathOperator op) : operation(op) {}
 };
 
 class CORE_EXPORT SizesCalcParser {
@@ -40,6 +44,8 @@
   bool Calculate();
   void AppendNumber(const CSSParserToken&);
   bool AppendLength(const CSSParserToken&);
+  bool HandleComma(Vector<CSSParserToken>& stack, const CSSParserToken&);
+  bool HandleRightParenthesis(Vector<CSSParserToken>& stack);
   bool HandleOperator(Vector<CSSParserToken>& stack, const CSSParserToken&);
   void AppendOperator(const CSSParserToken&);
 
diff --git a/third_party/blink/renderer/core/css/parser/sizes_calc_parser_test.cc b/third_party/blink/renderer/core/css/parser/sizes_calc_parser_test.cc
index 718e684a..d5e92f8 100644
--- a/third_party/blink/renderer/core/css/parser/sizes_calc_parser_test.cc
+++ b/third_party/blink/renderer/core/css/parser/sizes_calc_parser_test.cc
@@ -5,14 +5,22 @@
 #include "third_party/blink/renderer/core/css/parser/sizes_calc_parser.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/css/css_primitive_value.h"
+#include "third_party/blink/renderer/core/css/css_math_function_value.h"
+#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
 #include "third_party/blink/renderer/core/css/media_values_cached.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
 #include "third_party/blink/renderer/core/media_type_names.h"
+#include "third_party/blink/renderer/platform/fonts/font.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 
 namespace blink {
 
+namespace {
+// |float| has roughly 7 digits of precision.
+const double epsilon = 1e-6;
+}  // namespace
+
 struct SizesCalcTestCase {
   const char* input;
   const float output;
@@ -20,32 +28,42 @@
   const bool dont_run_in_css_calc;
 };
 
+#define EXPECT_APPROX_EQ(expected, actual)            \
+  {                                                   \
+    double actual_error = actual - expected;          \
+    double allowed_error = expected * epsilon;        \
+    EXPECT_LE(abs(actual_error), abs(allowed_error)); \
+  }
+
 static void VerifyCSSCalc(String text,
                           double value,
                           bool valid,
                           unsigned font_size,
                           unsigned viewport_width,
                           unsigned viewport_height) {
-  CSSLengthArray length_array;
   const CSSValue* css_value = CSSParser::ParseSingleValue(
       CSSPropertyID::kLeft, text,
       StrictCSSParserContext(SecureContextMode::kInsecureContext));
-  const auto* primitive_value = To<CSSPrimitiveValue>(css_value);
-  if (primitive_value)
-    primitive_value->AccumulateLengthArray(length_array);
-  else
-    ASSERT_EQ(valid, false);
-  float length = length_array.values.at(CSSPrimitiveValue::kUnitTypePixels);
-  length +=
-      length_array.values.at(CSSPrimitiveValue::kUnitTypeFontSize) * font_size;
-  length += length_array.values.at(CSSPrimitiveValue::kUnitTypeViewportWidth) *
-            viewport_width / 100.0;
-  length += length_array.values.at(CSSPrimitiveValue::kUnitTypeViewportHeight) *
-            viewport_height / 100.0;
-  ASSERT_EQ(value, length);
+  const auto* math_value = DynamicTo<CSSMathFunctionValue>(css_value);
+  if (!math_value) {
+    EXPECT_FALSE(valid) << text;
+    return;
+  }
+
+  ASSERT_TRUE(valid) << text;
+
+  Font font;
+  CSSToLengthConversionData::FontSizes font_sizes(font_size, font_size, &font);
+  CSSToLengthConversionData::ViewportSize viewport_size(viewport_width,
+                                                        viewport_height);
+  CSSToLengthConversionData conversion_data(nullptr, font_sizes, viewport_size,
+                                            1.0);
+  EXPECT_APPROX_EQ(value, math_value->ComputeLength<float>(conversion_data));
 }
 
 TEST(SizesCalcParserTest, Basic) {
+  ScopedCSSComparisonFunctionsForTest scope(true);
+
   SizesCalcTestCase test_cases[] = {
       {"calc(500px + 10em)", 660, true, false},
       {"calc(500px / 8)", 62.5, true, false},
@@ -105,6 +123,33 @@
       {"calc((100vw - 2 * 2 / 2 * 40px - 2 * 30px) / 3)", 120, true, false},
       {"calc((100vw - 2 * 2 * 20px - 2 * 30px) / 3)", 120, true, false},
       {"calc((100vw - 320px / 2 / 2 - 2 * 30px) / 3)", 120, true, false},
+      // Following test cases contain comparison functions.
+      {"min()", 0, false, false},
+      {"min(100px)", 100, true, false},
+      {"min(200px, 100px, 300px, 40px, 1000px)", 40, true, false},
+      {"min( 100px , 200px )", 100, true, false},
+      {"min(100, 200, 300)", 0, false, false},
+      {"min(100, 200px, 300px)", 0, false, false},
+      {"min(100px 200px)", 0, false, false},
+      {"min(100px, , 200px)", 0, false, false},
+      {"min(100px, 200px,)", 0, false, false},
+      {"min(, 100px, 200px)", 0, false, false},
+      {"max()", 0, false, false},
+      {"max(100px)", 100, true, false},
+      {"max(200px, 100px, 300px, 40px, 1000px)", 1000, true, false},
+      {"max( 100px , 200px )", 200, true, false},
+      {"max(100, 200, 300)", 0, false, false},
+      {"max(100, 200px, 300px)", 0, false, false},
+      {"max(100px 200px)", 0, false, false},
+      {"max(100px, , 200px)", 0, false, false},
+      {"max(100px, 200px,)", 0, false, false},
+      {"max(, 100px, 200px)", 0, false, false},
+      {"calc(min(100px, 200px) + max(300px, 400px))", 500, true, false},
+      {"calc(max(300px, 400px) - min(100px, 200px))", 300, true, false},
+      {"calc(min(100px, 200px) * max(3, 4, 5))", 500, true, false},
+      {"calc(min(100px, 200px) / max(3, 4, 5))", 20, true, false},
+      {"max(10px, min(20px, 1em))", 16, true, false},
+      {"min(20px, max(10px, 1em))", 16, true, false},
       {nullptr, 0, true, false}  // Do not remove the terminator line.
   };
 
@@ -130,7 +175,7 @@
         media_values);
     ASSERT_EQ(test_cases[i].valid, calc_parser.IsValid());
     if (calc_parser.IsValid())
-      ASSERT_EQ(test_cases[i].output, calc_parser.Result());
+      EXPECT_APPROX_EQ(test_cases[i].output, calc_parser.Result());
   }
 
   for (unsigned i = 0; test_cases[i].input; ++i) {
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h
index cf7e198..31449902 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -142,6 +142,8 @@
   // lock is locked any time the state is not kUnlocked or kCommitting.
   bool IsLocked() const { return state_ != kUnlocked && state_ != kCommitting; }
 
+  bool UpdateForced() const { return update_forced_; }
+
   // Called when the layout tree is attached. This is used to verify
   // containment.
   void DidAttachLayoutTree();
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
index e9b5ae6d..fcf786b 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
 #include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/dom/text.h"
 #include "third_party/blink/renderer/core/editing/editing_boundary.h"
 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
@@ -48,29 +49,80 @@
   DCHECK(enclosing_block);
   DCHECK_EQ(enclosing_block,
             EnclosingBlock(range.EndPosition(), kCannotCrossEditingBoundary));
-  const HeapVector<Member<Element>>& elements_to_activate =
-      ActivatableLockedInclusiveAncestors(*enclosing_block);
-  for (Element* element : elements_to_activate) {
-    // We save the elements to a vector and go through & activate them one by
-    // one like this because the DOM structure might change due to running event
-    // handlers of the beforeactivate event.
-    element->ActivateDisplayLockIfNeeded();
+  return enclosing_block->ActivateDisplayLockIfNeeded();
+}
+
+bool DisplayLockUtilities::ActivateSelectionRangeIfNeeded(
+    const EphemeralRangeInFlatTree& range) {
+  if (range.IsNull() || range.IsCollapsed())
+    return false;
+  if (!RuntimeEnabledFeatures::DisplayLockingEnabled() ||
+      range.GetDocument().LockedDisplayLockCount() ==
+          range.GetDocument().ActivationBlockingDisplayLockCount())
+    return false;
+  UpdateStyleAndLayoutForRangeIfNeeded(range);
+  HeapHashSet<Member<Element>> elements_to_activate;
+  for (Node& node : range.Nodes()) {
+    DCHECK(!node.GetDocument().NeedsLayoutTreeUpdateForNode(node));
+    const ComputedStyle* style = node.GetComputedStyle();
+    if (!style || style->UserSelect() == EUserSelect::kNone)
+      continue;
+    if (auto* nearest_locked_ancestor = NearestLockedExclusiveAncestor(node))
+      elements_to_activate.insert(nearest_locked_ancestor);
   }
+  for (Element* element : elements_to_activate)
+    element->ActivateDisplayLockIfNeeded();
   return !elements_to_activate.IsEmpty();
 }
 
+bool DisplayLockUtilities::UpdateStyleAndLayoutForRangeIfNeeded(
+    const EphemeralRangeInFlatTree& range) {
+  if (range.IsNull() || range.IsCollapsed())
+    return false;
+  if (!RuntimeEnabledFeatures::DisplayLockingEnabled() ||
+      range.GetDocument().LockedDisplayLockCount() ==
+          range.GetDocument().ActivationBlockingDisplayLockCount())
+    return false;
+  Vector<DisplayLockContext::ScopedForcedUpdate> scoped_forced_update_list_;
+  for (Node& node : range.Nodes()) {
+    for (Element* locked_activatable_ancestor :
+         ActivatableLockedInclusiveAncestors(node)) {
+      DCHECK(locked_activatable_ancestor->GetDisplayLockContext());
+      DCHECK(locked_activatable_ancestor->GetDisplayLockContext()->IsLocked());
+      if (locked_activatable_ancestor->GetDisplayLockContext()->UpdateForced())
+        break;
+      scoped_forced_update_list_.push_back(
+          locked_activatable_ancestor->GetDisplayLockContext()
+              ->GetScopedForcedUpdate());
+    }
+  }
+  if (!scoped_forced_update_list_.IsEmpty())
+    range.GetDocument().UpdateStyleAndLayout();
+  return !scoped_forced_update_list_.IsEmpty();
+}
+
 const HeapVector<Member<Element>>
-DisplayLockUtilities::ActivatableLockedInclusiveAncestors(Element& element) {
+DisplayLockUtilities::ActivatableLockedInclusiveAncestors(const Node& node) {
   HeapVector<Member<Element>> elements_to_activate;
-  const_cast<Element*>(&element)->UpdateDistributionForFlatTreeTraversal();
-  for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(element)) {
+  const_cast<Node*>(&node)->UpdateDistributionForFlatTreeTraversal();
+  if (!RuntimeEnabledFeatures::DisplayLockingEnabled() ||
+      node.GetDocument().LockedDisplayLockCount() ==
+          node.GetDocument().ActivationBlockingDisplayLockCount())
+    return elements_to_activate;
+
+  for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(node)) {
     auto* ancestor_element = DynamicTo<Element>(ancestor);
     if (!ancestor_element)
       continue;
     if (auto* context = ancestor_element->GetDisplayLockContext()) {
-      DCHECK(context->IsActivatable());
       if (!context->IsLocked())
         continue;
+      if (!context->IsActivatable()) {
+        // If we find a non-activatable locked ancestor, then we shouldn't
+        // activate anything.
+        elements_to_activate.clear();
+        return elements_to_activate;
+      }
       elements_to_activate.push_back(ancestor_element);
     }
   }
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
index 3944b4e..83949181 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h
@@ -39,12 +39,22 @@
   static bool ActivateFindInPageMatchRangeIfNeeded(
       const EphemeralRangeInFlatTree& range);
 
-  // Returns activatable-locked inclusive ancestors of |element|.
-  // Note that this function will have failing DCHECKs if |element| is inside a
+  // Activates all locked nodes in |range| that are activatable and doesn't
+  // have user-select:none. Returns true if we activated at least one node.
+  static bool ActivateSelectionRangeIfNeeded(
+      const EphemeralRangeInFlatTree& range);
+
+  // Updates style for all locked nodes in |range|. Returns true if there's at
+  // least one locked node encountered.
+  static bool UpdateStyleAndLayoutForRangeIfNeeded(
+      const EphemeralRangeInFlatTree& range);
+
+  // Returns activatable-locked inclusive ancestors of |node|.
+  // Note that this function will return an empty list if |node| is inside a
   // non-activatable locked subtree (e.g. at least one ancestor is not
   // activatable-locked).
   static const HeapVector<Member<Element>> ActivatableLockedInclusiveAncestors(
-      Element& element);
+      const Node& node);
 
   // Returns the nearest inclusive ancestor of |node| that is display locked.
   static const Element* NearestLockedInclusiveAncestor(const Node& node);
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index ad1ba76..fdbdc08e 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -35,6 +35,7 @@
 #include "base/auto_reset.h"
 #include "base/macros.h"
 #include "base/optional.h"
+#include "base/time/time.h"
 #include "cc/input/overscroll_behavior.h"
 #include "cc/input/scroll_snap_data.h"
 #include "services/metrics/public/cpp/mojo_ukm_recorder.h"
@@ -298,14 +299,12 @@
 #include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
-#include "third_party/blink/renderer/platform/text/date_components.h"
 #include "third_party/blink/renderer/platform/text/platform_locale.h"
 #include "third_party/blink/renderer/platform/web_test_support.h"
 #include "third_party/blink/renderer/platform/weborigin/origin_access_entry.h"
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-#include "third_party/blink/renderer/platform/wtf/date_math.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/hash_functions.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -5900,10 +5899,9 @@
   }
 }
 
-// http://www.whatwg.org/specs/web-apps/current-work/#dom-document-lastmodified
+// https://html.spec.whatwg.org/C#dom-document-lastmodified
 String Document::lastModified() const {
-  // TODO(tkent): Use base::Time::LocalExplode() instead of DateComponents.
-  DateComponents date;
+  base::Time::Exploded exploded;
   bool found_date = false;
   AtomicString http_last_modified = override_last_modified_;
   if (http_last_modified.IsEmpty() && frame_) {
@@ -5915,8 +5913,7 @@
   if (!http_last_modified.IsEmpty()) {
     base::Optional<base::Time> date_value = ParseDate(http_last_modified);
     if (date_value) {
-      date.SetMillisecondsSinceEpochForDateTimeLocal(
-          ConvertToLocalTime(date_value.value()).InMillisecondsF());
+      date_value.value().LocalExplode(&exploded);
       found_date = true;
     }
   }
@@ -5924,12 +5921,11 @@
   // specificiation tells us to read the last modification date from the file
   // system.
   if (!found_date) {
-    date.SetMillisecondsSinceEpochForDateTimeLocal(
-        ConvertToLocalTime(base::Time::Now()).InMillisecondsF());
+    base::Time::Now().LocalExplode(&exploded);
   }
-  return String::Format("%02d/%02d/%04d %02d:%02d:%02d", date.Month() + 1,
-                        date.MonthDay(), date.FullYear(), date.Hour(),
-                        date.Minute(), date.Second());
+  return String::Format("%02d/%02d/%04d %02d:%02d:%02d", exploded.month,
+                        exploded.day_of_month, exploded.year, exploded.hour,
+                        exploded.minute, exploded.second);
 }
 
 void Document::SetFindInPageRoot(Element* find_in_page_root) {
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index ab9fabe..b424597 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3821,9 +3821,11 @@
          !DisplayLockPreventsActivation();
 }
 
-void Element::ActivateDisplayLockIfNeeded() {
-  if (!RuntimeEnabledFeatures::DisplayLockingEnabled())
-    return;
+bool Element::ActivateDisplayLockIfNeeded() {
+  if (!RuntimeEnabledFeatures::DisplayLockingEnabled() ||
+      GetDocument().LockedDisplayLockCount() ==
+          GetDocument().ActivationBlockingDisplayLockCount())
+    return false;
   const_cast<Element*>(this)->UpdateDistributionForFlatTreeTraversal();
 
   HeapVector<std::pair<Member<Element>, Member<Element>>> activatable_targets;
@@ -3834,23 +3836,26 @@
     if (auto* context = ancestor_element->GetDisplayLockContext()) {
       // If any of the ancestors is not activatable, we can't activate.
       if (!context->IsActivatable())
-        return;
+        return false;
       activatable_targets.push_back(std::make_pair(
           ancestor_element, &ancestor.GetTreeScope().Retarget(*this)));
     }
   }
 
+  bool activated = false;
   for (const auto& target : activatable_targets) {
     // Dispatch event on activatable ancestor (target.first), with
     // the retargeted element (target.second) as the |activatedElement|.
     if (auto* context = target.first->GetDisplayLockContext()) {
       if (context->ShouldCommitForActivation()) {
+        activated = true;
         target.first->DispatchEvent(
             *MakeGarbageCollected<BeforeActivateEvent>(*target.second));
         context->CommitForActivation();
       }
     }
   }
+  return activated;
 }
 
 bool Element::DisplayLockPreventsActivation() const {
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index f924460..6d0e470 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -916,7 +916,9 @@
   bool StyleRecalcBlockedByDisplayLock(
       DisplayLockContext::LifecycleTarget) const;
 
-  void ActivateDisplayLockIfNeeded();
+  // Activates all activatable locked ancestors for this element. Return true if
+  // we activated at least one previously locked element.
+  bool ActivateDisplayLockIfNeeded();
 
   virtual void SetActive(bool active);
   virtual void SetHovered(bool hovered);
diff --git a/third_party/blink/renderer/core/dom/mutation_observer.cc b/third_party/blink/renderer/core/dom/mutation_observer.cc
index 6405538..e917882 100644
--- a/third_party/blink/renderer/core/dom/mutation_observer.cc
+++ b/third_party/blink/renderer/core/dom/mutation_observer.cc
@@ -239,10 +239,13 @@
 
 void MutationObserver::EnqueueMutationRecord(MutationRecord* mutation) {
   DCHECK(IsMainThread());
+  ExecutionContext* execution_context = delegate_->GetExecutionContext();
+  // This might get called when the execution context is gone. crbug.com/982850
+  if (!execution_context)
+    return;
   records_.push_back(mutation);
   Activate();
-  probe::AsyncTaskScheduled(delegate_->GetExecutionContext(), mutation->type(),
-                            mutation);
+  probe::AsyncTaskScheduled(execution_context, mutation->type(), mutation);
 }
 
 void MutationObserver::SetHasTransientRegistration() {
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index 86a70c1..0207bb5 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
 #include "third_party/blink/renderer/core/dom/attr.h"
 #include "third_party/blink/renderer/core/dom/attribute.h"
 #include "third_party/blink/renderer/core/dom/child_list_mutation_scope.h"
@@ -1571,6 +1572,8 @@
 // FIXME: Shouldn't these functions be in the editing code?  Code that asks
 // questions about HTML in the core DOM class is obviously misplaced.
 bool Node::CanStartSelection() const {
+  if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*this))
+    GetDocument().UpdateStyleAndLayoutTreeForNode(this);
   if (HasEditableStyle(*this))
     return true;
 
diff --git a/third_party/blink/renderer/core/editing/ephemeral_range.cc b/third_party/blink/renderer/core/editing/ephemeral_range.cc
index 081263d7..8b9e78a 100644
--- a/third_party/blink/renderer/core/editing/ephemeral_range.cc
+++ b/third_party/blink/renderer/core/editing/ephemeral_range.cc
@@ -210,6 +210,23 @@
   return PrintEphemeralRange(ostream, range);
 }
 
+EphemeralRangeInFlatTree ToEphemeralRangeInFlatTree(
+    const EphemeralRange& range) {
+  PositionInFlatTree start = ToPositionInFlatTree(range.StartPosition());
+  PositionInFlatTree end = ToPositionInFlatTree(range.EndPosition());
+  if (start.IsNull() || end.IsNull() ||
+      start.GetDocument() != end.GetDocument())
+    return EphemeralRangeInFlatTree();
+  start.AnchorNode()->UpdateDistributionForFlatTreeTraversal();
+  end.AnchorNode()->UpdateDistributionForFlatTreeTraversal();
+  if (!start.IsValidFor(*start.GetDocument()) ||
+      !end.IsValidFor(*end.GetDocument()))
+    return EphemeralRangeInFlatTree();
+  if (start <= end)
+    return EphemeralRangeInFlatTree(start, end);
+  return EphemeralRangeInFlatTree(end, start);
+}
+
 template class CORE_TEMPLATE_EXPORT EphemeralRangeTemplate<EditingStrategy>;
 template class CORE_TEMPLATE_EXPORT
     EphemeralRangeTemplate<EditingInFlatTreeStrategy>;
diff --git a/third_party/blink/renderer/core/editing/ephemeral_range.h b/third_party/blink/renderer/core/editing/ephemeral_range.h
index f78232d..3e15fb2 100644
--- a/third_party/blink/renderer/core/editing/ephemeral_range.h
+++ b/third_party/blink/renderer/core/editing/ephemeral_range.h
@@ -153,6 +153,9 @@
 CORE_EXPORT std::ostream& operator<<(std::ostream&,
                                      const EphemeralRangeInFlatTree&);
 
+CORE_EXPORT EphemeralRangeInFlatTree
+ToEphemeralRangeInFlatTree(const EphemeralRange&);
+
 }  // namespace blink
 
 #endif
diff --git a/third_party/blink/renderer/core/editing/frame_selection.cc b/third_party/blink/renderer/core/editing/frame_selection.cc
index 8567849e..d299253d 100644
--- a/third_party/blink/renderer/core/editing/frame_selection.cc
+++ b/third_party/blink/renderer/core/editing/frame_selection.cc
@@ -29,6 +29,7 @@
 #include "third_party/blink/public/platform/web_scroll_into_view_params.h"
 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
 #include "third_party/blink/renderer/core/dom/character_data.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
@@ -237,6 +238,8 @@
   if (is_changed) {
     AssertUserSelection(new_selection, options);
     selection_editor_->SetSelectionAndEndTyping(new_selection);
+    DisplayLockUtilities::ActivateSelectionRangeIfNeeded(
+        ToEphemeralRangeInFlatTree(new_selection.ComputeRange()));
   }
   is_directional_ = options.IsDirectional();
   should_shrink_next_tap_ = options.ShouldShrinkNextTap();
diff --git a/third_party/blink/renderer/core/editing/visible_units.cc b/third_party/blink/renderer/core/editing/visible_units.cc
index 0913662..bd5727e9 100644
--- a/third_party/blink/renderer/core/editing/visible_units.cc
+++ b/third_party/blink/renderer/core/editing/visible_units.cc
@@ -450,6 +450,8 @@
 // the text node. It seems weird to return false in this case.
 bool HasRenderedNonAnonymousDescendantsWithHeight(
     const LayoutObject* layout_object) {
+  if (DisplayLockUtilities::NearestLockedInclusiveAncestor(*layout_object))
+    return false;
   const LayoutObject* stop = layout_object->NextInPreOrderAfterChildren();
   // TODO(editing-dev): Avoid single-character parameter names.
   for (LayoutObject* o = layout_object->SlowFirstChild(); o && o != stop;
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index e2b9189..a525e46 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -141,8 +141,13 @@
                 kAcceleratedCompositedResourceUsage;
           }
         } else {
-          usage = CanvasResourceProvider::ResourceUsage::
-              kSoftwareCompositedResourceUsage;
+          if (LowLatencyEnabled()) {
+            usage = CanvasResourceProvider::ResourceUsage::
+                kSoftwareCompositedDirect2DResourceUsage;
+          } else {
+            usage = CanvasResourceProvider::ResourceUsage::
+                kSoftwareCompositedResourceUsage;
+          }
         }
 
         const CanvasResourceProvider::PresentationMode presentation_mode =
diff --git a/third_party/blink/renderer/core/html/forms/resources/color_picker.css b/third_party/blink/renderer/core/html/forms/resources/color_picker.css
index a54b79d..aa7cd80 100644
--- a/third_party/blink/renderer/core/html/forms/resources/color_picker.css
+++ b/third_party/blink/renderer/core/html/forms/resources/color_picker.css
@@ -19,75 +19,6 @@
   height: 59%;
 }
 
-color-well {
-  border-radius: 2px 2px 0px 0px;
-  display: block;
-  height: 77%;
-  position: relative;
-  overflow: hidden;
-}
-
-hue-slider {
-  height: 100%;
-  margin-left: 6%;
-  position: relative;
-  width: 130px;
-}
-
-#visual-color-picker-strip {
-  display: flex;
-  height: 18%;
-  margin-top: 3%;
-  position: relative;
-}
-
-eye-dropper {
-  height: 32px;
-  margin-left: 2%;
-  position: relative;
-  width: 32px;
-}
-
-color-viewer {
-  border: 1px solid rgba(0, 0, 0, 0.19);
-  border-radius: 50%;
-  box-sizing: border-box;
-  height: 32px;
-  margin-left: 2%;
-  width: 32px;
-}
-
-color-well > canvas {
-  height: 100%;
-  width: 100%;
-}
-
-hue-slider > canvas {
-  border-radius: 2px;
-  height: 11px;
-  margin-top: 7%;
-  width: 100%;
-}
-
-color-selection-ring {
-  border: 2px solid #FFFFFF;
-  border-radius: 50%;
-  box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.4);
-  box-sizing: border-box;
-  position: absolute;
-}
-
-color-well > color-selection-ring {
-  height: 12px;
-  width: 12px;
-}
-
-hue-slider > color-selection-ring {
-  height: 16px;
-  margin-top: 7%;
-  width: 16px;
-}
-
 manual-color-picker {
   height: 28%;
 }
diff --git a/third_party/blink/renderer/core/html/forms/resources/color_picker.js b/third_party/blink/renderer/core/html/forms/resources/color_picker.js
index 0eb00142..218d8196 100644
--- a/third_party/blink/renderer/core/html/forms/resources/color_picker.js
+++ b/third_party/blink/renderer/core/html/forms/resources/color_picker.js
@@ -158,7 +158,8 @@
           Color.hexToRGB(this.hexValue_);
     } else if (this.hValue_ !== undefined) {
       [this.rValue_, this.gValue_, this.bValue_] =
-          Color.hslToRGB(this.hValue_, this.sValue_, this.lValue_);
+          Color.hslToRGB(this.hValue_, this.sValue_, this.lValue_)
+          .map(Math.round);
     }
   }
 
@@ -199,10 +200,11 @@
       // Already computed.
     } else if (this.rValue_ !== undefined) {
       [this.hValue_, this.sValue_, this.lValue_] =
-          Color.rgbToHSL(this.rValue_, this.gValue_, this.bValue_);
+          Color.rgbToHSL(this.rValue_, this.gValue_, this.bValue_)
+          .map(Math.round);
     } else if (this.hexValue_ !== undefined) {
       [this.hValue_, this.sValue_, this.lValue_] =
-          Color.hexToHSL(this.hexValue_);
+          Color.hexToHSL(this.hexValue_).map(Math.round);
     }
   }
 
@@ -286,9 +288,9 @@
         bValue = x;
       }
     }
-    rValue = Math.round((rValue + match) * 255);
-    gValue = Math.round((gValue + match) * 255);
-    bValue = Math.round((bValue + match) * 255);
+    rValue = (rValue + match) * 255;
+    gValue = (gValue + match) * 255;
+    bValue = (bValue + match) * 255;
     return [rValue, gValue, bValue];
   }
 
@@ -315,13 +317,13 @@
         // max === bValue
         hValue = ((rValue - gValue) / diff) + 4;
       }
-      hValue = Math.round(hValue * 60);
+      hValue *= 60;
       if (hValue < 0) {
         hValue += 360;
       }
-      sValue = Math.round((diff / (1 - Math.abs(2 * lValue - 1))) * 100);
+      sValue = (diff / (1 - Math.abs(2 * lValue - 1))) * 100;
     }
-    lValue = Math.round(lValue * 100);
+    lValue *= 100;
     return [hValue, sValue, lValue];
   }
 
@@ -330,7 +332,7 @@
    * @returns {string}
    */
   static hslToHex(...hslValues) {
-    return Color.rgbToHex(...Color.hslToRGB(...hslValues));
+    return Color.rgbToHex(...Color.hslToRGB(...hslValues).map(Math.round));
   }
 
   /**
@@ -340,61 +342,6 @@
   static hexToHSL(hexValue) {
     return Color.rgbToHSL(...Color.hexToRGB(hexValue));
   }
-
-  /**
-   * @param {number[]} colorTripleA RGB or HSL values
-   * @param {number[]} colorTripleB RGB or HSL values
-   * Both color triples must be of the same color format.
-   */
-  static distance(colorTripleA, colorTripleB) {
-    return Math.sqrt(Math.pow(colorTripleA[0] - colorTripleB[0], 2)
-        + Math.pow(colorTripleA[1] - colorTripleB[1], 2)
-        + Math.pow(colorTripleA[2] - colorTripleB[2], 2));
-  }
-}
-
-/**
- * Point: Helper class to get/set coordinates for two dimensional points.
- */
-class Point {
-  /**
-   * @param {number} x
-   * @param {number} y
-   */
-  constructor(x, y) {
-    this.set(x, y);
-  }
-
-  /**
-   * @param {number} x
-   * @param {number} y
-   */
-  set(x, y) {
-    this.x = x;
-    this.y = y;
-  }
-
-  get x() {
-    return this.x_;
-  }
-
-  /**
-   * @param {number} x
-   */
-  set x(x) {
-    this.x_ = x;
-  }
-
-  get y() {
-    return this.y_;
-  }
-
-  /**
-   * @param {number} y
-   */
-  set y(y) {
-    this.y_ = y;
-  }
 }
 
 /**
@@ -422,15 +369,8 @@
                 this.manualColorPicker_,
                 this.submissionControls_);
 
-    this.visualColorPicker_.addEventListener('visual-color-picker-initialized',
-        this.initializeListeners_);
-  }
-
-  initializeListeners_ = () => {
     this.manualColorPicker_
         .addEventListener('manual-color-change', this.onManualColorChange_);
-
-    this.addEventListener('visual-color-change', this.onVisualColorChange_);
   }
 
   get selectedColor() {
@@ -451,36 +391,7 @@
     const newColor = event.detail.color;
     if (!this.selectedColor.equals(newColor)) {
       this.selectedColor = newColor;
-
-      // There may not be an exact match for newColor in the HueSlider or
-      // ColorWell, in which case we will display the closest match. When this
-      // happens though, we want the manually chosen values to remain the
-      // selected values (as they were explicitly specified by the user).
-      // Therefore, we need to prevent them from getting overwritten when
-      // onVisualColorChange_ runs. We do this by setting the
-      // processingManualColorChange_ flag here and checking for it inside
-      // onVisualColorChange_. If the flag is set, the manual color values
-      // will not be updated with the color shown in the visual color picker.
-      this.processingManualColorChange_ = true;
-      this.visualColorPicker_.color = newColor;
-      this.processingManualColorChange_ = false;
-    }
-  }
-
-  /**
-   * @param {!Event} event
-   */
-  onVisualColorChange_ = (event) => {
-    const newColor = event.detail.color;
-    if (!this.selectedColor.equals(newColor)) {
-      if (!this.processingManualColorChange_) {
-        this.selectedColor = newColor;
-        this.manualColorPicker_.color = newColor;
-      } else {
-        // We are making a visual color change in response to a manual color
-        // change. So we do not overwrite the manually specified values and do
-        // not change the selected color.
-      }
+      this.visualColorPicker_.setSelectedColor(newColor);
     }
   }
 
@@ -500,6 +411,8 @@
 /**
  * VisualColorPicker: Provides functionality to see the selected color and
  *                    select a different color visually.
+ * TODO(crbug.com/983311): Allow colors to be selected from within the visual
+ *                         color picker.
  */
 class VisualColorPicker extends HTMLElement {
   /**
@@ -508,675 +421,19 @@
   constructor(initialColor) {
     super();
 
-    let visualColorPickerStrip = document.createElement('span');
-    visualColorPickerStrip.setAttribute('id', 'visual-color-picker-strip');
-    this.eyeDropper_ = new EyeDropper();
-    this.colorViewer_ = new ColorViewer(initialColor);
-    this.hueSlider_ = new HueSlider(initialColor);
-    visualColorPickerStrip.append(this.eyeDropper_,
-                                  this.colorViewer_,
-                                  this.hueSlider_);
-    this.append(visualColorPickerStrip);
-
-    this.colorWell_ = new ColorWell(initialColor);
-    this.prepend(this.colorWell_);
-
-    this.colorWell_.addEventListener('color-well-initialized', () => {
-      this.initializeListeners_();
-    });
-
-    this.hueSlider_.addEventListener('hue-slider-initialized', () => {
-      this.initializeListeners_();
-    });
-  }
-
-  initializeListeners_ = () => {
-    if (this.colorWell_.initialized && this.hueSlider_.initialized) {
-      this.addEventListener('hue-slider-update', this.onHueSliderUpdate_);
-      this.addEventListener('visual-color-change', this.onVisualColorChange_);
-      this.colorWell_
-          .addEventListener('mousedown', this.onColorWellMouseDown_);
-      this.hueSlider_
-          .addEventListener('mousedown', this.onHueSliderMouseDown_);
-      this.colorWell_
-          .addEventListener('mousedown', (event) => event.preventDefault());
-      this.hueSlider_
-          .addEventListener('mousedown', (event) => event.preventDefault());
-      document.documentElement
-          .addEventListener('mousemove', this.onMouseMove_);
-      document.documentElement.addEventListener('mouseup', this.onMouseUp_);
-
-      this.dispatchEvent(new CustomEvent('visual-color-picker-initialized'));
-    }
-  }
-
-  onHueSliderUpdate_ = () => {
-    this.colorWell_.fillColor = this.hueSlider_.color;
-  }
-
-  /**
-   * @param {!Event} event
-   */
-  onVisualColorChange_ = (event) => {
-    this.colorViewer_.color = event.detail.color;
-  }
-
-  /**
-   * @param {!Event} event
-   */
-  onColorWellMouseDown_ = (event) => {
-    this.colorWell_.mouseDown(new Point(event.clientX, event.clientY));
-  }
-
-  /**
-   * @param {!Event} event
-   */
-  onMouseMove_ = (event) => {
-    var point = new Point(event.clientX, event.clientY);
-    this.colorWell_.mouseMove(point);
-    this.hueSlider_.mouseMove(point);
-  }
-
-  onMouseUp_ = () => {
-    this.colorWell_.mouseUp();
-    this.hueSlider_.mouseUp();
-  }
-
-  /**
-   * @param {!Event} event
-   */
-  onHueSliderMouseDown_ = (event) => {
-    this.hueSlider_.mouseDown(new Point(event.clientX, event.clientY));
+    this.setSelectedColor(initialColor);
   }
 
   /**
    * @param {!Color} newColor
    */
-  set color(newColor) {
-    this.hueSlider_.color = newColor;
-    this.colorWell_.selectedColor = newColor;
+  setSelectedColor(newColor) {
+    this.style.backgroundColor = newColor.asHex();
   }
 }
 window.customElements.define('visual-color-picker', VisualColorPicker);
 
 /**
- * EyeDropper: Allows color selection from content outside the color picker.
- *             (This is currently just a placeholder for a future
- *             implementation.)
- * TODO(http://crbug.com/992297): Implement eye dropper
- */
-class EyeDropper extends HTMLElement { }
-window.customElements.define('eye-dropper', EyeDropper);
-
-/**
- * ColorViewer: Provides a view of the selected color.
- */
-class ColorViewer extends HTMLElement {
-  /**
-   * @param {!Color} initialColor
-   */
-  constructor(initialColor) {
-    super();
-
-    this.color = initialColor;
-  }
-
-  get color() {
-    return this.color_;
-  }
-
-  /**
-   * @param {!Color} color
-   */
-  set color(color) {
-    if (this.color_ === undefined || !this.color_.equals(color)) {
-      this.color_ = color;
-      this.style.backgroundColor = color.asRGB();
-    }
-  }
-}
-window.customElements.define('color-viewer', ColorViewer);
-
-/**
- * ColorSelectionArea: Base class for ColorWell and HueSlider that encapsulates
- *                     a ColorPalette and a ColorSelectionRing.
- */
-class ColorSelectionArea extends HTMLElement {
-  constructor() {
-    super();
-
-    this.colorPalette_ = new ColorPalette();
-    this.colorSelectionRing_ = new ColorSelectionRing(this.colorPalette_);
-    this.append(this.colorPalette_, this.colorSelectionRing_);
-    this.initialized_ = false;
-  }
-
-  get initialized() {
-    return this.initialized_;
-  }
-
-  /**
-   * @param {!Point} point
-   */
-  mouseDown(point) {
-    this.colorSelectionRing_.drag = true;
-    this.moveColorSelectionRingTo_(point);
-  }
-
-  /**
-   * @param {!Point} point
-   */
-  mouseMove(point) {
-    if (this.colorSelectionRing_.drag) {
-      this.moveColorSelectionRingTo_(point);
-    }
-  }
-
-  mouseUp() {
-    this.colorSelectionRing_.drag = false;
-  }
-}
-window.customElements.define('color-selection-area', ColorSelectionArea);
-
-/**
- * ColorPalette: Displays a range of colors.
- */
-class ColorPalette extends HTMLCanvasElement {
-  constructor() {
-    super();
-
-    this.gradients_ = [];
-  }
-
-  /**
-   * @param {...CanvasGradient} gradients
-   */
-  initialize(...gradients) {
-    this.width = this.offsetWidth;
-    this.height = this.offsetHeight;
-    this.renderingContext.rect(0, 0, this.width, this.height);
-    this.gradients_.push(...gradients);
-    this.fillColor = new Color('hsl(0, 100%, 50%)');
-  }
-
-  get hslImageData() {
-    if (this.pendingColorChange_) {
-      const rgbaImageData = this.renderingContext
-          .getImageData(0, 0, this.width, this.height).data;
-      this.hslImageData_ = rgbaImageData
-          .reduce((hslArray, {}, currentIndex, rgbaArray) => {
-            if ((currentIndex % 4) === 0) {
-              hslArray.push(...Color.rgbToHSL(rgbaArray[currentIndex],
-                                              rgbaArray[currentIndex + 1],
-                                              rgbaArray[currentIndex + 2]));
-            }
-            return hslArray;
-          }, []);
-      this.pendingColorChange_ = false;
-    }
-    if (this.pendingHueChange_) {
-      const hValueToSet = this.fillColor.hValue;
-      this.hslImageData_.forEach(({}, currentIndex, hslArray) => {
-        if ((currentIndex % 3) === 0) {
-          hslArray[currentIndex] = hValueToSet;
-        }
-      });
-
-      this.pendingHueChange_ = false;
-    }
-    return this.hslImageData_;
-  }
-
-  /**
-   * @param {!Point} point
-   */
-  colorAtPoint(point) {
-    const hslImageDataAtPoint =
-        this.hslImageDataAtPoint_(point.x - this.left, point.y - this.top);
-    return new Color(ColorFormat.HSL, hslImageDataAtPoint[0],
-        hslImageDataAtPoint[1], hslImageDataAtPoint[2]);
-  }
-
-  /**
-   * @param {number} x
-   * @param {number} y
-   */
-  hslImageDataAtPoint_(x, y) {
-    const offset = Math.round(y * this.width + x) * 3;
-    return this.hslImageData.slice(offset, offset + 3);
-  }
-
-  get renderingContext() {
-    return this.getContext('2d');
-  }
-
-  get fillColor() {
-    return this.fillColor_;
-  }
-
-  /**
-   * @param {!Color} color
-   */
-  set fillColor(color) {
-    this.fillColor_ = color;
-    this.fillColorAndGradients_();
-    this.pendingColorChange_ = true;
-  }
-
-  /**
-   * @param {!Color} color
-   */
-  fillHue(color) {
-    this.fillColor_ = new Color(ColorFormat.HSL, color.hValue,
-        this.fillColor_.sValue, this.fillColor_.lValue);
-    this.fillColorAndGradients_();
-    this.pendingHueChange_ = true;
-  }
-
-  fillColorAndGradients_() {
-    this.fillWithStyle_(this.fillColor_.asRGB());
-    this.gradients_.forEach((gradient) => this.fillWithStyle_(gradient));
-  }
-
-  /**
-   * @param {string|!CanvasGradient} fillStyle
-   */
-  fillWithStyle_(fillStyle) {
-    let colorPaletteCtx = this.renderingContext;
-    colorPaletteCtx.fillStyle = fillStyle;
-    colorPaletteCtx.fill();
-  }
-
-  /**
-   * @param {!Point} point
-   */
-  nearestPointOnColorPalette(point) {
-    if (!this.isXCoordinateOnColorPalette_(point)) {
-      if (point.x >= this.right) {
-        point.x = this.right - 1;
-      } else if (point.x < this.left) {
-        point.x = this.left;
-      }
-    }
-    if (!this.isYCoordinateOnColorPalette_(point)) {
-      if (point.y >= this.bottom) {
-        point.y = this.bottom - 1;
-      } else if (point.y < this.top) {
-        point.y = this.top;
-      }
-    }
-    return point;
-  }
-
-  /**
-   * @param {!Point} point
-   */
-  isXCoordinateOnColorPalette_(point) {
-    return (point.x >= this.left) && (point.x < this.right);
-  }
-
-  /**
-   * @param {!Point} point
-   */
-  isYCoordinateOnColorPalette_(point) {
-    return (point.y >= this.top) && (point.y < this.bottom);
-  }
-
-  get left() {
-    return this.getBoundingClientRect().left;
-  }
-
-  get right() {
-    return this.getBoundingClientRect().right;
-  }
-
-  get top() {
-    return this.getBoundingClientRect().top;
-  }
-
-  get bottom() {
-    return this.getBoundingClientRect().bottom;
-  }
-}
-window.customElements.define('color-palette',
-                             ColorPalette,
-                             { extends: 'canvas' });
-
-/**
- * ColorSelectionRing: Provides movement and color selection functionality to
- *                     pick colors from a given ColorPalette.
- */
-class ColorSelectionRing extends HTMLElement {
-  /**
-   * @param {!ColorPalette} backingColorPalette
-   */
-  constructor(backingColorPalette) {
-    super();
-
-    this.backingColorPalette_ = backingColorPalette;
-    this.position_ = new Point(0, 0);
-    this.drag_ = false;
-  }
-
-  initialize() {
-    this.set(this.backingColorPalette_.left, this.backingColorPalette_.top);
-  }
-
-  /**
-   * @param {!Point} newPosition
-   */
-  moveTo(newPosition) {
-    this.set(newPosition.x, newPosition.y);
-  }
-
-  /**
-   * @param {number} x
-   * @param {number} y
-   */
-  set(x, y) {
-    if ((x !== this.position_.x) || (y !== this.position_.y)) {
-      this.position_.x = x;
-      this.position_.y = y;
-      this.onPositionChange_();
-    }
-  }
-
-  /**
-   * @param {number} x
-   */
-  setX(x) {
-    if (x !== this.position_.x) {
-      this.position_.x = x;
-      this.onPositionChange_();
-    }
-  }
-
-  /**
-   * @param {number} shiftFactor
-   */
-  shiftX(shiftFactor) {
-    this.setX(this.position_.x + shiftFactor);
-  }
-
-  onPositionChange_() {
-    this.setElementPosition_();
-    this.updateColor();
-  }
-
-  setElementPosition_() {
-    if (this.height > this.backingColorPalette_.height) {
-      this.style.top = this.top
-          - (this.height - this.backingColorPalette_.height) / 2
-          - this.backingColorPalette_.top + 'px';
-    } else {
-      this.style.top = this.top - this.radius
-          - this.backingColorPalette_.top + 'px';
-    }
-    if (this.width > this.backingColorPalette_.width) {
-      this.style.left = this.left
-          - (this.width - this.backingColorPalette_.width) / 2
-          - this.backingColorPalette_.left + 'px';
-    } else {
-      this.style.left = this.left - this.radius
-          - this.backingColorPalette_.left + 'px';
-    }
-  }
-
-  updateColor() {
-    this.color = this.backingColorPalette_.colorAtPoint(this.position_);
-    this.dispatchEvent(new CustomEvent('color-selection-ring-update'));
-  }
-
-  get color() {
-    return this.color_;
-  }
-
-  /**
-   * @param {!Color} color
-   */
-  set color(color) {
-    if (this.color_ === undefined || !this.color_.equals(color)) {
-      this.color_ = color;
-      this.style.backgroundColor = color.asRGB();
-    }
-  }
-
-  get drag() {
-    return this.drag_;
-  }
-
-  /**
-   * @param {boolean} drag
-   */
-  set drag(drag) {
-    this.drag_ = drag;
-  }
-
-  get radius() {
-    return this.width / 2;
-  }
-
-  get width() {
-    return this.getBoundingClientRect().width;
-  }
-
-  get height() {
-    return this.getBoundingClientRect().height;
-  }
-
-  get left() {
-    return this.position_.x;
-  }
-
-  get top() {
-    return this.position_.y;
-  }
-}
-window.customElements.define('color-selection-ring', ColorSelectionRing);
-
-/**
- * ColorWell: Allows selection from a range of colors, between black and white,
- *            that have the same hue value.
- */
-class ColorWell extends ColorSelectionArea {
-  /**
-   * @param {!Color} initialColor
-   */
-  constructor(initialColor) {
-    super();
-
-    this.fillColor_ = new Color(ColorFormat.HSL, initialColor.hValue, 100, 50);
-    this.selectedColor_ = initialColor;
-
-    this.resizeObserver_ = new ResizeObserver(() => {
-      let whiteGradient = this.colorPalette_.renderingContext
-          .createLinearGradient(0, 0, this.colorPalette_.offsetWidth, 0);
-      whiteGradient.addColorStop(0.01, 'hsla(0, 0%, 100%, 1)');
-      whiteGradient.addColorStop(0.99, 'hsla(0, 0%, 100%, 0)');
-      let blackGradient = this.colorPalette_.renderingContext
-          .createLinearGradient(0, this.colorPalette_.offsetHeight, 0, 0);
-      blackGradient.addColorStop(0.01, 'hsla(0, 0%, 0%, 1)');
-      blackGradient.addColorStop(0.99, 'hsla(0, 0%, 0%, 0)');
-      this.colorPalette_.initialize(whiteGradient, blackGradient);
-      this.colorPalette_.fillHue(this.fillColor_);
-      this.colorSelectionRing_.initialize();
-
-      this.colorSelectionRing_.addEventListener('color-selection-ring-update',
-          this.onColorSelectionRingUpdate_);
-
-      this.moveColorSelectionRingTo_(this.selectedColor_);
-
-      this.resizeObserver_.disconnect();
-      this.resizeObserver_ = null;
-
-      this.initialized_ = true;
-      this.dispatchEvent(new CustomEvent('color-well-initialized'));
-    });
-    this.resizeObserver_.observe(this);
-  }
-
-  /**
-   * @param {!Point|!Color} newPositionOrColor
-   */
-  moveColorSelectionRingTo_(newPositionOrColor) {
-    if (newPositionOrColor instanceof Point) {
-      const point =
-          this.colorPalette_.nearestPointOnColorPalette(newPositionOrColor);
-      this.colorSelectionRing_.moveTo(point);
-    } else {
-      const closestHSLValueIndex = this.colorPalette_.hslImageData
-          .reduce((closestSoFar, {}, index, array) => {
-            if ((index % 3) === 0) {
-              const currentHSLValueDistance = Color.distance([array[index],
-                  array[index + 1], array[index + 2]],
-                    newPositionOrColor.hslValues());
-              const closestHSLValueDistance =
-                  Color.distance([array[closestSoFar], array[closestSoFar + 1],
-                    array[closestSoFar + 2]], newPositionOrColor.hslValues());
-              if (currentHSLValueDistance < closestHSLValueDistance) {
-                return index;
-              }
-            }
-            return closestSoFar;
-          }, 0);
-      const offsetX = (closestHSLValueIndex / 3) % this.colorPalette_.width;
-      const offsetY =
-          Math.floor((closestHSLValueIndex / 3) / this.colorPalette_.width);
-      this.colorSelectionRing_.set(this.colorPalette_.left + offsetX,
-                                  this.colorPalette_.top + offsetY);
-    }
-  }
-
-  get selectedColor() {
-    return this.selectedColor_;
-  }
-
-  /**
-   * @param {!Color} newColor
-   */
-  set selectedColor(newColor) {
-    if (!this.selectedColor_.equals(newColor)) {
-      this.selectedColor_ = newColor;
-      this.moveColorSelectionRingTo_(newColor);
-    }
-  }
-
-  get fillColor() {
-    return this.fillColor_;
-  }
-
-  /**
-   * @param {!Color} color
-   */
-  set fillColor(color) {
-    if (!this.fillColor_.equals(color)) {
-      this.fillColor_ = color;
-      this.colorPalette_.fillHue(color);
-      this.colorSelectionRing_.updateColor();
-    }
-  }
-
-  onColorSelectionRingUpdate_ = () => {
-    this.selectedColor_ = this.colorSelectionRing_.color;
-    this.dispatchEvent(new CustomEvent('visual-color-change', {
-      bubbles: true,
-      detail: {
-        color: this.selectedColor
-      }
-    }));
-  }
-}
-window.customElements.define('color-well', ColorWell);
-
-/**
- * HueSlider: Allows selection from a range of colors with distinct hue values.
- */
-class HueSlider extends ColorSelectionArea {
-  /**
-   * @param {!Color} initialColor
-   */
-  constructor(initialColor) {
-    super();
-
-    this.color_ = new Color(ColorFormat.HSL, initialColor.hValue, 100, 50);
-
-    this.resizeObserver_ = new ResizeObserver(() => {
-      let hueSliderPaletteGradient = this.colorPalette_.renderingContext
-          .createLinearGradient(0, 0, this.colorPalette_.offsetWidth, 0);
-      hueSliderPaletteGradient.addColorStop(0.01, 'hsl(0, 100%, 50%)');
-      hueSliderPaletteGradient.addColorStop(0.17, 'hsl(300, 100%, 50%)');
-      hueSliderPaletteGradient.addColorStop(0.33, 'hsl(240, 100%, 50%)');
-      hueSliderPaletteGradient.addColorStop(0.5, 'hsl(180, 100%, 50%)');
-      hueSliderPaletteGradient.addColorStop(0.67, 'hsl(120, 100%, 50%)');
-      hueSliderPaletteGradient.addColorStop(0.83, 'hsl(60, 100%, 50%)');
-      hueSliderPaletteGradient.addColorStop(0.99, 'hsl(0, 100%, 50%)');
-      this.colorPalette_.initialize(hueSliderPaletteGradient);
-      this.colorSelectionRing_.initialize();
-
-      this.colorSelectionRing_.addEventListener('color-selection-ring-update',
-          this.onColorSelectionRingUpdate_);
-
-      this.moveColorSelectionRingTo_(this.color_);
-
-      this.resizeObserver_.disconnect();
-      this.resizeObserver_ = null;
-
-      this.initialized_ = true;
-      this.dispatchEvent(new CustomEvent('hue-slider-initialized'));
-    });
-    this.resizeObserver_.observe(this);
-  }
-
-  /**
-   * @param {!Point|!Color} newPositionOrColor
-   */
-  moveColorSelectionRingTo_(newPositionOrColor) {
-    if (newPositionOrColor instanceof Point) {
-      const point =
-          this.colorPalette_.nearestPointOnColorPalette(newPositionOrColor);
-      this.colorSelectionRing_.shiftX(point.x - this.colorSelectionRing_.left);
-    } else {
-      const targetHValue = newPositionOrColor.hValue;
-      if (targetHValue !== this.colorSelectionRing_.color.hValue) {
-        const closestHValueIndex = this.colorPalette_.hslImageData
-            .reduce((closestHValueIndexSoFar, currentHValue, index, array) => {
-              if ((index % 3 === 0) &&
-                  (Math.abs(currentHValue - targetHValue) <
-                    Math.abs(array[closestHValueIndexSoFar] - targetHValue))) {
-                return index;
-              }
-              return closestHValueIndexSoFar;
-        }, 0);
-        const offsetX = (closestHValueIndex / 3) % this.colorPalette_.width;
-        this.colorSelectionRing_.setX(this.colorPalette_.left + offsetX);
-      }
-    }
-  }
-
-  get color() {
-    return this.color_;
-  }
-
-  /**
-   * @param {!Color} newColor
-   */
-  set color(newColor) {
-    if (this.color_.hValue !== newColor.hValue) {
-      this.color_ = new Color(ColorFormat.HSL, newColor.hValue, 100, 50);
-      this.moveColorSelectionRingTo_(this.color_);
-    }
-  }
-
-  onColorSelectionRingUpdate_ = () => {
-    this.color_ = this.colorSelectionRing_.color;
-    this.dispatchEvent(new CustomEvent('hue-slider-update', {
-      bubbles: true
-    }));
-  }
-}
-window.customElements.define('hue-slider', HueSlider);
-
-/**
  * ManualColorPicker: Provides functionality to change the selected color by
  *                    manipulating its numeric values.
  */
@@ -1231,13 +488,7 @@
    * @param {!Event} event
    */
   onManualColorChange_ = (event) => {
-    this.color = event.detail.color;
-  }
-
-  /**
-   * @param {!Color} newColor
-   */
-  set color(newColor) {
+    const newColor = event.detail.color;
     this.colorValueContainers_.forEach((colorValueContainer) =>
         colorValueContainer.color = newColor);
   }
@@ -1343,33 +594,19 @@
     this.colorChannel_ = colorChannel;
     switch(colorChannel) {
       case ColorChannel.HEX:
-        this.setAttribute('id', 'hexValueContainer');
         this.setAttribute('maxlength', '7');
         break;
       case ColorChannel.R:
-        this.setAttribute('id', 'rValueContainer');
-        this.setAttribute('maxlength', '3');
-        break;
       case ColorChannel.G:
-        this.setAttribute('id', 'gValueContainer');
-        this.setAttribute('maxlength', '3');
-        break;
       case ColorChannel.B:
-        this.setAttribute('id', 'bValueContainer');
         this.setAttribute('maxlength', '3');
         break;
       case ColorChannel.H:
-        this.setAttribute('id', 'hValueContainer');
         this.setAttribute('maxlength', '3');
         break;
       case ColorChannel.S:
-        // up to 3 digits plus '%'
-        this.setAttribute('id', 'sValueContainer');
-        this.setAttribute('maxlength', '4');
-        break;
       case ColorChannel.L:
         // up to 3 digits plus '%'
-        this.setAttribute('id', 'lValueContainer');
         this.setAttribute('maxlength', '4');
         break;
     }
@@ -1455,10 +692,10 @@
           }
           break;
         case ColorChannel.H:
-          if (value.match(/^\d+$/) && (0 <= value) && (value < 360)) {
-            this.channelValue_ = Number(value);
-          }
-          break;
+            if (value.match(/^\d+$/) && (0 <= value) && (value < 360)) {
+              this.channelValue_ = Number(value);
+            }
+            break;
         case ColorChannel.S:
         case ColorChannel.L:
           if (value.endsWith('%')) {
diff --git a/third_party/blink/renderer/core/html/html_slot_element.cc b/third_party/blink/renderer/core/html/html_slot_element.cc
index 8197b6b..fe00537 100644
--- a/third_party/blink/renderer/core/html/html_slot_element.cc
+++ b/third_party/blink/renderer/core/html/html_slot_element.cc
@@ -434,6 +434,32 @@
     return;
   probe::DidPerformSlotDistribution(this);
 
+  // It is very important to minimize the number of reattaching nodes in
+  // |new_assigned_nodes| here. The following *works*, in terms of the
+  // correctness of the rendering,
+  //
+  // for (auto& node: new_slotted) {
+  //   node->FlatTreeParentChanged();
+  // }
+  //
+  // However, reattaching all ndoes is not good in terms of performance.
+  // Reattach is very expensive operation.
+  //
+  // A possible approach is: Find the Longest Commons Subsequence (LCS) between
+  // |old_slotted| and |new_slotted|, and reattach nodes in |new_slotted| which
+  // LCS does not include.
+  //
+  // Note that a relative order between nodes which are not reattached should be
+  // preserved in old and new. For example,
+  //
+  // - old: [1, 4, 2, 3]
+  // - new: [3, 1, 2]
+  //
+  // This case, we must reattach 3 here, as the best possible solution.  If we
+  // don't reattach 3, 3's LayoutObject will have an invalid next sibling
+  // pointer.  We don't have any chance to update their sibling pointers (3's
+  // next and 1's previous).  Sibling pointers between 1 and 2 are correctly
+  // updated when we reattach 4, which is done in another code path.
   if (old_slotted.size() + 1 > kLCSTableSizeLimit ||
       new_slotted.size() + 1 > kLCSTableSizeLimit) {
     // Since DP takes O(N^2), we don't use DP if the size is larger than the
@@ -461,74 +487,110 @@
 void HTMLSlotElement::NotifySlottedNodesOfFlatTreeChangeNaive(
     const HeapVector<Member<Node>>& old_assigned_nodes,
     const HeapVector<Member<Node>>& new_assigned_nodes) {
-  // Use naive heuristic to minimize the number of reattaching nodes in
-  // |new_assigned_nodes|. Though this algorithm is not perfect, it works well
-  // in some common cases, such as:
+  // Use O(N) naive greedy algorithm to find a *suboptimal* longest common
+  // subsequence (LCS), and reattach nodes which are not in suboptimal LCS.  We
+  // run a greedy algorithm twice in both directions (scan forward and scan
+  // backward), and use the better result.  Though this greedy algorithm is not
+  // perfect, it works well in some common cases, such as:
 
-  // Case 1) Appending a node:
+  // Inserting a node:
   // old assigned nodes: [a, b ...., z]
   // new assigned nodes: [a, b ...., z, A]
   // => The algorithm reattaches only node |A|.
 
-  // Case 2) Prepending a node:
-  // - old assigned nodes: [a, b, ..., z]
-  // - new assigned nodes: [A, a, b, ..., z]
-  // => The algorithm reattaches only node |A|.
-
-  // Case 3) Removing the first node:
-  // - old assigned nodes: [a, b, ..., z]
-  // - new assigned nodes: [b, ..., z]
+  // Removing a node:
+  // - old assigned nodes: [a, b, ..., m, n, o, ..., z]
+  // - new assigned nodes: [a, b, ..., m, o, ... , z]
   // => The algorithm does not reattach any node.
 
-  // Case 4) Removing the last node:
-  // - old assigned nodes: [a, b, ..., z]
-  // - new assigned nodes: [a, b, ...]
-  // => The algorithm does not reattach any node.
-
-  // Case 5) Rotating children:
+  // Moving a node:
   // - old assigned nodes: [a, b, ..., z]
   // - new assigned nodes: [b, ..., z, a]
-  // => The algorithm reattaches all nodes. It doesn't work well for this case.
+  // => The algorithm reattaches only node |a|.
 
-  // TODO(hayato): Further improvement would be possible.
-  // An algorighm can be somewhat like vdom library's diffiling node lists,
-  // such as
-  // https://github.com/Polymer/lit-html/blob/34f621406867fbfd3a90f145420f0dbb7e8ab341/src/directives/repeat.ts#L141
+  // Swapping the first node and the last node
+  // - old assigned nodes: [a, b, ..., y, z]
+  // - new assigned nodes: [z, b, ..., y, a]
+  // => Ideally, we should reattach only |a| and |z|, however, the algorithm
+  // does not work well here, reattaching [a, b, ...., y] (or [b, ... y, z]).
+  // We could reconsider to support this case if a compelling case arises.
+
+  // TODO(hayato): Consider to write an unit test for the algorithm.  We
+  // probably want to make the algorithm templatized so we can test it
+  // easily.  Like, Vec<T> greedy_suboptimal_lcs(Vec<T> old, Vec<T> new)
+
+  HeapHashMap<Member<Node>, wtf_size_t> old_index_map;
+  for (wtf_size_t i = 0; i < old_assigned_nodes.size(); ++i) {
+    old_index_map.insert(old_assigned_nodes[i], i);
+  }
+
+  // Scan forward
+  HeapVector<Member<Node>> forward_result;
 
   wtf_size_t i = 0;
   wtf_size_t j = 0;
-  for (; i < old_assigned_nodes.size() && j < new_assigned_nodes.size();
-       ++i, ++j) {
-    if (old_assigned_nodes.size() < new_assigned_nodes.size()) {
-      // If |new_assigned_nodes| is larger than |old_assigned_nodes|, reattach
-      // all nodes in |new_assigned_nodes| that were different from
-      // |old_assigned_nodes[i]|.
-      while (j < new_assigned_nodes.size() &&
-             old_assigned_nodes[i] != new_assigned_nodes[j]) {
-        new_assigned_nodes[j]->FlatTreeParentChanged();
-        ++j;
-      }
-      if (j == new_assigned_nodes.size())
-        break;
-    } else if (old_assigned_nodes.size() > new_assigned_nodes.size()) {
-      // If |old_assigned_nodes| is larger than |old_assigned_nodes|, skip all
-      // nodes in |old_assigned_nodes| that were different from
-      // new_assigned_nodes[j].
-      while (i < old_assigned_nodes.size() &&
-             old_assigned_nodes[i] != new_assigned_nodes[j]) {
-        ++i;
-      }
-    } else if (old_assigned_nodes[i] != new_assigned_nodes[j]) {
-      // If both assigned nodes are the same length, reattach all nodes
-      // in |new_assigned_nodes| that were different from the old one at the
-      // same position.
-      new_assigned_nodes[j]->FlatTreeParentChanged();
+
+  while (i < old_assigned_nodes.size() && j < new_assigned_nodes.size()) {
+    auto& new_node = new_assigned_nodes[j];
+    if (old_assigned_nodes[i] == new_node) {
+      ++i;
+      ++j;
+      continue;
     }
+    if (old_index_map.Contains(new_node)) {
+      wtf_size_t old_index = old_index_map.at(new_node);
+      if (old_index > i) {
+        i = old_index_map.at(new_node) + 1;
+        ++j;
+        continue;
+      }
+    }
+    forward_result.push_back(new_node);
+    ++j;
   }
 
-  // We need to reattach all remaining new assigned nodes.
   for (; j < new_assigned_nodes.size(); ++j) {
-    new_assigned_nodes[j]->FlatTreeParentChanged();
+    forward_result.push_back(new_assigned_nodes[j]);
+  }
+
+  // Scan backward
+  HeapVector<Member<Node>> backward_result;
+
+  i = old_assigned_nodes.size();
+  j = new_assigned_nodes.size();
+
+  while (i > 0 && j > 0) {
+    auto& new_node = new_assigned_nodes[j - 1];
+    if (old_assigned_nodes[i - 1] == new_node) {
+      --i;
+      --j;
+      continue;
+    }
+    if (old_index_map.Contains(new_node)) {
+      wtf_size_t old_index = old_index_map.at(new_node);
+      if (old_index < i - 1) {
+        i = old_index;
+        --j;
+        continue;
+      }
+    }
+    backward_result.push_back(new_node);
+    --j;
+  }
+
+  for (; j > 0; --j) {
+    backward_result.push_back(new_assigned_nodes[j - 1]);
+  }
+
+  // Reattach nodes
+  if (forward_result.size() <= backward_result.size()) {
+    for (auto& node : forward_result) {
+      node->FlatTreeParentChanged();
+    }
+  } else {
+    for (auto& node : backward_result) {
+      node->FlatTreeParentChanged();
+    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index 0721530..38b9a71e 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -39,6 +39,7 @@
 FlexItem::FlexItem(LayoutBox* box,
                    LayoutUnit flex_base_content_size,
                    MinMaxSize min_max_sizes,
+                   base::Optional<MinMaxSize> min_max_cross_axis_sizes,
                    LayoutUnit main_axis_border_padding,
                    LayoutUnit main_axis_margin)
     : algorithm(nullptr),
@@ -46,6 +47,7 @@
       box(box),
       flex_base_content_size(flex_base_content_size),
       min_max_sizes(min_max_sizes),
+      min_max_cross_sizes(min_max_cross_axis_sizes),
       hypothetical_main_content_size(
           min_max_sizes.ClampSizeToMinAndMax(flex_base_content_size)),
       main_axis_border_padding(main_axis_border_padding),
@@ -142,9 +144,6 @@
 }
 
 void FlexItem::ComputeStretchedSize() {
-  // TODO(dgrogan): Pass resolved cross-axis MinMaxSize to FlexItem
-  // constructor. Then use cross_axis_min_max.ClampSizeToMinAndMax instead of
-  // relying on legacy in this method.
   DCHECK_EQ(Alignment(), ItemPosition::kStretch);
   if (MainAxisIsInlineAxis() && box->StyleRef().LogicalHeight().IsAuto()) {
     LayoutUnit stretched_logical_height =
@@ -154,16 +153,16 @@
         stretched_logical_height, box->IntrinsicContentLogicalHeight());
   } else if (!MainAxisIsInlineAxis() &&
              box->StyleRef().LogicalWidth().IsAuto()) {
-    // This doesn't work in NG because CrossAxisContentExtent() isn't yet
-    // implemented there.
-    if (box->Parent()->IsLayoutNGFlexibleBox())
-      return;
     LayoutUnit child_width =
         (Line()->cross_axis_extent - CrossAxisMarginExtent())
             .ClampNegativeToZero();
-    LayoutFlexibleBox* flexbox = ToLayoutFlexibleBox(box->Parent());
-    cross_axis_size = box->ConstrainLogicalWidthByMinMax(
-        child_width, flexbox->CrossAxisContentExtent(), flexbox);
+    if (LayoutFlexibleBox* flexbox = ToLayoutFlexibleBoxOrNull(box->Parent())) {
+      cross_axis_size = box->ConstrainLogicalWidthByMinMax(
+          child_width, flexbox->CrossAxisContentExtent(), flexbox);
+    } else {
+      DCHECK(box->Parent()->IsLayoutNGFlexibleBox());
+      cross_axis_size = min_max_cross_sizes->ClampSizeToMinAndMax(child_width);
+    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
index 46e8f5c..fdff3fe 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -76,7 +76,9 @@
   //   border/scrollbar/padding.
   FlexItem(LayoutBox*,
            LayoutUnit flex_base_content_size,
-           MinMaxSize min_max_sizes,
+           MinMaxSize min_max_main_axis_sizes,
+           // Ignored for legacy, required for NG:
+           base::Optional<MinMaxSize> min_max_cross_axis_sizes,
            LayoutUnit main_axis_border_padding,
            LayoutUnit main_axis_margin);
 
@@ -129,6 +131,7 @@
   LayoutBox* box;
   const LayoutUnit flex_base_content_size;
   const MinMaxSize min_max_sizes;
+  const base::Optional<MinMaxSize> min_max_cross_sizes;
   const LayoutUnit hypothetical_main_content_size;
   const LayoutUnit main_axis_border_padding;
   const LayoutUnit main_axis_margin;
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index bb7fd481..343b24a4 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -1238,6 +1238,7 @@
   LayoutUnit margin =
       IsHorizontalFlow() ? child.MarginWidth() : child.MarginHeight();
   algorithm->emplace_back(&child, child_inner_flex_base_size, sizes,
+                          /* cross axis min max sizes */ base::nullopt,
                           border_and_padding, margin);
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_table_cell.cc b/third_party/blink/renderer/core/layout/layout_table_cell.cc
index 7b44e7aa..582ea70 100644
--- a/third_party/blink/renderer/core/layout/layout_table_cell.cc
+++ b/third_party/blink/renderer/core/layout/layout_table_cell.cc
@@ -1112,6 +1112,11 @@
                                         ScrollbarChangeContext context) {
   LayoutBlock::ScrollbarsChanged(horizontal_scrollbar_changed,
                                  vertical_scrollbar_changed);
+
+  // The intrinsic-padding adjustment for scrollbars is directly handled by NG.
+  if (IsLayoutNGObject())
+    return;
+
   if (context != kLayout)
     return;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index 069e3fa..d44ae2d6 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -390,8 +390,10 @@
 
   // All of the above calculations with border_scrollbar_padding_ shouldn't
   // include the table cell's intrinsic padding. We can now add this.
-  border_scrollbar_padding_ +=
-      ComputeIntrinsicPadding(ConstraintSpace(), Node());
+  if (ConstraintSpace().IsTableCell()) {
+    border_scrollbar_padding_ += ComputeIntrinsicPadding(
+        ConstraintSpace(), Style(), container_builder_.Scrollbar());
+  }
 
   if (ConstraintSpace().HasBlockFragmentation())
     container_builder_.SetHasBlockFragmentation();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
index 5badecd..b1985ddf 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
@@ -94,6 +94,11 @@
     builder.SetIsRestrictedBlockSizeTableCell(
         !cell.StyleRef().LogicalHeight().IsAuto() ||
         !cell.Table()->StyleRef().LogicalHeight().IsAuto());
+    builder.SetTableCellBorders({cell.BorderStart(), cell.BorderEnd(),
+                                 cell.BorderBefore(), cell.BorderAfter()});
+    builder.SetTableCellIntrinsicPadding(
+        {LayoutUnit(), LayoutUnit(), LayoutUnit(cell.IntrinsicPaddingBefore()),
+         LayoutUnit(cell.IntrinsicPaddingAfter())});
   }
 
   builder.SetAvailableSize(available_size);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index e3b3363..6a5a40d0 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -236,6 +236,17 @@
     return LayoutUnit();
   }
 
+  // Return the borders which should be used for a table-cell.
+  NGBoxStrut TableCellBorders() const {
+    return HasRareData() ? rare_data_->table_cell_borders : NGBoxStrut();
+  }
+
+  // Return the "intrinsic" padding for a table-cell.
+  NGBoxStrut TableCellIntrinsicPadding() const {
+    return HasRareData() ? rare_data_->table_cell_intrinsic_padding
+                         : NGBoxStrut();
+  }
+
   LayoutUnit FragmentainerBlockSize() const {
     return HasRareData() ? rare_data_->fragmentainer_block_size
                          : kIndefiniteSize;
@@ -561,6 +572,9 @@
     base::Optional<LayoutUnit> forced_bfc_block_offset;
     LayoutUnit clearance_offset = LayoutUnit::Min();
 
+    NGBoxStrut table_cell_borders;
+    NGBoxStrut table_cell_intrinsic_padding;
+
     LayoutUnit fragmentainer_block_size = kIndefiniteSize;
     LayoutUnit fragmentainer_space_at_bfc_start = kIndefiniteSize;
 
@@ -571,6 +585,9 @@
     bool MaySkipLayout(const RareData& other) const {
       return margin_strut == other.margin_strut &&
              forced_bfc_block_offset == other.forced_bfc_block_offset &&
+             table_cell_borders == other.table_cell_borders &&
+             table_cell_intrinsic_padding ==
+                 other.table_cell_intrinsic_padding &&
              fragmentainer_block_size == other.fragmentainer_block_size &&
              fragmentainer_space_at_bfc_start ==
                  other.fragmentainer_space_at_bfc_start &&
@@ -585,6 +602,8 @@
     bool IsInitialForMaySkipLayout() const {
       return margin_strut == NGMarginStrut() &&
              forced_bfc_block_offset == base::nullopt &&
+             table_cell_borders == NGBoxStrut() &&
+             table_cell_intrinsic_padding == NGBoxStrut() &&
              fragmentainer_block_size == kIndefiniteSize &&
              fragmentainer_space_at_bfc_start == kIndefiniteSize &&
              block_direction_fragmentation_type == kFragmentNone &&
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
index 3fbeb45..84bfd8e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -249,6 +249,27 @@
       space_.EnsureRareData()->clearance_offset = clearance_offset;
   }
 
+  void SetTableCellBorders(const NGBoxStrut& table_cell_borders) {
+#if DCHECK_IS_ON()
+    DCHECK(!is_table_cell_borders_set_);
+    is_table_cell_borders_set_ = true;
+#endif
+    if (table_cell_borders != NGBoxStrut())
+      space_.EnsureRareData()->table_cell_borders = table_cell_borders;
+  }
+
+  void SetTableCellIntrinsicPadding(
+      const NGBoxStrut& table_cell_intrinsic_padding) {
+#if DCHECK_IS_ON()
+    DCHECK(!is_table_cell_intrinsic_padding_set_);
+    is_table_cell_intrinsic_padding_set_ = true;
+#endif
+    if (table_cell_intrinsic_padding != NGBoxStrut()) {
+      space_.EnsureRareData()->table_cell_intrinsic_padding =
+          table_cell_intrinsic_padding;
+    }
+  }
+
   void SetTableCellChildLayoutMode(
       NGTableCellChildLayoutMode table_cell_child_layout_mode) {
     space_.bitfields_.table_cell_child_layout_mode =
@@ -312,6 +333,8 @@
   bool is_optimistic_bfc_block_offset_set_ = false;
   bool is_forced_bfc_block_offset_set_ = false;
   bool is_clearance_offset_set_ = false;
+  bool is_table_cell_borders_set_ = false;
+  bool is_table_cell_intrinsic_padding_set_ = false;
 
   bool to_constraint_space_called_ = false;
 #endif
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
index 99e5363..829a2cc 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -251,19 +251,49 @@
 
     MinMaxSize min_max_sizes_in_main_axis_direction{LayoutUnit(),
                                                     LayoutUnit::Max()};
+    MinMaxSize min_max_sizes_in_cross_axis_direction{LayoutUnit(),
+                                                     LayoutUnit::Max()};
     const Length& max_property_in_main_axis = is_horizontal_flow_
                                                   ? child.Style().MaxWidth()
                                                   : child.Style().MaxHeight();
+    const Length& max_property_in_cross_axis = is_horizontal_flow_
+                                                   ? child.Style().MaxHeight()
+                                                   : child.Style().MaxWidth();
+    const Length& min_property_in_cross_axis = is_horizontal_flow_
+                                                   ? child.Style().MinHeight()
+                                                   : child.Style().MinWidth();
     if (MainAxisIsInlineAxis(child)) {
       min_max_sizes_in_main_axis_direction.max_size = ResolveMaxInlineLength(
           child_space, child_style, border_padding_in_child_writing_mode,
           intrinsic_sizes_border_box, max_property_in_main_axis,
           LengthResolvePhase::kLayout);
+      min_max_sizes_in_cross_axis_direction.max_size =
+          ResolveMaxBlockLength(child_space, child_style,
+                                border_scrollbar_padding_in_child_writing_mode,
+                                max_property_in_cross_axis,
+                                fragment_in_child_writing_mode.BlockSize(),
+                                LengthResolvePhase::kLayout);
+      min_max_sizes_in_cross_axis_direction.min_size =
+          ResolveMinBlockLength(child_space, child_style,
+                                border_scrollbar_padding_in_child_writing_mode,
+                                min_property_in_cross_axis,
+                                fragment_in_child_writing_mode.BlockSize(),
+                                LengthResolvePhase::kLayout);
     } else {
       min_max_sizes_in_main_axis_direction.max_size = ResolveMaxBlockLength(
           child_space, child_style, border_padding_in_child_writing_mode,
           max_property_in_main_axis, fragment_in_child_writing_mode.BlockSize(),
           LengthResolvePhase::kLayout);
+      min_max_sizes_in_cross_axis_direction.max_size = ResolveMaxInlineLength(
+          child_space, child_style,
+          border_scrollbar_padding_in_child_writing_mode,
+          intrinsic_sizes_border_box, max_property_in_cross_axis,
+          LengthResolvePhase::kLayout);
+      min_max_sizes_in_cross_axis_direction.min_size = ResolveMinInlineLength(
+          child_space, child_style,
+          border_scrollbar_padding_in_child_writing_mode,
+          intrinsic_sizes_border_box, min_property_in_cross_axis,
+          LengthResolvePhase::kLayout);
     }
 
     const Length& min = is_horizontal_flow_ ? child.Style().MinWidth()
@@ -335,6 +365,7 @@
     algorithm_
         ->emplace_back(child.GetLayoutBox(), flex_base_content_size,
                        min_max_sizes_in_main_axis_direction,
+                       min_max_sizes_in_cross_axis_direction,
                        main_axis_border_padding, main_axis_margin)
         .ng_input_node = child;
   }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
index 4be6001..67bff45 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
@@ -7,7 +7,6 @@
 #include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
 #include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
 #include "third_party/blink/renderer/core/layout/layout_replaced.h"
-#include "third_party/blink/renderer/core/layout/layout_table_cell.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_node.h"
@@ -102,14 +101,6 @@
                   LayoutUnit(legacy_sizing_info.aspect_ratio.Height()));
 }
 
-LayoutUnit NGLayoutInputNode::IntrinsicPaddingBlockStart() const {
-  return LayoutUnit(ToLayoutTableCell(box_)->IntrinsicPaddingBefore());
-}
-
-LayoutUnit NGLayoutInputNode::IntrinsicPaddingBlockEnd() const {
-  return LayoutUnit(ToLayoutTableCell(box_)->IntrinsicPaddingAfter());
-}
-
 NGLayoutInputNode NGLayoutInputNode::NextSibling() {
   auto* inline_node = DynamicTo<NGInlineNode>(this);
   return inline_node ? inline_node->NextSibling()
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index 29950aae..34ab075 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -159,9 +159,6 @@
                      base::Optional<LayoutUnit>* computed_block_size,
                      LogicalSize* aspect_ratio) const;
 
-  LayoutUnit IntrinsicPaddingBlockStart() const;
-  LayoutUnit IntrinsicPaddingBlockEnd() const;
-
   // Returns the next sibling.
   NGLayoutInputNode NextSibling();
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index ae15d04..2dcae1e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -837,11 +837,9 @@
 
   // If we are a table cell we just access the values set by the parent table
   // layout as border may be collapsed etc.
-  if (constraint_space.IsTableCell()) {
-    const LayoutBox* box = node.GetLayoutBox();
-    return NGBoxStrut(box->BorderStart(), box->BorderEnd(), box->BorderBefore(),
-                      box->BorderAfter());
-  }
+  if (constraint_space.IsTableCell())
+    return constraint_space.TableCellBorders();
+
   return ComputeBordersInternal(node.Style());
 }
 
@@ -854,18 +852,24 @@
 }
 
 NGBoxStrut ComputeIntrinsicPadding(const NGConstraintSpace& constraint_space,
-                                   const NGLayoutInputNode node) {
-  if (constraint_space.IsAnonymous() || !constraint_space.IsTableCell())
-    return NGBoxStrut();
+                                   const ComputedStyle& style,
+                                   const NGBoxStrut& scrollbar) {
+  DCHECK(constraint_space.IsTableCell());
+  DCHECK(!scrollbar.block_start);
 
-  // At the moment we just access the values set by the parent table layout.
-  // Once we have a NGTableLayoutAlgorithm this should pass the intrinsic
-  // padding via the constraint space object.
+  // During the "layout" table phase, adjust the given intrinsic-padding to
+  // accommodate the scrollbar.
+  NGBoxStrut intrinsic_padding = constraint_space.TableCellIntrinsicPadding();
+  if (constraint_space.IsFixedBlockSize()) {
+    if (style.VerticalAlign() == EVerticalAlign::kMiddle) {
+      intrinsic_padding.block_start -= scrollbar.block_end / 2;
+      intrinsic_padding.block_end -= scrollbar.block_end / 2;
+    } else {
+      intrinsic_padding.block_end -= scrollbar.block_end;
+    }
+  }
 
-  // TODO(karlo): intrinsic padding can sometimes be negative; that seems
-  // insane, but works in the old code; in NG it trips DCHECKs.
-  return {LayoutUnit(), LayoutUnit(), node.IntrinsicPaddingBlockStart(),
-          node.IntrinsicPaddingBlockEnd()};
+  return intrinsic_padding;
 }
 
 NGBoxStrut ComputePadding(const NGConstraintSpace& constraint_space,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
index 66eaa64..a652cb6 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
@@ -368,7 +368,8 @@
 CORE_EXPORT NGBoxStrut ComputeBordersForTest(const ComputedStyle& style);
 
 CORE_EXPORT NGBoxStrut ComputeIntrinsicPadding(const NGConstraintSpace&,
-                                               const NGLayoutInputNode);
+                                               const ComputedStyle&,
+                                               const NGBoxStrut& scrollbar);
 
 CORE_EXPORT NGBoxStrut ComputePadding(const NGConstraintSpace&,
                                       const ComputedStyle&);
diff --git a/third_party/blink/renderer/core/streams/promise_handler.cc b/third_party/blink/renderer/core/streams/promise_handler.cc
index d90d3dd..556956f 100644
--- a/third_party/blink/renderer/core/streams/promise_handler.cc
+++ b/third_party/blink/renderer/core/streams/promise_handler.cc
@@ -8,6 +8,12 @@
 
 namespace blink {
 
+namespace {
+
+void NoopFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>&) {}
+
+}  // namespace
+
 PromiseHandler::PromiseHandler(ScriptState* script_state)
     : PromiseHandlerBase(script_state) {}
 
@@ -33,7 +39,19 @@
   v8::MaybeLocal<v8::Promise> result_maybe;
   if (!on_fulfilled) {
     DCHECK(on_rejected);
-    result_maybe = promise->Catch(context, on_rejected->BindToV8Function());
+    // v8::Promise::Catch is not safe as it calls promise.then() which can be
+    // tampered with by JavaScript. v8::Promise::Then won't accept an undefined
+    // value for on_fulfilled, it has to be a function. So we pass a no-op
+    // function, which gives us approximately the semantics we need.
+    // TODO(ricea): Add a safe variant of v8::Promise::Catch to V8.
+    v8::Local<v8::Function> noop;
+    if (!v8::Function::New(context, NoopFunctionCallback).ToLocal(&noop)) {
+      DVLOG(3) << "Assuming that the failure of v8::Function::New() is caused "
+               << "by shutdown and ignoring it";
+      return v8::Promise::Resolver::New(context).ToLocalChecked()->GetPromise();
+    }
+    result_maybe =
+        promise->Then(context, noop, on_rejected->BindToV8Function());
   } else if (on_rejected) {
     result_maybe = promise->Then(context, on_fulfilled->BindToV8Function(),
                                  on_rejected->BindToV8Function());
diff --git a/third_party/blink/renderer/core/streams/promise_handler.h b/third_party/blink/renderer/core/streams/promise_handler.h
index 2195e63..733f17a 100644
--- a/third_party/blink/renderer/core/streams/promise_handler.h
+++ b/third_party/blink/renderer/core/streams/promise_handler.h
@@ -49,7 +49,7 @@
 // A convenience wrapper for promise->Then() for when all paths are
 // PromiseHandlers. It avoids having to call BindToV8Function()
 // explicitly. If |on_rejected| is null then behaves like single-argument
-// Then(). If |on_fulfilled| is null then it calls Catch().
+// Then(). If |on_fulfilled| is null then it behaves like Catch().
 v8::Local<v8::Promise> StreamThenPromise(
     v8::Local<v8::Context>,
     v8::Local<v8::Promise>,
diff --git a/third_party/blink/renderer/core/timing/layout_shift.idl b/third_party/blink/renderer/core/timing/layout_shift.idl
index 639c82d..53b66c6 100644
--- a/third_party/blink/renderer/core/timing/layout_shift.idl
+++ b/third_party/blink/renderer/core/timing/layout_shift.idl
@@ -9,6 +9,5 @@
     readonly attribute boolean hadRecentInput;
     readonly attribute DOMHighResTimeStamp lastInputTime;
 
-    // TODO(peria): toJSON is not in spec. https://crbug.com/736332
     [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
 };
diff --git a/third_party/blink/renderer/core/timing/performance_element_timing.idl b/third_party/blink/renderer/core/timing/performance_element_timing.idl
index e691f56..867981d21 100644
--- a/third_party/blink/renderer/core/timing/performance_element_timing.idl
+++ b/third_party/blink/renderer/core/timing/performance_element_timing.idl
@@ -15,6 +15,5 @@
     readonly attribute Element? element;
     readonly attribute DOMString url;
 
-    // TODO(peria): toJSON is not in spec. https://crbug.com/736332
     [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
 };
diff --git a/third_party/blink/renderer/core/timing/performance_event_timing.idl b/third_party/blink/renderer/core/timing/performance_event_timing.idl
index 466db50..13fecf6 100644
--- a/third_party/blink/renderer/core/timing/performance_event_timing.idl
+++ b/third_party/blink/renderer/core/timing/performance_event_timing.idl
@@ -9,6 +9,5 @@
     readonly attribute DOMHighResTimeStamp processingEnd;
     readonly attribute boolean cancelable;
 
-    // TODO(peria): toJSON is not in spec. https://crbug.com/736332
     [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
 };
diff --git a/third_party/blink/renderer/core/timing/performance_long_task_timing.idl b/third_party/blink/renderer/core/timing/performance_long_task_timing.idl
index 10296db..43336b3 100644
--- a/third_party/blink/renderer/core/timing/performance_long_task_timing.idl
+++ b/third_party/blink/renderer/core/timing/performance_long_task_timing.idl
@@ -6,6 +6,5 @@
 interface PerformanceLongTaskTiming : PerformanceEntry {
     [SameObject, SaveSameObject] readonly attribute FrozenArray<TaskAttributionTiming> attribution;
 
-    // TODO(peria): toJSON is not in spec. https://crbug.com/736332
     [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
 };
diff --git a/third_party/blink/renderer/core/timing/task_attribution_timing.idl b/third_party/blink/renderer/core/timing/task_attribution_timing.idl
index f1684d5e..ee84a2c 100644
--- a/third_party/blink/renderer/core/timing/task_attribution_timing.idl
+++ b/third_party/blink/renderer/core/timing/task_attribution_timing.idl
@@ -10,6 +10,5 @@
     readonly attribute DOMString containerId;
     readonly attribute DOMString containerName;
 
-    // TODO(peria): toJSON is not in spec. https://crbug.com/736332
     [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
 };
diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc
index 21ecd0a..391a9d1 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.cc
+++ b/third_party/blink/renderer/core/workers/worker_thread.cc
@@ -433,11 +433,18 @@
 }
 
 WorkerThread::WorkerThread(WorkerReportingProxy& worker_reporting_proxy)
+    : WorkerThread(worker_reporting_proxy, Thread::Current()->GetTaskRunner()) {
+}
+
+WorkerThread::WorkerThread(WorkerReportingProxy& worker_reporting_proxy,
+                           scoped_refptr<base::SingleThreadTaskRunner>
+                               parent_thread_default_task_runner)
     : time_origin_(base::TimeTicks::Now()),
       worker_thread_id_(GetNextWorkerThreadId()),
       forcible_termination_delay_(kForcibleTerminationDelay),
       worker_reporting_proxy_(worker_reporting_proxy),
-      parent_thread_default_task_runner_(Thread::Current()->GetTaskRunner()),
+      parent_thread_default_task_runner_(
+          std::move(parent_thread_default_task_runner)),
       shutdown_event_(RefCountedWaitableEvent::Create()) {
   DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_);
   MutexLocker lock(ThreadSetMutex());
diff --git a/third_party/blink/renderer/core/workers/worker_thread.h b/third_party/blink/renderer/core/workers/worker_thread.h
index 745e3c6d..bd4616301 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.h
+++ b/third_party/blink/renderer/core/workers/worker_thread.h
@@ -251,6 +251,12 @@
 
  protected:
   explicit WorkerThread(WorkerReportingProxy&);
+  // For service workers. When service workers are started on the IO thread
+  // Thread::Current() wouldn't be available so we need to pass the parent
+  // thread default task runner explicitly.
+  WorkerThread(WorkerReportingProxy&,
+               scoped_refptr<base::SingleThreadTaskRunner>
+                   parent_thread_default_task_runner);
 
   virtual WebThreadType GetThreadType() const = 0;
 
diff --git a/third_party/blink/renderer/modules/csspaint/README.md b/third_party/blink/renderer/modules/csspaint/README.md
index 033614a..2b70c76 100644
--- a/third_party/blink/renderer/modules/csspaint/README.md
+++ b/third_party/blink/renderer/modules/csspaint/README.md
@@ -5,6 +5,62 @@
 See [CSS Paint API](https://drafts.css-houdini.org/css-paint-api/) for the web exposed APIs this
 implements.
 
+See [Explainer](https://github.com/w3c/css-houdini-drafts/blob/master/css-paint-api/EXPLAINER.md)
+of this feature, as well as [Samples](https://github.com/GoogleChromeLabs/houdini-samples/tree/master/paint-worklet).
+
+## Workflow
+
+Historically the CSS Paint API (PaintWorklet) implementation ran on the main
+thread, but is currently being optimized to run on the compositor thread. We
+will use an example to show the workflow of both cases.
+
+Here is a simple example of using PaintWorklet to draw something on the screen.
+
+<style>
+#demo {
+  background-image: paint(foo);
+  width: 200px;
+  height: 200px;
+}
+</style>
+<script>
+registerPaint('foo', class {
+  paint(ctx, size) {
+    ctx.fillStyle = 'green';
+    ctx.fillRect(0, 0, size.width, size.height);
+  }
+});
+</script>
+
+In our implementation, there is one [PaintWorklet](paint_worklet.h) instance
+created from the frame. There are two
+[PaintWorkletGlobalScope](paint_worklet_global_scope.h) created to enforce
+stateless. The number of global scopes can be arbitrary, and our implementation
+chose two.
+
+During `PaintWorkletGlobalScope#registerPaint`, the Javascript inside the paint
+function is turned into a V8 paint callback. We randomly choose one of the two
+global scopes to execute the callback. The execution of the callback
+produces a PaintRecord, which contains a set of skia draw commands. The V8 paint
+callback is executed on a shared V8 isolate.
+
+### Main thread workflow
+
+During the main thread paint, the `PaintWorklet::Paint` is called, which
+executes the V8 paint callback synchronously. A PaintRecord is produced and
+passed to the compositor thread to raster.
+
+### Off main thread workflow
+
+During the main thread paint, a
+[PaintWorkletInput](../../core/css/cssom/paint_worklet_input.h) is created and
+passed to the compositor. The PaintWorkletInput contains all necessary
+information for the compositor to run the V8 paint callback. The compositor
+thread asynchronously dispatches the V8 paint callback to a Worklet thread.
+The V8 paint callback is then executed on the Worklet thread and a PaintRecord is
+given back to the compositor thread. The compositor thread then rasters the
+PaintRecord.
+
 ## Implementation
 
 ### [CSSPaintDefinition](css_paint_definition.h)
@@ -39,8 +95,7 @@
 [generator-impl]: css_paint_image_generator_impl.h
 [paint-value]: ../../core/css/css_paint_value.h
 
-### Generating a
-[PaintGeneratedImage](../../platform/graphics/paint_generated_image.h)
+### Generating a [PaintGeneratedImage](../../platform/graphics/paint_generated_image.h)
 
 `PaintGeneratedImage` is a `Image` which just paints a single `PaintRecord`.
 
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
index 5d46a34..6b82bea 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
@@ -156,7 +156,8 @@
 }
 
 void WebEmbeddedWorkerImpl::StartWorkerContext(
-    const WebEmbeddedWorkerStartData& data) {
+    const WebEmbeddedWorkerStartData& data,
+    scoped_refptr<base::SingleThreadTaskRunner> initiator_thread_task_runner) {
   DCHECK(!asked_to_terminate_);
   DCHECK_EQ(pause_after_download_state_, kDontPauseAfterDownload);
   worker_start_data_ = data;
@@ -182,7 +183,7 @@
 
   devtools_worker_token_ = data.devtools_worker_token;
   wait_for_debugger_mode_ = worker_start_data_.wait_for_debugger_mode;
-  StartWorkerThread();
+  StartWorkerThread(std::move(initiator_thread_task_runner));
 }
 
 void WebEmbeddedWorkerImpl::TerminateWorkerContext() {
@@ -217,7 +218,8 @@
   // parent context so there is no drop-in replacement.
 }
 
-void WebEmbeddedWorkerImpl::StartWorkerThread() {
+void WebEmbeddedWorkerImpl::StartWorkerThread(
+    scoped_refptr<base::SingleThreadTaskRunner> initiator_thread_task_runner) {
   DCHECK(!asked_to_terminate_);
 
   // For now we don't use global scope name for service workers.
@@ -285,8 +287,10 @@
       kV8CacheOptionsFullCodeWithoutHeatCheck;
 
   worker_thread_ = std::make_unique<ServiceWorkerThread>(
-      ServiceWorkerGlobalScopeProxy::Create(*this, *worker_context_client_),
-      std::move(installed_scripts_manager_), std::move(cache_storage_info_));
+      std::make_unique<ServiceWorkerGlobalScopeProxy>(
+          *this, *worker_context_client_, initiator_thread_task_runner),
+      std::move(installed_scripts_manager_), std::move(cache_storage_info_),
+      initiator_thread_task_runner);
 
   auto devtools_params = std::make_unique<WorkerDevToolsParams>();
   devtools_params->devtools_worker_token = devtools_worker_token_;
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
index 9d39352..7db9445 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
@@ -70,7 +70,9 @@
   ~WebEmbeddedWorkerImpl() override;
 
   // WebEmbeddedWorker overrides.
-  void StartWorkerContext(const WebEmbeddedWorkerStartData&) override;
+  void StartWorkerContext(const WebEmbeddedWorkerStartData&,
+                          scoped_refptr<base::SingleThreadTaskRunner>
+                              initiator_thread_task_runner) override;
   void TerminateWorkerContext() override;
   void ResumeAfterDownload() override;
   void AddMessageToConsole(const WebConsoleMessage&) override;
@@ -82,7 +84,7 @@
   void WaitForShutdownForTesting();
 
  private:
-  void StartWorkerThread();
+  void StartWorkerThread(scoped_refptr<base::SingleThreadTaskRunner>);
 
   // Creates a cross-thread copyable outside settings object for top-level
   // worker script fetch.
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.cc b/third_party/blink/renderer/modules/mediastream/media_devices.cc
index 26f2c6b..fa0e41fb 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -27,8 +27,6 @@
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
-using blink::mojom::blink::MediaDeviceType;
-
 namespace blink {
 
 namespace {
@@ -200,7 +198,7 @@
 }
 
 void MediaDevices::OnDevicesChanged(
-    MediaDeviceType type,
+    mojom::blink::MediaDeviceType type,
     Vector<mojom::blink::MediaDeviceInfoPtr> device_infos) {
   Document* document = To<Document>(GetExecutionContext());
   DCHECK(document);
@@ -277,41 +275,44 @@
     return;
   }
 
-  DCHECK_EQ(static_cast<wtf_size_t>(MediaDeviceType::NUM_MEDIA_DEVICE_TYPES),
+  DCHECK_EQ(static_cast<wtf_size_t>(
+                mojom::blink::MediaDeviceType::NUM_MEDIA_DEVICE_TYPES),
             enumeration.size());
 
   if (!video_input_capabilities.IsEmpty()) {
-    DCHECK_EQ(
-        enumeration[static_cast<wtf_size_t>(MediaDeviceType::MEDIA_VIDEO_INPUT)]
-            .size(),
-        video_input_capabilities.size());
+    DCHECK_EQ(enumeration[static_cast<wtf_size_t>(
+                              mojom::blink::MediaDeviceType::MEDIA_VIDEO_INPUT)]
+                  .size(),
+              video_input_capabilities.size());
   }
   if (!audio_input_capabilities.IsEmpty()) {
-    DCHECK_EQ(
-        enumeration[static_cast<wtf_size_t>(MediaDeviceType::MEDIA_AUDIO_INPUT)]
-            .size(),
-        audio_input_capabilities.size());
+    DCHECK_EQ(enumeration[static_cast<wtf_size_t>(
+                              mojom::blink::MediaDeviceType::MEDIA_AUDIO_INPUT)]
+                  .size(),
+              audio_input_capabilities.size());
   }
 
   MediaDeviceInfoVector media_devices;
   for (wtf_size_t i = 0;
-       i < static_cast<wtf_size_t>(MediaDeviceType::NUM_MEDIA_DEVICE_TYPES);
+       i < static_cast<wtf_size_t>(
+               mojom::blink::MediaDeviceType::NUM_MEDIA_DEVICE_TYPES);
        ++i) {
     for (wtf_size_t j = 0; j < enumeration[i].size(); ++j) {
-      MediaDeviceType device_type = static_cast<MediaDeviceType>(i);
+      mojom::blink::MediaDeviceType device_type =
+          static_cast<mojom::blink::MediaDeviceType>(i);
       mojom::blink::MediaDeviceInfoPtr device_info =
           std::move(enumeration[i][j]);
-      if (device_type == MediaDeviceType::MEDIA_AUDIO_INPUT ||
-          device_type == MediaDeviceType::MEDIA_VIDEO_INPUT) {
+      if (device_type == mojom::blink::MediaDeviceType::MEDIA_AUDIO_INPUT ||
+          device_type == mojom::blink::MediaDeviceType::MEDIA_VIDEO_INPUT) {
         InputDeviceInfo* input_device_info =
             InputDeviceInfo::Create(device_info->device_id, device_info->label,
                                     device_info->group_id, device_type);
-        if (device_type == MediaDeviceType::MEDIA_VIDEO_INPUT &&
+        if (device_type == mojom::blink::MediaDeviceType::MEDIA_VIDEO_INPUT &&
             !video_input_capabilities.IsEmpty()) {
           input_device_info->SetVideoInputCapabilities(
               std::move(video_input_capabilities[j]));
         }
-        if (device_type == MediaDeviceType::MEDIA_AUDIO_INPUT &&
+        if (device_type == mojom::blink::MediaDeviceType::MEDIA_AUDIO_INPUT &&
             !audio_input_capabilities.IsEmpty()) {
           input_device_info->SetAudioInputCapabilities(
               std::move(audio_input_capabilities[j]));
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.h b/third_party/blink/renderer/modules/mediastream/media_devices.h
index 8a40990..e7aa1f3 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.h
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.h
@@ -66,7 +66,7 @@
   void ContextDestroyed(ExecutionContext*) override;
 
   // mojom::blink::MediaDevicesListener implementation.
-  void OnDevicesChanged(MediaDeviceType,
+  void OnDevicesChanged(mojom::blink::MediaDeviceType,
                         Vector<mojom::blink::MediaDeviceInfoPtr>) override;
 
   // Callback for testing only.
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
index f3efdbe..8d68949 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
@@ -20,7 +20,6 @@
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 using blink::mojom::blink::MediaDeviceInfoPtr;
-using blink::mojom::blink::MediaDeviceType;
 
 namespace blink {
 
@@ -43,8 +42,8 @@
                         bool request_video_input_capabilities,
                         bool request_audio_input_capabilities,
                         EnumerateDevicesCallback callback) override {
-    Vector<Vector<MediaDeviceInfoPtr>> enumeration(
-        static_cast<size_t>(MediaDeviceType::NUM_MEDIA_DEVICE_TYPES));
+    Vector<Vector<MediaDeviceInfoPtr>> enumeration(static_cast<size_t>(
+        blink::mojom::blink::MediaDeviceType::NUM_MEDIA_DEVICE_TYPES));
     Vector<mojom::blink::VideoInputDeviceCapabilitiesPtr>
         video_input_capabilities;
     Vector<mojom::blink::AudioInputDeviceCapabilitiesPtr>
@@ -55,14 +54,16 @@
       device_info->device_id = kFakeAudioInputDeviceId1;
       device_info->label = "Fake Audio Input 1";
       device_info->group_id = kFakeCommonGroupId1;
-      enumeration[static_cast<size_t>(MediaDeviceType::MEDIA_AUDIO_INPUT)]
+      enumeration[static_cast<size_t>(
+                      blink::mojom::blink::MediaDeviceType::MEDIA_AUDIO_INPUT)]
           .push_back(std::move(device_info));
 
       device_info = mojom::blink::MediaDeviceInfo::New();
       device_info->device_id = kFakeAudioInputDeviceId2;
       device_info->label = "Fake Audio Input 2";
       device_info->group_id = "fake_group 2";
-      enumeration[static_cast<size_t>(MediaDeviceType::MEDIA_AUDIO_INPUT)]
+      enumeration[static_cast<size_t>(
+                      blink::mojom::blink::MediaDeviceType::MEDIA_AUDIO_INPUT)]
           .push_back(std::move(device_info));
 
       // TODO(crbug.com/935960): add missing mocked capabilities and related
@@ -73,14 +74,16 @@
       device_info->device_id = kFakeVideoInputDeviceId1;
       device_info->label = "Fake Video Input 1";
       device_info->group_id = kFakeCommonGroupId1;
-      enumeration[static_cast<size_t>(MediaDeviceType::MEDIA_VIDEO_INPUT)]
+      enumeration[static_cast<size_t>(
+                      blink::mojom::blink::MediaDeviceType::MEDIA_VIDEO_INPUT)]
           .push_back(std::move(device_info));
 
       device_info = mojom::blink::MediaDeviceInfo::New();
       device_info->device_id = kFakeVideoInputDeviceId2;
       device_info->label = "Fake Video Input 2";
       device_info->group_id = kFakeVideoInputGroupId2;
-      enumeration[static_cast<size_t>(MediaDeviceType::MEDIA_VIDEO_INPUT)]
+      enumeration[static_cast<size_t>(
+                      blink::mojom::blink::MediaDeviceType::MEDIA_VIDEO_INPUT)]
           .push_back(std::move(device_info));
 
       if (request_video_input_capabilities) {
@@ -103,7 +106,8 @@
       device_info->device_id = kFakeAudioOutputDeviceId1;
       device_info->label = "Fake Audio Input 1";
       device_info->group_id = kFakeCommonGroupId1;
-      enumeration[static_cast<size_t>(MediaDeviceType::MEDIA_AUDIO_OUTPUT)]
+      enumeration[static_cast<size_t>(
+                      blink::mojom::blink::MediaDeviceType::MEDIA_AUDIO_OUTPUT)]
           .push_back(std::move(device_info));
     }
     std::move(callback).Run(std::move(enumeration),
@@ -225,8 +229,9 @@
 
   void SimulateDeviceChange() {
     DCHECK(listener());
-    listener()->OnDevicesChanged(MediaDeviceType::MEDIA_AUDIO_INPUT,
-                                 Vector<MediaDeviceInfoPtr>());
+    listener()->OnDevicesChanged(
+        blink::mojom::blink::MediaDeviceType::MEDIA_AUDIO_INPUT,
+        Vector<MediaDeviceInfoPtr>());
   }
 
   void DevicesEnumerated(const MediaDeviceInfoVector& device_infos) {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index 0f2aa72..3bc03d9 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -60,15 +60,8 @@
 
 namespace blink {
 
-std::unique_ptr<ServiceWorkerGlobalScopeProxy>
-ServiceWorkerGlobalScopeProxy::Create(WebEmbeddedWorkerImpl& embedded_worker,
-                                      WebServiceWorkerContextClient& client) {
-  return std::make_unique<ServiceWorkerGlobalScopeProxy>(embedded_worker,
-                                                         client);
-}
-
 ServiceWorkerGlobalScopeProxy::~ServiceWorkerGlobalScopeProxy() {
-  DCHECK(parent_task_runner_->BelongsToCurrentThread());
+  DCHECK(parent_thread_default_task_runner_->BelongsToCurrentThread());
   // Verify that the proxy has been detached.
   DCHECK(!embedded_worker_);
 }
@@ -259,7 +252,7 @@
   // ServiceWorkerGlobalScope expects us to terminate the thread, so request
   // that here.
   PostCrossThreadTask(
-      *parent_task_runner_, FROM_HERE,
+      *parent_thread_default_task_runner_, FROM_HERE,
       CrossThreadBindOnce(&WebEmbeddedWorkerImpl::TerminateWorkerContext,
                           CrossThreadUnretained(embedded_worker_)));
 
@@ -308,22 +301,26 @@
 
 ServiceWorkerGlobalScopeProxy::ServiceWorkerGlobalScopeProxy(
     WebEmbeddedWorkerImpl& embedded_worker,
-    WebServiceWorkerContextClient& client)
+    WebServiceWorkerContextClient& client,
+    scoped_refptr<base::SingleThreadTaskRunner>
+        parent_thread_default_task_runner)
     : embedded_worker_(&embedded_worker),
+      parent_thread_default_task_runner_(
+          std::move(parent_thread_default_task_runner)),
       client_(&client),
       worker_global_scope_(nullptr) {
   DETACH_FROM_THREAD(worker_thread_checker_);
-  parent_task_runner_ = Thread::Current()->GetTaskRunner();
+  DCHECK(parent_thread_default_task_runner_);
 }
 
 void ServiceWorkerGlobalScopeProxy::Detach() {
-  DCHECK(parent_task_runner_->BelongsToCurrentThread());
+  DCHECK(parent_thread_default_task_runner_->BelongsToCurrentThread());
   embedded_worker_ = nullptr;
   client_ = nullptr;
 }
 
 void ServiceWorkerGlobalScopeProxy::TerminateWorkerContext() {
-  DCHECK(parent_task_runner_->BelongsToCurrentThread());
+  DCHECK(parent_thread_default_task_runner_->BelongsToCurrentThread());
   embedded_worker_->TerminateWorkerContext();
 }
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
index ff536d1..7a36845 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
@@ -68,12 +68,10 @@
 class ServiceWorkerGlobalScopeProxy final : public WebServiceWorkerContextProxy,
                                             public WorkerReportingProxy {
  public:
-  static std::unique_ptr<ServiceWorkerGlobalScopeProxy> Create(
-      WebEmbeddedWorkerImpl&,
-      WebServiceWorkerContextClient&);
-
   ServiceWorkerGlobalScopeProxy(WebEmbeddedWorkerImpl&,
-                                WebServiceWorkerContextClient&);
+                                WebServiceWorkerContextClient&,
+                                scoped_refptr<base::SingleThreadTaskRunner>
+                                    parent_thread_default_task_runner);
   ~ServiceWorkerGlobalScopeProxy() override;
 
   // WebServiceWorkerContextProxy overrides:
@@ -148,7 +146,8 @@
   // as part of its finalization.
   WebEmbeddedWorkerImpl* embedded_worker_;
 
-  scoped_refptr<base::SingleThreadTaskRunner> parent_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner>
+      parent_thread_default_task_runner_;
 
   WebServiceWorkerContextClient* client_;
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc b/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc
index 119e391..56a1e81 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_thread.cc
@@ -49,8 +49,11 @@
     std::unique_ptr<ServiceWorkerGlobalScopeProxy> global_scope_proxy,
     std::unique_ptr<ServiceWorkerInstalledScriptsManager>
         installed_scripts_manager,
-    mojom::blink::CacheStoragePtrInfo cache_storage_info)
-    : WorkerThread(*global_scope_proxy),
+    mojom::blink::CacheStoragePtrInfo cache_storage_info,
+    scoped_refptr<base::SingleThreadTaskRunner>
+        parent_thread_default_task_runner)
+    : WorkerThread(*global_scope_proxy,
+                   std::move(parent_thread_default_task_runner)),
       global_scope_proxy_(std::move(global_scope_proxy)),
       worker_backing_thread_(std::make_unique<WorkerBackingThread>(
           ThreadCreationParams(GetThreadType()))),
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_thread.h b/third_party/blink/renderer/modules/service_worker/service_worker_thread.h
index a96c3cfe..cbe8d17a 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_thread.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_thread.h
@@ -49,7 +49,9 @@
   // Persistent.
   ServiceWorkerThread(std::unique_ptr<ServiceWorkerGlobalScopeProxy>,
                       std::unique_ptr<ServiceWorkerInstalledScriptsManager>,
-                      mojom::blink::CacheStoragePtrInfo cache_storage_info);
+                      mojom::blink::CacheStoragePtrInfo cache_storage_info,
+                      scoped_refptr<base::SingleThreadTaskRunner>
+                          parent_thread_default_task_runner);
   ~ServiceWorkerThread() override;
 
   WorkerBackingThread& GetWorkerBackingThread() override {
diff --git a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
index ef7c2d3..4e56f38 100644
--- a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
@@ -258,7 +258,7 @@
 }  // namespace
 
 TEST_F(WebEmbeddedWorkerImplTest, TerminateSoonAfterStart) {
-  worker_->StartWorkerContext(start_data_);
+  worker_->StartWorkerContext(start_data_, Thread::Current()->GetTaskRunner());
   testing::Mock::VerifyAndClearExpectations(mock_client_.get());
 
   worker_->TerminateWorkerContext();
@@ -269,7 +269,7 @@
 TEST_F(WebEmbeddedWorkerImplTest, TerminateWhileWaitingForDebugger) {
   start_data_.wait_for_debugger_mode =
       WebEmbeddedWorkerStartData::kWaitForDebugger;
-  worker_->StartWorkerContext(start_data_);
+  worker_->StartWorkerContext(start_data_, Thread::Current()->GetTaskRunner());
   testing::Mock::VerifyAndClearExpectations(mock_client_.get());
 
   worker_->TerminateWorkerContext();
@@ -282,7 +282,7 @@
               IsScriptInstalled(KURL(start_data_.script_url)))
       .Times(testing::AtLeast(1))
       .WillRepeatedly(testing::Return(false));
-  worker_->StartWorkerContext(start_data_);
+  worker_->StartWorkerContext(start_data_, Thread::Current()->GetTaskRunner());
   testing::Mock::VerifyAndClearExpectations(mock_client_.get());
   testing::Mock::VerifyAndClearExpectations(mock_installed_scripts_manager_);
 
@@ -307,7 +307,7 @@
       .Times(testing::AtLeast(1))
       .WillRepeatedly(testing::Return(false));
   // Start worker and load the script.
-  worker_->StartWorkerContext(start_data_);
+  worker_->StartWorkerContext(start_data_, Thread::Current()->GetTaskRunner());
   testing::Mock::VerifyAndClearExpectations(mock_client_.get());
   testing::Mock::VerifyAndClearExpectations(mock_installed_scripts_manager_);
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index b0e44fd..8b2fc1b 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -172,6 +172,12 @@
   return ContextProviderWrapper()->ContextProvider()->GetGrContext();
 }
 
+SkImageInfo CanvasResource::CreateSkImageInfo() const {
+  return SkImageInfo::Make(
+      Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
+      ColorParams().GetSkAlphaType(), ColorParams().GetSkColorSpace());
+}
+
 GLenum CanvasResource::GLFilter() const {
   return filter_quality_ == kNone_SkFilterQuality ? GL_NEAREST : GL_LINEAR;
 }
@@ -686,12 +692,14 @@
     const CanvasColorParams& color_params,
     bool is_overlay_candidate,
     bool is_origin_top_left,
-    bool allow_concurrent_read_write_access)
+    bool allow_concurrent_read_write_access,
+    bool is_accelerated)
     : CanvasResource(std::move(provider), filter_quality, color_params),
       context_provider_wrapper_(std::move(context_provider_wrapper)),
       is_overlay_candidate_(is_overlay_candidate),
       size_(size),
       is_origin_top_left_(is_origin_top_left),
+      is_accelerated_(is_accelerated),
       texture_target_(
           is_overlay_candidate_
               ? gpu::GetBufferTextureTarget(
@@ -705,6 +713,20 @@
   if (!context_provider_wrapper_)
     return;
 
+  auto* gpu_memory_buffer_manager =
+      Platform::Current()->GetGpuMemoryBufferManager();
+  if (!is_accelerated_) {
+    DCHECK(gpu_memory_buffer_manager);
+
+    gpu_memory_buffer_ = gpu_memory_buffer_manager->CreateGpuMemoryBuffer(
+        gfx::Size(size), ColorParams().GetBufferFormat(),
+        gfx::BufferUsage::SCANOUT_CPU_READ_WRITE, gpu::kNullSurfaceHandle);
+    if (!gpu_memory_buffer_)
+      return;
+
+    gpu_memory_buffer_->SetColorSpace(color_params.GetStorageGfxColorSpace());
+  }
+
   auto* shared_image_interface =
       context_provider_wrapper_->ContextProvider()->SharedImageInterface();
   DCHECK(shared_image_interface);
@@ -717,9 +739,16 @@
   if (allow_concurrent_read_write_access)
     flags |= gpu::SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE;
 
-  auto shared_image_mailbox = shared_image_interface->CreateSharedImage(
-      ColorParams().TransferableResourceFormat(), gfx::Size(size),
-      ColorParams().GetStorageGfxColorSpace(), flags);
+  gpu::Mailbox shared_image_mailbox;
+  if (gpu_memory_buffer_) {
+    shared_image_mailbox = shared_image_interface->CreateSharedImage(
+        gpu_memory_buffer_.get(), gpu_memory_buffer_manager,
+        ColorParams().GetStorageGfxColorSpace(), flags);
+  } else {
+    shared_image_mailbox = shared_image_interface->CreateSharedImage(
+        ColorParams().TransferableResourceFormat(), gfx::Size(size),
+        ColorParams().GetStorageGfxColorSpace(), flags);
+  }
 
   // Wait for the mailbox to be ready to be used.
   WaitSyncToken(shared_image_interface->GenUnverifiedSyncToken());
@@ -729,6 +758,11 @@
   owning_thread_data().shared_image_mailbox = shared_image_mailbox;
   owning_thread_data().texture_id_for_read_access =
       gl->CreateAndTexStorage2DSharedImageCHROMIUM(shared_image_mailbox.name);
+
+  // For the non-accelerated case, writes are done on the CPU. So we don't need
+  // a texture for writes.
+  if (!is_accelerated_)
+    return;
   if (allow_concurrent_read_write_access) {
     owning_thread_data().texture_id_for_write_access =
         gl->CreateAndTexStorage2DSharedImageCHROMIUM(shared_image_mailbox.name);
@@ -746,12 +780,13 @@
     const CanvasColorParams& color_params,
     bool is_overlay_candidate,
     bool is_origin_top_left,
-    bool allow_concurrent_read_write_access) {
+    bool allow_concurrent_read_write_access,
+    bool is_accelerated) {
   TRACE_EVENT0("blink", "CanvasResourceSharedImage::Create");
   auto resource = base::AdoptRef(new CanvasResourceSharedImage(
       size, std::move(context_provider_wrapper), std::move(provider),
       filter_quality, color_params, is_overlay_candidate, is_origin_top_left,
-      allow_concurrent_read_write_access));
+      allow_concurrent_read_write_access, is_accelerated));
   return resource->IsValid() ? resource : nullptr;
 }
 
@@ -806,6 +841,12 @@
 void CanvasResourceSharedImage::WillDraw() {
   DCHECK(!is_cross_thread())
       << "Write access is only allowed on the owning thread";
+
+  // Sync token for software mode is generated from SharedImageInterface each
+  // time the GMB is updated.
+  if (!is_accelerated_)
+    return;
+
   // If skia is accessing the resource, it can modify the texture's filter
   // params. Make sure to set them to the desired value before sending the
   // resource to the display compositor.
@@ -868,6 +909,18 @@
 scoped_refptr<StaticBitmapImage> CanvasResourceSharedImage::Bitmap() {
   TRACE_EVENT0("blink", "CanvasResourceSharedImage::Bitmap");
 
+  SkImageInfo image_info = CreateSkImageInfo();
+  if (!is_accelerated_) {
+    if (!gpu_memory_buffer_->Map())
+      return nullptr;
+
+    SkPixmap pixmap(CreateSkImageInfo(), gpu_memory_buffer_->memory(0),
+                    gpu_memory_buffer_->stride(0));
+    auto sk_image = SkImage::MakeRasterCopy(pixmap);
+    gpu_memory_buffer_->Unmap();
+    return sk_image ? StaticBitmapImage::Create(sk_image) : nullptr;
+  }
+
   // In order to avoid creating multiple representations for this shared image
   // on the same context, the AcceleratedStaticBitmapImage uses the texture id
   // of the resource here. We keep a count of pending shared image releases to
@@ -898,9 +951,6 @@
       has_read_ref_on_texture));
 
   scoped_refptr<StaticBitmapImage> image;
-  SkImageInfo image_info = SkImageInfo::Make(
-      Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
-      ColorParams().GetSkAlphaType(), ColorParams().GetSkColorSpace());
 
   // If its cross thread, then the sync token was already verified. If not, then
   // it doesn't need to be verified.
@@ -924,6 +974,24 @@
   return image;
 }
 
+void CanvasResourceSharedImage::CopyRenderingResultsToGpuMemoryBuffer(
+    const sk_sp<SkImage>& image) {
+  DCHECK(!is_cross_thread());
+
+  if (!ContextProviderWrapper() || !gpu_memory_buffer_->Map())
+    return;
+
+  auto surface = SkSurface::MakeRasterDirect(CreateSkImageInfo(),
+                                             gpu_memory_buffer_->memory(0),
+                                             gpu_memory_buffer_->stride(0));
+  surface->getCanvas()->drawImage(image, 0, 0);
+  auto* sii =
+      ContextProviderWrapper()->ContextProvider()->SharedImageInterface();
+  gpu_memory_buffer_->Unmap();
+  sii->UpdateSharedImage(gpu::SyncToken(), mailbox());
+  owning_thread_data().sync_token = sii->GenUnverifiedSyncToken();
+}
+
 const gpu::Mailbox& CanvasResourceSharedImage::GetOrCreateGpuMailbox(
     MailboxSyncMode sync_mode) {
   if (!is_cross_thread()) {
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.h b/third_party/blink/renderer/platform/graphics/canvas_resource.h
index 4605b29..0f43c52 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.h
@@ -108,6 +108,7 @@
   }
 
   SkFilterQuality FilterQuality() const { return filter_quality_; }
+  SkImageInfo CreateSkImageInfo() const;
 
  protected:
   CanvasResource(base::WeakPtr<CanvasResourceProvider>,
@@ -336,11 +337,12 @@
       const CanvasColorParams&,
       bool is_overlay_candidate,
       bool is_origin_top_left,
-      bool allow_concurrent_read_write_access);
+      bool allow_concurrent_read_write_access,
+      bool is_accelerated);
   ~CanvasResourceSharedImage() override;
 
   bool IsRecycleable() const final { return true; }
-  bool IsAccelerated() const final { return true; }
+  bool IsAccelerated() const final { return is_accelerated_; }
   bool SupportsAcceleratedCompositing() const override { return true; }
   bool IsValid() const final;
   IntSize Size() const final { return size_; }
@@ -360,6 +362,12 @@
   }
   void TakeSkImage(sk_sp<SkImage> image) final { NOTREACHED(); }
   void NotifyResourceLost() final;
+  bool NeedsReadLockFences() const final {
+    // If the resource is not accelerated, it will be written to on the CPU. We
+    // need read lock fences to ensure that all reads on the GPU are done when
+    // the resource is returned by the display compositor.
+    return !is_accelerated_;
+  }
 
   GLuint GetTextureIdForReadAccess() const {
     return owning_thread_data().texture_id_for_read_access;
@@ -376,6 +384,7 @@
     return owning_thread_data().bitmap_image_read_refs > 0u;
   }
   bool is_lost() const { return owning_thread_data().is_lost; }
+  void CopyRenderingResultsToGpuMemoryBuffer(const sk_sp<SkImage>& image);
 
  private:
   // These members are either only accessed on the owning thread, or are only
@@ -423,7 +432,8 @@
                             const CanvasColorParams&,
                             bool is_overlay_candidate,
                             bool is_origin_top_left,
-                            bool allow_concurrent_read_write_access);
+                            bool allow_concurrent_read_write_access,
+                            bool is_accelerated);
   void SetGLFilterIfNeeded();
 
   OwningThreadData& owning_thread_data() {
@@ -454,10 +464,15 @@
   // active readers or not.
   bool is_origin_clean_ = true;
 
+  // GMB based software raster path. The resource is written to on the CPU but
+  // passed using the mailbox to the display compositor for use as an overlay.
+  std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_;
+
   // Accessed on any thread.
   const bool is_overlay_candidate_;
   const IntSize size_;
   const bool is_origin_top_left_;
+  const bool is_accelerated_;
   const GLenum texture_target_;
   const base::PlatformThreadId owning_thread_id_;
   const scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner_;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index a0d8c4f..9626001 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -479,18 +479,22 @@
       base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher,
       bool is_origin_top_left,
       bool is_overlay_candidate,
-      bool maybe_single_buffered)
+      bool maybe_single_buffered,
+      bool is_accelerated)
       : CanvasResourceProvider(
             kSharedImage,
             size,
             filter_quality,
-            CanvasColorParams(color_params, true /* force_rgba */),
+            // TODO(khushalsagar): The software path seems to be assuming N32
+            // somewhere in the later pipeline but for offscreen canvas only.
+            CanvasColorParams(color_params, is_accelerated /* force_rgba */),
             std::move(context_provider_wrapper),
             std::move(resource_dispatcher)),
         msaa_sample_count_(msaa_sample_count),
         is_origin_top_left_(is_origin_top_left),
         is_overlay_candidate_(is_overlay_candidate),
-        maybe_single_buffered_(maybe_single_buffered) {
+        maybe_single_buffered_(maybe_single_buffered),
+        is_accelerated_(is_accelerated) {
     resource_ = NewOrRecycledResource();
     if (resource_)
       EnsureWriteAccess();
@@ -499,12 +503,14 @@
   ~CanvasResourceProviderSharedImage() override {}
 
   bool IsValid() const final { return GetSkSurface() && !IsGpuContextLost(); }
-  bool IsAccelerated() const final { return true; }
+  bool IsAccelerated() const final { return is_accelerated_; }
   bool SupportsDirectCompositing() const override { return true; }
   bool SupportsSingleBuffering() const override {
     return maybe_single_buffered_;
   }
   GLuint GetBackingTextureHandleForOverwrite() override {
+    DCHECK(is_accelerated_);
+
     if (IsGpuContextLost())
       return 0u;
 
@@ -522,10 +528,13 @@
     return CanvasResourceSharedImage::Create(
         Size(), ContextProviderWrapper(), CreateWeakPtr(), FilterQuality(),
         ColorParams(), is_overlay_candidate_, is_origin_top_left_,
-        allow_concurrent_read_write_access);
+        allow_concurrent_read_write_access, is_accelerated_);
   }
 
   void NotifyTexParamsModified(const CanvasResource* resource) override {
+    if (!is_accelerated_)
+      return;
+
     if (resource_.get() == resource) {
       DCHECK(!current_resource_has_write_access_);
       // Note that the call below is guarenteed to not issue any GPU work for
@@ -569,6 +578,12 @@
     if (!IsValid())
       return nullptr;
 
+    // We don't need to EndWriteAccess here since that's required to make the
+    // rendering results visible on the GpuMemoryBuffer while we return cpu
+    // memory, rendererd to by skia, here.
+    if (!is_accelerated_)
+      return SnapshotInternal();
+
     if (!cached_snapshot_) {
       EndWriteAccess();
       cached_snapshot_ = resource_->Bitmap();
@@ -593,7 +608,10 @@
     // token for these writes.
     cached_snapshot_.reset();
 
-    if (DoCopyOnWrite()) {
+    // We don't need to do copy-on-write for the resource here since writes to
+    // the GMB are deferred until it needs to be dispatched to the display
+    // compositor via ProduceCanvasResource.
+    if (is_accelerated_ && DoCopyOnWrite()) {
       DCHECK(!current_resource_has_write_access_)
           << "Write access must be released before sharing the resource";
 
@@ -626,15 +644,17 @@
   }
 
   bool DoCopyOnWrite() {
+    // If the canvas is single buffered, concurrent read/writes to the resource
+    // are allowed. Note that we ignore the resource lost case as well since
+    // that only indicates that we did not get a sync token for read/write
+    // synchronization which is not a requirement for single buffered canvas.
+    if (IsSingleBuffered())
+      return false;
+
     // If the resource was lost, we can not use it for writes again.
     if (resource()->is_lost())
       return true;
 
-    // If the canvas is single buffered, concurrent read/writes to the resource
-    // are allowed.
-    if (IsSingleBuffered())
-      return false;
-
     // We have the only ref to the resource which implies there are no active
     // readers.
     if (resource_->HasOneRef())
@@ -643,7 +663,8 @@
     // Its possible to have deferred work in skia which uses this resource. Try
     // flushing once to see if that releases the read refs. We can avoid a copy
     // by queuing this work before writing to this resource.
-    surface_->flush();
+    if (is_accelerated_)
+      surface_->flush();
 
     return !resource_->HasOneRef();
   }
@@ -653,11 +674,19 @@
     if (IsGpuContextLost())
       return nullptr;
 
-    return SkSurface::MakeFromBackendTexture(
-        GetGrContext(), CreateGrTextureForResource(), GetGrSurfaceOrigin(),
-        msaa_sample_count_, ColorParams().GetSkColorType(),
-        ColorParams().GetSkColorSpaceForSkSurfaces(),
-        ColorParams().GetSkSurfaceProps());
+    if (is_accelerated_) {
+      return SkSurface::MakeFromBackendTexture(
+          GetGrContext(), CreateGrTextureForResource(), GetGrSurfaceOrigin(),
+          msaa_sample_count_, ColorParams().GetSkColorType(),
+          ColorParams().GetSkColorSpaceForSkSurfaces(),
+          ColorParams().GetSkSurfaceProps());
+    }
+
+    // For software raster path, we render into cpu memory managed internally
+    // by SkSurface and copy the rendered results to the GMB before dispatching
+    // it to the display compositor.
+    return SkSurface::MakeRaster(resource_->CreateSkImageInfo(),
+                                 ColorParams().GetSkSurfaceProps());
   }
 
   GrSurfaceOrigin GetGrSurfaceOrigin() const {
@@ -666,6 +695,8 @@
   }
 
   GrBackendTexture CreateGrTextureForResource() const {
+    DCHECK(is_accelerated_);
+
     GrGLTextureInfo texture_info = {};
     texture_info.fID = resource()->GetTextureIdForWriteAccess();
     texture_info.fTarget = resource_->TextureTarget();
@@ -675,6 +706,8 @@
   }
 
   void FlushGrContext() {
+    DCHECK(is_accelerated_);
+
     // The resource may have been imported and used in skia. Make sure any
     // operations using this resource are flushed to the underlying context.
     // Note that its not sufficient to flush the SkSurface here since it will
@@ -688,7 +721,11 @@
 
   void EnsureWriteAccess() {
     DCHECK(resource_);
-    DCHECK(resource_->HasOneRef() || IsSingleBuffered())
+    // In software mode, we don't need write access to the resource during
+    // drawing since it is executed on cpu memory managed by skia. We ensure
+    // exclusive access to the resource when the results are copied onto the
+    // GMB in EndWriteAccess.
+    DCHECK(resource_->HasOneRef() || IsSingleBuffered() || !is_accelerated_)
         << "Write access requires exclusive access to the resource";
     DCHECK(!resource()->is_cross_thread())
         << "Write access is only allowed on the owning thread";
@@ -696,9 +733,15 @@
     if (current_resource_has_write_access_ || IsGpuContextLost())
       return;
 
-    auto texture_id = resource()->GetTextureIdForWriteAccess();
-    ContextGL()->BeginSharedImageAccessDirectCHROMIUM(
-        texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
+    if (is_accelerated_) {
+      auto texture_id = resource()->GetTextureIdForWriteAccess();
+      ContextGL()->BeginSharedImageAccessDirectCHROMIUM(
+          texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
+    }
+
+    // For the non-accelerated path, we don't need a texture for writes since
+    // its on the CPU, but we set this bit to know whether the GMB needs to be
+    // updated.
     current_resource_has_write_access_ = true;
   }
 
@@ -708,10 +751,18 @@
     if (!current_resource_has_write_access_ || IsGpuContextLost())
       return;
 
-    // Issue any skia work using this resource before releasing write access.
-    FlushGrContext();
-    auto texture_id = resource()->GetTextureIdForWriteAccess();
-    ContextGL()->EndSharedImageAccessDirectCHROMIUM(texture_id);
+    if (is_accelerated_) {
+      // Issue any skia work using this resource before releasing write access.
+      FlushGrContext();
+      auto texture_id = resource()->GetTextureIdForWriteAccess();
+      ContextGL()->EndSharedImageAccessDirectCHROMIUM(texture_id);
+    } else {
+      if (DoCopyOnWrite())
+        resource_ = NewOrRecycledResource();
+      resource()->CopyRenderingResultsToGpuMemoryBuffer(
+          surface_->makeImageSnapshot());
+    }
+
     current_resource_has_write_access_ = false;
   }
 
@@ -726,6 +777,7 @@
   const bool is_origin_top_left_;
   const bool is_overlay_candidate_;
   const bool maybe_single_buffered_;
+  const bool is_accelerated_;
   bool current_resource_has_write_access_ = false;
   scoped_refptr<CanvasResource> resource_;
   scoped_refptr<StaticBitmapImage> cached_snapshot_;
@@ -810,8 +862,7 @@
   });
 
   static const Vector<CanvasResourceType> kSoftwareCompositedFallbackList({
-      // TODO(khushalsagar): Use shared image once it supports software raster
-      // with GMBs.
+      CanvasResourceType::kSharedImage,
       CanvasResourceType::kBitmapGpuMemoryBuffer,
       CanvasResourceType::kSharedBitmap,
       // Fallback to no direct compositing support
@@ -831,7 +882,7 @@
   });
   DCHECK(std::equal(kAcceleratedCompositedFallbackList.begin() + 3,
                     kAcceleratedCompositedFallbackList.end(),
-                    kSoftwareCompositedFallbackList.begin(),
+                    kSoftwareCompositedFallbackList.begin() + 1,
                     kSoftwareCompositedFallbackList.end()));
 
   static const Vector<CanvasResourceType> kAcceleratedDirect2DFallbackList({
@@ -891,6 +942,9 @@
     case CanvasResourceProvider::ResourceUsage::
         kAcceleratedDirect3DResourceUsage:
       return kAcceleratedDirect3DFallbackList;
+    case CanvasResourceProvider::ResourceUsage::
+        kSoftwareCompositedDirect2DResourceUsage:
+      return kSoftwareCompositedFallbackList;
   }
   NOTREACHED();
 }
@@ -1023,12 +1077,17 @@
             resource_dispatcher);
         break;
       case CanvasResourceType::kSharedImage: {
+        DCHECK_NE(usage, ResourceUsage::kSoftwareResourceUsage);
+
         const bool usage_wants_single_buffered =
             usage == ResourceUsage::kAcceleratedDirect2DResourceUsage ||
-            usage == ResourceUsage::kAcceleratedDirect3DResourceUsage;
+            usage == ResourceUsage::kAcceleratedDirect3DResourceUsage ||
+            usage == ResourceUsage::kSoftwareCompositedDirect2DResourceUsage;
         const bool usage_wants_overlays =
             usage_wants_single_buffered ||
-            usage == ResourceUsage::kAcceleratedCompositedResourceUsage;
+            usage == ResourceUsage::kAcceleratedCompositedResourceUsage ||
+            usage == ResourceUsage::kSoftwareCompositedResourceUsage;
+
         // texture_storage_image is required to create shared images supporting
         // scanout usage.
         const bool can_use_overlays =
@@ -1036,15 +1095,33 @@
             context_provider_wrapper->ContextProvider()
                 ->GetCapabilities()
                 .texture_storage_image;
+        const bool can_use_gmbs =
+            is_gpu_memory_buffer_image_allowed &&
+            Platform::Current()->GetGpuMemoryBufferManager();
 
         const bool is_overlay_candidate =
             usage_wants_overlays && can_use_overlays;
+        const bool is_accelerated =
+            usage == ResourceUsage::kAcceleratedResourceUsage ||
+            usage == ResourceUsage::kAcceleratedCompositedResourceUsage ||
+            usage == ResourceUsage::kAcceleratedDirect2DResourceUsage;
+
+        // If the rendering will be in software and we don't have GMB support,
+        // fallback to bitmap provider type.
+        if (!is_accelerated && !can_use_gmbs)
+          continue;
+
+        // TODO(khushalsagar) Single buffering requires concurrent
+        // read/write access to the resource which is sub-optimal for software
+        // raster since that would require concurrent access to the resource on
+        // the CPU and GPU. Check if we should disable it in software mode.
         const bool maybe_single_buffered =
-            usage_wants_single_buffered && can_use_overlays;
+            usage_wants_single_buffered && can_use_gmbs;
+
         provider = std::make_unique<CanvasResourceProviderSharedImage>(
             size, msaa_sample_count, filter_quality, color_params,
             context_provider_wrapper, resource_dispatcher, is_origin_top_left,
-            is_overlay_candidate, maybe_single_buffered);
+            is_overlay_candidate, maybe_single_buffered, is_accelerated);
       } break;
     }
     if (!provider->IsValid())
@@ -1083,7 +1160,7 @@
       return std::make_unique<CanvasResourceProviderSharedImage>(
           size, msaa_sample_count, kLow_SkFilterQuality, color_params,
           context_provider_wrapper, resource_dispatcher, is_origin_top_left,
-          false, false);
+          false, false, true);
     case CanvasResourceProvider::kTextureGpuMemoryBuffer:
       return std::make_unique<CanvasResourceProviderTextureGpuMemoryBuffer>(
           size, msaa_sample_count, kLow_SkFilterQuality, color_params,
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index 3342ba3..d547264 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -57,7 +57,8 @@
     kAcceleratedCompositedResourceUsage = 3,
     kAcceleratedDirect2DResourceUsage = 4,
     kAcceleratedDirect3DResourceUsage = 5,
-    kMaxValue = kAcceleratedDirect3DResourceUsage,
+    kSoftwareCompositedDirect2DResourceUsage = 6,
+    kMaxValue = kSoftwareCompositedDirect2DResourceUsage,
   };
 
   enum PresentationMode {
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
index fb66c8d..c0419f4 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
@@ -217,7 +217,8 @@
 
   auto provider = CanvasResourceProvider::Create(
       kSize,
-      CanvasResourceProvider::ResourceUsage::kSoftwareCompositedResourceUsage,
+      CanvasResourceProvider::ResourceUsage::
+          kSoftwareCompositedDirect2DResourceUsage,
       context_provider_wrapper_, 0 /* msaa_sample_count */,
       kLow_SkFilterQuality, kColorParams,
       CanvasResourceProvider::kAllowImageChromiumPresentationMode,
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer b/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer
index 4c0d83b..e4a0325 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer
+++ b/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer
@@ -1,6 +1,3 @@
 # Tests fail even with a fuzzy pixel diff. They require a re-baseline.
-crbug.com/954328 compositing/lots-of-img-layers.html [ Failure ]
 crbug.com/954328 media/video-layer-crash.html [ Failure ]
 crbug.com/954328 transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ]
-
-crbug.com/918155 compositing/overflow/scrollbar-layer-placement-negative-z-index-child.html [ Failure ]
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization b/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization
index fe65588d..73eb04a 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization
+++ b/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization
@@ -81,9 +81,6 @@
 crbug.com/935970 media/audio-delete-while-slider-thumb-clicked.html [ Skip ]
 
 # Tests fail even with a fuzzy pixel diff. They require a re-baseline.
-crbug.com/954328 compositing/fixed-background-after-style-recalc.html [ Failure ]
-crbug.com/954328 compositing/overflow/mask-with-filter.html [ Failure ]
-crbug.com/954328 compositing/overflow/scrollbar-layer-placement-negative-z-index-child.html [ Failure ]
 crbug.com/954328 css3/filters/filter-change-repaint.html [ Failure ]
 crbug.com/954328 css3/filters/filter-repaint-blur.html [ Failure ]
 crbug.com/954328 css3/filters/filter-repaint-child-layers.html [ Failure ]
diff --git a/third_party/blink/web_tests/FlagExpectations/use-gl=any b/third_party/blink/web_tests/FlagExpectations/use-gl=any
index 94a7f8e..5d39dea 100644
--- a/third_party/blink/web_tests/FlagExpectations/use-gl=any
+++ b/third_party/blink/web_tests/FlagExpectations/use-gl=any
@@ -1,4 +1,5 @@
 # Need a Skia GL specific baseline.
+crbug.com/993384 compositing/lots-of-img-layers.html [ Skip ]
 crbug.com/993384 css3/blending/background-blend-mode-crossfade-image-gradient.html [ Skip ]
 crbug.com/993384 css3/blending/background-blend-mode-gradient-image.html [ Skip ]
 crbug.com/993384 css3/blending/background-blend-mode-image-color.html [ Skip ]
diff --git a/third_party/blink/web_tests/FlagExpectations/use-vulkan=native b/third_party/blink/web_tests/FlagExpectations/use-vulkan=native
index 407e7e4..69b5ce5 100644
--- a/third_party/blink/web_tests/FlagExpectations/use-vulkan=native
+++ b/third_party/blink/web_tests/FlagExpectations/use-vulkan=native
@@ -1,5 +1,4 @@
 # Tests fail even with a fuzzy pixel diff. They require a re-baseline.
-crbug.com/954328 compositing/lots-of-img-layers.html [ Failure ]
 crbug.com/954328 media/video-layer-crash.html [ Failure ]
 crbug.com/954328 transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ]
 
@@ -22,7 +21,6 @@
 crbug.com/972621 compositing/iframes/composited-iframe-alignment.html [ Skip ]
 crbug.com/972621 compositing/overflow/border-radius-above-composited-subframe.html [ Skip ]
 crbug.com/972621 compositing/overflow/border-radius-composited-subframe.html [ Skip ]
-crbug.com/972621 compositing/overflow/mask-with-filter.html [ Skip ]
 crbug.com/972621 compositing/overflow/scrollbar-layer-placement-negative-z-index-child-positioned.html [ Skip ]
 crbug.com/972621 compositing/overflow/scrollbar-layer-placement.html [ Skip ]
 crbug.com/972621 compositing/shadows/shadow-drawing.html [ Skip ]
@@ -104,7 +102,6 @@
 crbug.com/963542 media/alpha-video-playback.html [ Skip ]
 
 # Rebaseline
-crbug.com/972637 compositing/fixed-background-after-style-recalc.html [ Skip ]
 crbug.com/972637 css3/masking/mask-luminance-png.html [ Skip ]
 crbug.com/972637 css3/masking/mask-repeat-space-border.html [ Skip ]
 crbug.com/972637 images/color-profile-animate-rotate.html [ Skip ]
@@ -132,6 +129,7 @@
 crbug.com/972637 media/video-poster-scale.html [ Skip ]
 
 # Need a Vulkan native specific baseline.
+crbug.com/993384 compositing/lots-of-img-layers.html [ Skip ]
 crbug.com/993384 css3/blending/background-blend-mode-crossfade-image-gradient.html [ Skip ]
 crbug.com/993384 css3/blending/background-blend-mode-gradient-image.html [ Skip ]
 crbug.com/993384 css3/blending/background-blend-mode-image-color.html [ Skip ]
diff --git a/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader b/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader
index 0d68b65..43684b4 100644
--- a/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader
+++ b/third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader
@@ -1,7 +1,3 @@
-# Opacity Filters need rebaseline.
-crbug.com/935580 compositing/masks/mask-with-added-filters.html [ Skip ]
-crbug.com/935580 compositing/masks/mask-with-removed-filters.html [ Skip ]
-
 # Flaky BlinkTestController::OnPixelDumpCaptured Crash. We want to still run to
 # detect failures other than the crash.
 crbug.com/963542 media/alpha-video-playback.html [ Skip ]
@@ -25,15 +21,12 @@
 crbug.com/972621 compositing/culling/scrolled-within-boxshadow.html [ Skip ]
 crbug.com/972621 compositing/culling/translated-boxshadow.html [ Skip ]
 crbug.com/972621 compositing/culling/unscrolled-within-boxshadow.html [ Skip ]
-crbug.com/972621 compositing/fixed-background-after-style-recalc.html [ Skip ]
 crbug.com/972621 compositing/geometry/clipping-foreground.html [ Skip ]
 crbug.com/972621 compositing/geometry/foreground-layer.html [ Skip ]
 crbug.com/972621 compositing/geometry/vertical-scroll-composited.html [ Skip ]
 crbug.com/972621 compositing/iframes/composited-iframe-alignment.html [ Skip ]
-crbug.com/972621 compositing/lots-of-img-layers.html [ Skip ]
 crbug.com/972621 compositing/overflow/border-radius-above-composited-subframe.html [ Skip ]
 crbug.com/972621 compositing/overflow/border-radius-composited-subframe.html [ Skip ]
-crbug.com/972621 compositing/overflow/mask-with-filter.html [ Skip ]
 crbug.com/972621 compositing/overflow/scrollbar-layer-placement-negative-z-index-child-positioned.html [ Skip ]
 crbug.com/972621 compositing/overflow/scrollbar-layer-placement.html [ Skip ]
 crbug.com/972621 compositing/shadows/shadow-drawing.html [ Skip ]
@@ -149,3 +142,6 @@
 crbug.com/977289 css3/filters/effect-reference-add-hw.html [ Skip ]
 crbug.com/977289 css3/filters/effect-reference-source-alpha-hw.html [ Skip ]
 crbug.com/977289 css3/filters/effect-reference-subregion-hidpi-hw.html [ Skip ]
+
+# Times out.
+crbug.com/994331 compositing/lots-of-img-layers.html [ Skip ]
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations
index 13ac6f1..f3cbe70 100644
--- a/third_party/blink/web_tests/MSANExpectations
+++ b/third_party/blink/web_tests/MSANExpectations
@@ -334,3 +334,5 @@
 crbug.com/856601 [ Linux ] http/tests/devtools/a11y-axe-core/elements/main-tool-test.js [ Pass Timeout ]
 crbug.com/856601 [ Linux ] webaudio/Analyser/realtimeanalyser-freq-data.html [ Pass Timeout ]
 crbug.com/856601 [ Linux ] external/wpt/secure-contexts/idlharness.any.serviceworker.html [ Pass Timeout ]
+crbug.com/993953 [ Linux ] http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js [ Pass Timeout ]
+crbug.com/993953 [ Linux ] virtual/wasm-site-isolated-code-cache/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 480c9a1a..9bf9022 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -2140,6 +2140,9 @@
 virtual/feature-policy-permissions/external/wpt/mediacapture-streams/MediaStreamTrack-end-manual.https.html [ WontFix ]
 virtual/audio-service/external/wpt/mediacapture-streams/MediaStream-MediaElement-preload-none-manual.https.html [ WontFix ]
 virtual/audio-service/external/wpt/mediacapture-streams/MediaStreamTrack-end-manual.https.html [ WontFix ]
+virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ WontFix ]
+virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ WontFix ]
+virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ WontFix ]
 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ WontFix ]
 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ WontFix ]
 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ WontFix ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index cb196495..b02d306 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1877,7 +1877,8 @@
 ### virtual/layout_ng_experimental/css3/flexbox/
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/auto-height-column-with-border-and-padding.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/box-sizing-min-max-sizes.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/columns-height-set-via-top-bottom.html [ Failure ]
+crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/columns-center-with-margins-and-wrap.html [ Failure ]
+crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/columns-center-with-margins.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-baseline.html [ Skip ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-column.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-end.html [ Failure ]
@@ -1896,7 +1897,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-baseline-margins.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-baseline.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-overflow-auto.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexitem.html [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/inline-flexbox-wrap-vertically-width-calculation.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/minimum-size-image.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-align-content-horizontal-column.html [ Failure ]
@@ -1914,10 +1914,8 @@
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/position-absolute-child.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relayout-align-items.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relpos-with-percentage-top.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/stretch-input-in-column.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/style-change.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/true-centering.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/wrapping-column-dynamic-changes.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/writing-modes.html [ Failure ]
 
 ### virtual/layout_ng_experimental/css3/flexbox/mozilla/
@@ -1925,8 +1923,6 @@
 
 ### virtual/layout_ng_experimental/external/wpt/css/css-flexbox/
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/Flexible-order.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-002.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-004.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-items-001.htm [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-items-003.htm [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-items-004.htm [ Failure ]
@@ -3092,6 +3088,7 @@
 crbug.com/832071 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
 crbug.com/832071 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
 crbug.com/832071 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
+crbug.com/832071 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
 
 # failures in external/wpt/css/css-animations/ and web-animations/ from Mozilla tests
 crbug.com/849859 external/wpt/css/css-animations/CSSAnimation-pausing.tentative.html [ Failure ]
@@ -3244,6 +3241,27 @@
 crbug.com/994214 external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-rule-nested-balancing-003.html [ Failure ]
+crbug.com/626703 [ Mac ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-rule-nested-balancing-003.html [ Failure ]
+crbug.com/626703 [ Win ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-rule-nested-balancing-003.html [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/css/css-multicol/multicol-rule-nested-balancing-003.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-multicol/multicol-rule-nested-balancing-003.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-multicol/multicol-rule-nested-balancing-003.html [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/css/css-lists/li-value-reversed-005.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-lists/li-value-reversed-005.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-lists/li-value-reversed-005.html [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/css/css-multicol/multicol-breaking-nobackground-004.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-multicol/multicol-breaking-nobackground-004.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-multicol/multicol-breaking-nobackground-004.html [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/css/css-lists/li-value-reversed-004.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-lists/li-value-reversed-004.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-lists/li-value-reversed-004.html [ Failure ]
+crbug.com/626703 [ Linux ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-breaking-nobackground-004.html [ Failure ]
+crbug.com/626703 [ Mac ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-breaking-nobackground-004.html [ Failure ]
+crbug.com/626703 [ Win ] virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-breaking-nobackground-004.html [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/css/css-lists/li-value-reversed-003.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-lists/li-value-reversed-003.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-lists/li-value-reversed-003.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/css/css-lists/inline-list-with-table-child.html [ Failure ]
 crbug.com/626703 [ Mac ] external/wpt/css/css-lists/inline-list-with-table-child.html [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/css/css-lists/inline-list-with-table-child.html [ Failure ]
@@ -3555,6 +3573,7 @@
 crbug.com/699040 external/wpt/svg/text/reftests/text-xml-space-001.svg [ Failure ]
 crbug.com/626703 external/wpt/service-workers/service-worker/ready.https.html [ Timeout ]
 crbug.com/626703 virtual/blink-cors/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ]
+crbug.com/626703 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ]
 crbug.com/626703 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ]
 crbug.com/626703 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ]
 crbug.com/626703 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ]
@@ -4353,6 +4372,7 @@
 crbug.com/626703 external/wpt/screen-orientation/onchange-event-subframe.html [ Timeout ]
 crbug.com/648295 external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
 crbug.com/648295 virtual/blink-cors/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
+crbug.com/648295 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
 crbug.com/648295 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
 crbug.com/648295 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
 crbug.com/648295 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
@@ -4761,6 +4781,7 @@
 # This test requires a special browser flag and seems not suitable for a wpt test, see bug.
 crbug.com/691944 external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
 crbug.com/691944 virtual/blink-cors/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
+crbug.com/691944 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
 crbug.com/691944 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
 crbug.com/691944 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
 crbug.com/691944 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
@@ -4768,6 +4789,7 @@
 # These tests (erroneously) see a platform-specific User-Agent header
 crbug.com/595993 external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
 crbug.com/595993 virtual/blink-cors/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
+crbug.com/595993 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
 crbug.com/595993 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
 crbug.com/595993 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
 crbug.com/595993 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
@@ -5029,6 +5051,7 @@
 crbug.com/889798 virtual/blink-cors/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ]
 crbug.com/889798 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ]
 crbug.com/889798 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ]
+crbug.com/889798 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ]
 crbug.com/889798 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ]
 
 # Sheriff failures 2017-07-03
@@ -5943,6 +5966,7 @@
 # These started failing when network service was enabled by default.
 crbug.com/933880 external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
 crbug.com/933880 virtual/blink-cors/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
+crbug.com/933880 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
 crbug.com/933880 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
 crbug.com/933880 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
 crbug.com/933880 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 6ead432c..6e149604 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -571,6 +571,11 @@
     "args": ["--enable-features=SignedExchangeSubresourcePrefetch"]
   },
   {
+    "prefix": "omt-service-worker-startup",
+    "base": "external/wpt/service-workers",
+    "args": ["--enable-features=OffMainThreadServiceWorkerStartup"]
+  },
+  {
     "prefix": "omt-worker-fetch",
     "base": "external/wpt/content-security-policy/inside-worker",
     "args": ["--enable-features=OffMainThreadDedicatedWorkerScriptFetch,PlzDedicatedWorker"]
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 40b3abb..9657087 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
@@ -53219,6 +53219,66 @@
      {}
     ]
    ],
+   "css/css-lists/li-value-reversed-001.html": [
+    [
+     "css/css-lists/li-value-reversed-001.html",
+     [
+      [
+       "/css/css-lists/li-value-reversed-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-lists/li-value-reversed-002.html": [
+    [
+     "css/css-lists/li-value-reversed-002.html",
+     [
+      [
+       "/css/css-lists/li-value-reversed-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-lists/li-value-reversed-003.html": [
+    [
+     "css/css-lists/li-value-reversed-003.html",
+     [
+      [
+       "/css/css-lists/li-value-reversed-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-lists/li-value-reversed-004.html": [
+    [
+     "css/css-lists/li-value-reversed-004.html",
+     [
+      [
+       "/css/css-lists/li-value-reversed-004-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-lists/li-value-reversed-005.html": [
+    [
+     "css/css-lists/li-value-reversed-005.html",
+     [
+      [
+       "/css/css-lists/li-value-reversed-004-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-lists/li-with-height-001.html": [
     [
      "css/css-lists/li-with-height-001.html",
@@ -55823,6 +55883,18 @@
      {}
     ]
    ],
+   "css/css-multicol/multicol-breaking-nobackground-004.html": [
+    [
+     "css/css-multicol/multicol-breaking-nobackground-004.html",
+     [
+      [
+       "/css/css-multicol/multicol-breaking-nobackground-004-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-multicol/multicol-clip-001.xht": [
     [
      "css/css-multicol/multicol-clip-001.xht",
@@ -56867,6 +56939,18 @@
      {}
     ]
    ],
+   "css/css-multicol/multicol-rule-nested-balancing-003.html": [
+    [
+     "css/css-multicol/multicol-rule-nested-balancing-003.html",
+     [
+      [
+       "/css/css-multicol/multicol-rule-nested-balancing-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-multicol/multicol-rule-none-000.xht": [
     [
      "css/css-multicol/multicol-rule-none-000.xht",
@@ -64607,6 +64691,18 @@
      {}
     ]
    ],
+   "css/css-tables/table-cell-overflow-auto.html": [
+    [
+     "css/css-tables/table-cell-overflow-auto.html",
+     [
+      [
+       "/css/css-tables/table-cell-overflow-auto-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-tables/table-has-box-sizing-border-box-001.html": [
     [
      "css/css-tables/table-has-box-sizing-border-box-001.html",
@@ -87123,6 +87219,30 @@
      {}
     ]
    ],
+   "css/css-typed-om/width-by-max-px-em.html": [
+    [
+     "css/css-typed-om/width-by-max-px-em.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square-only.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-typed-om/width-by-min-px-em.html": [
+    [
+     "css/css-typed-om/width-by-min-px-em.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square-only.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-ui/appearance-auto-001.html": [
     [
      "css/css-ui/appearance-auto-001.html",
@@ -89163,6 +89283,30 @@
      {}
     ]
    ],
+   "css/css-values/max-length-percent-001.html": [
+    [
+     "css/css-values/max-length-percent-001.html",
+     [
+      [
+       "/css/css-values/reference/200-200-green.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-values/min-length-percent-001.html": [
+    [
+     "css/css-values/min-length-percent-001.html",
+     [
+      [
+       "/css/css-values/reference/200-200-green.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-values/q-unit-case-insensitivity-001.html": [
     [
      "css/css-values/q-unit-case-insensitivity-001.html",
@@ -115241,6 +115385,30 @@
      {}
     ]
    ],
+   "html/rendering/replaced-elements/the-select-element/select-1-block-size-001-2.html": [
+    [
+     "html/rendering/replaced-elements/the-select-element/select-1-block-size-001-2.html",
+     [
+      [
+       "/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "html/rendering/replaced-elements/the-select-element/select-1-block-size-001.html": [
+    [
+     "html/rendering/replaced-elements/the-select-element/select-1-block-size-001.html",
+     [
+      [
+       "/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/rendering/replaced-elements/the-select-element/select-1-block-size.html": [
     [
      "html/rendering/replaced-elements/the-select-element/select-1-block-size.html",
@@ -116997,6 +117165,66 @@
      {}
     ]
    ],
+   "mathml/presentation-markup/direction/direction-006.html": [
+    [
+     "mathml/presentation-markup/direction/direction-006.html",
+     [
+      [
+       "/mathml/presentation-markup/direction/direction-006-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "mathml/presentation-markup/direction/direction-007.html": [
+    [
+     "mathml/presentation-markup/direction/direction-007.html",
+     [
+      [
+       "/mathml/presentation-markup/direction/direction-007-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "mathml/presentation-markup/direction/direction-008.html": [
+    [
+     "mathml/presentation-markup/direction/direction-008.html",
+     [
+      [
+       "/mathml/presentation-markup/direction/direction-008-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "mathml/presentation-markup/direction/direction-009.html": [
+    [
+     "mathml/presentation-markup/direction/direction-009.html",
+     [
+      [
+       "/mathml/presentation-markup/direction/direction-009-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "mathml/presentation-markup/direction/direction-010.html": [
+    [
+     "mathml/presentation-markup/direction/direction-010.html",
+     [
+      [
+       "/mathml/presentation-markup/direction/direction-010-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "mathml/presentation-markup/direction/direction-overall.html": [
     [
      "mathml/presentation-markup/direction/direction-overall.html",
@@ -117933,6 +118161,18 @@
      {}
     ]
    ],
+   "quirks/dd-dl-firefox-001.html": [
+    [
+     "quirks/dd-dl-firefox-001.html",
+     [
+      [
+       "/quirks/dd-dl-firefox-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "quirks/historical/list-item-bullet-size.html": [
     [
      "quirks/historical/list-item-bullet-size.html",
@@ -139715,6 +139955,15 @@
    "css/css-lists/li-value-counter-reset-001-ref.html": [
     []
    ],
+   "css/css-lists/li-value-reversed-001-ref.html": [
+    []
+   ],
+   "css/css-lists/li-value-reversed-002-ref.html": [
+    []
+   ],
+   "css/css-lists/li-value-reversed-004-ref.html": [
+    []
+   ],
    "css/css-lists/li-with-height-001-ref.html": [
     []
    ],
@@ -140096,6 +140345,9 @@
    "css/css-multicol/multicol-breaking-nobackground-003-ref.html": [
     []
    ],
+   "css/css-multicol/multicol-breaking-nobackground-004-ref.html": [
+    []
+   ],
    "css/css-multicol/multicol-clip-001-ref.xht": [
     []
    ],
@@ -140282,6 +140534,9 @@
    "css/css-multicol/multicol-rule-nested-balancing-002-ref.html": [
     []
    ],
+   "css/css-multicol/multicol-rule-nested-balancing-003-ref.html": [
+    []
+   ],
    "css/css-multicol/multicol-rule-ref.xht": [
     []
    ],
@@ -142109,6 +142364,9 @@
    "css/css-tables/support/base.css": [
     []
    ],
+   "css/css-tables/table-cell-overflow-auto-ref.html": [
+    []
+   ],
    "css/css-tables/table-model-fixup-expected.txt": [
     []
    ],
@@ -142148,6 +142406,9 @@
    "css/css-text-decor/parsing/text-decoration-line-valid-expected.txt": [
     []
    ],
+   "css/css-text-decor/parsing/text-decoration-valid-expected.txt": [
+    []
+   ],
    "css/css-text-decor/reference/line-through-vertical-ref.html": [
     []
    ],
@@ -145139,6 +145400,9 @@
    "css/css-transforms/translateY/reference/svg-translatey-ref.html": [
     []
    ],
+   "css/css-transitions/AnimationEffect-getComputedTiming.tentative-expected.txt": [
+    []
+   ],
    "css/css-transitions/CSSPseudoElement-getAnimations.tentative-expected.txt": [
     []
    ],
@@ -145178,6 +145442,9 @@
    "css/css-transitions/properties-value-003-expected.txt": [
     []
    ],
+   "css/css-transitions/properties-value-auto-001-expected.txt": [
+    []
+   ],
    "css/css-transitions/properties-value-implicit-001-expected.txt": [
     []
    ],
@@ -159038,6 +159305,9 @@
    "html/interaction/focus/processing-model/support/preventScroll-helper.html": [
     []
    ],
+   "html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter-expected.txt": [
+    []
+   ],
    "html/obsolete/META.yml": [
     []
    ],
@@ -159380,6 +159650,12 @@
    "html/rendering/replaced-elements/the-option-element/option-with-br-ref.html": [
     []
    ],
+   "html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html": [
+    []
+   ],
+   "html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html": [
+    []
+   ],
    "html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html": [
     []
    ],
@@ -163163,6 +163439,21 @@
    "mathml/README.md": [
     []
    ],
+   "mathml/presentation-markup/direction/direction-006-ref.html": [
+    []
+   ],
+   "mathml/presentation-markup/direction/direction-007-ref.html": [
+    []
+   ],
+   "mathml/presentation-markup/direction/direction-008-ref.html": [
+    []
+   ],
+   "mathml/presentation-markup/direction/direction-009-ref.html": [
+    []
+   ],
+   "mathml/presentation-markup/direction/direction-010-ref.html": [
+    []
+   ],
    "mathml/presentation-markup/direction/direction-overall-ref.html": [
     []
    ],
@@ -165365,6 +165656,9 @@
    "quirks/body-fills-html-quirk-ref.html": [
     []
    ],
+   "quirks/dd-dl-firefox-001-ref.html": [
+    []
+   ],
    "quirks/hashless-hex-color/support/common.js": [
     []
    ],
@@ -212287,14 +212581,6 @@
      {}
     ]
    ],
-   "css/css-transitions/transitions-animatable-properties-01.html": [
-    [
-     "css/css-transitions/transitions-animatable-properties-01.html",
-     {
-      "timeout": "long"
-     }
-    ]
-   ],
    "css/css-transitions/zero-duration-multiple-transition.html": [
     [
      "css/css-transitions/zero-duration-multiple-transition.html",
@@ -239420,6 +239706,12 @@
      }
     ]
    ],
+   "html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter.html": [
+    [
+     "html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter.html",
+     {}
+    ]
+   ],
    "html/interaction/focus/tabindex-focus-flag.html": [
     [
      "html/interaction/focus/tabindex-focus-flag.html",
@@ -250936,9 +251228,9 @@
      {}
     ]
    ],
-   "intersection-observer/cross-origin-iframe.html": [
+   "intersection-observer/cross-origin-iframe.sub.html": [
     [
-     "intersection-observer/cross-origin-iframe.html",
+     "intersection-observer/cross-origin-iframe.sub.html",
      {}
     ]
    ],
@@ -281654,6 +281946,14 @@
      {}
     ]
    ],
+   "shadow-dom/focus/DocumentOrShadowRoot-activeElement.html": [
+    [
+     "shadow-dom/focus/DocumentOrShadowRoot-activeElement.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "shadow-dom/focus/focus-tabindex-order-shadow-negative.html": [
     [
      "shadow-dom/focus/focus-tabindex-order-shadow-negative.html",
@@ -345401,7 +345701,7 @@
    "testharness"
   ],
   "css/css-animations/Element-getAnimations.tentative-expected.txt": [
-   "8fe889e1167494fc5d208f70122f4258be0eb3a5",
+   "ab7c1c8c984164536cb52269217c78ab6bd28cdf",
    "support"
   ],
   "css/css-animations/Element-getAnimations.tentative.html": [
@@ -368424,6 +368724,38 @@
    "0e91c3a03d618a9d17194c883f80fd90899d4459",
    "reftest"
   ],
+  "css/css-lists/li-value-reversed-001-ref.html": [
+   "7b5c5d86087fa9ad09296b519e582e6d0f161b09",
+   "support"
+  ],
+  "css/css-lists/li-value-reversed-001.html": [
+   "616d7ccc66bb7fbe543daf4a469344e568013f0d",
+   "reftest"
+  ],
+  "css/css-lists/li-value-reversed-002-ref.html": [
+   "71c187d3069c3ca4e6961c4788365d05ee15bd4f",
+   "support"
+  ],
+  "css/css-lists/li-value-reversed-002.html": [
+   "0c89ad21222aad4a4773833f3600dd48b22e0e81",
+   "reftest"
+  ],
+  "css/css-lists/li-value-reversed-003.html": [
+   "6e4d3d5f1ced2349355eae1fc097ae68daa0d591",
+   "reftest"
+  ],
+  "css/css-lists/li-value-reversed-004-ref.html": [
+   "da95a042cfdc4a701d2293f3834c3598d95f5648",
+   "support"
+  ],
+  "css/css-lists/li-value-reversed-004.html": [
+   "48ac24a6a2f6e5b81c380cdfc71350099a8eb93a",
+   "reftest"
+  ],
+  "css/css-lists/li-value-reversed-005.html": [
+   "84f017b4992f0f268537dcd9706bef2c454d17b8",
+   "reftest"
+  ],
   "css/css-lists/li-with-height-001-ref.html": [
    "486009d5604ab7a2cb66df735efff3c11c00b685",
    "support"
@@ -370280,6 +370612,14 @@
    "edf18f98981753750ec6588e5fd0ff97c1475005",
    "reftest"
   ],
+  "css/css-multicol/multicol-breaking-nobackground-004-ref.html": [
+   "2245fae043e11c8c0b00113186b497abca3faa70",
+   "support"
+  ],
+  "css/css-multicol/multicol-breaking-nobackground-004.html": [
+   "7b810423c91d862b80891902c4ba405975c0a493",
+   "reftest"
+  ],
   "css/css-multicol/multicol-clip-001-ref.xht": [
    "d742ea716d38b186ce5598b4e7db28e6ae74985b",
    "support"
@@ -370900,6 +371240,14 @@
    "b38f90947a917fba51d6b7192e567ec7816de1c8",
    "reftest"
   ],
+  "css/css-multicol/multicol-rule-nested-balancing-003-ref.html": [
+   "573afe683fe963ef980cb232ceeb50f420ae72bd",
+   "support"
+  ],
+  "css/css-multicol/multicol-rule-nested-balancing-003.html": [
+   "3dea42550e5e50846de681efc95e0221036511bb",
+   "reftest"
+  ],
   "css/css-multicol/multicol-rule-none-000.xht": [
    "32ca043957782f09c69bd77bd4933345228b81d7",
    "reftest"
@@ -377928,6 +378276,14 @@
    "52be1bb4e52e5705319ebf5525f6d89839356d65",
    "support"
   ],
+  "css/css-tables/table-cell-overflow-auto-ref.html": [
+   "18163de30320bd1f0f1a7248cd4c2f2d2897d0c5",
+   "support"
+  ],
+  "css/css-tables/table-cell-overflow-auto.html": [
+   "6b688561b91321990f18680f88aa4873dd35916a",
+   "reftest"
+  ],
   "css/css-tables/table-has-box-sizing-border-box-001.html": [
    "e3cddd12a6686bec09e5b0d0f47e62e6517c69ae",
    "reftest"
@@ -378244,8 +378600,12 @@
    "d47303f80546526c1c96b2c1e58d5c5e45ecedd9",
    "testharness"
   ],
+  "css/css-text-decor/parsing/text-decoration-valid-expected.txt": [
+   "54054b8c5c12ea7b776446faad593bca8bd12321",
+   "support"
+  ],
   "css/css-text-decor/parsing/text-decoration-valid.html": [
-   "1c1aef3ff00a9f0d3867be9d395485d5b93bbede",
+   "fd12ab4dc31d5de8e1212f26fa18adb0d0e7166c",
    "testharness"
   ],
   "css/css-text-decor/parsing/text-shadow-computed.html": [
@@ -391460,6 +391820,10 @@
    "c8caa6bd7c17de28dcd3f50c6357adc574084225",
    "reftest"
   ],
+  "css/css-transitions/AnimationEffect-getComputedTiming.tentative-expected.txt": [
+   "dfb103d1b940d787c00b3c0c975d7588cf99cac8",
+   "support"
+  ],
   "css/css-transitions/AnimationEffect-getComputedTiming.tentative.html": [
    "4b6a28b5694f52103bcb6b383dbcd1ad6553cf3a",
    "testharness"
@@ -391497,7 +391861,7 @@
    "testharness"
   ],
   "css/css-transitions/CSSTransition-startTime.tentative.html": [
-   "b6482f8047422f6d5abf6e1ae5a14b8fdc9a41f8",
+   "4dbe8634192a3e2431aa7c0f542071fec47e2ba7",
    "testharness"
   ],
   "css/css-transitions/CSSTransition-transitionProperty.tentative.html": [
@@ -391685,63 +392049,67 @@
    "testharness"
   ],
   "css/css-transitions/properties-value-001-expected.txt": [
-   "e7f8cfe2f2b39c4a90052a85dc0d610fe7ad1c56",
+   "b0b445bbaca938e82673558fabb4a192ad5439e2",
    "support"
   ],
   "css/css-transitions/properties-value-001.html": [
-   "a4d196a56474c95463ecb00d5bf374eb87c1e615",
+   "1f6d49881bfa2bcc5fa95b316af20a8806e620b5",
    "testharness"
   ],
   "css/css-transitions/properties-value-002-expected.txt": [
-   "a7c6fc646705e565750c6cf83dcc3605fb9126e6",
+   "7e5dfd48eadb4300d8e52776ed4859ec68082ad2",
    "support"
   ],
   "css/css-transitions/properties-value-002.html": [
-   "a1f91682e0cb3c27877b03e7a3ca1cebb6ad7619",
+   "9c5d9afbb931256251ef59f055d00619282a2e9f",
    "testharness"
   ],
   "css/css-transitions/properties-value-003-expected.txt": [
-   "290eb66deaace33c68396767f23f69360c0ec575",
+   "7553c96c1e49c4f0d42d3aec21acce5588c54ab4",
    "support"
   ],
   "css/css-transitions/properties-value-003.html": [
-   "49c8dfbd786cb133f64b538ce2d8a557bc9bde7c",
+   "4f6bbda53bc2df17f28987d13ff8288fc94290c4",
    "testharness"
   ],
+  "css/css-transitions/properties-value-auto-001-expected.txt": [
+   "89aeac52eb457b7bb4d0e2fc7c7078681720886a",
+   "support"
+  ],
   "css/css-transitions/properties-value-auto-001.html": [
-   "dd077f05f5d40a0ac85f78b26eb92446d9417393",
+   "6c932aa7cd6c9156e943027551a7cbbce3786365",
    "testharness"
   ],
   "css/css-transitions/properties-value-implicit-001-expected.txt": [
-   "595ad3b4a28c923909d3c255463c9e4b0dd26d68",
+   "b8b3104a8de43763f21c51f1216090a14d289731",
    "support"
   ],
   "css/css-transitions/properties-value-implicit-001.html": [
-   "fe7664986b493d506f7e495609a623a6b7c72718",
+   "8500436c529707f43349354ee87ef460e2d7d63b",
    "testharness"
   ],
   "css/css-transitions/properties-value-inherit-001-expected.txt": [
-   "4b2acfc217205dc7ee6651b81152f451a3081166",
+   "a255768430a996a8a943c69549f7b9aeede463a5",
    "support"
   ],
   "css/css-transitions/properties-value-inherit-001.html": [
-   "0e91c7101b27584e735c8959463f6d02ec581bed",
+   "abbdecdfae9159fd0d315d6dea955e81aec988ce",
    "testharness"
   ],
   "css/css-transitions/properties-value-inherit-002-expected.txt": [
-   "e7f8cfe2f2b39c4a90052a85dc0d610fe7ad1c56",
+   "b0b445bbaca938e82673558fabb4a192ad5439e2",
    "support"
   ],
   "css/css-transitions/properties-value-inherit-002.html": [
-   "49ee3140f7b33bee500c7db9d7ccea0568b1b80b",
+   "9556cf7e23af7f755d5c1e9d09571fb8a9ee91aa",
    "testharness"
   ],
   "css/css-transitions/properties-value-inherit-003.html": [
-   "046ba43c41f2732b3c67aa8c3881904e1532a517",
+   "13a16132134c14b273a443779a9b95468ec1af9f",
    "testharness"
   ],
   "css/css-transitions/pseudo-elements-001.html": [
-   "ae9db1e5c6328f84f3bcd30a898401d37af84dfd",
+   "146c533e235f0061872586039172a51c2d779873",
    "testharness"
   ],
   "css/css-transitions/pseudo-elements-002.html": [
@@ -391873,7 +392241,7 @@
    "support"
   ],
   "css/css-transitions/support/runParallelAsyncHarness.js": [
-   "fa3b09c7d8413cddf887680551434c9cdebfe780",
+   "de9b7837900b4daa3884babe6545b57ea901da15",
    "support"
   ],
   "css/css-transitions/support/square-purple.png": [
@@ -392256,10 +392624,6 @@
    "cd47469ec742106ace7d904dc588d746ac514ba5",
    "testharness"
   ],
-  "css/css-transitions/transitions-animatable-properties-01.html": [
-   "48a7d1e2e016ae914dbc9b8c08eadbc0e2a669a2",
-   "testharness"
-  ],
   "css/css-transitions/zero-duration-multiple-transition.html": [
    "4268ce766d76f14af0a211e829f50434f131bd20",
    "testharness"
@@ -392553,7 +392917,7 @@
    "testharness"
   ],
   "css/css-typed-om/stylevalue-subclasses/numeric-objects/parse.tentative.html": [
-   "80e4f44b3a01be23e6459e7e9e1d7dd44318e809",
+   "98384b6fcc5efd446833e7d8a9f4d8a7ff61167c",
    "testharness"
   ],
   "css/css-typed-om/stylevalue-subclasses/numeric-objects/resources/testhelper.js": [
@@ -393912,6 +394276,14 @@
    "53773fb96fc1b6112ad5b297480dac56360de343",
    "testharness"
   ],
+  "css/css-typed-om/width-by-max-px-em.html": [
+   "2aac59b70744e24fccd91bfc92d1177d6bb5c3a6",
+   "reftest"
+  ],
+  "css/css-typed-om/width-by-min-px-em.html": [
+   "615cb15708c35caf3e3c8af49f349a93df9429ff",
+   "reftest"
+  ],
   "css/css-ui/META.yml": [
    "7ce4b54a22c78576dc2318ebd651dfd1cce374ad",
    "support"
@@ -397072,6 +397444,14 @@
    "295b418f304a76cde4dba21a1d24022557882b18",
    "testharness"
   ],
+  "css/css-values/max-length-percent-001.html": [
+   "ffb6c27db278bc030923745d0e06c47d2af897c3",
+   "reftest"
+  ],
+  "css/css-values/min-length-percent-001.html": [
+   "73069ecfe1e6d5b198f6e01df48facbe117d6828",
+   "reftest"
+  ],
   "css/css-values/q-unit-case-insensitivity-001.html": [
    "b4a08aa117952c6f92e2aec6f57843b46a460104",
    "reftest"
@@ -433032,6 +433412,14 @@
    "bda7c846878833fd50daf1a877ba068a18bc7833",
    "testharness"
   ],
+  "html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter-expected.txt": [
+   "25e2da07f6ca5e45b9b43818aabb29713c72a284",
+   "support"
+  ],
+  "html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter.html": [
+   "773739804b3aeaea268080317cd0cb79fba486d7",
+   "testharness"
+  ],
   "html/interaction/focus/tabindex-focus-flag.html": [
    "e40bc077594351019591de8cbfae8fb0d6af13fe",
    "testharness"
@@ -434240,6 +434628,22 @@
    "3b8d992cc2a07dfd902dbb1011e2c348e862baaa",
    "reftest"
   ],
+  "html/rendering/replaced-elements/the-select-element/select-1-block-size-001-2.html": [
+   "5f03a761dc8729632ef74dcf189b7945ae3cee8d",
+   "reftest"
+  ],
+  "html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html": [
+   "385c2a75d427dde8ef0ba71cc777f298027423b9",
+   "support"
+  ],
+  "html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html": [
+   "ad504846dfa29297927a369149d427499f0657b5",
+   "support"
+  ],
+  "html/rendering/replaced-elements/the-select-element/select-1-block-size-001.html": [
+   "5dc0fc15dc52c8f3af4595a7901fd89b1827f2a2",
+   "reftest"
+  ],
   "html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html": [
    "3e437494c0ad8dadd4d58b630194678753516fde",
    "support"
@@ -437829,7 +438233,7 @@
    "support"
   ],
   "html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-display-none-expected.txt": [
-   "6fb19bd4002feca97be42e7b5d25ba37103f2fbf",
+   "8db39100f978dca4be2c2c408e12707e9e906f76",
    "support"
   ],
   "html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-display-none.html": [
@@ -437837,7 +438241,7 @@
    "testharness"
   ],
   "html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-quirks-mode-expected.txt": [
-   "0e8e35af7e94b472a86ccca47d6864a31e309430",
+   "2b32a089e1e15e0c96613cedbb439fd463245eda",
    "support"
   ],
   "html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-quirks-mode.html": [
@@ -437845,7 +438249,7 @@
    "testharness"
   ],
   "html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-standards-mode-expected.txt": [
-   "c0e0f758b8cd3c10d8596abd92287826c0035f8a",
+   "db241964b0d701b4b670a062417cb49de88d0653",
    "support"
   ],
   "html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-standards-mode.html": [
@@ -437853,7 +438257,7 @@
    "testharness"
   ],
   "html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-width-1000px-expected.txt": [
-   "116a40919904f19d229bdecf361efdafba7b7258",
+   "944299d5544324bb4321af7e0fa2d9a538ec71b1",
    "support"
   ],
   "html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-width-1000px.html": [
@@ -446352,8 +446756,8 @@
    "f7ce6fa7246f006883b39479ad9bdda9ed84978c",
    "testharness"
   ],
-  "intersection-observer/cross-origin-iframe.html": [
-   "bdd6d3f529a0406d910580f477bce978c3e54c8c",
+  "intersection-observer/cross-origin-iframe.sub.html": [
+   "d444237f6b954b08952c502a510e7ead785c2eec",
    "testharness"
   ],
   "intersection-observer/disconnect.html": [
@@ -446441,7 +446845,7 @@
    "testharness"
   ],
   "intersection-observer/resources/cross-origin-subframe.html": [
-   "0cc117cb3a69d0f2ed19505f7d14f824cbad6d71",
+   "4305ed1719b68f227192e005c9696fec5fe58f83",
    "support"
   ],
   "intersection-observer/resources/iframe-no-root-subframe.html": [
@@ -446449,7 +446853,7 @@
    "support"
   ],
   "intersection-observer/resources/intersection-observer-test-utils.js": [
-   "44f794b0883b1bade51b1b7b8f5507ac6dfcb123",
+   "7db26d72df54505da7a6363009cab138772a7890",
    "support"
   ],
   "intersection-observer/resources/observer-in-iframe-subframe.html": [
@@ -447180,6 +447584,46 @@
    "9524d275e479ba2db2aaaab9fdbc1203c79009cb",
    "support"
   ],
+  "mathml/presentation-markup/direction/direction-006-ref.html": [
+   "39e6dabdfb19ac8ccd43605a01633b2730f6f95c",
+   "support"
+  ],
+  "mathml/presentation-markup/direction/direction-006.html": [
+   "904e7d3fed8c7ae6d1a19d522fe08a1e282a59c6",
+   "reftest"
+  ],
+  "mathml/presentation-markup/direction/direction-007-ref.html": [
+   "5c77395f2008ba5e6f1068b345e8ff1c58f93ee4",
+   "support"
+  ],
+  "mathml/presentation-markup/direction/direction-007.html": [
+   "7137e2640fa4ee76135f1d77f10ab329119c5332",
+   "reftest"
+  ],
+  "mathml/presentation-markup/direction/direction-008-ref.html": [
+   "492fa9539ae83285940b44f9463e1439c54705cf",
+   "support"
+  ],
+  "mathml/presentation-markup/direction/direction-008.html": [
+   "5c98b07410079806fc0163e1f9c4a98bcfe4cc3d",
+   "reftest"
+  ],
+  "mathml/presentation-markup/direction/direction-009-ref.html": [
+   "7ed4796814a7c0561b3ecaeeedf2eac7a5533e60",
+   "support"
+  ],
+  "mathml/presentation-markup/direction/direction-009.html": [
+   "bf8caf16aed28f2b55f5bdd96009f0cd9bfc1785",
+   "reftest"
+  ],
+  "mathml/presentation-markup/direction/direction-010-ref.html": [
+   "4f595ed49f698a7a70392edb5e72dd1df8471368",
+   "support"
+  ],
+  "mathml/presentation-markup/direction/direction-010.html": [
+   "6dc095ac1fd490ca3bcb869014c6e32428110f9e",
+   "reftest"
+  ],
   "mathml/presentation-markup/direction/direction-overall-ref.html": [
    "5ce6c5c42bb8068b895cdbe111644c339c4b9676",
    "support"
@@ -461336,6 +461780,14 @@
    "0fcad36776d5a7fe160244dc342f227b76083798",
    "testharness"
   ],
+  "quirks/dd-dl-firefox-001-ref.html": [
+   "46a4d7d156f6e99040cd500e241b56440e695796",
+   "support"
+  ],
+  "quirks/dd-dl-firefox-001.html": [
+   "96fc76f08f45b800f5e210aee135bf880f8f2d32",
+   "reftest"
+  ],
   "quirks/hashless-hex-color/limited-quirks.html": [
    "f7dd7ed4bd4634667f8f139b6d196824f8948c12",
    "testharness"
@@ -474829,7 +475281,7 @@
    "support"
   ],
   "service-workers/service-worker/resources/update-during-installation-worker.js": [
-   "3f89881c04384590b8b132c392977256bfb847ed",
+   "f1997bd824e8e165cc119a52082d742bd63f4e4d",
    "support"
   ],
   "service-workers/service-worker/resources/update-during-installation-worker.py": [
@@ -475508,6 +475960,10 @@
    "77da4476025fb6160f34efb1df9cfd87226cda02",
    "testharness"
   ],
+  "shadow-dom/focus/DocumentOrShadowRoot-activeElement.html": [
+   "20456b057e1e724cdac9bc656f3b3d6c7ac2f658",
+   "testharness"
+  ],
   "shadow-dom/focus/focus-tabindex-order-shadow-negative.html": [
    "ab25ea829bd10952ad6e96898fc95a1a1ae25d8f",
    "testharness"
@@ -477137,23 +477593,23 @@
    "support"
   ],
   "streams/readable-streams/patched-global.any-expected.txt": [
-   "95f34fb921ca5b3d8bd8b501e257c94d6844ca43",
+   "2e1b70634572385681e1d31b0b770a52fa60e241",
    "support"
   ],
   "streams/readable-streams/patched-global.any.js": [
-   "500979f5b37ad1af106fcbb76ca531d4dc539129",
+   "813dd42e68aa9f2c2bbb5e7bd6d8d4a78ef43db5",
    "testharness"
   ],
   "streams/readable-streams/patched-global.any.serviceworker-expected.txt": [
-   "95f34fb921ca5b3d8bd8b501e257c94d6844ca43",
+   "2e1b70634572385681e1d31b0b770a52fa60e241",
    "support"
   ],
   "streams/readable-streams/patched-global.any.sharedworker-expected.txt": [
-   "95f34fb921ca5b3d8bd8b501e257c94d6844ca43",
+   "2e1b70634572385681e1d31b0b770a52fa60e241",
    "support"
   ],
   "streams/readable-streams/patched-global.any.worker-expected.txt": [
-   "95f34fb921ca5b3d8bd8b501e257c94d6844ca43",
+   "2e1b70634572385681e1d31b0b770a52fa60e241",
    "support"
   ],
   "streams/readable-streams/reentrant-strategies.any.js": [
@@ -486281,7 +486737,7 @@
    "testharness"
   ],
   "user-timing/measure-with-dict.any.js": [
-   "99a2fe4d79841e5bd7fab3c0db50acb9434ef29b",
+   "95160fea8941d55a04381f46b730afc5a0956901",
    "testharness"
   ],
   "user-timing/measure.html": [
@@ -486293,7 +486749,7 @@
    "testharness"
   ],
   "user-timing/measure_exception.html": [
-   "f57d7f17999630000753f408772286a63845c765",
+   "df674d931f48f15e5164ff8b34d060c1966240d9",
    "testharness"
   ],
   "user-timing/measure_exceptions_navigation_timing.html": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-001-ref.html
new file mode 100644
index 0000000..7b5c5d86
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-001-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<ol>
+ <li value=3>three
+ <li value=6>six
+ <li value=5>five
+</ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-001.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-001.html
new file mode 100644
index 0000000..616d7cc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-001.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>Interaction of ol reversed and list-item value</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1573907">
+<link rel="help" href="https://html.spec.whatwg.org/#attr-ol-reversed">
+<link rel="help" href="https://html.spec.whatwg.org/#ordinal-value">
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="match" href="li-value-reversed-001-ref.html">
+<ol reversed>
+ <li>three
+ <li value=6>six
+ <li>five
+</ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-002-ref.html
new file mode 100644
index 0000000..71c187d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-002-ref.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<ol>
+ <li value=6>six
+ <li value=5>five
+ <li value=7>seven
+ <li value=6>six
+ <li value=10>ten
+ <li value=9>nine
+</ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-002.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-002.html
new file mode 100644
index 0000000..0c89ad2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-002.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>Interaction of ol reversed and list-item value</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1573907">
+<link rel="help" href="https://html.spec.whatwg.org/#attr-ol-reversed">
+<link rel="help" href="https://html.spec.whatwg.org/#ordinal-value">
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="match" href="li-value-reversed-002-ref.html">
+<ol reversed>
+ <li>six
+ <li>five
+ <li value=7>seven
+ <li>six
+ <li value=10>ten
+ <li>nine
+</ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-003.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-003.html
new file mode 100644
index 0000000..6e4d3d5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-003.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>Interaction of ol reversed and list-item value</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1573907">
+<link rel="help" href="https://html.spec.whatwg.org/#attr-ol-reversed">
+<link rel="help" href="https://html.spec.whatwg.org/#ordinal-value">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="match" href="li-value-reversed-002-ref.html">
+<ol reversed>
+ <li>six
+ <li>five
+ <li style="counter-set: list-item 7">seven
+ <li style="counter-increment: list-item -1">six
+ <li style="counter-set: list-item 10; counter-increment: list-item 1">ten
+ <li>nine
+</ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-004-ref.html
new file mode 100644
index 0000000..da95a04
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-004-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<ol>
+ <li value=2>two
+ <div></div>
+ <li value=0>zero
+</ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-004.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-004.html
new file mode 100644
index 0000000..48ac24a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-004.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>Non-list items with explicit list-item counter increments don't increment the ol reversed start value</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1573907">
+<link rel="help" href="https://html.spec.whatwg.org/#attr-ol-reversed">
+<link rel="help" href="https://html.spec.whatwg.org/#ordinal-value">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="match" href="li-value-reversed-004-ref.html">
+<ol reversed>
+ <li>two
+ <div style="counter-increment: list-item -1"></div>
+ <li>zero
+</ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-005.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-005.html
new file mode 100644
index 0000000..84f017b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-reversed-005.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>Non-list items with explicit list-item counter increments don't increment the ol reversed start value</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1573907">
+<link rel="help" href="https://html.spec.whatwg.org/#attr-ol-reversed">
+<link rel="help" href="https://html.spec.whatwg.org/#ordinal-value">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="match" href="li-value-reversed-004-ref.html">
+<ol reversed>
+ <li>two
+ <div style="counter-increment: list-item 1; counter-set: list-item 1"></div>
+ <li>zero
+</ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-breaking-nobackground-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-breaking-nobackground-004-ref.html
new file mode 100644
index 0000000..2245fae
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-breaking-nobackground-004-ref.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<title>CSS Test Reference: breaking of a multicolumn</title>
+<meta charset="utf-8">
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org/">
+<style>
+
+.outer {
+  height: 125px;
+  width: 800px;
+  background: rgba(0, 0, 255, 0.3);
+  position: relative;
+}
+
+.inner {
+  height: 100px;
+  width: 86px;
+  font: 16px/1.25 sans-serif;
+  position: absolute;
+  top: 0;
+}
+
+.border-bottom {
+  height: 25px;
+  width: 188px;
+  background: green;
+  position: absolute;
+  top: 100px;
+}
+
+.lefthalf {
+  border-right: 2px solid fuchsia;
+  padding-right: 7px;
+}
+
+.righthalf {
+  padding-left: 7px;
+}
+
+</style>
+
+<div class="outer">
+  <div class="inner lefthalf" style="left: 0">
+    AAAAA<br>
+    BBBBB<br>
+    CCCCC<br>
+    DDDDD<br>
+    EEEEE
+  </div>
+  <div class="inner righthalf" style="left: 95px">
+    FFFFF<br>
+    GGGGG<br>
+    HHHHH<br>
+    IIIII<br>
+    JJJJJ
+  </div>
+  <div class="border-bottom" style="left: 0"></div>
+  <div class="inner lefthalf" style="left: 204px">
+    KKKKK<br>
+    LLLLL<br>
+    MMMMM<br>
+    NNNNN
+  </div>
+  <div class="inner righthalf" style="left: 299px">
+    OOOOO<br>
+    PPPPP<br>
+    QQQQQ<br>
+  </div>
+  <div class="border-bottom" style="left: 204px;"></div>
+  <div class="border-bottom" style="left: 408px"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-breaking-nobackground-004.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-breaking-nobackground-004.html
new file mode 100644
index 0000000..7b81042
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-breaking-nobackground-004.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<title>CSS Test: breaking of a multicolumn</title>
+<meta charset="utf-8">
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org/">
+<link rel="help" href="https://drafts.csswg.org/css-multicol/#column-gaps-and-rules">
+<link rel="help" href="https://drafts.csswg.org/css-multicol/#cf">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
+<link rel="help" href="https://drafts.csswg.org/css-break/#break-decoration">
+<link rel="match" href="multicol-breaking-nobackground-004-ref.html">
+<style>
+
+.outer {
+  height: 125px;
+  column-fill: auto;
+  width: 800px;
+  column-count: 4;
+  column-gap: 16px;
+  background: rgba(0, 0, 255, 0.3);
+}
+
+.inner {
+  column-count: 2;
+  column-rule: 2px solid fuchsia;
+  column-gap: 16px;
+  font: 16px/1.25 sans-serif;
+  border: solid green;
+  border-width: 0 0 25px 0;
+  box-decoration-break: clone;
+}
+
+</style>
+
+<div class="outer">
+  <div class="inner" style="height: 300px">
+    AAAAA<br>
+    BBBBB<br>
+    CCCCC<br>
+    DDDDD<br>
+    EEEEE<br>
+    FFFFF<br>
+    GGGGG<br>
+    HHHHH<br>
+    IIIII<br>
+    JJJJJ<br>
+    KKKKK<br>
+    LLLLL<br>
+    MMMMM<br>
+    NNNNN<br>
+    OOOOO<br>
+    PPPPP<br>
+    QQQQQ
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-003-ref.html
new file mode 100644
index 0000000..573afe6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-003-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test Reference: Test the column rules' block-size with nested balancing multicol container</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+
+  <style>
+  .outer {
+    column-count: 2;
+    column-rule: 6px solid black;
+    column-fill: auto;
+    width: 400px;
+    height: 250px;
+  }
+  .inner {
+    column-count: 2;
+    column-rule: 3px solid gray;
+    column-fill: auto;
+    height: 200px;
+  }
+  .inner-block {
+    background-color: lightblue;
+    height: 400px;
+  }
+  .space {
+    height: 50px;
+  }
+  </style>
+
+  <article class="outer">
+    <article class="inner">
+      <div class="inner-block"></div>
+    </article>
+    <div class="space"></div>
+    <article class="inner">
+      <div class="inner-block"></div>
+    </article>
+    <div class="space"></div>
+  </article>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-003.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-003.html
new file mode 100644
index 0000000..3dea4255
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-rule-nested-balancing-003.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test the column rules' block-size with nested balancing multicol container</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#cf">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-gaps-and-rules">
+  <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
+  <link rel="match" href="multicol-rule-nested-balancing-003-ref.html">
+  <meta name="assert" content="This test verifies that the column-rules are extended to the content block-end edges of their corresponding inner and outer multicol container.">
+
+  <style>
+  .outer {
+    column-count: 2;
+    column-rule: 6px solid black;
+    width: 400px;
+    height: 250px;
+  }
+  .inner {
+    column-count: 2;
+    column-rule: 3px solid gray;
+    height: 400px;
+  }
+  .inner-block {
+    background-color: lightblue;
+    height: 800px;
+  }
+  </style>
+
+  <article class="outer">
+    <article class="inner">
+      <div class="inner-block"></div>
+    </article>
+  </article>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-overflow-auto-ref.html b/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-overflow-auto-ref.html
new file mode 100644
index 0000000..18163de3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-overflow-auto-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<div style="width: 100px; height: 100px; border: solid;">
+  <div style="display: table-cell; max-width: 100px; height: 100px; background: green; overflow-x: scroll; vertical-align: top;">
+     <div style="width: 120px; height: 50px; background: hotpink;"></div>
+   </div>
+</div>
+<br>
+<div style="width: 100px; height: 100px; border: solid;">
+  <div style="display: table-cell; max-width: 100px; height: 100px; background: green; overflow-x: scroll; vertical-align: middle;">
+     <div style="width: 120px; height: 50px; background: hotpink;"></div>
+   </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-overflow-auto.html b/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-overflow-auto.html
new file mode 100644
index 0000000..6b68856
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-overflow-auto.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-tables-3/#row-layout">
+<link rel="match" href="table-cell-overflow-auto-ref.html">
+<meta name="assert" content="horizontal scrollbars show up on table-cells with overflowing content and overflow:auto, vertical-align: middle/top" />
+<div style="width: 100px; height: 100px; border: solid;">
+  <div style="display: table-cell; max-width: 100px; height: 100px; background: green; overflow-x: auto; vertical-align: top;">
+     <div style="width: 120px; height: 50px; background: hotpink;"></div>
+   </div>
+</div>
+<br>
+<div style="width: 100px; height: 100px; border: solid;">
+  <div style="display: table-cell; max-width: 100px; height: 100px; background: green; overflow-x: auto; vertical-align: middle;">
+     <div style="width: 120px; height: 50px; background: hotpink;"></div>
+   </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-valid-expected.txt
new file mode 100644
index 0000000..54054b8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-valid-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS e.style['text-decoration'] = "none" should set the property value
+PASS e.style['text-decoration'] = "line-through" should set the property value
+FAIL e.style['text-decoration'] = "solid" should set the property value assert_equals: serialization should be canonical expected "none" but got "solid"
+FAIL e.style['text-decoration'] = "currentcolor" should set the property value assert_equals: serialization should be canonical expected "none" but got "currentcolor"
+FAIL e.style['text-decoration'] = "auto" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration'] = "from-font" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration'] = "10px" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['text-decoration'] = "double overline underline" should set the property value
+PASS e.style['text-decoration'] = "underline overline line-through red" should set the property value
+PASS e.style['text-decoration'] = "rgba(10, 20, 30, 0.4) dotted" should set the property value
+FAIL e.style['text-decoration'] = "overline green from-font" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['text-decoration'] = "underline dashed green" should set the property value
+FAIL e.style['text-decoration'] = "underline auto" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration'] = "line-through 20px" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['text-decoration'] = "overline 3em" 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/parsing/text-decoration-valid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-valid.html
index 1c1aef3..fd12ab4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-valid.html
@@ -9,12 +9,18 @@
 <script>
 test_valid_value("text-decoration", "none");
 test_valid_value("text-decoration", "line-through");
-test_valid_value("text-decoration", "solid");
-test_valid_value("text-decoration", "currentcolor");
+test_valid_value("text-decoration", "solid", "none");
+test_valid_value("text-decoration", "currentcolor", "none");
+test_valid_value("text-decoration", "auto", "none");
+test_valid_value("text-decoration", "from-font");
+test_valid_value("text-decoration", "10px");
 
 test_valid_value("text-decoration", "double overline underline", "underline overline double");
 test_valid_value("text-decoration", "underline overline line-through red");
 test_valid_value("text-decoration", "rgba(10, 20, 30, 0.4) dotted", "dotted rgba(10, 20, 30, 0.4)");
-
+test_valid_value("text-decoration", "overline green from-font");
 test_valid_value("text-decoration", "underline dashed green");
+test_valid_value("text-decoration", "underline auto", "underline");
+test_valid_value("text-decoration", "line-through 20px");
+test_valid_value("text-decoration", "overline 3em");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter-expected.txt b/third_party/blink/web_tests/external/wpt/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter-expected.txt
new file mode 100644
index 0000000..25e2da0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter-expected.txt
@@ -0,0 +1,104 @@
+This is a testharness.js-based test.
+Found 100 tests; 94 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS input.tabIndex should return 0 by default
+PASS input.tabIndex should return -1 when set to -1
+PASS input.tabIndex should return 0 when set to 0
+PASS input.tabIndex should return 1 when set to 1
+PASS input[type='hidden'].tabIndex should return 0 by default
+PASS input[type='hidden'].tabIndex should return -1 when set to -1
+PASS input[type='hidden'].tabIndex should return 0 when set to 0
+PASS input[type='hidden'].tabIndex should return 1 when set to 1
+PASS button.tabIndex should return 0 by default
+PASS button.tabIndex should return -1 when set to -1
+PASS button.tabIndex should return 0 when set to 0
+PASS button.tabIndex should return 1 when set to 1
+PASS button[disabled].tabIndex should return 0 by default
+PASS button[disabled].tabIndex should return -1 when set to -1
+PASS button[disabled].tabIndex should return 0 when set to 0
+PASS button[disabled].tabIndex should return 1 when set to 1
+PASS button[hidden].tabIndex should return 0 by default
+PASS button[hidden].tabIndex should return -1 when set to -1
+PASS button[hidden].tabIndex should return 0 when set to 0
+PASS button[hidden].tabIndex should return 1 when set to 1
+PASS a.tabIndex should return 0 by default
+PASS a.tabIndex should return -1 when set to -1
+PASS a.tabIndex should return 0 when set to 0
+PASS a.tabIndex should return 1 when set to 1
+PASS a[href].tabIndex should return 0 by default
+PASS a[href].tabIndex should return -1 when set to -1
+PASS a[href].tabIndex should return 0 when set to 0
+PASS a[href].tabIndex should return 1 when set to 1
+PASS svg a.tabIndex should return 0 by default
+PASS svg a.tabIndex should return -1 when set to -1
+PASS svg a.tabIndex should return 0 when set to 0
+PASS svg a.tabIndex should return 1 when set to 1
+PASS textarea.tabIndex should return 0 by default
+PASS textarea.tabIndex should return -1 when set to -1
+PASS textarea.tabIndex should return 0 when set to 0
+PASS textarea.tabIndex should return 1 when set to 1
+PASS select.tabIndex should return 0 by default
+PASS select.tabIndex should return -1 when set to -1
+PASS select.tabIndex should return 0 when set to 0
+PASS select.tabIndex should return 1 when set to 1
+PASS select[multiple].tabIndex should return 0 by default
+PASS select[multiple].tabIndex should return -1 when set to -1
+PASS select[multiple].tabIndex should return 0 when set to 0
+PASS select[multiple].tabIndex should return 1 when set to 1
+PASS option.tabIndex should return -1 by default
+PASS option.tabIndex should return -1 when set to -1
+FAIL option.tabIndex should return 0 when set to 0 assert_equals: expected 0 but got -1
+FAIL option.tabIndex should return 1 when set to 1 assert_equals: expected 1 but got -1
+PASS optgroup.tabIndex should return -1 by default
+PASS optgroup.tabIndex should return -1 when set to -1
+FAIL optgroup.tabIndex should return 0 when set to 0 assert_equals: expected 0 but got -1
+FAIL optgroup.tabIndex should return 1 when set to 1 assert_equals: expected 1 but got -1
+PASS iframe.tabIndex should return 0 by default
+PASS iframe.tabIndex should return -1 when set to -1
+PASS iframe.tabIndex should return 0 when set to 0
+PASS iframe.tabIndex should return 1 when set to 1
+FAIL embed.tabIndex should return -1 by default assert_equals: expected -1 but got 0
+PASS embed.tabIndex should return -1 when set to -1
+PASS embed.tabIndex should return 0 when set to 0
+PASS embed.tabIndex should return 1 when set to 1
+PASS object.tabIndex should return 0 by default
+PASS object.tabIndex should return -1 when set to -1
+PASS object.tabIndex should return 0 when set to 0
+PASS object.tabIndex should return 1 when set to 1
+PASS span.tabIndex should return -1 by default
+PASS span.tabIndex should return -1 when set to -1
+PASS span.tabIndex should return 0 when set to 0
+PASS span.tabIndex should return 1 when set to 1
+PASS div.tabIndex should return -1 by default
+PASS div.tabIndex should return -1 when set to -1
+PASS div.tabIndex should return 0 when set to 0
+PASS div.tabIndex should return 1 when set to 1
+PASS link#nohref.tabIndex should return -1 by default
+PASS link#nohref.tabIndex should return -1 when set to -1
+PASS link#nohref.tabIndex should return 0 when set to 0
+PASS link#nohref.tabIndex should return 1 when set to 1
+PASS link[href].tabIndex should return -1 by default
+PASS link[href].tabIndex should return -1 when set to -1
+PASS link[href].tabIndex should return 0 when set to 0
+PASS link[href].tabIndex should return 1 when set to 1
+PASS details.tabIndex should return -1 by default
+PASS details.tabIndex should return -1 when set to -1
+PASS details.tabIndex should return 0 when set to 0
+PASS details.tabIndex should return 1 when set to 1
+PASS summary.tabIndex should return 0 by default
+PASS summary.tabIndex should return -1 when set to -1
+PASS summary.tabIndex should return 0 when set to 0
+PASS summary.tabIndex should return 1 when set to 1
+PASS summary#secondsummary.tabIndex should return -1 by default
+PASS summary#secondsummary.tabIndex should return -1 when set to -1
+PASS summary#secondsummary.tabIndex should return 0 when set to 0
+PASS summary#secondsummary.tabIndex should return 1 when set to 1
+FAIL #hostDelegatesFocus.tabIndex should return -1 by default assert_equals: expected -1 but got 0
+PASS #hostDelegatesFocus.tabIndex should return -1 when set to -1
+PASS #hostDelegatesFocus.tabIndex should return 0 when set to 0
+PASS #hostDelegatesFocus.tabIndex should return 1 when set to 1
+PASS #hostNonDelegatesFocus.tabIndex should return -1 by default
+PASS #hostNonDelegatesFocus.tabIndex should return -1 when set to -1
+PASS #hostNonDelegatesFocus.tabIndex should return 0 when set to 0
+PASS #hostNonDelegatesFocus.tabIndex should return 1 when set to 1
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter.html b/third_party/blink/web_tests/external/wpt/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter.html
new file mode 100644
index 0000000..77373980
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/tabindex-getter.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: tabIndex getter return value</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#dom-tabindex">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<input>
+<input type="hidden">
+<button>button</button>
+<button disabled>button</button>
+<button hidden>button</button>
+<a>a</a>
+<a href="#">a</a>
+<svg><a>svg a</a></svg>
+<svg><a>svg a</a></svg>
+<link id="nohref">
+<textarea></textarea>
+<select><optgroup><option>option</option></optgroup></select>
+<select multiple></select>
+<iframe width="10" height="10"></iframe>
+<embed width="10" height="10"></embed>
+<object width="10" height="10"></object>
+<span></span>
+<div></div>
+<details><summary>summary</summary><summary id="secondsummary">second summary</summary>details</details>
+<div id="hostDelegatesFocus"></div>
+<div id="hostNonDelegatesFocus"></div>
+<script>
+document.getElementById("hostDelegatesFocus").attachShadow({ mode: "open", delegatesFocus: true });
+document.getElementById("hostNonDelegatesFocus").attachShadow({ mode: "open", delegatesFocus: false });
+const defaultList = [
+  ["input", 0],
+  ["input[type='hidden']", 0],
+  ["button", 0],
+  ["button[disabled]", 0],
+  ["button[hidden]", 0],
+  ["a", 0],
+  ["a[href]", 0],
+  ["svg a", 0],
+  ["textarea", 0],
+  ["select", 0],
+  ["select[multiple]", 0],
+  ["option", -1],
+  ["optgroup", -1],
+  ["iframe", 0],
+  ["embed", -1],
+  ["object", 0],
+  ["span", -1],
+  ["div", -1],
+  ["link#nohref", -1],
+  ["link[href]", -1],
+  ["details", -1],
+  ["summary", 0],
+  ["summary#secondsummary", -1],
+  ["#hostDelegatesFocus", -1],
+  ["#hostNonDelegatesFocus", -1],
+];
+const tabIndexValue = [-1, 0, 1];
+for (const entry of defaultList) {
+  const element = document.querySelector(entry[0]);
+  test(() => {
+    assert_equals(element.tabIndex, entry[1]);
+  }, entry[0] + ".tabIndex should return " + entry[1] + " by default");
+  for (const setValue of tabIndexValue ) {
+    test(() => {
+      element.setAttribute("tabindex", setValue);
+      assert_equals(element.tabIndex, setValue);
+    }, entry[0] + ".tabIndex should return " + setValue + " when set to " + setValue);
+  }
+}
+</script>
+</body>
+
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-2.html b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-2.html
new file mode 100644
index 0000000..5f03a761
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-2.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>Select block size when line-height is specified</title>
+<!--
+  FIXME: This is just a copy of select-1-block-size-001.html, but if I move the
+  <link rel="match"> in this file to select-1-block-size-001-ref.html (which is
+  the "right" way to do this), fuzzy annotations do not work.
+-->
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1571764">
+<link rel="match" href="select-1-block-size-001-ref-2.html">
+<style>
+select {
+  -webkit-appearance: none;
+  appearance: none;
+
+  background: black;
+  color: black;
+
+  line-height: 100px;
+  width: 100px;
+
+  border: 0;
+  border-radius: 0;
+  padding: 0;
+}
+</style>
+<select></select>
+<select><option>A</option></select>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html
new file mode 100644
index 0000000..385c2a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref-2.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1571764">
+<style>
+div {
+  -webkit-appearance: none;
+  appearance: none;
+
+  background: black;
+  color: black;
+
+  line-height: 100px;
+  width: 100px;
+
+  border: 0;
+  padding: 0;
+
+  display: inline-block;
+}
+</style>
+<div>A</div>
+<div>A</div>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html
new file mode 100644
index 0000000..ad50484
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001-ref.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1571764">
+<style>
+button {
+  -webkit-appearance: none;
+  appearance: none;
+
+  background: black;
+  color: black;
+
+  line-height: 100px;
+  width: 100px;
+
+  border: 0;
+  border-radius: 0;
+  padding: 0;
+}
+</style>
+<button>A</button>
+<button>A</button>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001.html b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001.html
new file mode 100644
index 0000000..5dc0fc15
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/the-select-element/select-1-block-size-001.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<title>Select block size when line-height is specified</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1571764">
+<link rel="match" href="select-1-block-size-001-ref.html">
+<style>
+select {
+  -webkit-appearance: none;
+  appearance: none;
+
+  background: black;
+  color: black;
+
+  line-height: 100px;
+  width: 100px;
+
+  border: 0;
+  border-radius: 0;
+  padding: 0;
+}
+</style>
+<select></select>
+<select><option>A</option></select>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-display-none-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-display-none-expected.txt
index 6fb19bd..8db39100 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-display-none-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-display-none-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 171 tests; 154 PASS, 17 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 171 tests; 158 PASS, 13 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS <img srcset="/images/green-1x1.png?a2 300w, /images/green-16x16.png?a2 301w"> ref sizes="100vw" (display:none)
 PASS <img srcset="/images/green-1x1.png?b2 450w, /images/green-16x16.png?b2 451w"> ref sizes="100vw" (display:none)
 PASS <img srcset="/images/green-1x1.png?c2 600w, /images/green-16x16.png?c2 601w"> ref sizes="100vw" (display:none)
@@ -39,11 +39,11 @@
 PASS <img srcset="/images/green-1x1.png?e34 50w, /images/green-16x16.png?e34 51w" sizes="\[,1px"> ref sizes="1px" (display:none)
 PASS <img srcset="/images/green-1x1.png?e35 50w, /images/green-16x16.png?e35 51w" sizes="1\p\x"> ref sizes="1px" (display:none)
 PASS <img srcset="/images/green-1x1.png?e36 50w, /images/green-16x16.png?e36 51w" sizes="calc(1px)"> ref sizes="1px" (display:none)
-FAIL <img srcset="/images/green-1x1.png?e36a 50w, /images/green-16x16.png?e36a 51w" sizes="min(1px, 100px)"> ref sizes="1px" (display:none) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
-FAIL <img srcset="/images/green-1x1.png?e36b 50w, /images/green-16x16.png?e36b 51w" sizes="min(-100px, 1px)"> ref sizes="1px" (display:none) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
+PASS <img srcset="/images/green-1x1.png?e36a 50w, /images/green-16x16.png?e36a 51w" sizes="min(1px, 100px)"> ref sizes="1px" (display:none)
+PASS <img srcset="/images/green-1x1.png?e36b 50w, /images/green-16x16.png?e36b 51w" sizes="min(-100px, 1px)"> ref sizes="1px" (display:none)
 PASS <img srcset="/images/green-1x1.png?e37 50w, /images/green-16x16.png?e37 51w" sizes="(min-width:0) calc(1px)"> ref sizes="1px" (display:none)
-FAIL <img srcset="/images/green-1x1.png?e37a 50w, /images/green-16x16.png?e37a 51w" sizes="(min-width:0) min(1px, 100px)"> ref sizes="1px" (display:none) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
-FAIL <img srcset="/images/green-1x1.png?e37b 50w, /images/green-16x16.png?e37b 51w" sizes="(min-width:0) max(-100px, 1px)"> ref sizes="1px" (display:none) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
+PASS <img srcset="/images/green-1x1.png?e37a 50w, /images/green-16x16.png?e37a 51w" sizes="(min-width:0) min(1px, 100px)"> ref sizes="1px" (display:none)
+PASS <img srcset="/images/green-1x1.png?e37b 50w, /images/green-16x16.png?e37b 51w" sizes="(min-width:0) max(-100px, 1px)"> ref sizes="1px" (display:none)
 PASS <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (display:none)
 FAIL <img srcset="/images/green-1x1.png?e38a 50w, /images/green-16x16.png?e38a 51w" sizes="(min-width:min(0, 200vw)) 1px"> ref sizes="1px" (display:none) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
 FAIL <img srcset="/images/green-1x1.png?e38b 50w, /images/green-16x16.png?e38b 51w" sizes="(min-width:max(-200vw, 0)) 1px"> ref sizes="1px" (display:none) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-quirks-mode-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-quirks-mode-expected.txt
index 0e8e35a..2b32a08 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-quirks-mode-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-quirks-mode-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 171 tests; 154 PASS, 17 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 171 tests; 158 PASS, 13 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS <img srcset="/images/green-1x1.png?a2 300w, /images/green-16x16.png?a2 301w"> ref sizes="100vw" (quirks mode)
 PASS <img srcset="/images/green-1x1.png?b2 450w, /images/green-16x16.png?b2 451w"> ref sizes="100vw" (quirks mode)
 PASS <img srcset="/images/green-1x1.png?c2 600w, /images/green-16x16.png?c2 601w"> ref sizes="100vw" (quirks mode)
@@ -39,11 +39,11 @@
 PASS <img srcset="/images/green-1x1.png?e34 50w, /images/green-16x16.png?e34 51w" sizes="\[,1px"> ref sizes="1px" (quirks mode)
 PASS <img srcset="/images/green-1x1.png?e35 50w, /images/green-16x16.png?e35 51w" sizes="1\p\x"> ref sizes="1px" (quirks mode)
 PASS <img srcset="/images/green-1x1.png?e36 50w, /images/green-16x16.png?e36 51w" sizes="calc(1px)"> ref sizes="1px" (quirks mode)
-FAIL <img srcset="/images/green-1x1.png?e36a 50w, /images/green-16x16.png?e36a 51w" sizes="min(1px, 100px)"> ref sizes="1px" (quirks mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
-FAIL <img srcset="/images/green-1x1.png?e36b 50w, /images/green-16x16.png?e36b 51w" sizes="min(-100px, 1px)"> ref sizes="1px" (quirks mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
+PASS <img srcset="/images/green-1x1.png?e36a 50w, /images/green-16x16.png?e36a 51w" sizes="min(1px, 100px)"> ref sizes="1px" (quirks mode)
+PASS <img srcset="/images/green-1x1.png?e36b 50w, /images/green-16x16.png?e36b 51w" sizes="min(-100px, 1px)"> ref sizes="1px" (quirks mode)
 PASS <img srcset="/images/green-1x1.png?e37 50w, /images/green-16x16.png?e37 51w" sizes="(min-width:0) calc(1px)"> ref sizes="1px" (quirks mode)
-FAIL <img srcset="/images/green-1x1.png?e37a 50w, /images/green-16x16.png?e37a 51w" sizes="(min-width:0) min(1px, 100px)"> ref sizes="1px" (quirks mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
-FAIL <img srcset="/images/green-1x1.png?e37b 50w, /images/green-16x16.png?e37b 51w" sizes="(min-width:0) max(-100px, 1px)"> ref sizes="1px" (quirks mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
+PASS <img srcset="/images/green-1x1.png?e37a 50w, /images/green-16x16.png?e37a 51w" sizes="(min-width:0) min(1px, 100px)"> ref sizes="1px" (quirks mode)
+PASS <img srcset="/images/green-1x1.png?e37b 50w, /images/green-16x16.png?e37b 51w" sizes="(min-width:0) max(-100px, 1px)"> ref sizes="1px" (quirks mode)
 PASS <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (quirks mode)
 FAIL <img srcset="/images/green-1x1.png?e38a 50w, /images/green-16x16.png?e38a 51w" sizes="(min-width:min(0, 200vw)) 1px"> ref sizes="1px" (quirks mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
 FAIL <img srcset="/images/green-1x1.png?e38b 50w, /images/green-16x16.png?e38b 51w" sizes="(min-width:max(-200vw, 0)) 1px"> ref sizes="1px" (quirks mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-standards-mode-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-standards-mode-expected.txt
index c0e0f75..db241964 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-standards-mode-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-standards-mode-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 171 tests; 154 PASS, 17 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 171 tests; 158 PASS, 13 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS <img srcset="/images/green-1x1.png?a2 300w, /images/green-16x16.png?a2 301w"> ref sizes="100vw" (standards mode)
 PASS <img srcset="/images/green-1x1.png?b2 450w, /images/green-16x16.png?b2 451w"> ref sizes="100vw" (standards mode)
 PASS <img srcset="/images/green-1x1.png?c2 600w, /images/green-16x16.png?c2 601w"> ref sizes="100vw" (standards mode)
@@ -39,11 +39,11 @@
 PASS <img srcset="/images/green-1x1.png?e34 50w, /images/green-16x16.png?e34 51w" sizes="\[,1px"> ref sizes="1px" (standards mode)
 PASS <img srcset="/images/green-1x1.png?e35 50w, /images/green-16x16.png?e35 51w" sizes="1\p\x"> ref sizes="1px" (standards mode)
 PASS <img srcset="/images/green-1x1.png?e36 50w, /images/green-16x16.png?e36 51w" sizes="calc(1px)"> ref sizes="1px" (standards mode)
-FAIL <img srcset="/images/green-1x1.png?e36a 50w, /images/green-16x16.png?e36a 51w" sizes="min(1px, 100px)"> ref sizes="1px" (standards mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
-FAIL <img srcset="/images/green-1x1.png?e36b 50w, /images/green-16x16.png?e36b 51w" sizes="min(-100px, 1px)"> ref sizes="1px" (standards mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
+PASS <img srcset="/images/green-1x1.png?e36a 50w, /images/green-16x16.png?e36a 51w" sizes="min(1px, 100px)"> ref sizes="1px" (standards mode)
+PASS <img srcset="/images/green-1x1.png?e36b 50w, /images/green-16x16.png?e36b 51w" sizes="min(-100px, 1px)"> ref sizes="1px" (standards mode)
 PASS <img srcset="/images/green-1x1.png?e37 50w, /images/green-16x16.png?e37 51w" sizes="(min-width:0) calc(1px)"> ref sizes="1px" (standards mode)
-FAIL <img srcset="/images/green-1x1.png?e37a 50w, /images/green-16x16.png?e37a 51w" sizes="(min-width:0) min(1px, 100px)"> ref sizes="1px" (standards mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
-FAIL <img srcset="/images/green-1x1.png?e37b 50w, /images/green-16x16.png?e37b 51w" sizes="(min-width:0) max(-100px, 1px)"> ref sizes="1px" (standards mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
+PASS <img srcset="/images/green-1x1.png?e37a 50w, /images/green-16x16.png?e37a 51w" sizes="(min-width:0) min(1px, 100px)"> ref sizes="1px" (standards mode)
+PASS <img srcset="/images/green-1x1.png?e37b 50w, /images/green-16x16.png?e37b 51w" sizes="(min-width:0) max(-100px, 1px)"> ref sizes="1px" (standards mode)
 PASS <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (standards mode)
 FAIL <img srcset="/images/green-1x1.png?e38a 50w, /images/green-16x16.png?e38a 51w" sizes="(min-width:min(0, 200vw)) 1px"> ref sizes="1px" (standards mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
 FAIL <img srcset="/images/green-1x1.png?e38b 50w, /images/green-16x16.png?e38b 51w" sizes="(min-width:max(-200vw, 0)) 1px"> ref sizes="1px" (standards mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-width-1000px-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-width-1000px-expected.txt
index 116a409..944299d5 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-width-1000px-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-width-1000px-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 171 tests; 154 PASS, 17 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 171 tests; 158 PASS, 13 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS <img srcset="/images/green-1x1.png?a2 300w, /images/green-16x16.png?a2 301w"> ref sizes="100vw" (width:1000px)
 PASS <img srcset="/images/green-1x1.png?b2 450w, /images/green-16x16.png?b2 451w"> ref sizes="100vw" (width:1000px)
 PASS <img srcset="/images/green-1x1.png?c2 600w, /images/green-16x16.png?c2 601w"> ref sizes="100vw" (width:1000px)
@@ -39,11 +39,11 @@
 PASS <img srcset="/images/green-1x1.png?e34 50w, /images/green-16x16.png?e34 51w" sizes="\[,1px"> ref sizes="1px" (width:1000px)
 PASS <img srcset="/images/green-1x1.png?e35 50w, /images/green-16x16.png?e35 51w" sizes="1\p\x"> ref sizes="1px" (width:1000px)
 PASS <img srcset="/images/green-1x1.png?e36 50w, /images/green-16x16.png?e36 51w" sizes="calc(1px)"> ref sizes="1px" (width:1000px)
-FAIL <img srcset="/images/green-1x1.png?e36a 50w, /images/green-16x16.png?e36a 51w" sizes="min(1px, 100px)"> ref sizes="1px" (width:1000px) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
-FAIL <img srcset="/images/green-1x1.png?e36b 50w, /images/green-16x16.png?e36b 51w" sizes="min(-100px, 1px)"> ref sizes="1px" (width:1000px) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
+PASS <img srcset="/images/green-1x1.png?e36a 50w, /images/green-16x16.png?e36a 51w" sizes="min(1px, 100px)"> ref sizes="1px" (width:1000px)
+PASS <img srcset="/images/green-1x1.png?e36b 50w, /images/green-16x16.png?e36b 51w" sizes="min(-100px, 1px)"> ref sizes="1px" (width:1000px)
 PASS <img srcset="/images/green-1x1.png?e37 50w, /images/green-16x16.png?e37 51w" sizes="(min-width:0) calc(1px)"> ref sizes="1px" (width:1000px)
-FAIL <img srcset="/images/green-1x1.png?e37a 50w, /images/green-16x16.png?e37a 51w" sizes="(min-width:0) min(1px, 100px)"> ref sizes="1px" (width:1000px) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
-FAIL <img srcset="/images/green-1x1.png?e37b 50w, /images/green-16x16.png?e37b 51w" sizes="(min-width:0) max(-100px, 1px)"> ref sizes="1px" (width:1000px) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
+PASS <img srcset="/images/green-1x1.png?e37a 50w, /images/green-16x16.png?e37a 51w" sizes="(min-width:0) min(1px, 100px)"> ref sizes="1px" (width:1000px)
+PASS <img srcset="/images/green-1x1.png?e37b 50w, /images/green-16x16.png?e37b 51w" sizes="(min-width:0) max(-100px, 1px)"> ref sizes="1px" (width:1000px)
 PASS <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (width:1000px)
 FAIL <img srcset="/images/green-1x1.png?e38a 50w, /images/green-16x16.png?e38a 51w" sizes="(min-width:min(0, 200vw)) 1px"> ref sizes="1px" (width:1000px) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
 FAIL <img srcset="/images/green-1x1.png?e38b 50w, /images/green-16x16.png?e38b 51w" sizes="(min-width:max(-200vw, 0)) 1px"> ref sizes="1px" (width:1000px) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-006-ref.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-006-ref.html
new file mode 100644
index 0000000..39e6dabd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-006-ref.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>RTL mtable and mtable with frame</title>
+    <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+    <style>
+      math, math * {
+          font: 25px Ahem;
+      }
+    </style>
+  </head>
+  <body>
+
+    <p>
+      <math>
+        <mtable>
+          <mtr>
+            <mtd>
+              <mtext>É</mtext>
+            </mtd>
+            <mtd>
+              <mtext>p</mtext>
+            </mtd>
+            <mtd>
+              <mtext>X</mtext>
+            </mtd>
+          </mtr>
+          <mtr>
+            <mtd>
+              <mtext>pÉ</mtext>
+            </mtd>
+            <mtd>
+              <mtext>XÉ</mtext>
+            </mtd>
+            <mtd>
+              <mtext>Xp</mtext>
+            </mtd>
+          </mtr>
+        </mtable>
+      </math>
+    </p>
+
+    <p>
+      <math>
+        <mtable frame="solid">
+          <mtr>
+            <mtd>
+              <mtext>É</mtext>
+            </mtd>
+            <mtd>
+              <mtext>p</mtext>
+            </mtd>
+            <mtd>
+              <mtext>X</mtext>
+            </mtd>
+          </mtr>
+          <mtr>
+            <mtd>
+              <mtext>pÉ</mtext>
+            </mtd>
+            <mtd>
+              <mtext>XÉ</mtext>
+            </mtd>
+            <mtd>
+              <mtext>Xp</mtext>
+            </mtd>
+          </mtr>
+        </mtable>
+      </math>
+    </p>
+
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-006.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-006.html
new file mode 100644
index 0000000..904e7d3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-006.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>RTL mtable and mtable with frame</title>
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#tabular-math">
+    <meta name="assert" content="Verify RTL math table renders the same as the column mirrored.">
+    <link rel="match" href="direction-006-ref.html">
+    <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+    <style>
+      math, math * {
+          font: 25px Ahem;
+      }
+    </style>
+  </head>
+  <body>
+
+    <p>
+      <math dir="rtl">
+        <mtable>
+          <mtr>
+            <mtd>
+              <mtext>X</mtext>
+            </mtd>
+            <mtd>
+              <mtext>p</mtext>
+            </mtd>
+            <mtd>
+              <mtext>É</mtext>
+            </mtd>
+          </mtr>
+          <mtr>
+            <mtd>
+              <mtext>Xp</mtext>
+            </mtd>
+            <mtd>
+              <mtext>XÉ</mtext>
+            </mtd>
+            <mtd>
+              <mtext>pÉ</mtext>
+            </mtd>
+          </mtr>
+        </mtable>
+      </math>
+    </p>
+
+    <p>
+      <math dir="rtl">
+        <mtable frame="solid">
+          <mtr>
+            <mtd>
+              <mtext>X</mtext>
+            </mtd>
+            <mtd>
+              <mtext>p</mtext>
+            </mtd>
+            <mtd>
+              <mtext>É</mtext>
+            </mtd>
+          </mtr>
+          <mtr>
+            <mtd>
+              <mtext>Xp</mtext>
+            </mtd>
+            <mtd>
+              <mtext>XÉ</mtext>
+            </mtd>
+            <mtd>
+              <mtext>pÉ</mtext>
+            </mtd>
+          </mtr>
+        </mtable>
+      </math>
+    </p>
+
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-007-ref.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-007-ref.html
new file mode 100644
index 0000000..5c77395f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-007-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>mo and embellished mrow/munderover (lspace=1em rspace=2em)</title>
+    <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+    <style>
+      math, math * {
+          font: 25px/1 Ahem;
+      }
+    </style>
+  </head>
+  <body>
+
+    <p>
+      <math>
+        <mtext>p</mtext><mo lspace="2em" rspace="1em">X</mo><mtext>p</mtext>
+      </math>
+    </p>
+
+    <p>
+      <math>
+        <mtext>p</mtext>
+        <mrow><mo lspace="2em" rspace="1em">X</mo></mrow>
+        <mtext>p</mtext>
+      </math>
+    </p>
+
+    <p>
+      <math>
+        <mtext>p</mtext>
+        <munderover>
+          <mo lspace="2em" rspace="1em">X</mo>
+          <mtext>É</mtext>
+          <mtext>É</mtext>
+        </munderover>
+        <mtext>p</mtext>
+      </math>
+    </p>
+
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-007.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-007.html
new file mode 100644
index 0000000..7137e264
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-007.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>mo and embellished mrow/munderover (lspace=1em rspace=2em)</title>
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#embellished-operators">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+    <meta name="assert" content="Verify that the lspace/rspace on an mo or an embellished mrow/munderover element are switched in RTL mode">
+    <link rel="match" href="direction-007-ref.html">
+    <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+    <style>
+      math, math * {
+          font: 25px/1 Ahem;
+      }
+    </style>
+  </head>
+  <body>
+
+    <p>
+      <math dir="rtl">
+        <mtext>p</mtext><mo lspace="1em" rspace="2em">X</mo><mtext>p</mtext>
+      </math>
+    </p>
+
+    <p>
+      <math dir="rtl">
+        <mtext>p</mtext>
+        <mrow><mo lspace="1em" rspace="2em">X</mo></mrow>
+        <mtext>p</mtext>
+      </math>
+    </p>
+
+    <p>
+      <math dir="rtl">
+        <mtext>p</mtext>
+        <munderover>
+          <mo lspace="1em" rspace="2em">X</mo>
+          <mtext>É</mtext>
+          <mtext>É</mtext>
+        </munderover>
+        <mtext>p</mtext>
+      </math>
+    </p>
+
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-008-ref.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-008-ref.html
new file mode 100644
index 0000000..492fa95
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-008-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>embellished mfrac (lspace=1em rspace=2em)</title>
+    <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+    <style>
+      math, math * {
+          font: 25px/1 Ahem;
+      }
+    </style>
+  </head>
+  <body>
+
+    <p>
+      <math>
+        <mtext>p</mtext>
+        <mfrac>
+          <mo lspace="2em" rspace="1em">X</mo>
+          <mtext>É</mtext>
+        </mfrac>
+        <mtext>p</mtext>
+      </math>
+    </p>
+
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-008.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-008.html
new file mode 100644
index 0000000..5c98b07
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-008.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>embellished mfrac (lspace=1em rspace=2em)</title>
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#fractions-mfrac">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#embellished-operators">
+    <meta name="assert" content="Verify that the lspace/rspace on an embellished mfrac element are switched in RTL mode">
+    <link rel="match" href="direction-008-ref.html">
+    <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+    <style>
+      math, math * {
+          font: 25px/1 Ahem;
+      }
+    </style>
+  </head>
+  <body>
+
+    <p>
+      <math dir="rtl">
+        <mtext>p</mtext>
+        <mfrac>
+          <mo lspace="1em" rspace="2em">X</mo>
+          <mtext>É</mtext>
+        </mfrac>
+        <mtext>p</mtext>
+      </math>
+    </p>
+
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-009-ref.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-009-ref.html
new file mode 100644
index 0000000..7ed4796
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-009-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>RTL ms lquote="X" rquote="p"</title>
+    <style>
+      math {
+          font: 25px/1 Ahem;
+      }
+    </style>
+  </head>
+  <body>
+
+    <p>
+      <math>
+        <ms lquote="p" rquote="X">É</ms>
+      </math>
+    </p>
+
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-009.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-009.html
new file mode 100644
index 0000000..bf8caf1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-009.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>RTL ms lquote="X" rquote="p"</title>
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#string-literal-ms">
+    <meta name="assert" content="Verify that a RTL ms element renders the same as if its left and right quotes were switched.">
+    <link rel="match" href="direction-009-ref.html">
+    <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+    <style>
+      math {
+          font: 25px/1 Ahem;
+      }
+    </style>
+  </head>
+  <body>
+
+    <p>
+      <math dir="rtl">
+        <ms lquote="X" rquote="p">É</ms>
+      </math>
+    </p>
+
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-010-ref.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-010-ref.html
new file mode 100644
index 0000000..4f595ed
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-010-ref.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>dir="rtl" VS direction: rtl on math/mrow/mstyle</title>
+    <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+    <style>
+      math {
+          font: 25px/1 Ahem;
+      }
+    </style>
+  </head>
+  <body>
+
+    <p>
+      <math style="direction: rtl">
+        <mtext>X</mtext>
+        <mtext>p</mtext>
+        <mtext>É</mtext>
+      </math>
+    </p>
+
+    <p>
+      <math>
+        <mrow style="direction: rtl">
+          <mtext>X</mtext>
+          <mtext>p</mtext>
+          <mtext>É</mtext>
+        </mrow>
+      </math>
+    </p>
+
+    <p>
+      <math>
+        <mstyle mathcolor="blue" style="direction: rtl">
+          <mtext>X</mtext>
+          <mtext>p</mtext>
+          <mtext>É</mtext>
+        </mstyle>
+      </math>
+    </p>
+
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-010.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-010.html
new file mode 100644
index 0000000..6dc095a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-010.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>dir="rtl" VS direction: rtl on math/mrow/mstyle</title>
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#css-styling">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#style-change-mstyle">
+    <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-top-level-math-element">
+    <meta name="assert" content="Verify that math, mrow and mstyle with a dir=rtl attribute render the same as CSS direction right-to-left.">
+    <link rel="match" href="direction-010-ref.html">
+    <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+    <style>
+      math {
+          font: 25px/1 Ahem;
+      }
+    </style>
+  </head>
+  <body>
+
+    <p>
+      <math dir="rtl">
+        <mtext>X</mtext>
+        <mtext>p</mtext>
+        <mtext>É</mtext>
+      </math>
+    </p>
+
+    <p>
+      <math>
+        <mrow dir="rtl">
+          <mtext>X</mtext>
+          <mtext>p</mtext>
+          <mtext>É</mtext>
+        </mrow>
+      </math>
+    </p>
+
+    <p>
+      <math>
+        <mstyle mathcolor="blue" dir="rtl">
+          <mtext>X</mtext>
+          <mtext>p</mtext>
+          <mtext>É</mtext>
+        </mstyle>
+      </math>
+    </p>
+
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/quirks/dd-dl-firefox-001-ref.html b/third_party/blink/web_tests/external/wpt/quirks/dd-dl-firefox-001-ref.html
new file mode 100644
index 0000000..46a4d7d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/quirks/dd-dl-firefox-001-ref.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<div>Prevent quirky dl margin from messing up with us</div>
+<dl>
+  <dd>One</dd>
+  <dl>Two</dl>
+</dl>
+<dd>Three</dd><dd>Four</dd>
diff --git a/third_party/blink/web_tests/external/wpt/quirks/dd-dl-firefox-001.html b/third_party/blink/web_tests/external/wpt/quirks/dd-dl-firefox-001.html
new file mode 100644
index 0000000..96fc76f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/quirks/dd-dl-firefox-001.html
@@ -0,0 +1,18 @@
+<!-- quirks -->
+<title>dd and dl don't have weird text-indent quirks</title>
+<link rel="match" href="dd-dl-firefox-001-ref.html">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=782551">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<style>
+  /* Firefox used to (sometimes) implement dd indentation in quirks mode via
+     the ::before pseudo-element; this rule should do nothing in compliant
+     browsers */
+  dd::before { content: "" }
+</style>
+<div>Prevent quirky dl margin from messing up with us</div>
+<dl>
+  <dd>One</dd>
+  <dl>Two</dl>
+</dl>
+<dd>Three</dd><dd>Four</dd>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/update-during-installation-worker.js b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/update-during-installation-worker.js
index 3f89881..f1997bd 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/update-during-installation-worker.js
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/update-during-installation-worker.js
@@ -14,6 +14,9 @@
 });
 
 addEventListener('message', event => {
+  let resolveWaitUntil;
+  event.waitUntil(new Promise(resolve => { resolveWaitUntil = resolve; }));
+
   // Use a dedicated MessageChannel for every request so senders can wait for
   // individual requests to finish, and concurrent requests (to different
   // workers) don't cause race conditions.
@@ -23,13 +26,13 @@
       case 'awaitInstallEvent':
         installEventFired.then(() => {
             port.postMessage('installEventFired');
-        });
+        }).finally(resolveWaitUntil);
         break;
 
       case 'finishInstall':
         installFinished.then(() => {
             port.postMessage('installFinished');
-        });
+        }).finally(resolveWaitUntil);
         finishInstall();
         break;
 
@@ -44,13 +47,14 @@
                 success: false,
                 exception: exception.name,
             });
-        });
+        }).finally(resolveWaitUntil);
         port.postMessage(channel.port1, [channel.port1]);
         break;
       }
 
       default:
         port.postMessage('Unexpected command ' + event.data);
+        resolveWaitUntil();
         break;
     }
   };
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/focus/DocumentOrShadowRoot-activeElement.html b/third_party/blink/web_tests/external/wpt/shadow-dom/focus/DocumentOrShadowRoot-activeElement.html
new file mode 100644
index 0000000..20456b0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/shadow-dom/focus/DocumentOrShadowRoot-activeElement.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: DocumentOrShadowRoot.activeElement</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<body>
+<script>
+function createChildAndFocus(focusParent) {
+  const focused = document.createElement("div");
+  focused.tabIndex = 0;
+  focusParent.appendChild(focused);
+  focused.focus();
+  return focused;
+}
+
+test(() => {
+  const host = document.createElement("div");
+  const shadowRoot = host.attachShadow({ mode: "open" });
+  document.body.appendChild(host);
+
+  const focused = createChildAndFocus(shadowRoot);
+  assert_equals(document.activeElement, host);
+  assert_equals(shadowRoot.activeElement, focused);
+}, "activeElement on document & shadow root when focused element is in the shadow tree");
+
+test(() => {
+  const host = document.createElement("div");
+  const shadowRoot = host.attachShadow({ mode: "open" });
+  document.body.appendChild(host);
+
+  const focused = createChildAndFocus(document.body);
+  assert_equals(document.activeElement, focused);
+  assert_equals(shadowRoot.activeElement, null);
+}, "activeElement on document & shadow root when focused element is in the document");
+
+test(() => {
+  const host = document.createElement("div");
+  const shadowRoot = host.attachShadow({ mode: "open" });
+  shadowRoot.appendChild(document.createElement("slot"));
+  document.body.appendChild(host);
+
+  // Child of |host|, will be slotted to the slot in |shadowRoot|.
+  const focused = createChildAndFocus(host);
+  assert_equals(document.activeElement, focused);
+  assert_equals(shadowRoot.activeElement, null);
+}, "activeElement on document & shadow root when focused element is slotted");
+
+test(() => {
+  const host = document.createElement("div");
+  const shadowRoot = host.attachShadow({ mode: "open" });
+  document.body.appendChild(host);
+  const neighborHost = document.createElement("div");
+  const neighborShadowRoot = neighborHost.attachShadow({ mode: "open" });
+  document.body.appendChild(neighborHost);
+
+  const focused = createChildAndFocus(shadowRoot);
+  assert_equals(document.activeElement, host);
+  assert_equals(shadowRoot.activeElement, focused);
+  assert_equals(neighborShadowRoot.activeElement, null);
+}, "activeElement on a neighboring host when focused element is in another shadow tree");
+
+test(() => {
+  const host = document.createElement("div");
+  const shadowRoot = host.attachShadow({ mode: "open" });
+  document.body.appendChild(host);
+  const nestedHost = document.createElement("div");
+  const nestedShadowRoot = nestedHost.attachShadow({ mode: "open" });
+  shadowRoot.appendChild(nestedHost);
+
+  const focused = createChildAndFocus(nestedShadowRoot);
+  assert_equals(document.activeElement, host);
+  assert_equals(shadowRoot.activeElement, nestedHost);
+  assert_equals(nestedShadowRoot.activeElement, focused);
+}, "activeElement when focused element is in a nested shadow tree");
+
+test(() => {
+  const host = document.createElement("div");
+  const shadowRoot = host.attachShadow({ mode: "open" });
+  document.body.appendChild(host);
+  const nestedHost = document.createElement("div");
+  const nestedShadowRoot = nestedHost.attachShadow({ mode: "open" });
+  shadowRoot.appendChild(nestedHost);
+
+  const focused = createChildAndFocus(shadowRoot);
+  assert_equals(document.activeElement, host);
+  assert_equals(shadowRoot.activeElement, focused);
+  assert_equals(nestedShadowRoot.activeElement, null);
+}, "activeElement when focused element is in a parent shadow tree");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any-expected.txt
index 95f34fb..2e1b706 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any-expected.txt
@@ -2,5 +2,7 @@
 PASS ReadableStream tee() should not touch Object.prototype properties
 PASS ReadableStream tee() should not call the global ReadableStream
 FAIL ReadableStream getIterator() should use the original values of getReader() and ReadableStreamDefaultReader methods promise_test: Unhandled rejection with value: object "TypeError: rs is not async iterable"
+PASS tee() should not call Promise.prototype.then()
+PASS pipeTo() should not call Promise.prototype.then()
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.js b/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.js
index 500979f..813dd42 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.js
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.js
@@ -107,3 +107,35 @@
   // stream should be cancelled
   await reader.closed;
 }, 'ReadableStream getIterator() should use the original values of getReader() and ReadableStreamDefaultReader methods');
+
+test(t => {
+  const oldPromiseThen = Promise.prototype.then;
+  Promise.prototype.then = () => {
+    throw new Error('patched then() called');
+  };
+  t.add_cleanup(() => {
+    Promise.prototype.then = oldPromiseThen;
+  });
+  const [branch1, branch2] = new ReadableStream().tee();
+  assert_true(isReadableStream(branch1), 'branch1 should be a ReadableStream');
+  assert_true(isReadableStream(branch2), 'branch2 should be a ReadableStream');
+}, 'tee() should not call Promise.prototype.then()');
+
+test(t => {
+  const oldPromiseThen = Promise.prototype.then;
+  Promise.prototype.then = () => {
+    throw new Error('patched then() called');
+  };
+  t.add_cleanup(() => {
+    Promise.prototype.then = oldPromiseThen;
+  });
+  let readableController;
+  const rs = new ReadableStream({
+    start(c) {
+      readableController = c;
+    }
+  });
+  const ws = new WritableStream();
+  rs.pipeTo(ws);
+  readableController.close();
+}, 'pipeTo() should not call Promise.prototype.then()');
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.serviceworker-expected.txt
index 95f34fb..2e1b706 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.serviceworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.serviceworker-expected.txt
@@ -2,5 +2,7 @@
 PASS ReadableStream tee() should not touch Object.prototype properties
 PASS ReadableStream tee() should not call the global ReadableStream
 FAIL ReadableStream getIterator() should use the original values of getReader() and ReadableStreamDefaultReader methods promise_test: Unhandled rejection with value: object "TypeError: rs is not async iterable"
+PASS tee() should not call Promise.prototype.then()
+PASS pipeTo() should not call Promise.prototype.then()
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.sharedworker-expected.txt
index 95f34fb..2e1b706 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.sharedworker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.sharedworker-expected.txt
@@ -2,5 +2,7 @@
 PASS ReadableStream tee() should not touch Object.prototype properties
 PASS ReadableStream tee() should not call the global ReadableStream
 FAIL ReadableStream getIterator() should use the original values of getReader() and ReadableStreamDefaultReader methods promise_test: Unhandled rejection with value: object "TypeError: rs is not async iterable"
+PASS tee() should not call Promise.prototype.then()
+PASS pipeTo() should not call Promise.prototype.then()
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.worker-expected.txt
index 95f34fb..2e1b706 100644
--- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/patched-global.any.worker-expected.txt
@@ -2,5 +2,7 @@
 PASS ReadableStream tee() should not touch Object.prototype properties
 PASS ReadableStream tee() should not call the global ReadableStream
 FAIL ReadableStream getIterator() should use the original values of getReader() and ReadableStreamDefaultReader methods promise_test: Unhandled rejection with value: object "TypeError: rs is not async iterable"
+PASS tee() should not call Promise.prototype.then()
+PASS pipeTo() should not call Promise.prototype.then()
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/accumulate-values-width-animation.html b/third_party/blink/web_tests/external/wpt/svg/animations/accumulate-values-width-animation.html
new file mode 100644
index 0000000..7813494
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/accumulate-values-width-animation.html
@@ -0,0 +1,110 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>This tests values animation and accumulate='sum'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/SVGAnimationTestCase-testharness.js"></script>
+
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<!-- an1: Change width to 100 in 10s with a wobbling animation -->
+<rect width="20" height="100" fill="green">
+    <animate id="an1" attributeName="width" dur="2s" values="0; 30; 20" accumulate="sum" repeatCount="5" fill="freeze"/>
+</rect>
+
+</svg>
+
+<script>
+var rootSVGElement = document.querySelector("svg");
+var epsilon = 1.0;
+
+// Setup animation test
+function sample1() {
+    assert_approx_equals(rect.width.animVal.value, 0, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+function sample2() {
+    assert_approx_equals(rect.width.animVal.value, 30, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+function sample3() {
+    assert_approx_equals(rect.width.animVal.value, 20, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+function sample4() {
+    assert_approx_equals(rect.width.animVal.value, 50, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+function sample5() {
+    assert_approx_equals(rect.width.animVal.value, 40, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+function sample6() {
+    assert_approx_equals(rect.width.animVal.value, 70, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+function sample7() {
+    assert_approx_equals(rect.width.animVal.value, 60, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+function sample8() {
+    assert_approx_equals(rect.width.animVal.value, 90, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+function sample9() {
+    assert_approx_equals(rect.width.animVal.value, 80, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+function sample10() {
+    assert_approx_equals(rect.width.animVal.value, 110, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+function sample11() {
+    assert_approx_equals(rect.width.animVal.value, 100, epsilon);
+    assert_equals(rect.width.baseVal.value, 20);
+}
+
+smil_async_test((t) => {
+    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
+
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["an1", 0.0,    sample1],
+        ["an1", 1.0,    sample2],
+        ["an1", 1.999,  sample3],
+        ["an1", 2.001,  sample3],
+        ["an1", 3.0,    sample4],
+        ["an1", 3.999,  sample5],
+        ["an1", 4.001,  sample5],
+        ["an1", 5.0,    sample6],
+        ["an1", 5.999,  sample7],
+        ["an1", 6.001,  sample7],
+        ["an1", 7.0,    sample8],
+        ["an1", 7.999,  sample9],
+        ["an1", 8.001,  sample9],
+        ["an1", 9.0,    sample10],
+        ["an1", 9.999,  sample11],
+        ["an1", 10.001, sample11],
+        ["an1", 11.0,   sample11],
+        ["an1", 60.0,   sample11]
+    ];
+
+    runAnimationTest(t, expectedValues);
+});
+
+window.animationStartsImmediately = true;
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/additive-from-to-width-animation.html b/third_party/blink/web_tests/external/wpt/svg/animations/additive-from-to-width-animation.html
new file mode 100644
index 0000000..0899f5e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/additive-from-to-width-animation.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>This tests multiple additive='sum' animations running at the same time</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/SVGAnimationTestCase-testharness.js"></script>
+
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<!-- an1: Change width from 10 to 50 in 4s -->
+<!-- an2: Change width from 10 to 25 + additive=sum. This results in a change from 20 to 75 -->
+<!-- an3: Change width from 0 to 25 + additve=sum. This results in a final change from 20 to 100 -->
+<rect width="10" height="100" fill="green">
+    <animate id="an1" attributeType="XML" attributeName="width" fill="freeze" from="10" to="50" begin="0s" dur="4s"/>
+    <animate id="an2" attributeType="XML" attributeName="width" additive="sum" fill="freeze" from="10" to="25" begin="0s" dur="4s"/>
+    <animate id="an3" attributeType="XML" attributeName="width" additive="sum" fill="freeze" from="0" to="25" begin="0s" dur="4s"/>
+</rect>
+
+</svg>
+
+<script>
+var rootSVGElement = document.querySelector("svg");
+var epsilon = 1.0;
+
+// Setup animation test
+function sample1() {
+    assert_approx_equals(rect.width.animVal.value, 20, epsilon);
+    assert_equals(rect.width.baseVal.value, 10);
+}
+
+function sample2() {
+    assert_approx_equals(rect.width.animVal.value, 60, epsilon);
+    assert_equals(rect.width.baseVal.value, 10);
+}
+
+function sample3() {
+    assert_approx_equals(rect.width.animVal.value, 100, epsilon);
+    assert_equals(rect.width.baseVal.value, 10);
+}
+
+smil_async_test((t) => {
+    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
+
+    // All animations in the test file use the same duration, so it's not needed to list all sample points individually for an5/an6/an7/an8.
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["an1", 0.0,  sample1],
+        ["an1", 2.0,  sample2],
+        ["an1", 4.0,  sample3],
+        ["an1", 60.0, sample3]
+    ];
+
+    runAnimationTest(t, expectedValues);
+});
+
+window.animationStartsImmediately = true;
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/additive-type-by-animation.html b/third_party/blink/web_tests/external/wpt/svg/animations/additive-type-by-animation.html
new file mode 100644
index 0000000..2dc7732d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/additive-type-by-animation.html
@@ -0,0 +1,275 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>This by animation for all XML property types</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/SVGAnimationTestCase-testharness.js"></script>
+
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg id="svg" viewBox="0 0 300 300" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<!-- All additive types except AnimatedPath are tested here -->
+<defs>
+    <marker id="marker" viewBox="0 0 10 10" markerWidth="4" markerHeight="3" refX="1" refY="5" orient="-45deg">
+        <polyline id="polyline" points="0,0 10,5 0,10 1,5" fill="green"/>
+    </marker>
+
+    <filter id="filter">
+        <feConvolveMatrix id="feConvolveMatrix" kernelUnitLength="20 30" kernelMatrix="0 1 0   0 1 0   0 1 0" divisor="37.5" order="6 6" targetX="5" preserveAlpha="false"/>
+    </filter>
+</defs>
+
+<!-- Non-additive types AnimatedBoolean, AnimatedEnumeration, AnimatedPreserveAspectRatio, AnimatedString are tested in non-additive-type-by-animation.svg -->
+
+<path id="path" d="M45,50 L55,50" transform="rotate(45)" stroke-width="10" stroke="green" marker-end="url(#marker)"/>
+<rect id="rect" y="0" width="100" height="100" fill="black" filter="url(#filter)"/>
+<text id="text" x="50" y="50" dy="5 -10 10 -10">ABCD</text>
+
+<!-- AnimatedAngle -->
+<animate id="an1" xlink:href="#marker" attributeName="orient" begin="0s" dur="4s" by="45deg" fill="freeze"/>
+
+<!-- AnimatedColor -->
+<animate xlink:href="#rect" attributeName="fill" begin="0s" dur="4s" by="green" fill="freeze"/>
+
+<!-- AnimatedLength -->
+<animate xlink:href="#rect" attributeName="y" begin="0s" dur="4s" by="100" fill="freeze"/>
+
+<!-- AnimatedLengthList -->
+<animate xlink:href="#text" attributeName="dy" begin="0s" dur="4s" by="-10 20 -20 20" fill="freeze"/>
+
+<!-- AnimatedNumberOptionalNumber -->
+<animate xlink:href="#feConvolveMatrix" attributeName="kernelUnitLength" begin="0s" dur="4s" by="-10 -20" fill="freeze"/>
+
+<!-- AnimatedNumber -->
+<animate xlink:href="#feConvolveMatrix" attributeName="divisor" begin="0s" dur="4s" by="-17.5" fill="freeze"/>
+
+<!-- AnimatedNumberList -->
+<animate xlink:href="#feConvolveMatrix" attributeName="kernelMatrix" begin="0s" dur="4s" by="2 1 3   2 1 3   2 1 3" fill="freeze"/>
+
+<!-- AnimatedIntegerOptionalInteger -->
+<animate xlink:href="#feConvolveMatrix" attributeName="order" begin="0s" dur="4s" by="-3 -3" fill="freeze"/>
+
+<!-- AnimatedInteger -->
+<animate xlink:href="#feConvolveMatrix" attributeName="targetX" begin="0s" dur="4s" by="-4" fill="freeze"/>
+
+<!-- AnimatedPoints -->
+<animate xlink:href="#polyline" attributeName="points" begin="0s" dur="4s" by="0,0 10,5 0,10 1,5" fill="freeze"/>
+
+<!-- AnimatedRect -->
+<animate xlink:href="#svg" attributeName="viewBox" begin="0s" dur="4s" by="0 0 -100 -100" fill="freeze"/>
+
+<!-- AnimatedTransformList -->
+<animateTransform xlink:href="#path" attributeName="transform" type="rotate" begin="0s" dur="4s" by="-45" fill="freeze"/>
+
+</svg>
+
+<script>
+var rootSVGElement = document.querySelector("svg");
+var epsilon = 1.0;
+
+// Setup animation test
+function checkBaseVal() {
+    assert_equals(marker.orientAngle.baseVal.value, -45);
+    assert_equals(feConvolveMatrix.divisor.baseVal, 37.5);
+    assert_equals(feConvolveMatrix.orderX.baseVal, 6);
+    assert_equals(feConvolveMatrix.orderY.baseVal, 6);
+    assert_equals(feConvolveMatrix.targetX.baseVal, 5);
+    assert_equals(feConvolveMatrix.kernelUnitLengthX.baseVal, 20);
+    assert_equals(feConvolveMatrix.kernelUnitLengthY.baseVal, 30);
+    assert_equals(feConvolveMatrix.kernelMatrix.baseVal.numberOfItems, 9);
+    assert_equals(feConvolveMatrix.kernelMatrix.baseVal.getItem(0).value, 0);
+    assert_equals(feConvolveMatrix.kernelMatrix.baseVal.getItem(1).value, 1);
+    assert_equals(feConvolveMatrix.kernelMatrix.baseVal.getItem(2).value, 0);
+    assert_equals(feConvolveMatrix.kernelMatrix.baseVal.getItem(3).value, 0);
+    assert_equals(feConvolveMatrix.kernelMatrix.baseVal.getItem(4).value, 1);
+    assert_equals(feConvolveMatrix.kernelMatrix.baseVal.getItem(5).value, 0);
+    assert_equals(feConvolveMatrix.kernelMatrix.baseVal.getItem(6).value, 0);
+    assert_equals(feConvolveMatrix.kernelMatrix.baseVal.getItem(7).value, 1);
+    assert_equals(feConvolveMatrix.kernelMatrix.baseVal.getItem(8).value, 0);
+    assert_equals(rect.y.baseVal.value, 0);
+    assert_equals(text.dy.baseVal.numberOfItems, 4);
+    assert_equals(text.dy.baseVal.getItem(0).value, 5);
+    assert_equals(text.dy.baseVal.getItem(1).value, -10);
+    assert_equals(text.dy.baseVal.getItem(2).value, 10);
+    assert_equals(text.dy.baseVal.getItem(3).value, -10);
+    assert_equals(svg.viewBox.baseVal.x, 0);
+    assert_equals(svg.viewBox.baseVal.y, 0);
+    assert_equals(svg.viewBox.baseVal.width, 300);
+    assert_equals(svg.viewBox.baseVal.height, 300);
+    assert_equals(polyline.points.numberOfItems, 4);
+    assert_equals(polyline.points.getItem(0).x, 0);
+    assert_equals(polyline.points.getItem(0).y, 0);
+    assert_equals(polyline.points.getItem(1).x, 10);
+    assert_equals(polyline.points.getItem(1).y, 5);
+    assert_equals(polyline.points.getItem(1).x, 10);
+    assert_equals(polyline.points.getItem(1).y, 5);
+    assert_equals(polyline.points.getItem(2).x, 0);
+    assert_equals(polyline.points.getItem(2).y, 10);
+    assert_equals(path.transform.baseVal.numberOfItems, 1);
+    assert_equals(path.transform.baseVal.getItem(0).type, SVGTransform.SVG_TRANSFORM_ROTATE);
+    assert_equals(path.transform.baseVal.getItem(0).angle, 45);
+}
+
+function sample1() {
+    assert_approx_equals(marker.orientAngle.animVal.value, -45, epsilon);
+    assert_approx_equals(feConvolveMatrix.divisor.animVal, 37.5, epsilon);
+    assert_approx_equals(feConvolveMatrix.orderX.animVal, 6, epsilon);
+    assert_approx_equals(feConvolveMatrix.orderY.animVal, 6, epsilon);
+    assert_approx_equals(feConvolveMatrix.targetX.animVal, 5, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelUnitLengthX.animVal, 20, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelUnitLengthY.animVal, 30, epsilon);
+    assert_equals(feConvolveMatrix.kernelMatrix.animVal.numberOfItems, 9);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(0).value, 0, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(1).value, 1, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(2).value, 0, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(3).value, 0, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(4).value, 1, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(5).value, 0, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(6).value, 0, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(7).value, 1, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(8).value, 0, epsilon);
+    assert_approx_equals(rect.y.animVal.value, 0, epsilon);
+    assert_equals(text.dy.animVal.numberOfItems, 4);
+    assert_approx_equals(text.dy.animVal.getItem(0).value, 5, epsilon);
+    assert_approx_equals(text.dy.animVal.getItem(1).value, -10, epsilon);
+    assert_approx_equals(text.dy.animVal.getItem(2).value, 10, epsilon);
+    assert_approx_equals(text.dy.animVal.getItem(3).value, -10, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.x, 0, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.y, 0, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.width, 300, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.height, 300, epsilon);
+    assert_equals(polyline.animatedPoints.numberOfItems, 4);
+    assert_approx_equals(polyline.animatedPoints.getItem(0).x, 0, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(0).y, 0, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).x, 10, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).y, 5, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).x, 10, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).y, 5, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(2).x, 0, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(2).y, 10, epsilon);
+    assert_equals(path.transform.animVal.numberOfItems, 2);
+    assert_equals(path.transform.animVal.getItem(0).type, SVGTransform.SVG_TRANSFORM_ROTATE);
+    assert_equals(path.transform.animVal.getItem(0).angle, 45);
+    assert_equals(path.transform.animVal.getItem(1).type, SVGTransform.SVG_TRANSFORM_ROTATE);
+    assert_approx_equals(path.transform.animVal.getItem(1).angle, 0, epsilon);
+    expectFillColor(rect, 0, 0, 0);
+    checkBaseVal();
+}
+
+function sample2() {
+    assert_approx_equals(marker.orientAngle.animVal.value, -22.5, epsilon);
+    assert_approx_equals(feConvolveMatrix.divisor.animVal, 28.75, epsilon);
+    assert_approx_equals(feConvolveMatrix.orderX.animVal, 5, epsilon);
+    assert_approx_equals(feConvolveMatrix.orderY.animVal, 5, epsilon);
+    assert_approx_equals(feConvolveMatrix.targetX.animVal, 3, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelUnitLengthX.animVal, 15, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelUnitLengthY.animVal, 20, epsilon);
+    assert_equals(feConvolveMatrix.kernelMatrix.animVal.numberOfItems, 9);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(0).value, 1, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(1).value, 1.5, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(2).value, 1.5, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(3).value, 1, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(4).value, 1.5, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(5).value, 1.5, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(6).value, 1, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(7).value, 1.5, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(8).value, 1.5, epsilon);
+    assert_approx_equals(rect.y.animVal.value, 50, epsilon);
+    assert_equals(text.dy.animVal.numberOfItems, 4);
+    assert_approx_equals(text.dy.animVal.getItem(0).value, 0, epsilon);
+    assert_approx_equals(text.dy.animVal.getItem(1).value, 0, epsilon);
+    assert_approx_equals(text.dy.animVal.getItem(2).value, 0, epsilon);
+    assert_approx_equals(text.dy.animVal.getItem(3).value, 0, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.x, 0, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.y, 0, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.width, 250, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.height, 250, epsilon);
+    assert_equals(polyline.animatedPoints.numberOfItems, 4);
+    assert_approx_equals(polyline.animatedPoints.getItem(0).x, 0, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(0).y, 0, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).x, 15, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).y, 7.5, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).x, 15, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).y, 7.5, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(2).x, 0, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(2).y, 15, epsilon);
+    assert_equals(path.transform.animVal.numberOfItems, 2);
+    assert_equals(path.transform.animVal.getItem(0).type, SVGTransform.SVG_TRANSFORM_ROTATE);
+    assert_equals(path.transform.animVal.getItem(0).angle, 45);
+    assert_equals(path.transform.animVal.getItem(1).type, SVGTransform.SVG_TRANSFORM_ROTATE);
+    assert_approx_equals(path.transform.animVal.getItem(1).angle, -22.5, epsilon);
+    expectFillColor(rect, 0, 63, 0);
+    checkBaseVal();
+}
+
+function sample3() {
+    assert_approx_equals(marker.orientAngle.animVal.value, 0, epsilon);
+    assert_approx_equals(feConvolveMatrix.divisor.animVal, 20, epsilon);
+    assert_approx_equals(feConvolveMatrix.orderX.animVal, 3, epsilon);
+    assert_approx_equals(feConvolveMatrix.orderY.animVal, 3, epsilon);
+    assert_approx_equals(feConvolveMatrix.targetX.animVal, 1, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelUnitLengthX.animVal, 10, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelUnitLengthY.animVal, 10, epsilon);
+    assert_equals(feConvolveMatrix.kernelMatrix.animVal.numberOfItems, 9);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(0).value, 2, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(1).value, 2, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(2).value, 3, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(3).value, 2, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(4).value, 2, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(5).value, 3, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(6).value, 2, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(7).value, 2, epsilon);
+    assert_approx_equals(feConvolveMatrix.kernelMatrix.animVal.getItem(8).value, 3, epsilon);
+    assert_approx_equals(rect.y.animVal.value, 100, epsilon);
+    assert_equals(text.dy.animVal.numberOfItems, 4);
+    assert_approx_equals(text.dy.animVal.getItem(0).value, -5, epsilon);
+    assert_approx_equals(text.dy.animVal.getItem(1).value, 10, epsilon);
+    assert_approx_equals(text.dy.animVal.getItem(2).value, -10, epsilon);
+    assert_approx_equals(text.dy.animVal.getItem(3).value, 10, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.x, 0, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.y, 0, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.width, 200, epsilon);
+    assert_approx_equals(svg.viewBox.animVal.height, 200, epsilon);
+    assert_equals(polyline.animatedPoints.numberOfItems, 4);
+    assert_approx_equals(polyline.animatedPoints.getItem(0).x, 0, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(0).y, 0, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).x, 20, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).y, 10, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).x, 20, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(1).y, 10, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(2).x, 0, epsilon);
+    assert_approx_equals(polyline.animatedPoints.getItem(2).y, 20, epsilon);
+    assert_equals(path.transform.animVal.numberOfItems, 2);
+    assert_equals(path.transform.animVal.getItem(0).type, SVGTransform.SVG_TRANSFORM_ROTATE);
+    assert_equals(path.transform.animVal.getItem(0).angle, 45);
+    assert_equals(path.transform.animVal.getItem(1).type, SVGTransform.SVG_TRANSFORM_ROTATE);
+    assert_approx_equals(path.transform.animVal.getItem(1).angle, -45, epsilon);
+    expectFillColor(rect, 0, 128, 0);
+    checkBaseVal();
+}
+
+smil_async_test((t) => {
+    marker = rootSVGElement.ownerDocument.getElementsByTagName("marker")[0];
+    filter = rootSVGElement.ownerDocument.getElementsByTagName("filter")[0];
+    feConvolveMatrix = rootSVGElement.ownerDocument.getElementsByTagName("feConvolveMatrix")[0];
+    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
+    svg = rootSVGElement.ownerDocument.getElementsByTagName("svg")[0];
+    path = rootSVGElement.ownerDocument.getElementsByTagName("path")[0];
+    polyline = rootSVGElement.ownerDocument.getElementsByTagName("polyline")[0];
+    text = rootSVGElement.ownerDocument.getElementsByTagName("text")[0];
+
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["an1", 0.0,   sample1],
+        ["an1", 2.0,   sample2],
+        ["an1", 4.001, sample3]
+    ];
+
+    runAnimationTest(t, expectedValues);
+});
+
+window.animationStartsImmediately = true;
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/additive-values-width-animation.html b/third_party/blink/web_tests/external/wpt/svg/animations/additive-values-width-animation.html
new file mode 100644
index 0000000..5b874f5a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/additive-values-width-animation.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>This tests values animation and additive='sum'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/SVGAnimationTestCase-testharness.js"></script>
+
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<!-- an1: Change width from 0 to 50 to 100, all linear interpolated. As additive is set to sum it should add the current baseValue
+          to the new animated value each time a value from the values list is consumed. Expected:
+          At 0s, width=10, at 2s, width=50+10=60, at 4s, width=100+10=110.
+
+          Our testing harness will change the baseValue from 10 to 60 at 5s. The current animated value (before the script change)
+          is: <baseValue>+<animValue>: 10 + (100/6*5) = 93.333 at this point. As we change the baseValue to 60, the equation now looks like:
+          60 + (100/6*5) = 143.333. Before the script change the last second of the animation would have animated width from 85 to 110.
+          Due the script change its now animating from 93.999 to 143.333 during the last second.
+-->
+<rect width="10" height="100" fill="green">
+    <animate id="an1" attributeType="XML" attributeName="width" fill="freeze" additive="sum" values="0; 50; 100" begin="0s" dur="6s"/>
+</rect>
+
+</svg>
+
+<script>
+var rootSVGElement = document.querySelector("svg");
+var epsilon = 1.0;
+
+// Setup animation test
+function sample1() {
+    assert_approx_equals(rect.width.animVal.value, 10, epsilon);
+    assert_equals(rect.width.baseVal.value, 10);
+}
+
+function sample2() {
+    assert_approx_equals(rect.width.animVal.value, 60, epsilon);
+    assert_equals(rect.width.baseVal.value, 10);
+}
+
+function sample3() {
+    assert_approx_equals(rect.width.animVal.value, 93.3, epsilon);
+    assert_equals(rect.width.baseVal.value, 10);
+}
+
+function changeBaseVal() {
+    // At 5s, only change the baseVal.
+    rect.width.baseVal.value = 60;
+}
+
+function sample4() {
+    assert_approx_equals(rect.width.animVal.value, 143.33, epsilon);
+    assert_equals(rect.width.baseVal.value, 60);
+}
+
+function sample5() {
+    assert_approx_equals(rect.width.animVal.value, 160, epsilon);
+    assert_equals(rect.width.baseVal.value, 60);
+}
+
+smil_async_test((t) => {
+    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
+
+    // All animations in the test file use the same duration, so it's not needed to list all sample points individually for an5/an6/an7/an8.
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["an1", 0.0,   sample1],
+        ["an1", 3.0,   sample2],
+        ["an1", 4.999, sample3],
+        ["an1", 5.0,   changeBaseVal],
+        ["an1", 5.001, sample4],
+        ["an1", 6.001, sample5],
+        ["an1", 60.0,  sample5]
+    ];
+
+    runAnimationTest(t, expectedValues);
+});
+
+window.animationStartsImmediately = true;
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-calcMode-spline-by.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-calcMode-spline-by.html
new file mode 100644
index 0000000..5ce9bcc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-calcMode-spline-by.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>Test calcMode spline with by animation. You should see a green 100x100 rect and only PASS messages</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/SVGAnimationTestCase-testharness.js"></script>
+
+<svg>
+</svg>
+
+<script>
+var rootSVGElement = document.querySelector("svg");
+var epsilon = 1.0;
+
+// Setup test document
+var rect = createSVGElement("rect");
+rect.setAttribute("id", "rect");
+rect.setAttribute("x", "100");
+rect.setAttribute("width", "100");
+rect.setAttribute("height", "100");
+rect.setAttribute("fill", "green");
+rect.setAttribute("onclick", "executeTest()");
+
+var animate = createSVGElement("animate");
+animate.setAttribute("id", "animation");
+animate.setAttribute("attributeName", "x");
+animate.setAttribute("by", "-100");
+animate.setAttribute("begin", "0s");
+animate.setAttribute("dur", "4s");
+animate.setAttribute("keyTimes", "0;1");
+animate.setAttribute("keySplines", "0.25 .5 .25 0.85");
+animate.setAttribute("calcMode", "spline");
+rect.appendChild(animate);
+rootSVGElement.appendChild(rect);
+
+// Setup animation test
+function sample1() {
+    // Check initial/end conditions
+    assert_approx_equals(rect.x.animVal.value, 100, epsilon);
+    assert_equals(rect.x.baseVal.value, 100);
+}
+
+function sample2() {
+    // Check half-time conditions
+    assert_approx_equals(rect.x.animVal.value, 18.8, epsilon);
+    assert_equals(rect.x.baseVal.value, 100);
+}
+
+function sample3() {
+    // Check just before-end conditions
+    assert_approx_equals(rect.x.animVal.value, 0, epsilon);
+    assert_equals(rect.x.baseVal.value, 100);
+}
+
+smil_async_test((t) => {
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["animation", 0.0,   sample1],
+        ["animation", 2.0,   sample2],
+        ["animation", 3.999, sample3],
+        ["animation", 4.001, sample1]
+    ];
+
+    runAnimationTest(t, expectedValues);
+});
+
+window.clickX = 150;
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-calcMode-spline-from-by.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-calcMode-spline-from-by.html
new file mode 100644
index 0000000..1f15760c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-calcMode-spline-from-by.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>Test calcMode spline with from-by animation. You should see a green 100x100 rect and only PASS messages</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/SVGAnimationTestCase-testharness.js"></script>
+
+<svg>
+</svg>
+
+<script>
+var rootSVGElement = document.querySelector("svg");
+var epsilon = 1.0;
+
+// Setup test document
+var rect = createSVGElement("rect");
+rect.setAttribute("id", "rect");
+rect.setAttribute("x", "100");
+rect.setAttribute("width", "100");
+rect.setAttribute("height", "100");
+rect.setAttribute("fill", "green");
+rect.setAttribute("onclick", "executeTest()");
+
+var animate = createSVGElement("animate");
+animate.setAttribute("id", "animation");
+animate.setAttribute("attributeName", "x");
+animate.setAttribute("from", "100");
+animate.setAttribute("by", "-100");
+animate.setAttribute("begin", "0s");
+animate.setAttribute("dur", "4s");
+animate.setAttribute("keyTimes", "0;1");
+animate.setAttribute("keySplines", "0.25 .5 .25 0.85");
+animate.setAttribute("calcMode", "spline");
+rect.appendChild(animate);
+rootSVGElement.appendChild(rect);
+
+// Setup animation test
+function sample1() {
+    // Check initial/end conditions
+    assert_approx_equals(rect.x.animVal.value, 100, epsilon);
+    assert_equals(rect.x.baseVal.value, 100);
+}
+
+function sample2() {
+    // Check half-time conditions
+    assert_approx_equals(rect.x.animVal.value, 18.8, epsilon);
+    assert_equals(rect.x.baseVal.value, 100);
+}
+
+function sample3() {
+    // Check just before-end conditions
+    assert_approx_equals(rect.x.animVal.value, 0, epsilon);
+    assert_equals(rect.x.baseVal.value, 100);
+}
+
+smil_async_test((t) => {
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["animation", 0.0,   sample1],
+        ["animation", 2.0,   sample2],
+        ["animation", 3.999, sample3],
+        ["animation", 4.001, sample1]
+    ];
+
+    runAnimationTest(t, expectedValues);
+});
+
+window.clickX = 150;
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-calcMode-spline-from-to.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-calcMode-spline-from-to.html
new file mode 100644
index 0000000..4d60800
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-calcMode-spline-from-to.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>Test calcMode spline with from-to animation. You should see a green 100x100 rect and only PASS messages</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/SVGAnimationTestCase-testharness.js"></script>
+
+<svg>
+</svg>
+
+<script>
+var rootSVGElement = document.querySelector("svg");
+var epsilon = 1.0;
+
+// Setup test document
+var rect = createSVGElement("rect");
+rect.setAttribute("id", "rect");
+rect.setAttribute("x", "100");
+rect.setAttribute("width", "100");
+rect.setAttribute("height", "100");
+rect.setAttribute("fill", "green");
+rect.setAttribute("onclick", "executeTest()");
+
+var animate = createSVGElement("animate");
+animate.setAttribute("id", "animation");
+animate.setAttribute("attributeName", "x");
+animate.setAttribute("from", "100");
+animate.setAttribute("to", "0");
+animate.setAttribute("begin", "0s");
+animate.setAttribute("dur", "4s");
+animate.setAttribute("keyTimes", "0;1");
+animate.setAttribute("keySplines", "0.25 .5 .25 0.85");
+animate.setAttribute("calcMode", "spline");
+rect.appendChild(animate);
+rootSVGElement.appendChild(rect);
+
+// Setup animation test
+function sample1() {
+    // Check initial/end conditions
+    assert_approx_equals(rect.x.animVal.value, 100, epsilon);
+    assert_equals(rect.x.baseVal.value, 100);
+}
+
+function sample2() {
+    // Check half-time conditions
+    assert_approx_equals(rect.x.animVal.value, 18.8, epsilon);
+    assert_equals(rect.x.baseVal.value, 100);
+}
+
+function sample3() {
+    // Check just before-end conditions
+    assert_approx_equals(rect.x.animVal.value, 0, epsilon);
+    assert_equals(rect.x.baseVal.value, 100);
+}
+
+smil_async_test((t) => {
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["animation", 0.0,   sample1],
+        ["animation", 2.0,   sample2],
+        ["animation", 3.999, sample3],
+        ["animation", 4.001, sample1]
+    ];
+
+    runAnimationTest(t, expectedValues);
+});
+
+window.clickX = 150;
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
deleted file mode 100644
index 0164694..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click.html
deleted file mode 100644
index 78a992aa..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-testRunner.setUseMockTheme(false);
-testRunner.waitUntilDone();
-</script>
-<script src='../../../forms/resources/picker-common.js'></script>
-</head>
-<body>
-<input type='color' id='color' value='#80D9FF'>
-
-<p id='description' style='opacity: 0'></p>
-<div id='console' style='opacity: 0'></div>
-
-<script>
-openPicker(document.getElementById('color'), openPickerSuccessfulCallback, () => testRunner.notifyDone());
-
-function openPickerSuccessfulCallback() {
-  popupWindow.focus();
-  const popupDocument = popupWindow.document;
-  const colorWell = popupDocument.querySelector('color-well');
-  const colorWellRect = colorWell.getBoundingClientRect();
-  eventSender.mouseMoveTo(colorWellRect.left + (colorWellRect.width * 4 / 10), colorWellRect.top + (colorWellRect.height * 6 / 10));
-  eventSender.mouseDown();
-  eventSender.mouseUp();
-  testRunner.notifyDone();
-}
-</script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
deleted file mode 100644
index 0164694..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag.html
deleted file mode 100644
index 68580ee..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-testRunner.setUseMockTheme(false);
-testRunner.waitUntilDone();
-</script>
-<script src='../../../forms/resources/picker-common.js'></script>
-</head>
-<body>
-<input type='color' id='color' value='#80D9FF'>
-
-<p id='description' style='opacity: 0'></p>
-<div id='console' style='opacity: 0'></div>
-
-<script>
-openPicker(document.getElementById('color'), openPickerSuccessfulCallback, () => testRunner.notifyDone());
-
-function openPickerSuccessfulCallback() {
-  popupWindow.focus();
-  const popupDocument = popupWindow.document;
-  const colorWell = popupDocument.querySelector('color-well');
-  const colorWellRect = colorWell.getBoundingClientRect();
-  eventSender.mouseMoveTo(colorWellRect.left, colorWellRect.top);
-  eventSender.mouseDown();
-  eventSender.mouseMoveTo(colorWellRect.left + (colorWellRect.width * 4 / 10), colorWellRect.top + (colorWellRect.height * 6 / 10));
-  eventSender.mouseUp();
-  testRunner.notifyDone();
-}
-</script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
deleted file mode 100644
index d5370777..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click.html
deleted file mode 100644
index b24aad3e..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-testRunner.setUseMockTheme(false);
-testRunner.waitUntilDone();
-</script>
-<script src='../../../forms/resources/picker-common.js'></script>
-</head>
-<body>
-<input type='color' id='color'>
-
-<p id='description' style='opacity: 0'></p>
-<div id='console' style='opacity: 0'></div>
-
-<script>
-openPicker(document.getElementById('color'), openPickerSuccessfulCallback, () => testRunner.notifyDone());
-
-function openPickerSuccessfulCallback() {
-  popupWindow.focus();
-  const popupDocument = popupWindow.document;
-  const hueSlider = popupDocument.querySelector('hue-slider');
-  const hueSliderRect = hueSlider.getBoundingClientRect();
-  eventSender.mouseMoveTo(hueSliderRect.left + (hueSliderRect.width / 2), hueSliderRect.top);
-  eventSender.mouseDown();
-  eventSender.mouseUp();
-  testRunner.notifyDone();
-}
-</script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
deleted file mode 100644
index d5370777..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag.html
deleted file mode 100644
index 2bc9ad4..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-testRunner.setUseMockTheme(false);
-testRunner.waitUntilDone();
-</script>
-<script src='../../../forms/resources/picker-common.js'></script>
-</head>
-<body>
-<input type='color' id='color'>
-
-<p id='description' style='opacity: 0'></p>
-<div id='console' style='opacity: 0'></div>
-
-<script>
-openPicker(document.getElementById('color'), openPickerSuccessfulCallback, () => testRunner.notifyDone());
-
-function openPickerSuccessfulCallback() {
-  popupWindow.focus();
-  const popupDocument = popupWindow.document;
-  const hueSlider = popupDocument.querySelector('hue-slider');
-  const hueSliderRect = hueSlider.getBoundingClientRect();
-  eventSender.mouseMoveTo(hueSliderRect.left, hueSliderRect.top);
-  eventSender.mouseDown();
-  eventSender.mouseMoveTo(hueSliderRect.left + (hueSliderRect.width / 2), hueSliderRect.top);
-  eventSender.mouseUp();
-  testRunner.notifyDone();
-}
-</script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
deleted file mode 100644
index dae8a211..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue.html
deleted file mode 100644
index a15d319f0..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-testRunner.setUseMockTheme(false);
-testRunner.waitUntilDone();
-</script>
-<script src='../../../forms/resources/picker-common.js'></script>
-</head>
-<body>
-<input type='color' id='color' value='#FF0000'>
-
-<p id='description' style='opacity: 0'></p>
-<div id='console' style='opacity: 0'></div>
-
-<script>
-openPicker(document.getElementById('color'), openPickerSuccessfulCallback, () => testRunner.notifyDone());
-
-function openPickerSuccessfulCallback() {
-  popupWindow.focus();
-  const popupDocument = popupWindow.document;
-  const formatToggler = popupDocument.querySelector('format-toggler');
-  formatToggler.click();
-  testRunner.notifyDone();
-}
-</script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
deleted file mode 100644
index dae8a211..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue.html
deleted file mode 100644
index a0d8e771..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-testRunner.setUseMockTheme(false);
-testRunner.waitUntilDone();
-</script>
-<script src='../../../forms/resources/picker-common.js'></script>
-</head>
-<body>
-<input type='color' id='color' value='#FF0000'>
-
-<p id='description' style='opacity: 0'></p>
-<div id='console' style='opacity: 0'></div>
-
-<script>
-openPicker(document.getElementById('color'), openPickerSuccessfulCallback, () => testRunner.notifyDone());
-
-function openPickerSuccessfulCallback() {
-  popupWindow.focus();
-  const popupDocument = popupWindow.document;
-  const formatToggler = popupDocument.querySelector('format-toggler');
-  formatToggler.click();
-  const hueSlider = popupDocument.querySelector('hue-slider');
-  const hueSliderRect = hueSlider.getBoundingClientRect();
-  eventSender.mouseMoveTo(hueSliderRect.left, hueSliderRect.top);
-  eventSender.mouseDown();
-  eventSender.mouseMoveTo(hueSliderRect.right - 1, hueSliderRect.top);
-  eventSender.mouseUp();
-  testRunner.notifyDone();
-  testRunner.notifyDone();
-}
-</script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
deleted file mode 100644
index b846542..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match.html
deleted file mode 100644
index 2653fcf..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-testRunner.setUseMockTheme(false);
-testRunner.waitUntilDone();
-</script>
-<script src='../../../forms/resources/picker-common.js'></script>
-</head>
-<body>
-<input type='color' id='color' value='#EA5FB0'>
-
-<p id='description' style='opacity: 0'></p>
-<div id='console' style='opacity: 0'></div>
-
-<script>
-openPicker(document.getElementById('color'), openPickerSuccessfulCallback, () => testRunner.notifyDone());
-
-function openPickerSuccessfulCallback() {
-  popupWindow.focus();
-  const popupDocument = popupWindow.document;
-  const formatToggler = popupDocument.querySelector('format-toggler');
-  formatToggler.click();
-  const hValueContainer = popupDocument.getElementById('hValueContainer');
-  const hValueContainerRect = hValueContainer.getBoundingClientRect();
-  eventSender.mouseMoveTo(hValueContainerRect.right - 1, hValueContainerRect.bottom - 1);
-  eventSender.mouseDown();
-  eventSender.mouseUp();
-  eventSender.keyDown('Backspace');
-  eventSender.keyDown('1');
-  testRunner.notifyDone();
-}
-</script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
deleted file mode 100644
index b846542..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change.html
deleted file mode 100644
index 8b40fdd2..0000000
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-testRunner.setUseMockTheme(false);
-testRunner.waitUntilDone();
-</script>
-<script src='../../../forms/resources/picker-common.js'></script>
-</head>
-<body>
-<input type='color' id='color' value='#EA5FB0'>
-
-<p id='description' style='opacity: 0'></p>
-<div id='console' style='opacity: 0'></div>
-
-<script>
-openPicker(document.getElementById('color'), openPickerSuccessfulCallback, () => testRunner.notifyDone());
-
-function openPickerSuccessfulCallback() {
-  popupWindow.focus();
-  const popupDocument = popupWindow.document;
-  const formatToggler = popupDocument.querySelector('format-toggler');
-  formatToggler.click();
-  const hValueContainer = popupDocument.getElementById('hValueContainer');
-  const hValueContainerRect = hValueContainer.getBoundingClientRect();
-  eventSender.mouseMoveTo(hValueContainerRect.right - 1, hValueContainerRect.top);
-  eventSender.mouseDown();
-  eventSender.mouseUp();
-  eventSender.keyDown('Backspace');
-  eventSender.keyDown('Backspace');
-  eventSender.keyDown('Backspace');
-  eventSender.keyDown('2');
-  eventSender.keyDown('7');
-  eventSender.keyDown('6');
-  testRunner.notifyDone();
-}
-</script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-color-class.html b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-color-class.html
index 91838d31..b8df01c 100644
--- a/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-color-class.html
+++ b/third_party/blink/web_tests/fast/forms/controls-new-ui/color/color-picker-color-class.html
@@ -29,7 +29,6 @@
 testAsHex();
 testAsRGB();
 testAsHSL();
-testDistance();
 
 function testEquals() {
   test(() => {
@@ -480,29 +479,6 @@
     assert_equals('hsl(307,64%,54%)', new Color(ColorFormat.HSL, 307, 64, 54).asHSL());
   }, 'new Color(ColorFormat.HSL, 307, 64, 54).asHSL()');
 }
-
-function testDistance() {
-  test(() => {
-    assert_equals(Color.distance([255, 255, 255], [255, 255, 255]), 0);
-  }, 'Color.distance([255,255,255], [255,255,255])');
-
-  test(() => {
-    assert_equals(Color.distance([120, 100, 50], [120, 100, 50]), 0);
-  }, 'Color.distance([120, 100, 50], [120, 100, 50])');
-
-  test(() => {
-    assert_equals(Color.distance([120, 100, 50], [0, 100, 50]), 120);
-  }, 'Color.distance([120, 100, 50], [0, 100, 50])');
-
-  test(() => {
-    assert_equals(Math.round(Color.distance([255, 255, 255], [0, 0, 0])), 442);
-  }, 'Color.distance([255,255,255], [0, 0, 0])');
-
-  test(() => {
-    assert_equals(Math.round(Color.distance([235, 77, 65], [234, 84, 59])), 9);
-  }, 'Color.distance([235, 77, 65], [234, 84, 59])');
-
-}
 </script>
 </body>
 </html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/compositing/fixed-background-after-style-recalc-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/compositing/fixed-background-after-style-recalc-expected.png
new file mode 100644
index 0000000..3433773
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/compositing/fixed-background-after-style-recalc-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/compositing/lots-of-img-layers-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/compositing/lots-of-img-layers-expected.png
new file mode 100644
index 0000000..35b2d50
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/compositing/lots-of-img-layers-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/compositing/overflow/mask-with-filter-expected.png b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/compositing/overflow/mask-with-filter-expected.png
new file mode 100644
index 0000000..42ad9838
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-gpu-rasterization/compositing/overflow/mask-with-filter-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
deleted file mode 100644
index 290ef86..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
deleted file mode 100644
index 290ef86..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
index 1cc4653..eff0693 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
index 95e7fb7..f2b6ebf 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
index 992eb05..75be482 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
deleted file mode 100644
index bb11078..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
deleted file mode 100644
index bb11078..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
deleted file mode 100644
index 68afb4c..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
deleted file mode 100644
index 367c418..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
deleted file mode 100644
index 2bb26e3e..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
deleted file mode 100644
index cd360e0a..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
index 38548ef..31a8f882 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
index fd75baf..fe0d28c 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
index 10ca19c..98c4d4d 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
index 5dd9dcd8..b1a44cc 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
index 2ce807c0..6cfffe6 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
deleted file mode 100644
index 738581f3..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
deleted file mode 100644
index 738581f3..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
index 931c3dc..428e9e1 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
index 96977e89..8e139ac 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
index 85c0c18..15fd22a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
deleted file mode 100644
index bad041a..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
deleted file mode 100644
index bad041a..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
deleted file mode 100644
index 79c64c4..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
deleted file mode 100644
index 5c2ed2f..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
deleted file mode 100644
index 0c1d55d..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
deleted file mode 100644
index c91d2b4..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
index 2b60317..7ef12e6b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
index 191dc5f..d095cf4 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
index cde0033..ab54c65 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
index b4a394e..c7c3da6 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
index dfdcdb9..efc72e6 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
deleted file mode 100644
index 0c155fd..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
deleted file mode 100644
index 0c155fd..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
index c9117799..aa9a8ee3 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
index 39eef19..36b4fae2 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
index b345ddb..60517cf 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
deleted file mode 100644
index 06892439..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
deleted file mode 100644
index 06892439..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
deleted file mode 100644
index 1a1024a..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
deleted file mode 100644
index b68a872..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
deleted file mode 100644
index 7e57edb..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
deleted file mode 100644
index a1266f7..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
index 1191997..1600d5e 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
index 84dfa2ae..c44f918 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
index b3ea6e3..01ac0b5c 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
index ae551468..8b3b494a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
index 72d216c..be33806 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
deleted file mode 100644
index 788a23f3..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
deleted file mode 100644
index 788a23f3..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
index 766d9ba88d..f0101ea 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
index 90e4da6..1543fa6 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
index 5957af2..9c29df10 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
deleted file mode 100644
index b2742697..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
deleted file mode 100644
index b2742697..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
deleted file mode 100644
index 70eee753..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
deleted file mode 100644
index f3bdb57..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
deleted file mode 100644
index 9e40a9e..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
deleted file mode 100644
index d598b1d0..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
index 6e339c48..ef3eef6 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
index ae52f7f..fd24e3e 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
index 8706e72..89bc04eb 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
index 1b0f72e..33bba57 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
index 214405ee..0b44a91b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
deleted file mode 100644
index 788a23f3..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
deleted file mode 100644
index 788a23f3..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
index 766d9ba88d..f0101ea 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
index a14781d..7551ba1 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
index ae4e9be..23a92111 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
deleted file mode 100644
index b2742697..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
deleted file mode 100644
index b2742697..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
deleted file mode 100644
index 92f01c09..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
deleted file mode 100644
index 343fa20..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
deleted file mode 100644
index c4bb77f..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
deleted file mode 100644
index 7ba66d2..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
index 6e339c48..ef3eef6 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
index ae52f7f..fd24e3e 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
index acf3815..8361990 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
index 1b0f72e..33bba57 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
index 6c2851a..5f654118 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
deleted file mode 100644
index aa39c2e..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
deleted file mode 100644
index aa39c2e..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
deleted file mode 100644
index adb12a9..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
deleted file mode 100644
index adb12a9..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
deleted file mode 100644
index 26bdee1..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
deleted file mode 100644
index 26bdee1..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
deleted file mode 100644
index 1a45db0e..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
deleted file mode 100644
index 1a45db0e..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
deleted file mode 100644
index 788a23f3..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
deleted file mode 100644
index 788a23f3..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
index 766d9ba88d..f0101ea 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
index a14781d..7551ba1 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
index ae4e9be..23a92111 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
deleted file mode 100644
index b2742697..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
deleted file mode 100644
index b2742697..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
deleted file mode 100644
index 92f01c09..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
deleted file mode 100644
index 343fa20..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
deleted file mode 100644
index c4bb77f..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
deleted file mode 100644
index 7ba66d2..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
index 6e339c48..ef3eef6 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
index ae52f7f..fd24e3e 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
index acf3815..8361990 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
index 1b0f72e..33bba57 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
index 6c2851a..5f654118 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/blink-cors/external/wpt/xhr/responsexml-document-properties-expected.txt b/third_party/blink/web_tests/platform/win7/virtual/blink-cors/external/wpt/xhr/responsexml-document-properties-expected.txt
new file mode 100644
index 0000000..a2076f9
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/blink-cors/external/wpt/xhr/responsexml-document-properties-expected.txt
@@ -0,0 +1,27 @@
+This is a testharness.js-based test.
+PASS domain
+PASS URL
+PASS documentURI
+PASS baseURI
+PASS referrer
+PASS title
+PASS contentType
+PASS readyState
+PASS location
+PASS defaultView
+PASS body
+PASS doctype
+PASS all
+PASS cookie
+PASS Test document URL properties after redirect
+PASS Test document URL properties of document with <base> after redirect
+FAIL lastModified set to time of response if no HTTP header provided assert_less_than_equal: expected a number less than or equal to 1565932912 but got 1565936512
+FAIL lastModified set to related HTTP header if provided assert_equals: expected 1565911066000 but got 1565907466000
+PASS cookie (after setting it)
+PASS styleSheets should be an object
+PASS implementation should be an object
+PASS images should be an object
+PASS forms should be an object
+PASS links should be an object
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
deleted file mode 100644
index 722790d8..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
deleted file mode 100644
index 722790d8..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
index 91e7d3b3..9919e26 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
index 328e495..1c958d81 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
index bb57d96..48752054 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
deleted file mode 100644
index 1d189a8..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
deleted file mode 100644
index 4313e59..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
deleted file mode 100644
index 39ef1e76..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
deleted file mode 100644
index 516552d..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
index 8b7e83a..0cd7913 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
index 8ddbaa95..2df3add8f0 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
index 1d2d471..27f9fa4 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
index 8776a9ec..ac0aac1 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
index 53358e2..e4f88b4 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/animations/accumulate-values-width-animation-expected.txt b/third_party/blink/web_tests/svg/animations/accumulate-values-width-animation-expected.txt
deleted file mode 100644
index d8432bb..0000000
--- a/third_party/blink/web_tests/svg/animations/accumulate-values-width-animation-expected.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-SVG 1.1 dynamic animation tests
-
-This tests values animation and accumulate='sum'
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS rect.width.animVal.value is 0
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 30
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 20
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 20
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 50
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 40
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 40
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 70
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 60
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 60
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 90
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 80
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 80
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 110
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 100
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 100
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 100
-PASS rect.width.baseVal.value is 20
-PASS rect.width.animVal.value is 100
-PASS rect.width.baseVal.value is 20
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/svg/animations/accumulate-values-width-animation.html b/third_party/blink/web_tests/svg/animations/accumulate-values-width-animation.html
deleted file mode 100644
index e994d29..0000000
--- a/third_party/blink/web_tests/svg/animations/accumulate-values-width-animation.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-<script src="resources/SVGTestCase.js"></script>
-<script src="resources/SVGAnimationTestCase.js"></script>
-</head>
-<body onload="runSMILTest()">
-<h1>SVG 1.1 dynamic animation tests</h1>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/accumulate-values-width-animation.js"></script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/svg/animations/additive-from-to-width-animation-expected.txt b/third_party/blink/web_tests/svg/animations/additive-from-to-width-animation-expected.txt
deleted file mode 100644
index fad854c..0000000
--- a/third_party/blink/web_tests/svg/animations/additive-from-to-width-animation-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-SVG 1.1 dynamic animation tests
-
-This tests multiple additive='sum' animations running at the same time
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS rect.width.animVal.value is 20
-PASS rect.width.baseVal.value is 10
-PASS rect.width.animVal.value is 60
-PASS rect.width.baseVal.value is 10
-PASS rect.width.animVal.value is 100
-PASS rect.width.baseVal.value is 10
-PASS rect.width.animVal.value is 100
-PASS rect.width.baseVal.value is 10
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/svg/animations/additive-from-to-width-animation.html b/third_party/blink/web_tests/svg/animations/additive-from-to-width-animation.html
deleted file mode 100644
index 32b0eea..0000000
--- a/third_party/blink/web_tests/svg/animations/additive-from-to-width-animation.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-<script src="resources/SVGTestCase.js"></script>
-<script src="resources/SVGAnimationTestCase.js"></script>
-</head>
-<body onload="runSMILTest()">
-<h1>SVG 1.1 dynamic animation tests</h1>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/additive-from-to-width-animation.js"></script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/svg/animations/additive-type-by-animation-expected.txt b/third_party/blink/web_tests/svg/animations/additive-type-by-animation-expected.txt
deleted file mode 100644
index fbc4267..0000000
--- a/third_party/blink/web_tests/svg/animations/additive-type-by-animation-expected.txt
+++ /dev/null
@@ -1,259 +0,0 @@
-SVG 1.1 dynamic animation tests
-
-This by animation for all XML property types
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS marker.orientAngle.animVal.value is -45
-PASS feConvolveMatrix.divisor.animVal is 37.5
-PASS feConvolveMatrix.orderX.animVal is 6
-PASS feConvolveMatrix.orderY.animVal is 6
-PASS feConvolveMatrix.targetX.animVal is 5
-PASS feConvolveMatrix.kernelUnitLengthX.animVal is 20
-PASS feConvolveMatrix.kernelUnitLengthY.animVal is 30
-PASS feConvolveMatrix.kernelMatrix.animVal.numberOfItems is 9
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(0).value is 0
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(1).value is 1
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(2).value is 0
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(3).value is 0
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(4).value is 1
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(5).value is 0
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(6).value is 0
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(7).value is 1
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(8).value is 0
-PASS rect.y.animVal.value is 0
-PASS text.dy.animVal.numberOfItems is 4
-PASS text.dy.animVal.getItem(0).value is 5
-PASS text.dy.animVal.getItem(1).value is -10
-PASS text.dy.animVal.getItem(2).value is 10
-PASS text.dy.animVal.getItem(3).value is -10
-PASS svg.viewBox.animVal.x is 0
-PASS svg.viewBox.animVal.y is 0
-PASS svg.viewBox.animVal.width is 300
-PASS svg.viewBox.animVal.height is 300
-PASS polyline.animatedPoints.numberOfItems is 4
-PASS polyline.animatedPoints.getItem(0).x is 0
-PASS polyline.animatedPoints.getItem(0).y is 0
-PASS polyline.animatedPoints.getItem(1).x is 10
-PASS polyline.animatedPoints.getItem(1).y is 5
-PASS polyline.animatedPoints.getItem(1).x is 10
-PASS polyline.animatedPoints.getItem(1).y is 5
-PASS polyline.animatedPoints.getItem(2).x is 0
-PASS polyline.animatedPoints.getItem(2).y is 10
-PASS path.transform.animVal.numberOfItems is 2
-PASS path.transform.animVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_ROTATE
-PASS path.transform.animVal.getItem(0).angle is 45
-PASS path.transform.animVal.getItem(1).type is SVGTransform.SVG_TRANSFORM_ROTATE
-PASS path.transform.animVal.getItem(1).angle is 0
-PASS colorComponents[1] is 0
-PASS colorComponents[2] is 0
-PASS colorComponents[3] is 0
-PASS marker.orientAngle.baseVal.value is -45
-PASS feConvolveMatrix.divisor.baseVal is 37.5
-PASS feConvolveMatrix.orderX.baseVal is 6
-PASS feConvolveMatrix.orderY.baseVal is 6
-PASS feConvolveMatrix.targetX.baseVal is 5
-PASS feConvolveMatrix.kernelUnitLengthX.baseVal is 20
-PASS feConvolveMatrix.kernelUnitLengthY.baseVal is 30
-PASS feConvolveMatrix.kernelMatrix.baseVal.numberOfItems is 9
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(0).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(1).value is 1
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(2).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(3).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(4).value is 1
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(5).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(6).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(7).value is 1
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(8).value is 0
-PASS rect.y.baseVal.value is 0
-PASS text.dy.baseVal.numberOfItems is 4
-PASS text.dy.baseVal.getItem(0).value is 5
-PASS text.dy.baseVal.getItem(1).value is -10
-PASS text.dy.baseVal.getItem(2).value is 10
-PASS text.dy.baseVal.getItem(3).value is -10
-PASS svg.viewBox.baseVal.x is 0
-PASS svg.viewBox.baseVal.y is 0
-PASS svg.viewBox.baseVal.width is 300
-PASS svg.viewBox.baseVal.height is 300
-PASS polyline.points.numberOfItems is 4
-PASS polyline.points.getItem(0).x is 0
-PASS polyline.points.getItem(0).y is 0
-PASS polyline.points.getItem(1).x is 10
-PASS polyline.points.getItem(1).y is 5
-PASS polyline.points.getItem(1).x is 10
-PASS polyline.points.getItem(1).y is 5
-PASS polyline.points.getItem(2).x is 0
-PASS polyline.points.getItem(2).y is 10
-PASS path.transform.baseVal.numberOfItems is 1
-PASS path.transform.baseVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_ROTATE
-PASS path.transform.baseVal.getItem(0).angle is 45
-PASS marker.orientAngle.animVal.value is -22.5
-PASS feConvolveMatrix.divisor.animVal is 28.75
-PASS feConvolveMatrix.orderX.animVal is 5
-PASS feConvolveMatrix.orderY.animVal is 5
-PASS feConvolveMatrix.targetX.animVal is 3
-PASS feConvolveMatrix.kernelUnitLengthX.animVal is 15
-PASS feConvolveMatrix.kernelUnitLengthY.animVal is 20
-PASS feConvolveMatrix.kernelMatrix.animVal.numberOfItems is 9
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(0).value is 1
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(1).value is 1.5
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(2).value is 1.5
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(3).value is 1
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(4).value is 1.5
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(5).value is 1.5
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(6).value is 1
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(7).value is 1.5
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(8).value is 1.5
-PASS rect.y.animVal.value is 50
-PASS text.dy.animVal.numberOfItems is 4
-PASS text.dy.animVal.getItem(0).value is 0
-PASS text.dy.animVal.getItem(1).value is 0
-PASS text.dy.animVal.getItem(2).value is 0
-PASS text.dy.animVal.getItem(3).value is 0
-PASS svg.viewBox.animVal.x is 0
-PASS svg.viewBox.animVal.y is 0
-PASS svg.viewBox.animVal.width is 250
-PASS svg.viewBox.animVal.height is 250
-PASS polyline.animatedPoints.numberOfItems is 4
-PASS polyline.animatedPoints.getItem(0).x is 0
-PASS polyline.animatedPoints.getItem(0).y is 0
-PASS polyline.animatedPoints.getItem(1).x is 15
-PASS polyline.animatedPoints.getItem(1).y is 7.5
-PASS polyline.animatedPoints.getItem(1).x is 15
-PASS polyline.animatedPoints.getItem(1).y is 7.5
-PASS polyline.animatedPoints.getItem(2).x is 0
-PASS polyline.animatedPoints.getItem(2).y is 15
-PASS path.transform.animVal.numberOfItems is 2
-PASS path.transform.animVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_ROTATE
-PASS path.transform.animVal.getItem(0).angle is 45
-PASS path.transform.animVal.getItem(1).type is SVGTransform.SVG_TRANSFORM_ROTATE
-PASS path.transform.animVal.getItem(1).angle is -22.5
-PASS colorComponents[1] is 0
-PASS colorComponents[2] is 63
-PASS colorComponents[3] is 0
-PASS marker.orientAngle.baseVal.value is -45
-PASS feConvolveMatrix.divisor.baseVal is 37.5
-PASS feConvolveMatrix.orderX.baseVal is 6
-PASS feConvolveMatrix.orderY.baseVal is 6
-PASS feConvolveMatrix.targetX.baseVal is 5
-PASS feConvolveMatrix.kernelUnitLengthX.baseVal is 20
-PASS feConvolveMatrix.kernelUnitLengthY.baseVal is 30
-PASS feConvolveMatrix.kernelMatrix.baseVal.numberOfItems is 9
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(0).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(1).value is 1
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(2).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(3).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(4).value is 1
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(5).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(6).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(7).value is 1
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(8).value is 0
-PASS rect.y.baseVal.value is 0
-PASS text.dy.baseVal.numberOfItems is 4
-PASS text.dy.baseVal.getItem(0).value is 5
-PASS text.dy.baseVal.getItem(1).value is -10
-PASS text.dy.baseVal.getItem(2).value is 10
-PASS text.dy.baseVal.getItem(3).value is -10
-PASS svg.viewBox.baseVal.x is 0
-PASS svg.viewBox.baseVal.y is 0
-PASS svg.viewBox.baseVal.width is 300
-PASS svg.viewBox.baseVal.height is 300
-PASS polyline.points.numberOfItems is 4
-PASS polyline.points.getItem(0).x is 0
-PASS polyline.points.getItem(0).y is 0
-PASS polyline.points.getItem(1).x is 10
-PASS polyline.points.getItem(1).y is 5
-PASS polyline.points.getItem(1).x is 10
-PASS polyline.points.getItem(1).y is 5
-PASS polyline.points.getItem(2).x is 0
-PASS polyline.points.getItem(2).y is 10
-PASS path.transform.baseVal.numberOfItems is 1
-PASS path.transform.baseVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_ROTATE
-PASS path.transform.baseVal.getItem(0).angle is 45
-PASS marker.orientAngle.animVal.value is 0
-PASS feConvolveMatrix.divisor.animVal is 20
-PASS feConvolveMatrix.orderX.animVal is 3
-PASS feConvolveMatrix.orderY.animVal is 3
-PASS feConvolveMatrix.targetX.animVal is 1
-PASS feConvolveMatrix.kernelUnitLengthX.animVal is 10
-PASS feConvolveMatrix.kernelUnitLengthY.animVal is 10
-PASS feConvolveMatrix.kernelMatrix.animVal.numberOfItems is 9
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(0).value is 2
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(1).value is 2
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(2).value is 3
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(3).value is 2
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(4).value is 2
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(5).value is 3
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(6).value is 2
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(7).value is 2
-PASS feConvolveMatrix.kernelMatrix.animVal.getItem(8).value is 3
-PASS rect.y.animVal.value is 100
-PASS text.dy.animVal.numberOfItems is 4
-PASS text.dy.animVal.getItem(0).value is -5
-PASS text.dy.animVal.getItem(1).value is 10
-PASS text.dy.animVal.getItem(2).value is -10
-PASS text.dy.animVal.getItem(3).value is 10
-PASS svg.viewBox.animVal.x is 0
-PASS svg.viewBox.animVal.y is 0
-PASS svg.viewBox.animVal.width is 200
-PASS svg.viewBox.animVal.height is 200
-PASS polyline.animatedPoints.numberOfItems is 4
-PASS polyline.animatedPoints.getItem(0).x is 0
-PASS polyline.animatedPoints.getItem(0).y is 0
-PASS polyline.animatedPoints.getItem(1).x is 20
-PASS polyline.animatedPoints.getItem(1).y is 10
-PASS polyline.animatedPoints.getItem(1).x is 20
-PASS polyline.animatedPoints.getItem(1).y is 10
-PASS polyline.animatedPoints.getItem(2).x is 0
-PASS polyline.animatedPoints.getItem(2).y is 20
-PASS path.transform.animVal.numberOfItems is 2
-PASS path.transform.animVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_ROTATE
-PASS path.transform.animVal.getItem(0).angle is 45
-PASS path.transform.animVal.getItem(1).type is SVGTransform.SVG_TRANSFORM_ROTATE
-PASS path.transform.animVal.getItem(1).angle is -45
-PASS colorComponents[1] is 0
-PASS colorComponents[2] is 128
-PASS colorComponents[3] is 0
-PASS marker.orientAngle.baseVal.value is -45
-PASS feConvolveMatrix.divisor.baseVal is 37.5
-PASS feConvolveMatrix.orderX.baseVal is 6
-PASS feConvolveMatrix.orderY.baseVal is 6
-PASS feConvolveMatrix.targetX.baseVal is 5
-PASS feConvolveMatrix.kernelUnitLengthX.baseVal is 20
-PASS feConvolveMatrix.kernelUnitLengthY.baseVal is 30
-PASS feConvolveMatrix.kernelMatrix.baseVal.numberOfItems is 9
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(0).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(1).value is 1
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(2).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(3).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(4).value is 1
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(5).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(6).value is 0
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(7).value is 1
-PASS feConvolveMatrix.kernelMatrix.baseVal.getItem(8).value is 0
-PASS rect.y.baseVal.value is 0
-PASS text.dy.baseVal.numberOfItems is 4
-PASS text.dy.baseVal.getItem(0).value is 5
-PASS text.dy.baseVal.getItem(1).value is -10
-PASS text.dy.baseVal.getItem(2).value is 10
-PASS text.dy.baseVal.getItem(3).value is -10
-PASS svg.viewBox.baseVal.x is 0
-PASS svg.viewBox.baseVal.y is 0
-PASS svg.viewBox.baseVal.width is 300
-PASS svg.viewBox.baseVal.height is 300
-PASS polyline.points.numberOfItems is 4
-PASS polyline.points.getItem(0).x is 0
-PASS polyline.points.getItem(0).y is 0
-PASS polyline.points.getItem(1).x is 10
-PASS polyline.points.getItem(1).y is 5
-PASS polyline.points.getItem(1).x is 10
-PASS polyline.points.getItem(1).y is 5
-PASS polyline.points.getItem(2).x is 0
-PASS polyline.points.getItem(2).y is 10
-PASS path.transform.baseVal.numberOfItems is 1
-PASS path.transform.baseVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_ROTATE
-PASS path.transform.baseVal.getItem(0).angle is 45
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/svg/animations/additive-type-by-animation.html b/third_party/blink/web_tests/svg/animations/additive-type-by-animation.html
deleted file mode 100644
index 542d5261..0000000
--- a/third_party/blink/web_tests/svg/animations/additive-type-by-animation.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-<script src="resources/SVGTestCase.js"></script>
-<script src="resources/SVGAnimationTestCase.js"></script>
-</head>
-<body onload="runSMILTest()">
-<h1>SVG 1.1 dynamic animation tests</h1>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/additive-type-by-animation.js"></script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/svg/animations/additive-values-width-animation-expected.txt b/third_party/blink/web_tests/svg/animations/additive-values-width-animation-expected.txt
deleted file mode 100644
index 8ab3646..0000000
--- a/third_party/blink/web_tests/svg/animations/additive-values-width-animation-expected.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-SVG 1.1 dynamic animation tests
-
-This tests values animation and additive='sum'
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS rect.width.animVal.value is 10
-PASS rect.width.baseVal.value is 10
-PASS rect.width.animVal.value is 60
-PASS rect.width.baseVal.value is 10
-PASS rect.width.animVal.value is 93.3
-PASS rect.width.baseVal.value is 10
-PASS rect.width.animVal.value is 143.33
-PASS rect.width.baseVal.value is 60
-PASS rect.width.animVal.value is 160
-PASS rect.width.baseVal.value is 60
-PASS rect.width.animVal.value is 160
-PASS rect.width.baseVal.value is 60
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/svg/animations/additive-values-width-animation.html b/third_party/blink/web_tests/svg/animations/additive-values-width-animation.html
deleted file mode 100644
index 6501197c..0000000
--- a/third_party/blink/web_tests/svg/animations/additive-values-width-animation.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-<script src="resources/SVGTestCase.js"></script>
-<script src="resources/SVGAnimationTestCase.js"></script>
-</head>
-<body onload="runSMILTest()">
-<h1>SVG 1.1 dynamic animation tests</h1>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/additive-values-width-animation.js"></script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-by-expected.txt b/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-by-expected.txt
deleted file mode 100644
index 91f7cea..0000000
--- a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-by-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-SVG 1.1 dynamic animation tests
-
-Test calcMode spline with by animation. You should see a green 100x100 rect and only PASS messages
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS rect.x.animVal.value is 100
-PASS rect.x.baseVal.value is 100
-PASS rect.x.animVal.value is 18.8
-PASS rect.x.baseVal.value is 100
-PASS rect.x.animVal.value is 0
-PASS rect.x.baseVal.value is 100
-PASS rect.x.animVal.value is 100
-PASS rect.x.baseVal.value is 100
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-by.html b/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-by.html
deleted file mode 100644
index c62f607..0000000
--- a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-by.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-<script src="resources/SVGTestCase.js"></script>
-<script src="resources/SVGAnimationTestCase.js"></script>
-</head>
-<body onload="runSMILTest()">
-<h1>SVG 1.1 dynamic animation tests</h1>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/animate-calcMode-spline-by.js"></script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-by-expected.txt b/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-by-expected.txt
deleted file mode 100644
index 421de344..0000000
--- a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-by-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-SVG 1.1 dynamic animation tests
-
-Test calcMode spline with from-by animation. You should see a green 100x100 rect and only PASS messages
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS rect.x.animVal.value is 100
-PASS rect.x.baseVal.value is 100
-PASS rect.x.animVal.value is 18.8
-PASS rect.x.baseVal.value is 100
-PASS rect.x.animVal.value is 0
-PASS rect.x.baseVal.value is 100
-PASS rect.x.animVal.value is 100
-PASS rect.x.baseVal.value is 100
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-by.html b/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-by.html
deleted file mode 100644
index 153973c..0000000
--- a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-by.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-<script src="resources/SVGTestCase.js"></script>
-<script src="resources/SVGAnimationTestCase.js"></script>
-</head>
-<body onload="runSMILTest()">
-<h1>SVG 1.1 dynamic animation tests</h1>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/animate-calcMode-spline-from-by.js"></script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-to-expected.txt b/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-to-expected.txt
deleted file mode 100644
index d56801f..0000000
--- a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-to-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-SVG 1.1 dynamic animation tests
-
-Test calcMode spline with from-to animation. You should see a green 100x100 rect and only PASS messages
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS rect.x.animVal.value is 100
-PASS rect.x.baseVal.value is 100
-PASS rect.x.animVal.value is 18.8
-PASS rect.x.baseVal.value is 100
-PASS rect.x.animVal.value is 0
-PASS rect.x.baseVal.value is 100
-PASS rect.x.animVal.value is 100
-PASS rect.x.baseVal.value is 100
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-to.html b/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-to.html
deleted file mode 100644
index 8a12186..0000000
--- a/third_party/blink/web_tests/svg/animations/animate-calcMode-spline-from-to.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-<script src="resources/SVGTestCase.js"></script>
-<script src="resources/SVGAnimationTestCase.js"></script>
-</head>
-<body onload="runSMILTest()">
-<h1>SVG 1.1 dynamic animation tests</h1>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/animate-calcMode-spline-from-to.js"></script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/svg/animations/resources/accumulate-values-width-animation.svg b/third_party/blink/web_tests/svg/animations/resources/accumulate-values-width-animation.svg
deleted file mode 100644
index af456b96..0000000
--- a/third_party/blink/web_tests/svg/animations/resources/accumulate-values-width-animation.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-
-<!-- an1: Change width to 100 in 10s with a wobbling animation -->
-<rect width="20" height="100" fill="green">
-    <animate id="an1" attributeName="width" dur="2s" values="0; 30; 20" accumulate="sum" repeatCount="5" fill="freeze"/>
-</rect>
-
-</svg>
diff --git a/third_party/blink/web_tests/svg/animations/resources/additive-from-to-width-animation.svg b/third_party/blink/web_tests/svg/animations/resources/additive-from-to-width-animation.svg
deleted file mode 100644
index 1507e2c..0000000
--- a/third_party/blink/web_tests/svg/animations/resources/additive-from-to-width-animation.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-
-<!-- an1: Change width from 10 to 50 in 4s -->
-<!-- an2: Change width from 10 to 25 + additive=sum. This results in a change from 20 to 75 -->
-<!-- an3: Change width from 0 to 25 + additve=sum. This results in a final change from 20 to 100 -->
-<rect width="10" height="100" fill="green">
-    <animate id="an1" attributeType="XML" attributeName="width" fill="freeze" from="10" to="50" begin="0s" dur="4s"/>
-    <animate id="an2" attributeType="XML" attributeName="width" additive="sum" fill="freeze" from="10" to="25" begin="0s" dur="4s"/>
-    <animate id="an3" attributeType="XML" attributeName="width" additive="sum" fill="freeze" from="0" to="25" begin="0s" dur="4s"/>
-</rect>
-
-</svg>
diff --git a/third_party/blink/web_tests/svg/animations/resources/additive-type-by-animation.svg b/third_party/blink/web_tests/svg/animations/resources/additive-type-by-animation.svg
deleted file mode 100644
index a2e24a51..0000000
--- a/third_party/blink/web_tests/svg/animations/resources/additive-type-by-animation.svg
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
-<svg id="svg" viewBox="0 0 300 300" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-
-<!-- All additive types except AnimatedPath are tested here -->
-<defs>
-    <marker id="marker" viewBox="0 0 10 10" markerWidth="4" markerHeight="3" refX="1" refY="5" orient="-45deg">
-        <polyline id="polyline" points="0,0 10,5 0,10 1,5" fill="green"/>
-    </marker>
-
-    <filter id="filter">
-        <feConvolveMatrix id="feConvolveMatrix" kernelUnitLength="20 30" kernelMatrix="0 1 0   0 1 0   0 1 0" divisor="37.5" order="6 6" targetX="5" preserveAlpha="false"/>
-    </filter>
-</defs>
-
-<!-- Non-additive types AnimatedBoolean, AnimatedEnumeration, AnimatedPreserveAspectRatio, AnimatedString are tested in non-additive-type-by-animation.svg -->
-
-<path id="path" d="M45,50 L55,50" transform="rotate(45)" stroke-width="10" stroke="green" marker-end="url(#marker)"/>
-<rect id="rect" y="0" width="100" height="100" fill="black" filter="url(#filter)"/>
-<text id="text" x="50" y="50" dy="5 -10 10 -10">ABCD</text>
-
-<!-- AnimatedAngle -->
-<animate id="an1" xlink:href="#marker" attributeName="orient" begin="0s" dur="4s" by="45deg" fill="freeze"/>
-
-<!-- AnimatedColor -->
-<animate xlink:href="#rect" attributeName="fill" begin="0s" dur="4s" by="green" fill="freeze"/>
-
-<!-- AnimatedLength -->
-<animate xlink:href="#rect" attributeName="y" begin="0s" dur="4s" by="100" fill="freeze"/>
-
-<!-- AnimatedLengthList -->
-<animate xlink:href="#text" attributeName="dy" begin="0s" dur="4s" by="-10 20 -20 20" fill="freeze"/>
-
-<!-- AnimatedNumberOptionalNumber -->
-<animate xlink:href="#feConvolveMatrix" attributeName="kernelUnitLength" begin="0s" dur="4s" by="-10 -20" fill="freeze"/>
-
-<!-- AnimatedNumber -->
-<animate xlink:href="#feConvolveMatrix" attributeName="divisor" begin="0s" dur="4s" by="-17.5" fill="freeze"/>
-
-<!-- AnimatedNumberList --> 
-<animate xlink:href="#feConvolveMatrix" attributeName="kernelMatrix" begin="0s" dur="4s" by="2 1 3   2 1 3   2 1 3" fill="freeze"/>
-
-<!-- AnimatedIntegerOptionalInteger -->
-<animate xlink:href="#feConvolveMatrix" attributeName="order" begin="0s" dur="4s" by="-3 -3" fill="freeze"/>
-
-<!-- AnimatedInteger -->
-<animate xlink:href="#feConvolveMatrix" attributeName="targetX" begin="0s" dur="4s" by="-4" fill="freeze"/>
-
-<!-- AnimatedPoints -->
-<animate xlink:href="#polyline" attributeName="points" begin="0s" dur="4s" by="0,0 10,5 0,10 1,5" fill="freeze"/>
-
-<!-- AnimatedRect -->
-<animate xlink:href="#svg" attributeName="viewBox" begin="0s" dur="4s" by="0 0 -100 -100" fill="freeze"/>
-
-<!-- AnimatedTransformList -->
-<animateTransform xlink:href="#path" attributeName="transform" type="rotate" begin="0s" dur="4s" by="-45" fill="freeze"/>
-
-</svg>
diff --git a/third_party/blink/web_tests/svg/animations/resources/additive-values-width-animation.svg b/third_party/blink/web_tests/svg/animations/resources/additive-values-width-animation.svg
deleted file mode 100644
index 02246d6..0000000
--- a/third_party/blink/web_tests/svg/animations/resources/additive-values-width-animation.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-
-<!-- an1: Change width from 0 to 50 to 100, all linear interpolated. As additive is set to sum it should add the current baseValue
-          to the new animated value each time a value from the values list is consumed. Expected:
-          At 0s, width=10, at 2s, width=50+10=60, at 4s, width=100+10=110.
-
-          Our testing harness will change the baseValue from 10 to 60 at 5s. The current animated value (before the script change)
-          is: <baseValue>+<animValue>: 10 + (100/6*5) = 93.333 at this point. As we change the baseValue to 60, the equation now looks like:
-          60 + (100/6*5) = 143.333. Before the script change the last second of the animation would have animated width from 85 to 110.
-          Due the script change its now animating from 93.999 to 143.333 during the last second.
--->
-<rect width="10" height="100" fill="green">
-    <animate id="an1" attributeType="XML" attributeName="width" fill="freeze" additive="sum" values="0; 50; 100" begin="0s" dur="6s"/>
-</rect>
-
-</svg>
diff --git a/third_party/blink/web_tests/svg/animations/script-tests/accumulate-values-width-animation.js b/third_party/blink/web_tests/svg/animations/script-tests/accumulate-values-width-animation.js
deleted file mode 100644
index 1a59fb9..0000000
--- a/third_party/blink/web_tests/svg/animations/script-tests/accumulate-values-width-animation.js
+++ /dev/null
@@ -1,89 +0,0 @@
-description("This tests values animation and accumulate='sum'");
-embedSVGTestCase("resources/accumulate-values-width-animation.svg");
-
-// Setup animation test
-function sample1() {
-    shouldBeCloseEnough("rect.width.animVal.value", "0");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function sample2() {
-    shouldBeCloseEnough("rect.width.animVal.value", "30");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function sample3() {
-    shouldBeCloseEnough("rect.width.animVal.value", "20");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function sample4() {
-    shouldBeCloseEnough("rect.width.animVal.value", "50");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function sample5() {
-    shouldBeCloseEnough("rect.width.animVal.value", "40");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function sample6() {
-    shouldBeCloseEnough("rect.width.animVal.value", "70");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function sample7() {
-    shouldBeCloseEnough("rect.width.animVal.value", "60");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function sample8() {
-    shouldBeCloseEnough("rect.width.animVal.value", "90");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function sample9() {
-    shouldBeCloseEnough("rect.width.animVal.value", "80");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function sample10() {
-    shouldBeCloseEnough("rect.width.animVal.value", "110");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function sample11() {
-    shouldBeCloseEnough("rect.width.animVal.value", "100");
-    shouldBe("rect.width.baseVal.value", "20");
-}
-
-function executeTest() {
-    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
-
-    const expectedValues = [
-        // [animationId, time, sampleCallback]
-        ["an1", 0.0,    sample1],
-        ["an1", 1.0,    sample2],
-        ["an1", 1.999,  sample3],
-        ["an1", 2.001,  sample3],
-        ["an1", 3.0,    sample4],
-        ["an1", 3.999,  sample5],
-        ["an1", 4.001,  sample5],
-        ["an1", 5.0,    sample6],
-        ["an1", 5.999,  sample7],
-        ["an1", 6.001,  sample7],
-        ["an1", 7.0,    sample8],
-        ["an1", 7.999,  sample9],
-        ["an1", 8.001,  sample9],
-        ["an1", 9.0,    sample10],
-        ["an1", 9.999,  sample11],
-        ["an1", 10.001, sample11],
-        ["an1", 11.0,   sample11],
-        ["an1", 60.0,   sample11]
-    ];
-
-    runAnimationTest(expectedValues);
-}
-
-window.animationStartsImmediately = true;
-var successfullyParsed = true;
diff --git a/third_party/blink/web_tests/svg/animations/script-tests/additive-from-to-width-animation.js b/third_party/blink/web_tests/svg/animations/script-tests/additive-from-to-width-animation.js
deleted file mode 100644
index 510a864..0000000
--- a/third_party/blink/web_tests/svg/animations/script-tests/additive-from-to-width-animation.js
+++ /dev/null
@@ -1,36 +0,0 @@
-description("This tests multiple additive='sum' animations running at the same time");
-embedSVGTestCase("resources/additive-from-to-width-animation.svg");
-
-// Setup animation test
-function sample1() {
-    shouldBeCloseEnough("rect.width.animVal.value", "20");
-    shouldBe("rect.width.baseVal.value", "10");
-}
-
-function sample2() {
-    shouldBeCloseEnough("rect.width.animVal.value", "60");
-    shouldBe("rect.width.baseVal.value", "10");
-}
-
-function sample3() {
-    shouldBeCloseEnough("rect.width.animVal.value", "100");
-    shouldBe("rect.width.baseVal.value", "10");
-}
-
-function executeTest() {
-    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
-
-    // All animations in the test file use the same duration, so it's not needed to list all sample points individually for an5/an6/an7/an8.
-    const expectedValues = [
-        // [animationId, time, sampleCallback]
-        ["an1", 0.0,  sample1],
-        ["an1", 2.0,  sample2],
-        ["an1", 4.0,  sample3],
-        ["an1", 60.0, sample3]
-    ];
-
-    runAnimationTest(expectedValues);
-}
-
-window.animationStartsImmediately = true;
-var successfullyParsed = true;
diff --git a/third_party/blink/web_tests/svg/animations/script-tests/additive-type-by-animation.js b/third_party/blink/web_tests/svg/animations/script-tests/additive-type-by-animation.js
deleted file mode 100644
index b15f319..0000000
--- a/third_party/blink/web_tests/svg/animations/script-tests/additive-type-by-animation.js
+++ /dev/null
@@ -1,206 +0,0 @@
-description("This by animation for all XML property types");
-embedSVGTestCase("resources/additive-type-by-animation.svg");
-
-// Setup animation test
-function checkBaseVal() {
-    shouldBe("marker.orientAngle.baseVal.value", "-45");
-    shouldBe("feConvolveMatrix.divisor.baseVal", "37.5");
-    shouldBe("feConvolveMatrix.orderX.baseVal", "6");
-    shouldBe("feConvolveMatrix.orderY.baseVal", "6");
-    shouldBe("feConvolveMatrix.targetX.baseVal", "5");
-    shouldBe("feConvolveMatrix.kernelUnitLengthX.baseVal", "20");
-    shouldBe("feConvolveMatrix.kernelUnitLengthY.baseVal", "30");
-    shouldBe("feConvolveMatrix.kernelMatrix.baseVal.numberOfItems", "9");
-    shouldBe("feConvolveMatrix.kernelMatrix.baseVal.getItem(0).value", "0");
-    shouldBe("feConvolveMatrix.kernelMatrix.baseVal.getItem(1).value", "1");
-    shouldBe("feConvolveMatrix.kernelMatrix.baseVal.getItem(2).value", "0");
-    shouldBe("feConvolveMatrix.kernelMatrix.baseVal.getItem(3).value", "0");
-    shouldBe("feConvolveMatrix.kernelMatrix.baseVal.getItem(4).value", "1");
-    shouldBe("feConvolveMatrix.kernelMatrix.baseVal.getItem(5).value", "0");
-    shouldBe("feConvolveMatrix.kernelMatrix.baseVal.getItem(6).value", "0");
-    shouldBe("feConvolveMatrix.kernelMatrix.baseVal.getItem(7).value", "1");
-    shouldBe("feConvolveMatrix.kernelMatrix.baseVal.getItem(8).value", "0");
-    shouldBe("rect.y.baseVal.value", "0");
-    shouldBe("text.dy.baseVal.numberOfItems", "4");
-    shouldBe("text.dy.baseVal.getItem(0).value", "5");
-    shouldBe("text.dy.baseVal.getItem(1).value", "-10");
-    shouldBe("text.dy.baseVal.getItem(2).value", "10");
-    shouldBe("text.dy.baseVal.getItem(3).value", "-10");
-    shouldBe("svg.viewBox.baseVal.x", "0");
-    shouldBe("svg.viewBox.baseVal.y", "0");
-    shouldBe("svg.viewBox.baseVal.width", "300");
-    shouldBe("svg.viewBox.baseVal.height", "300");
-    shouldBe("polyline.points.numberOfItems", "4");
-    shouldBe("polyline.points.getItem(0).x", "0");
-    shouldBe("polyline.points.getItem(0).y", "0");
-    shouldBe("polyline.points.getItem(1).x", "10");
-    shouldBe("polyline.points.getItem(1).y", "5");
-    shouldBe("polyline.points.getItem(1).x", "10");
-    shouldBe("polyline.points.getItem(1).y", "5");
-    shouldBe("polyline.points.getItem(2).x", "0");
-    shouldBe("polyline.points.getItem(2).y", "10");
-    shouldBe("path.transform.baseVal.numberOfItems", "1");
-    shouldBe("path.transform.baseVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_ROTATE");
-    shouldBe("path.transform.baseVal.getItem(0).angle", "45");
-}
-
-function sample1() {
-    shouldBeCloseEnough("marker.orientAngle.animVal.value", "-45");
-    shouldBeCloseEnough("feConvolveMatrix.divisor.animVal", "37.5");
-    shouldBeCloseEnough("feConvolveMatrix.orderX.animVal", "6");
-    shouldBeCloseEnough("feConvolveMatrix.orderY.animVal", "6");
-    shouldBeCloseEnough("feConvolveMatrix.targetX.animVal", "5");
-    shouldBeCloseEnough("feConvolveMatrix.kernelUnitLengthX.animVal", "20");
-    shouldBeCloseEnough("feConvolveMatrix.kernelUnitLengthY.animVal", "30");
-    shouldBe("feConvolveMatrix.kernelMatrix.animVal.numberOfItems", "9");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(0).value", "0");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(1).value", "1");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(2).value", "0");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(3).value", "0");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(4).value", "1");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(5).value", "0");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(6).value", "0");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(7).value", "1");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(8).value", "0");
-    shouldBeCloseEnough("rect.y.animVal.value", "0");
-    shouldBe("text.dy.animVal.numberOfItems", "4");
-    shouldBeCloseEnough("text.dy.animVal.getItem(0).value", "5");
-    shouldBeCloseEnough("text.dy.animVal.getItem(1).value", "-10");
-    shouldBeCloseEnough("text.dy.animVal.getItem(2).value", "10");
-    shouldBeCloseEnough("text.dy.animVal.getItem(3).value", "-10");
-    shouldBeCloseEnough("svg.viewBox.animVal.x", "0");
-    shouldBeCloseEnough("svg.viewBox.animVal.y", "0");
-    shouldBeCloseEnough("svg.viewBox.animVal.width", "300");
-    shouldBeCloseEnough("svg.viewBox.animVal.height", "300");
-    shouldBe("polyline.animatedPoints.numberOfItems", "4");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(0).x", "0");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(0).y", "0");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).x", "10");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).y", "5");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).x", "10");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).y", "5");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(2).x", "0");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(2).y", "10");
-    shouldBe("path.transform.animVal.numberOfItems", "2");
-    shouldBe("path.transform.animVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_ROTATE");
-    shouldBe("path.transform.animVal.getItem(0).angle", "45");
-    shouldBe("path.transform.animVal.getItem(1).type", "SVGTransform.SVG_TRANSFORM_ROTATE");
-    shouldBeCloseEnough("path.transform.animVal.getItem(1).angle", "0");
-    expectFillColor(rect, 0, 0, 0);
-    checkBaseVal();
-}
-
-function sample2() {
-    shouldBeCloseEnough("marker.orientAngle.animVal.value", "-22.5");
-    shouldBeCloseEnough("feConvolveMatrix.divisor.animVal", "28.75");
-    shouldBeCloseEnough("feConvolveMatrix.orderX.animVal", "5");
-    shouldBeCloseEnough("feConvolveMatrix.orderY.animVal", "5");
-    shouldBeCloseEnough("feConvolveMatrix.targetX.animVal", "3");
-    shouldBeCloseEnough("feConvolveMatrix.kernelUnitLengthX.animVal", "15");
-    shouldBeCloseEnough("feConvolveMatrix.kernelUnitLengthY.animVal", "20");
-    shouldBe("feConvolveMatrix.kernelMatrix.animVal.numberOfItems", "9");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(0).value", "1");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(1).value", "1.5");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(2).value", "1.5");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(3).value", "1");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(4).value", "1.5");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(5).value", "1.5");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(6).value", "1");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(7).value", "1.5");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(8).value", "1.5");
-    shouldBeCloseEnough("rect.y.animVal.value", "50");
-    shouldBe("text.dy.animVal.numberOfItems", "4");
-    shouldBeCloseEnough("text.dy.animVal.getItem(0).value", "0");
-    shouldBeCloseEnough("text.dy.animVal.getItem(1).value", "0");
-    shouldBeCloseEnough("text.dy.animVal.getItem(2).value", "0");
-    shouldBeCloseEnough("text.dy.animVal.getItem(3).value", "0");
-    shouldBeCloseEnough("svg.viewBox.animVal.x", "0");
-    shouldBeCloseEnough("svg.viewBox.animVal.y", "0");
-    shouldBeCloseEnough("svg.viewBox.animVal.width", "250");
-    shouldBeCloseEnough("svg.viewBox.animVal.height", "250");
-    shouldBe("polyline.animatedPoints.numberOfItems", "4");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(0).x", "0");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(0).y", "0");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).x", "15");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).y", "7.5");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).x", "15");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).y", "7.5");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(2).x", "0");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(2).y", "15");
-    shouldBe("path.transform.animVal.numberOfItems", "2");
-    shouldBe("path.transform.animVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_ROTATE");
-    shouldBe("path.transform.animVal.getItem(0).angle", "45");
-    shouldBe("path.transform.animVal.getItem(1).type", "SVGTransform.SVG_TRANSFORM_ROTATE");
-    shouldBeCloseEnough("path.transform.animVal.getItem(1).angle", "-22.5");
-    expectFillColor(rect, 0, 63, 0);
-    checkBaseVal();
-}
-
-function sample3() {
-    shouldBeCloseEnough("marker.orientAngle.animVal.value", "0");
-    shouldBeCloseEnough("feConvolveMatrix.divisor.animVal", "20");
-    shouldBeCloseEnough("feConvolveMatrix.orderX.animVal", "3");
-    shouldBeCloseEnough("feConvolveMatrix.orderY.animVal", "3");
-    shouldBeCloseEnough("feConvolveMatrix.targetX.animVal", "1");
-    shouldBeCloseEnough("feConvolveMatrix.kernelUnitLengthX.animVal", "10");
-    shouldBeCloseEnough("feConvolveMatrix.kernelUnitLengthY.animVal", "10");
-    shouldBe("feConvolveMatrix.kernelMatrix.animVal.numberOfItems", "9");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(0).value", "2");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(1).value", "2");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(2).value", "3");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(3).value", "2");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(4).value", "2");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(5).value", "3");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(6).value", "2");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(7).value", "2");
-    shouldBeCloseEnough("feConvolveMatrix.kernelMatrix.animVal.getItem(8).value", "3");
-    shouldBeCloseEnough("rect.y.animVal.value", "100");
-    shouldBe("text.dy.animVal.numberOfItems", "4");
-    shouldBeCloseEnough("text.dy.animVal.getItem(0).value", "-5");
-    shouldBeCloseEnough("text.dy.animVal.getItem(1).value", "10");
-    shouldBeCloseEnough("text.dy.animVal.getItem(2).value", "-10");
-    shouldBeCloseEnough("text.dy.animVal.getItem(3).value", "10");
-    shouldBeCloseEnough("svg.viewBox.animVal.x", "0");
-    shouldBeCloseEnough("svg.viewBox.animVal.y", "0");
-    shouldBeCloseEnough("svg.viewBox.animVal.width", "200");
-    shouldBeCloseEnough("svg.viewBox.animVal.height", "200");
-    shouldBe("polyline.animatedPoints.numberOfItems", "4");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(0).x", "0");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(0).y", "0");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).x", "20");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).y", "10");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).x", "20");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(1).y", "10");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(2).x", "0");
-    shouldBeCloseEnough("polyline.animatedPoints.getItem(2).y", "20");
-    shouldBe("path.transform.animVal.numberOfItems", "2");
-    shouldBe("path.transform.animVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_ROTATE");
-    shouldBe("path.transform.animVal.getItem(0).angle", "45");
-    shouldBe("path.transform.animVal.getItem(1).type", "SVGTransform.SVG_TRANSFORM_ROTATE");
-    shouldBeCloseEnough("path.transform.animVal.getItem(1).angle", "-45");
-    expectFillColor(rect, 0, 128, 0);
-    checkBaseVal();
-}
-
-function executeTest() {
-    marker = rootSVGElement.ownerDocument.getElementsByTagName("marker")[0];
-    filter = rootSVGElement.ownerDocument.getElementsByTagName("filter")[0];
-    feConvolveMatrix = rootSVGElement.ownerDocument.getElementsByTagName("feConvolveMatrix")[0];
-    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
-    svg = rootSVGElement.ownerDocument.getElementsByTagName("svg")[0];
-    path = rootSVGElement.ownerDocument.getElementsByTagName("path")[0];
-    polyline = rootSVGElement.ownerDocument.getElementsByTagName("polyline")[0];
-    text = rootSVGElement.ownerDocument.getElementsByTagName("text")[0];
-
-    const expectedValues = [
-        // [animationId, time, sampleCallback]
-        ["an1", 0.0,   sample1],
-        ["an1", 2.0,   sample2],
-        ["an1", 4.001, sample3]
-    ];
-
-    runAnimationTest(expectedValues);
-}
-
-window.animationStartsImmediately = true;
-var successfullyParsed = true;
diff --git a/third_party/blink/web_tests/svg/animations/script-tests/additive-values-width-animation.js b/third_party/blink/web_tests/svg/animations/script-tests/additive-values-width-animation.js
deleted file mode 100644
index 22d9bc08..0000000
--- a/third_party/blink/web_tests/svg/animations/script-tests/additive-values-width-animation.js
+++ /dev/null
@@ -1,54 +0,0 @@
-description("This tests values animation and additive='sum'");
-embedSVGTestCase("resources/additive-values-width-animation.svg");
-
-// Setup animation test
-function sample1() {
-    shouldBeCloseEnough("rect.width.animVal.value", "10");
-    shouldBe("rect.width.baseVal.value", "10");
-}
-
-function sample2() {
-    shouldBeCloseEnough("rect.width.animVal.value", "60");
-    shouldBe("rect.width.baseVal.value", "10");
-}
-
-function sample3() {
-    shouldBeCloseEnough("rect.width.animVal.value", "93.3");
-    shouldBe("rect.width.baseVal.value", "10");
-}
-
-function changeBaseVal() {
-    // At 5s, only change the baseVal.
-    rect.width.baseVal.value = 60;
-}
-
-function sample4() {
-    shouldBeCloseEnough("rect.width.animVal.value", "143.33");
-    shouldBe("rect.width.baseVal.value", "60");
-}
-
-function sample5() {
-    shouldBeCloseEnough("rect.width.animVal.value", "160");
-    shouldBe("rect.width.baseVal.value", "60");
-}
-
-function executeTest() {
-    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
-
-    // All animations in the test file use the same duration, so it's not needed to list all sample points individually for an5/an6/an7/an8.
-    const expectedValues = [
-        // [animationId, time, sampleCallback]
-        ["an1", 0.0,   sample1],
-        ["an1", 3.0,   sample2],
-        ["an1", 4.999, sample3],
-        ["an1", 5.0,   changeBaseVal],
-        ["an1", 5.001, sample4],
-        ["an1", 6.001, sample5],
-        ["an1", 60.0,  sample5]
-    ];
-
-    runAnimationTest(expectedValues);
-}
-
-window.animationStartsImmediately = true;
-var successfullyParsed = true;
diff --git a/third_party/blink/web_tests/svg/animations/script-tests/animate-calcMode-spline-by.js b/third_party/blink/web_tests/svg/animations/script-tests/animate-calcMode-spline-by.js
deleted file mode 100644
index d272227..0000000
--- a/third_party/blink/web_tests/svg/animations/script-tests/animate-calcMode-spline-by.js
+++ /dev/null
@@ -1,57 +0,0 @@
-description("Test calcMode spline with by animation. You should see a green 100x100 rect and only PASS messages");
-createSVGTestCase();
-
-// Setup test document
-var rect = createSVGElement("rect");
-rect.setAttribute("id", "rect");
-rect.setAttribute("x", "100");
-rect.setAttribute("width", "100");
-rect.setAttribute("height", "100");
-rect.setAttribute("fill", "green");
-rect.setAttribute("onclick", "executeTest()");
-
-var animate = createSVGElement("animate");
-animate.setAttribute("id", "animation");
-animate.setAttribute("attributeName", "x");
-animate.setAttribute("by", "-100");
-animate.setAttribute("begin", "click");
-animate.setAttribute("dur", "4s");
-animate.setAttribute("keyTimes", "0;1");
-animate.setAttribute("keySplines", "0.25 .5 .25 0.85");
-animate.setAttribute("calcMode", "spline");
-rect.appendChild(animate);
-rootSVGElement.appendChild(rect);
-
-// Setup animation test
-function sample1() {
-    // Check initial/end conditions
-    shouldBeCloseEnough("rect.x.animVal.value", "100");
-    shouldBe("rect.x.baseVal.value", "100");
-}
-
-function sample2() {
-    // Check half-time conditions
-    shouldBeCloseEnough("rect.x.animVal.value", "18.8");
-    shouldBe("rect.x.baseVal.value", "100");
-}
-
-function sample3() {
-    // Check just before-end conditions
-    shouldBeCloseEnough("rect.x.animVal.value", "0");
-    shouldBe("rect.x.baseVal.value", "100");
-}
-
-function executeTest() {
-    const expectedValues = [
-        // [animationId, time, sampleCallback]
-        ["animation", 0.0,   sample1],
-        ["animation", 2.0,   sample2],
-        ["animation", 3.999, sample3],
-        ["animation", 4.001, sample1]
-    ];
-
-    runAnimationTest(expectedValues);
-}
-
-window.clickX = 150;
-var successfullyParsed = true;
diff --git a/third_party/blink/web_tests/svg/animations/script-tests/animate-calcMode-spline-from-by.js b/third_party/blink/web_tests/svg/animations/script-tests/animate-calcMode-spline-from-by.js
deleted file mode 100644
index d71a8773..0000000
--- a/third_party/blink/web_tests/svg/animations/script-tests/animate-calcMode-spline-from-by.js
+++ /dev/null
@@ -1,58 +0,0 @@
-description("Test calcMode spline with from-by animation. You should see a green 100x100 rect and only PASS messages");
-createSVGTestCase();
-
-// Setup test document
-var rect = createSVGElement("rect");
-rect.setAttribute("id", "rect");
-rect.setAttribute("x", "100");
-rect.setAttribute("width", "100");
-rect.setAttribute("height", "100");
-rect.setAttribute("fill", "green");
-rect.setAttribute("onclick", "executeTest()");
-
-var animate = createSVGElement("animate");
-animate.setAttribute("id", "animation");
-animate.setAttribute("attributeName", "x");
-animate.setAttribute("from", "100");
-animate.setAttribute("by", "-100");
-animate.setAttribute("begin", "click");
-animate.setAttribute("dur", "4s");
-animate.setAttribute("keyTimes", "0;1");
-animate.setAttribute("keySplines", "0.25 .5 .25 0.85");
-animate.setAttribute("calcMode", "spline");
-rect.appendChild(animate);
-rootSVGElement.appendChild(rect);
-
-// Setup animation test
-function sample1() {
-    // Check initial/end conditions
-    shouldBeCloseEnough("rect.x.animVal.value", "100");
-    shouldBe("rect.x.baseVal.value", "100");
-}
-
-function sample2() {
-    // Check half-time conditions
-    shouldBeCloseEnough("rect.x.animVal.value", "18.8");
-    shouldBe("rect.x.baseVal.value", "100");
-}
-
-function sample3() {
-    // Check just before-end conditions
-    shouldBeCloseEnough("rect.x.animVal.value", "0");
-    shouldBe("rect.x.baseVal.value", "100");
-}
-
-function executeTest() {
-    const expectedValues = [
-        // [animationId, time, sampleCallback]
-        ["animation", 0.0,   sample1],
-        ["animation", 2.0,   sample2],
-        ["animation", 3.999, sample3],
-        ["animation", 4.001, sample1]
-    ];
-
-    runAnimationTest(expectedValues);
-}
-
-window.clickX = 150;
-var successfullyParsed = true;
diff --git a/third_party/blink/web_tests/svg/animations/script-tests/animate-calcMode-spline-from-to.js b/third_party/blink/web_tests/svg/animations/script-tests/animate-calcMode-spline-from-to.js
deleted file mode 100644
index dffe7e3..0000000
--- a/third_party/blink/web_tests/svg/animations/script-tests/animate-calcMode-spline-from-to.js
+++ /dev/null
@@ -1,58 +0,0 @@
-description("Test calcMode spline with from-to animation. You should see a green 100x100 rect and only PASS messages");
-createSVGTestCase();
-
-// Setup test document
-var rect = createSVGElement("rect");
-rect.setAttribute("id", "rect");
-rect.setAttribute("x", "100");
-rect.setAttribute("width", "100");
-rect.setAttribute("height", "100");
-rect.setAttribute("fill", "green");
-rect.setAttribute("onclick", "executeTest()");
-
-var animate = createSVGElement("animate");
-animate.setAttribute("id", "animation");
-animate.setAttribute("attributeName", "x");
-animate.setAttribute("from", "100");
-animate.setAttribute("to", "0");
-animate.setAttribute("begin", "click");
-animate.setAttribute("dur", "4s");
-animate.setAttribute("keyTimes", "0;1");
-animate.setAttribute("keySplines", "0.25 .5 .25 0.85");
-animate.setAttribute("calcMode", "spline");
-rect.appendChild(animate);
-rootSVGElement.appendChild(rect);
-
-// Setup animation test
-function sample1() {
-    // Check initial/end conditions
-    shouldBeCloseEnough("rect.x.animVal.value", "100");
-    shouldBe("rect.x.baseVal.value", "100");
-}
-
-function sample2() {
-    // Check half-time conditions
-    shouldBeCloseEnough("rect.x.animVal.value", "18.8");
-    shouldBe("rect.x.baseVal.value", "100");
-}
-
-function sample3() {
-    // Check just before-end conditions
-    shouldBeCloseEnough("rect.x.animVal.value", "0");
-    shouldBe("rect.x.baseVal.value", "100");
-}
-
-function executeTest() {
-    const expectedValues = [
-        // [animationId, time, sampleCallback]
-        ["animation", 0.0,   sample1],
-        ["animation", 2.0,   sample2],
-        ["animation", 3.999, sample3],
-        ["animation", 4.001, sample1]
-    ];
-
-    runAnimationTest(expectedValues);
-}
-
-window.clickX = 150;
-var successfullyParsed = true;
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
deleted file mode 100644
index bae2cb7..0000000
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
deleted file mode 100644
index bae2cb7..0000000
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-color-well-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
index 91e7d3b3..9919e26 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
index ef58dfc..7efa2e0 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hex-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
index 099af98..c388a509 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hsl-format-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
deleted file mode 100644
index 277dd65..0000000
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-click-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
deleted file mode 100644
index 277dd65..0000000
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-drag-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
deleted file mode 100644
index 05ea0a59..0000000
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-left-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
deleted file mode 100644
index d20976d..0000000
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-hue-slider-right-edge-zero-hue-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
deleted file mode 100644
index 12a1f6ec..0000000
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-imperfect-match-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
deleted file mode 100644
index 1f84122..0000000
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-manual-color-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
index 8b7e83a..0cd7913 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-type-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
index 8ddbaa95..2df3add8f0 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-set-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
index 6b2cc8ae..6b5de5d 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-value-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
index 8776a9ec..ac0aac1 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
index 53358e2..e4f88b4 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh/fast/forms/controls-new-ui/color/color-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/omt-service-worker-startup/README.md b/third_party/blink/web_tests/virtual/omt-service-worker-startup/README.md
new file mode 100644
index 0000000..980548fc
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/omt-service-worker-startup/README.md
@@ -0,0 +1,5 @@
+# virtual/omt-service-worker-startup
+
+https://crbug.com/692909
+
+Start service worker off-the-main-thread.
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/selection.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/selection.html
new file mode 100644
index 0000000..68fbdce3
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/activation/selection.html
@@ -0,0 +1,60 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: selection activates locked element</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/utils.js"></script>
+
+<div id="container">
+foo
+  <div id="nonActivatable">
+    bleh
+  </div>
+  <div id="nested">
+    bar
+  </div>
+</div>
+
+<script>
+promise_test(() => {
+  const acquirePromise = Promise.all(
+    [setInvisibleActivatable(container),
+     setInvisible(nonActivatable),
+     setInvisibleActivatable(nested)
+    ]);
+  return new Promise((resolve, reject) => {
+    const eventPromise = new Promise((resolve, reject) => {
+      // #container will get activated first, then #nested (and the event will bubble).
+      container.onbeforeactivate = (e) => {
+        if (e.target == container) {
+          assert_equals(e.activatedElement, container);
+        } else {
+          assert_equals(e.target, nested);
+          assert_equals(e.activatedElement, nested);
+          assert_equals(container.displayLock.locked, false);
+          resolve();
+        }
+      }
+      nested.onbeforeactivate = (e) => {
+        assert_equals(e.target, nested);
+        assert_equals(e.activatedElement, nested);
+      };
+      nonActivatable.onbeforeactivate = reject;
+    });
+
+    acquirePromise.then(() => {
+      window.getSelection().selectAllChildren(container);
+      eventPromise.then(() => {
+        assert_equals(window.getSelection().toString(), "foo\nbar");
+        assert_equals(container.displayLock.locked, false);
+        assert_equals(nonActivatable.displayLock.locked, true);
+        assert_equals(nested.displayLock.locked, false);
+        resolve();
+      });
+    });
+  });
+}, "Activating locked element through selection activates activatable elements");
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-ref.html
new file mode 100644
index 0000000..7f0fd4c
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-ref.html
@@ -0,0 +1,39 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: activatable allows selections (reference)</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<style>
+  div {
+    contain: style layout;
+  }
+  #nonActivatable {
+    width: 20px; height: 20px;
+  }
+  #userSelectNone {
+    width: 30px; height: 30px;
+  }
+</style>
+<div id="neighbor">
+  neighbor
+</div>
+<div id="container">
+  <div>
+    not locked!
+  </div>
+  <div id="nonActivatable">
+  </div>
+  <div id="userSelectNone">
+  </div>
+  <div id="nested">
+    nested activatable locked
+  </div>
+</div>
+<script>
+  window.getSelection().removeAllRanges();
+  const selectionRange = document.createRange();
+  selectionRange.setStart(neighbor.firstChild, 4);
+  selectionRange.setEnd(nested.firstChild, 7);
+  window.getSelection().addRange(selectionRange);
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow-ref.html
new file mode 100644
index 0000000..88654110
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow-ref.html
@@ -0,0 +1,62 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Display Locking: activatable allows selections (reference)</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<style>
+  div {
+    contain: style layout;
+  }
+  #nonActivatable {
+    width: 20px; height: 20px;
+  }
+</style>
+<div id="host">
+  <div id="slottedToFirst" slot="first">
+    slotted to first slot
+  </div>
+  <div id="slottedToSecond" slot="second">
+    slotted to second slot
+  </div>
+</div>
+
+<script>
+/*
+Structure:
+<div id=host>  // locked, activatable
+ #shadowRoot
+  <slot first>
+    <div id=slottedToFirst> // locked, activatable
+      slotted to first slot
+  shadow text
+  <div id=nonActivatable>     // locked, non-activatable
+    non activatable
+  <slot second>
+    <div id=slottedToSecond>
+      slotted to second slot
+*/
+
+async function runTest() {
+  const shadowRoot = host.attachShadow({ mode: "open" });
+  shadowRoot.innerHTML = "<style> div { contain: style layout; } </style>";
+
+  const firstSlot = document.createElement("slot");
+  firstSlot.name = "first";
+  shadowRoot.appendChild(firstSlot);
+  shadowRoot.appendChild(document.createTextNode("shadow text"));
+  const nonActivatable = document.createElement("div");
+  nonActivatable.style = "width: 20px; height: 20px;";
+  shadowRoot.appendChild(nonActivatable);
+  const secondSlot = document.createElement("slot");
+  secondSlot.name = "second";
+  shadowRoot.appendChild(secondSlot);
+  window.getSelection().removeAllRanges();
+  const selectionRange = document.createRange();
+  selectionRange.setStart(slottedToFirst.firstChild, 8);
+  selectionRange.setEnd(slottedToSecond.firstChild, 10);
+  window.getSelection().addRange(selectionRange);
+  requestAnimationFrame(takeScreenshot);
+}
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow.html
new file mode 100644
index 0000000..0e5f387
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection-shadow.html
@@ -0,0 +1,67 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Display Locking: activatable allows selections</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<link rel="match" href="selection-shadow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+  div {
+    contain: style layout;
+  }
+</style>
+
+<div id="host">
+  <div id="slottedToFirst" slot="first">
+    slotted to first slot
+  </div>
+  <div id="slottedToSecond" slot="second">
+    slotted to second slot
+  </div>
+</div>
+
+<script>
+/*
+Structure:
+<div id=host>  // locked, activatable
+ #shadowRoot
+  <slot first>
+    <div id=slottedToFirst> // locked, activatable
+      slotted to first slot
+  shadow text
+  <div id=nonActivatable>     // locked, non-activatable
+    non activatable
+  <slot second>
+    <div id=slottedToSecond>
+      slotted to second slot
+*/
+
+async function runTest() {
+  const shadowRoot = host.attachShadow({ mode: "open" });
+  shadowRoot.innerHTML = "<style> div { contain: style layout; } </style>";
+
+  const firstSlot = document.createElement("slot");
+  firstSlot.name = "first";
+  shadowRoot.appendChild(firstSlot);
+  shadowRoot.appendChild(document.createTextNode("shadow text"));
+  const nonActivatable = document.createElement("div");
+  nonActivatable.innerText = "non activatable";
+  shadowRoot.appendChild(nonActivatable);
+  const secondSlot = document.createElement("slot");
+  secondSlot.name = "second";
+  shadowRoot.appendChild(secondSlot);
+
+  // TODO(rakina): make this use rendersubtree once sizing is implemented.
+  await host.displayLock.acquire({ timeout: Infinity, activatable: true, size: [100, 100] });
+  await nonActivatable.displayLock.acquire({ timeout: Infinity, activatable: false, size: [20, 20] });
+  await slottedToFirst.displayLock.acquire({ timeout: Infinity, activatable: true, size: [40, 40] });
+  window.getSelection().removeAllRanges();
+  const selectionRange = document.createRange();
+  selectionRange.setStart(slottedToFirst.firstChild, 8);
+  selectionRange.setEnd(slottedToSecond.firstChild, 10);
+  window.getSelection().addRange(selectionRange);
+  requestAnimationFrame(takeScreenshot);
+}
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection.html b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection.html
new file mode 100644
index 0000000..f06f7e4a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/display-lock/rendersubtree/selection.html
@@ -0,0 +1,49 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>Display Locking: activatable allows selections</title>
+<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
+<link rel="help" href="https://github.com/WICG/display-locking">
+<link rel="match" href="selection-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+  div {
+    contain: style layout;
+  }
+  #userSelectNone {
+    user-select: none;
+  }
+</style>
+<div id="neighbor">
+  neighbor
+</div>
+<div id="container">
+  <div>
+    not locked!
+  </div>
+  <div id="nonActivatable">
+    non-activatable locked
+  </div>
+  <div id="userSelectNone">
+    activatable but user-select is none
+  </div>
+  <div id="nested">
+    nested activatable locked
+  </div>
+</div>
+<script>
+async function runTest() {
+  // TODO(rakina): make this use rendersubtree once sizing is implemented.
+  await container.displayLock.acquire({ timeout: Infinity, activatable: true, size: [100, 100] });
+  await nonActivatable.displayLock.acquire({ timeout: Infinity, activatable: false, size: [20, 20] });
+  await userSelectNone.displayLock.acquire({ timeout: Infinity, activatable: true, size: [30, 30] });
+  await nested.displayLock.acquire({ timeout: Infinity, activatable: true, size: [40, 40] });
+  window.getSelection().removeAllRanges();
+  const selectionRange = document.createRange();
+  selectionRange.setStart(neighbor.firstChild, 4);
+  selectionRange.setEnd(nested.firstChild, 7);
+  window.getSelection().addRange(selectionRange);
+  requestAnimationFrame(takeScreenshot);
+}
+window.onload = () => { requestAnimationFrame(runTest); };
+</script>
diff --git a/third_party/cct_dynamic_module/OWNERS b/third_party/cct_dynamic_module/OWNERS
index f640f91..eebf143 100644
--- a/third_party/cct_dynamic_module/OWNERS
+++ b/third_party/cct_dynamic_module/OWNERS
@@ -2,3 +2,4 @@
 amalova@chromium.org
 per-file *.aidl=set noparent
 per-file *.aidl=file://ipc/SECURITY_OWNERS
+# COMPONENT: UI>Browser>Mobile>CustomTabs
diff --git a/third_party/s2cellid/OWNERS b/third_party/s2cellid/OWNERS
index 45b1609c..6e9b9ec1 100644
--- a/third_party/s2cellid/OWNERS
+++ b/third_party/s2cellid/OWNERS
@@ -2,3 +2,4 @@
 jiameng@chromium.org
 napper@chromium.org
 renjieliu@chromium.org
+# COMPONENT: Internals
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index e6586660..2757266 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -49659,6 +49659,38 @@
   <int value="5" label="SPDY 4.0"/>
 </enum>
 
+<enum name="ProtoDatabaseInitState">
+  <summary>
+    Track the failure and success states of proto database migration.
+  </summary>
+  <int value="0" label="Shared DB init attempted"/>
+  <int value="1" label="Failed: unique DB corruption"/>
+  <int value="2" label="Failed: missing provider"/>
+  <int value="3" label="Failed: open for both unqiue and shared"/>
+  <int value="4" label="Failed: Shared DB client is missing"/>
+  <int value="5" label="Success: Unique DB, no shared db present"/>
+  <int value="6" label="Failed: Shared DB failed to open"/>
+  <int value="7" label="Success: Shared DB no unique db present"/>
+  <int value="8" label="Failed: Unique DB open failed"/>
+  <int value="9" label="Migration to shared attempted"/>
+  <int value="10" label="Migration to unique attempted"/>
+  <int value="11" label="Success: opened migrated shared DB"/>
+  <int value="12" label="Success: failed to delete old data"/>
+  <int value="13" label="Success: failed to migrate, using unique"/>
+  <int value="14" label="Success: failed to migrate, using shared"/>
+  <int value="15" label="Success: migrated to shared, deletion failed"/>
+  <int value="16" label="Success: migrated to unique, deletion failed"/>
+  <int value="17" label="Success: migrated to shared"/>
+  <int value="18" label="Success: migrated to unique"/>
+  <int value="19" label="Legacy init called"/>
+  <int value="20" label="Shared metadata db open failed"/>
+  <int value="21" label="Shared metadata write failed"/>
+  <int value="22" label="Shared db corruption for client"/>
+  <int value="23" label="Shared db client created"/>
+  <int value="24" label="Shared leveldb failed to open"/>
+  <int value="25" label="Shared leveldb does not exist"/>
+</enum>
+
 <enum name="ProvisionalLoadEvent">
   <int value="0" label="Stopped no error">
     This should represent the provisional load being stopped by the user, but
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index a4aad9c..65d2bc8 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -32324,6 +32324,9 @@
 
 <histogram name="Download.MaliciousDownloadClassified"
     enum="DownloadItem.DangerType" expires_after="M78">
+  <obsolete>
+    Deprecated as of 08/2019.
+  </obsolete>
   <owner>dtrainor@chromium.org</owner>
   <owner>felt@chromium.org</owner>
   <summary>
@@ -93590,7 +93593,7 @@
   </summary>
 </histogram>
 
-<histogram name="PageLoad.Clients.ThirdParty.Origins.Read" units="Count"
+<histogram name="PageLoad.Clients.ThirdParty.Origins.CookieRead" units="Count"
     expires_after="2021-07-01">
   <owner>jkarlin@chromium.org</owner>
   <summary>
@@ -93599,8 +93602,50 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Clients.ThirdParty.Origins.CookieWrite" units="Count"
+    expires_after="2021-07-01">
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    The number of third party origins on a page that changed cookies either via
+    resource response headers or document.cookie.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Clients.ThirdParty.Origins.LocalStorageAccess"
+    units="Count" expires_after="2021-07-01">
+  <owner>yaoxia@chromium.org</owner>
+  <summary>
+    The number of third party origins on a page that access local storage via
+    window.localStorage.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Clients.ThirdParty.Origins.Read" units="Count"
+    expires_after="2021-07-01">
+  <obsolete>
+    Renamed to PageLoad.Clients.ThirdParty.Origins.CookieRead.
+  </obsolete>
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    The number of third party origins on a page that read cookies either via
+    resource request headers or document.cookie.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Clients.ThirdParty.Origins.SessionStorageAccess"
+    units="Count" expires_after="2021-07-01">
+  <owner>yaoxia@chromium.org</owner>
+  <summary>
+    The number of third party origins on a page that access local storage via
+    window.localStorage.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Clients.ThirdParty.Origins.Write" units="Count"
     expires_after="2021-07-01">
+  <obsolete>
+    Renamed to PageLoad.Clients.ThirdParty.Origins.CookieWrite.
+  </obsolete>
   <owner>jkarlin@chromium.org</owner>
   <summary>
     The number of third party origins on a page that changed cookies either via
@@ -109269,6 +109314,19 @@
   <summary>Whether a ProtoDB LoadKeys call was successful or not.</summary>
 </histogram>
 
+<histogram name="ProtoDB.SharedDbInitStatus" enum="ProtoDatabaseInitState"
+    expires_after="2020-08-10">
+  <owner>ssid@chromium.org</owner>
+  <owner>salg@chromium.org</owner>
+  <summary>
+    Tracks the init state progress of a proto database. An enum value is
+    recorded for each state of progression through the initialization process.
+    Shows the number of users hitting each stage. The enum values starting with
+    success and failure indicate that the final output of initialization is a
+    success or failure.
+  </summary>
+</histogram>
+
 <histogram name="ProtoDB.UpdateErrorStatus" enum="LevelDBStatus"
     expires_after="M81">
   <owner>nyquist@chromium.org</owner>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index d6c4ba7..d4eca9c6 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -264,7 +264,7 @@
       },
     ],
     'dimension': {
-      'os': 'Ubuntu-14.04',
+      'os': 'Ubuntu-16.04',
       'pool': 'chrome.tests',
     },
     'perf_trigger': False,
@@ -311,7 +311,7 @@
       },
     ],
     'dimension': {
-      'os': 'Ubuntu-14.04',
+      'os': 'Ubuntu-16.04',
       'pool': 'chrome.tests',
     },
     'perf_trigger': False,
diff --git a/ui/android/java/res/values/colors.xml b/ui/android/java/res/values/colors.xml
index 216956c..36a7db4 100644
--- a/ui/android/java/res/values/colors.xml
+++ b/ui/android/java/res/values/colors.xml
@@ -67,6 +67,12 @@
     <color name="dropdown_divider_color">#E5E5E5</color>
     <color name="dropdown_dark_divider_color">#C0C0C0</color>
 
+    <!-- Snackbar colors -->
+    <color name="snackbar_background_color" tools:ignore="UnusedResources">@color/modern_primary_color</color>
+
+    <!-- Bottom sheet colors -->
+    <color name="sheet_bg_color" tools:ignore="UnusedResources">@color/modern_primary_color</color>
+
     <!-- Ripple colors for clickable widgets -->
     <color name="ripple_color_blue">@color/modern_blue_600</color>
 
diff --git a/ui/android/java/res_night/values-night/colors.xml b/ui/android/java/res_night/values-night/colors.xml
index 133b5f2..4de10e1 100644
--- a/ui/android/java/res_night/values-night/colors.xml
+++ b/ui/android/java/res_night/values-night/colors.xml
@@ -31,6 +31,12 @@
     <color name="default_bg_color_elev_3">@color/default_bg_color_dark_elev_3</color>
     <color name="default_bg_color_elev_4">@color/default_bg_color_dark_elev_4</color>
 
+    <!-- Bottom sheet colors -->
+    <color name="sheet_bg_color">@color/default_bg_color_dark_elev_4</color>
+
+    <!-- Snackbar colors -->
+    <color name="snackbar_background_color">@color/default_bg_color_dark_elev_4</color>
+
     <!-- Ripple colors for clickable widgets -->
     <color name="ripple_color_blue">@color/modern_blue_300</color>
 
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index 6a22ab2..d85807c 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -1217,24 +1217,32 @@
         }
       }
     }
-    // If a new file backed provided volume is mounted,
-    // then redirect to it in the focused window.
-    // Note, that this is a temporary solution for https://crbug.com/427776.
-    // If crostini is mounted, redirect if it is the currently selected dir.
     if (event.added.length !== 1) {
       return;
     }
-    if ((window.isFocused() &&
+    // Redirect to newly mounted volume when:
+    // * There is no directory currently selected, meaning it's the first volume
+    //   to appear.
+    // * A new file backed provided volume is mounted, then redirect to it in
+    //   the focused window, because this means a zip file has been mounted.
+    //   Note, that this is a temporary solution for https://crbug.com/427776.
+    // * Crostini is mounted, redirect if it is the currently selected dir.
+    if (!currentDir ||
+        (window.isFocused() &&
          event.added[0].volumeType ===
              VolumeManagerCommon.VolumeType.PROVIDED &&
          event.added[0].source === VolumeManagerCommon.Source.FILE) ||
         (event.added[0].volumeType ===
              VolumeManagerCommon.VolumeType.CROSTINI &&
          this.getCurrentRootType() === VolumeManagerCommon.RootType.CROSTINI)) {
+      // Resolving a display root on FSP volumes is instant, despite the
+      // asynchronous call.
       event.added[0].resolveDisplayRoot().then((displayRoot) => {
-        // Resolving a display root on FSP volumes is instant, despite the
-        // asynchronous call.
-        this.changeDirectoryEntry(event.added[0].displayRoot);
+        // Only change directory if "currentDir" hasn't changed during the
+        // display root resolution.
+        if (currentDir === this.getCurrentDirEntry()) {
+          this.changeDirectoryEntry(event.added[0].displayRoot);
+        }
       });
     }
   }