diff --git a/.gitignore b/.gitignore
index 41c6f68..4c7a9e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -149,6 +149,7 @@
 /chrome/test/data/vr/webvr_info/
 /chrome/test/data/webrtc/resources
 /chrome/test/media_router/internal
+/chrome/test/python_tests/
 /chrome/tools/memory
 /chrome/tools/test/reference_build
 /chrome/unit_tests_run.xml
diff --git a/BUILD.gn b/BUILD.gn
index 06c117e..24e7935c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1019,6 +1019,7 @@
       "//third_party/catapult/devil/",
       "//third_party/catapult/dependency_manager/",
       "//third_party/catapult/third_party/zipfile/",
+      "//third_party/catapult/third_party/typ/",
       "//third_party/depot_tools/pylint.py",
       "//third_party/depot_tools/pylintrc",
       "//third_party/depot_tools/third_party/logilab/",
@@ -1026,7 +1027,6 @@
       "//third_party/depot_tools/third_party/pylint.py",
       "//third_party/ply/",
       "//third_party/pymock/",
-      "//third_party/typ/",
       "//tools/idl_parser/",
     ]
   }
diff --git a/DEPS b/DEPS
index d6a7a44..fd56984e 100644
--- a/DEPS
+++ b/DEPS
@@ -89,11 +89,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '0d24c502113bf8538772ec9cde6fb5cab85fa278',
+  'skia_revision': 'af4be058fe8ba437aaa5c2e93291047b2856bba1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '6b76faea0a217398f7f05a6fa7c93599793b7c34',
+  'v8_revision': '8ba3ef5fcd21c5e717a1b7bd0713612a287b9500',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -101,7 +101,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '5f21df8318e9dae7e4eca2809a176f2989410da8',
+  'angle_revision': '505ea1bb56ccce114c4ac4d1b7b856cb8dcdc47e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -488,7 +488,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'ef1ada9adf6a5e1b8b0d4a4b51188dff91f39582',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '18483452ccd21ddc666e9cdbe41a037285e9e7f0',
       'condition': 'checkout_linux',
   },
 
@@ -953,7 +953,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '7c0541da63f571512c49758cbc0767117997a270',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'bd7392829a81d0720887dae9ac0bf83da8d9e80d', # commit position 21742
+    Var('webrtc_git') + '/src.git' + '@' + 'd085936e6a4e112e4c396b6430859f3cdcb56092', # commit position 21742
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/ash/accelerators/ash_focus_manager_factory.cc b/ash/accelerators/ash_focus_manager_factory.cc
index b544dac..0f125c61 100644
--- a/ash/accelerators/ash_focus_manager_factory.cc
+++ b/ash/accelerators/ash_focus_manager_factory.cc
@@ -7,8 +7,12 @@
 #include <memory>
 
 #include "ash/accelerators/accelerator_controller.h"
+#include "ash/magnifier/docked_magnifier_controller.h"
+#include "ash/magnifier/magnification_controller.h"
 #include "ash/shell.h"
+#include "ui/base/ime/text_input_client.h"
 #include "ui/views/focus/focus_manager.h"
+#include "ui/views/view.h"
 
 namespace ash {
 
@@ -31,4 +35,55 @@
   return controller && controller->Process(accelerator);
 }
 
+void AshFocusManagerFactory::Delegate::OnDidChangeFocus(
+    views::View* focused_before,
+    views::View* focused_now) {
+  if (!focused_now || focused_now == focused_before)
+    return;
+
+  const gfx::Rect bounds_in_screen = focused_now->GetBoundsInScreen();
+  if (bounds_in_screen.IsEmpty())
+    return;
+
+  // Note that both magnifiers are mutually exclusive.
+  DockedMagnifierController* docked_magnifier =
+      Shell::Get()->docked_magnifier_controller();
+  MagnificationController* fullscreen_magnifier =
+      Shell::Get()->magnification_controller();
+
+  gfx::Point point_of_interest = bounds_in_screen.CenterPoint();
+  const ui::InputMethod* input_method = focused_now->GetInputMethod();
+  if (input_method && input_method->GetTextInputClient() &&
+      input_method->GetTextInputClient()->GetTextInputType() !=
+          ui::TEXT_INPUT_TYPE_NONE) {
+    // If this view is a text input client with valid caret bounds, forward it
+    // to the enabled magnifier as an |OnCaretBoundsChanged()| event, since the
+    // magnifiers might have special handling for caret events.
+    const gfx::Rect caret_bounds =
+        input_method->GetTextInputClient()->GetCaretBounds();
+    // Note: Don't use Rect::IsEmpty() for the below check as in many cases the
+    // caret can have a zero width or height, but still be valid.
+    if (caret_bounds.width() || caret_bounds.height()) {
+      if (docked_magnifier->GetEnabled()) {
+        docked_magnifier->OnCaretBoundsChanged(
+            input_method->GetTextInputClient());
+      } else if (fullscreen_magnifier->IsEnabled()) {
+        fullscreen_magnifier->OnCaretBoundsChanged(
+            input_method->GetTextInputClient());
+      }
+
+      return;
+    }
+
+    // If the caret bounds are unavailable, then use the view's top left corner
+    // as the point of interest.
+    point_of_interest = bounds_in_screen.origin();
+  }
+
+  if (docked_magnifier->GetEnabled())
+    docked_magnifier->CenterOnPoint(point_of_interest);
+  else if (fullscreen_magnifier->IsEnabled())
+    fullscreen_magnifier->CenterOnPoint(point_of_interest);
+}
+
 }  // namespace ash
diff --git a/ash/accelerators/ash_focus_manager_factory.h b/ash/accelerators/ash_focus_manager_factory.h
index 5f05301..4788f89 100644
--- a/ash/accelerators/ash_focus_manager_factory.h
+++ b/ash/accelerators/ash_focus_manager_factory.h
@@ -32,6 +32,8 @@
 
     // views::FocusManagerDelegate overrides:
     bool ProcessAccelerator(const ui::Accelerator& accelerator) override;
+    void OnDidChangeFocus(views::View* focused_before,
+                          views::View* focused_now) override;
   };
 
   DISALLOW_COPY_AND_ASSIGN(AshFocusManagerFactory);
diff --git a/ash/display/display_configuration_observer.cc b/ash/display/display_configuration_observer.cc
index c9e5c870..dd32a41 100644
--- a/ash/display/display_configuration_observer.cc
+++ b/ash/display/display_configuration_observer.cc
@@ -65,7 +65,7 @@
   display::DisplayManager* display_manager = Shell::Get()->display_manager();
   was_in_mirror_mode_ = display_manager->IsInMirrorMode();
   display_manager->SetMirrorMode(display::MirrorMode::kNormal, base::nullopt);
-  display_manager->layout_store()->set_forced_mirror_mode(true);
+  display_manager->layout_store()->set_forced_mirror_mode_for_tablet(true);
 }
 
 void DisplayConfigurationObserver::EndMirrorMode() {
@@ -74,7 +74,7 @@
                                                    base::nullopt);
   }
   display::DisplayManager* display_manager = Shell::Get()->display_manager();
-  display_manager->layout_store()->set_forced_mirror_mode(false);
+  display_manager->layout_store()->set_forced_mirror_mode_for_tablet(false);
   save_preference_ = true;
 }
 
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 8d551463..b15c9af 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -3700,7 +3700,7 @@
   EXPECT_EQ(display::MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED,
             observer.GetStateForDisplayIds(outputs));
 
-  display_manager()->layout_store()->set_forced_mirror_mode(true);
+  display_manager()->layout_store()->set_forced_mirror_mode_for_tablet(true);
 
   observer.OnDisplayModeChanged(outputs);
 
@@ -3711,7 +3711,7 @@
   EXPECT_EQ(display::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR,
             observer.GetStateForDisplayIds(outputs));
 
-  display_manager()->layout_store()->set_forced_mirror_mode(false);
+  display_manager()->layout_store()->set_forced_mirror_mode_for_tablet(false);
 
   EXPECT_EQ(display::MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED,
             observer.GetStateForDisplayIds(outputs));
@@ -4565,4 +4565,131 @@
   EXPECT_TRUE(display_manager()->IsInMirrorMode());
 }
 
+TEST_F(DisplayManagerTest, SoftwareMirrorRotationForTablet) {
+  UpdateDisplay("400x300,800x800");
+  RunAllPendingInMessageLoop();
+
+  // Set the first display as internal display so that the tablet mode can be
+  // enabled.
+  display::test::DisplayManagerTestApi(display_manager())
+      .SetFirstDisplayAsInternalDisplay();
+
+  // Simulate turning on mirror mode triggered by tablet mode on.
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  RunAllPendingInMessageLoop();
+  EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
+  EXPECT_EQ(gfx::Rect(0, 0, 400, 300),
+            display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  MirrorWindowTestApi test_api;
+  std::vector<aura::WindowTreeHost*> host_list = test_api.GetHosts();
+  ASSERT_EQ(1U, host_list.size());
+  EXPECT_EQ(gfx::Size(800, 800), host_list[0]->GetBoundsInPixels().size());
+  EXPECT_EQ(gfx::Size(400, 300), host_list[0]->window()->bounds().size());
+
+  // Test the target display's bounds after the transforms are applied.
+  gfx::RectF transformed_rect1(
+      display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  Shell::Get()->GetPrimaryRootWindow()->transform().TransformRect(
+      &transformed_rect1);
+  host_list[0]->window()->transform().TransformRect(&transformed_rect1);
+  EXPECT_EQ(gfx::RectF(0.0f, 100.0f, 800.0f, 600.0f), transformed_rect1);
+
+  // Rotate the source display by 90 degrees.
+  UpdateDisplay("400x300/r,800x800");
+  EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
+  EXPECT_EQ(gfx::Rect(0, 0, 300, 400),
+            display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  host_list = test_api.GetHosts();
+  ASSERT_EQ(1U, host_list.size());
+  EXPECT_EQ(gfx::Size(800, 800), host_list[0]->GetBoundsInPixels().size());
+  EXPECT_EQ(gfx::Size(300, 400), host_list[0]->window()->bounds().size());
+
+  // Test the target display's bounds after the transforms are applied.
+  gfx::RectF transformed_rect2(
+      display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  Shell::Get()->GetPrimaryRootWindow()->transform().TransformRect(
+      &transformed_rect2);
+  host_list[0]->window()->transform().TransformRect(&transformed_rect2);
+  EXPECT_EQ(gfx::RectF(100.0f, 0.0f, 600.0f, 800.0f), transformed_rect2);
+
+  // Change the bounds of the source display and rotate the source display by 90
+  // degrees.
+  UpdateDisplay("300x400/r,800x800");
+  EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
+  EXPECT_EQ(gfx::Rect(0, 0, 400, 300),
+            display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  host_list = test_api.GetHosts();
+  ASSERT_EQ(1U, host_list.size());
+  EXPECT_EQ(gfx::Size(800, 800), host_list[0]->GetBoundsInPixels().size());
+  EXPECT_EQ(gfx::Size(400, 300), host_list[0]->window()->bounds().size());
+
+  // Test the target display's bounds after the transforms are applied.
+  gfx::RectF transformed_rect3(
+      display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  Shell::Get()->GetPrimaryRootWindow()->transform().TransformRect(
+      &transformed_rect3);
+  host_list[0]->window()->transform().TransformRect(&transformed_rect3);
+  EXPECT_EQ(gfx::RectF(0.0f, 100.0f, 800.0f, 600.0f), transformed_rect3);
+}
+
+TEST_F(DisplayManagerTest, SoftwareMirrorRotationForNonTablet) {
+  MirrorWindowTestApi test_api;
+  UpdateDisplay("400x300,800x800");
+
+  // Simulate turning on mirror mode not triggered by tablet mode.
+  SetSoftwareMirrorMode(true);
+  EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
+  EXPECT_EQ(gfx::Rect(0, 0, 400, 300),
+            display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  std::vector<aura::WindowTreeHost*> host_list = test_api.GetHosts();
+  ASSERT_EQ(1U, host_list.size());
+  EXPECT_EQ(gfx::Size(800, 800), host_list[0]->GetBoundsInPixels().size());
+  EXPECT_EQ(gfx::Size(400, 300), host_list[0]->window()->bounds().size());
+
+  // Test the target display's bounds after the transforms are applied.
+  gfx::RectF transformed_rect1(
+      display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  Shell::Get()->GetPrimaryRootWindow()->transform().TransformRect(
+      &transformed_rect1);
+  host_list[0]->window()->transform().TransformRect(&transformed_rect1);
+  EXPECT_EQ(gfx::RectF(0.0f, 100.0f, 800.0f, 600.0f), transformed_rect1);
+
+  // Rotate the source display by 90 degrees.
+  UpdateDisplay("400x300/r,800x800");
+  EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
+  EXPECT_EQ(gfx::Rect(0, 0, 300, 400),
+            display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  host_list = test_api.GetHosts();
+  ASSERT_EQ(1U, host_list.size());
+  EXPECT_EQ(gfx::Size(800, 800), host_list[0]->GetBoundsInPixels().size());
+  EXPECT_EQ(gfx::Size(400, 300), host_list[0]->window()->bounds().size());
+
+  // Test the target display's bounds after the transforms are applied.
+  gfx::RectF transformed_rect2(
+      display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  Shell::Get()->GetPrimaryRootWindow()->transform().TransformRect(
+      &transformed_rect2);
+  host_list[0]->window()->transform().TransformRect(&transformed_rect2);
+  EXPECT_EQ(gfx::RectF(0.0f, 100.0f, 800.0f, 600.0f), transformed_rect2);
+
+  // Change the bounds of the source display and rotate the source display by 90
+  // degrees.
+  UpdateDisplay("300x400/r,800x800");
+  EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
+  EXPECT_EQ(gfx::Rect(0, 0, 400, 300),
+            display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  host_list = test_api.GetHosts();
+  ASSERT_EQ(1U, host_list.size());
+  EXPECT_EQ(gfx::Size(800, 800), host_list[0]->GetBoundsInPixels().size());
+  EXPECT_EQ(gfx::Size(300, 400), host_list[0]->window()->bounds().size());
+
+  // Test the target display's bounds after the transforms are applied.
+  gfx::RectF transformed_rect3(
+      display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
+  Shell::Get()->GetPrimaryRootWindow()->transform().TransformRect(
+      &transformed_rect3);
+  host_list[0]->window()->transform().TransformRect(&transformed_rect3);
+  EXPECT_EQ(gfx::RectF(100.0f, 0.0f, 600.0f, 800.0f), transformed_rect3);
+}
+
 }  // namespace ash
diff --git a/ash/display/root_window_transformers.cc b/ash/display/root_window_transformers.cc
index 506241d..dc81096 100644
--- a/ash/display/root_window_transformers.cc
+++ b/ash/display/root_window_transformers.cc
@@ -14,6 +14,7 @@
 #include "base/command_line.h"
 #include "ui/compositor/dip_util.h"
 #include "ui/display/display.h"
+#include "ui/display/manager/display_layout_store.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/screen.h"
 #include "ui/gfx/geometry/insets.h"
@@ -36,7 +37,7 @@
   display::ManagedDisplayInfo info =
       Shell::Get()->display_manager()->GetDisplayInfo(display.id());
   return CreateRotationTransform(display::Display::ROTATE_0,
-                                 info.GetActiveRotation(), display);
+                                 info.GetActiveRotation(), display.bounds());
 }
 
 gfx::Transform CreateMagnifierTransform(aura::Window* root_window) {
@@ -163,6 +164,26 @@
       const display::ManagedDisplayInfo& source_display_info,
       const display::ManagedDisplayInfo& mirror_display_info) {
     root_bounds_ = gfx::Rect(source_display_info.bounds_in_native().size());
+
+    // The rotation of the source display (internal display) should be undone in
+    // the destination display (external display) if mirror mode is enabled in
+    // tablet mode.
+    bool should_undo_rotation = Shell::Get()
+                                    ->display_manager()
+                                    ->layout_store()
+                                    ->forced_mirror_mode_for_tablet();
+    gfx::Transform rotation_transform;
+    if (should_undo_rotation) {
+      // Calculate the transform to undo the rotation and apply it to the
+      // source display.
+      rotation_transform =
+          CreateRotationTransform(source_display_info.GetActiveRotation(),
+                                  display::Display::ROTATE_0, root_bounds_);
+      gfx::RectF rotated_bounds(root_bounds_);
+      rotation_transform.TransformRect(&rotated_bounds);
+      root_bounds_ = gfx::ToNearestRect(rotated_bounds);
+    }
+
     gfx::Rect mirror_display_rect =
         gfx::Rect(mirror_display_info.bounds_in_native().size());
 
@@ -193,6 +214,9 @@
       transform_.Translate(margin, 0);
       transform_.Scale(inverted_scale, inverted_scale);
     }
+
+    // Make sure the rotation transform is applied in the beginning.
+    transform_.PreconcatTransform(rotation_transform);
   }
 
   // aura::RootWindowTransformer overrides:
diff --git a/ash/magnifier/docked_magnifier_controller.cc b/ash/magnifier/docked_magnifier_controller.cc
index cef485e..71c16593 100644
--- a/ash/magnifier/docked_magnifier_controller.cc
+++ b/ash/magnifier/docked_magnifier_controller.cc
@@ -188,12 +188,6 @@
       delta_index, GetScale(), kMinMagnifierScale, kMaxMagnifierScale));
 }
 
-void DockedMagnifierController::SetClient(
-    mojom::DockedMagnifierClientPtr client) {
-  client_ = std::move(client);
-  NotifyClientWithStatusChanged();
-}
-
 void DockedMagnifierController::CenterOnPoint(
     const gfx::Point& point_in_screen) {
   if (!GetEnabled())
@@ -391,10 +385,6 @@
   }
 }
 
-void DockedMagnifierController::FlushClientPtrForTesting() {
-  client_.FlushForTesting();
-}
-
 const views::Widget* DockedMagnifierController::GetViewportWidgetForTesting()
     const {
   return viewport_widget_;
@@ -507,7 +497,6 @@
           base::Unretained(this)));
 
   OnEnabledPrefChanged();
-  NotifyClientWithStatusChanged();
 }
 
 void DockedMagnifierController::OnEnabledPrefChanged() {
@@ -550,8 +539,6 @@
   // We use software composited mouse cursor so that it can be mirrored into the
   // magnifier viewport.
   shell->UpdateCursorCompositingEnabled();
-
-  NotifyClientWithStatusChanged();
 }
 
 void DockedMagnifierController::OnScalePrefChanged() {
@@ -581,11 +568,6 @@
   CenterOnPoint(GetCursorScreenPoint());
 }
 
-void DockedMagnifierController::NotifyClientWithStatusChanged() {
-  if (client_)
-    client_->OnEnabledStatusChanged(GetEnabled());
-}
-
 void DockedMagnifierController::CreateMagnifierViewport() {
   DCHECK(GetEnabled());
   DCHECK(current_source_root_window_);
diff --git a/ash/magnifier/docked_magnifier_controller.h b/ash/magnifier/docked_magnifier_controller.h
index 095a185..e568b82 100644
--- a/ash/magnifier/docked_magnifier_controller.h
+++ b/ash/magnifier/docked_magnifier_controller.h
@@ -79,7 +79,6 @@
   void StepToNextScaleValue(int delta_index);
 
   // ash::mojom::DockedMagnifierController:
-  void SetClient(mojom::DockedMagnifierClientPtr client) override;
   void CenterOnPoint(const gfx::Point& point_in_screen) override;
 
   // ash::SessionObserver:
@@ -116,8 +115,6 @@
   bool GetFullscreenMagnifierEnabled() const;
   void SetFullscreenMagnifierEnabled(bool enabled);
 
-  void FlushClientPtrForTesting();
-
   const views::Widget* GetViewportWidgetForTesting() const;
 
   const ui::Layer* GetViewportMagnifierLayerForTesting() const;
@@ -202,8 +199,6 @@
 
   mojo::Binding<mojom::DockedMagnifierController> binding_;
 
-  mojom::DockedMagnifierClientPtr client_;
-
   DISALLOW_COPY_AND_ASSIGN(DockedMagnifierController);
 };
 
diff --git a/ash/magnifier/docked_magnifier_controller_unittest.cc b/ash/magnifier/docked_magnifier_controller_unittest.cc
index 9d9b10f..8c3b6f9 100644
--- a/ash/magnifier/docked_magnifier_controller_unittest.cc
+++ b/ash/magnifier/docked_magnifier_controller_unittest.cc
@@ -27,7 +27,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/session_manager_types.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
 #include "ui/display/display.h"
@@ -42,34 +41,6 @@
 constexpr char kUser1Email[] = "user1@dockedmagnifier";
 constexpr char kUser2Email[] = "user2@dockedmagnifier";
 
-// Mock mojo client of the Docked Magnifier.
-class DockedMagnifierTestClient : public mojom::DockedMagnifierClient {
- public:
-  DockedMagnifierTestClient() : binding_(this) {}
-  ~DockedMagnifierTestClient() override = default;
-
-  bool docked_magnifier_enabled() const { return docked_magnifier_enabled_; }
-
-  // Connects to the DockedMagnifierController.
-  void Start() {
-    ash::mojom::DockedMagnifierClientPtr client;
-    binding_.Bind(mojo::MakeRequest(&client));
-    Shell::Get()->docked_magnifier_controller()->SetClient(std::move(client));
-  }
-
-  // ash::mojom::DockedMagnifierClient:
-  void OnEnabledStatusChanged(bool enabled) override {
-    docked_magnifier_enabled_ = enabled;
-  }
-
- private:
-  mojo::Binding<ash::mojom::DockedMagnifierClient> binding_;
-
-  bool docked_magnifier_enabled_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(DockedMagnifierTestClient);
-};
-
 class DockedMagnifierTest : public NoSessionAshTestBase {
  public:
   DockedMagnifierTest() = default;
@@ -79,8 +50,6 @@
     return Shell::Get()->docked_magnifier_controller();
   }
 
-  DockedMagnifierTestClient* test_client() { return &test_client_; }
-
   PrefService* user1_pref_service() {
     return Shell::Get()->session_controller()->GetUserPrefServiceForUser(
         AccountId::FromUserEmail(kUser1Email));
@@ -109,8 +78,6 @@
     // Create user 2 session.
     GetSessionControllerClient()->AddUserSession(kUser2Email);
 
-    test_client_.Start();
-
     // Place the cursor in the first display.
     GetEventGenerator().MoveMouseTo(gfx::Point(0, 0));
   }
@@ -120,12 +87,7 @@
         AccountId::FromUserEmail(email));
   }
 
- protected:
-  MagnifierTextInputTestHelper text_input_helper_;
-
  private:
-  DockedMagnifierTestClient test_client_;
-
   base::test::ScopedFeatureList scoped_feature_list_;
 
   DISALLOW_COPY_AND_ASSIGN(DockedMagnifierTest);
@@ -157,37 +119,17 @@
   EXPECT_FALSE(controller()->GetFullscreenMagnifierEnabled());
 }
 
-// Tests the changes in the magnifier's status, user switches and the
-// interaction with the client.
+// Tests the changes in the magnifier's status, user switches.
 TEST_F(DockedMagnifierTest, TestEnableAndDisable) {
-  // Client should receive status updates.
-  EXPECT_FALSE(controller()->GetEnabled());
-  EXPECT_FALSE(test_client()->docked_magnifier_enabled());
+  // Enable for user 1, and switch to user 2. User 2 should have it disabled.
   controller()->SetEnabled(true);
-  controller()->FlushClientPtrForTesting();
   EXPECT_TRUE(controller()->GetEnabled());
-  EXPECT_TRUE(test_client()->docked_magnifier_enabled());
-  controller()->SetEnabled(false);
-  controller()->FlushClientPtrForTesting();
-  EXPECT_FALSE(controller()->GetEnabled());
-  EXPECT_FALSE(test_client()->docked_magnifier_enabled());
-
-  // Enable again for user 1, and switch to user 2. User 2 should have it
-  // disabled, the client should be updated accordingly.
-  controller()->SetEnabled(true);
-  controller()->FlushClientPtrForTesting();
-  EXPECT_TRUE(controller()->GetEnabled());
-  EXPECT_TRUE(test_client()->docked_magnifier_enabled());
   SwitchActiveUser(kUser2Email);
-  controller()->FlushClientPtrForTesting();
   EXPECT_FALSE(controller()->GetEnabled());
-  EXPECT_FALSE(test_client()->docked_magnifier_enabled());
 
   // Switch back to user 1, expect it to be enabled.
   SwitchActiveUser(kUser1Email);
-  controller()->FlushClientPtrForTesting();
   EXPECT_TRUE(controller()->GetEnabled());
-  EXPECT_TRUE(test_client()->docked_magnifier_enabled());
 }
 
 // Tests the magnifier's scale changes.
@@ -214,17 +156,12 @@
 // DockedMagnifierController (such as Settings UI) are observed and applied.
 TEST_F(DockedMagnifierTest, TestOutsidePrefsUpdates) {
   EXPECT_FALSE(controller()->GetEnabled());
-  EXPECT_FALSE(test_client()->docked_magnifier_enabled());
   user1_pref_service()->SetBoolean(prefs::kDockedMagnifierEnabled, true);
-  controller()->FlushClientPtrForTesting();
   EXPECT_TRUE(controller()->GetEnabled());
-  EXPECT_TRUE(test_client()->docked_magnifier_enabled());
   user1_pref_service()->SetDouble(prefs::kDockedMagnifierScale, 7.3f);
   EXPECT_FLOAT_EQ(7.3f, controller()->GetScale());
   user1_pref_service()->SetBoolean(prefs::kDockedMagnifierEnabled, false);
-  controller()->FlushClientPtrForTesting();
   EXPECT_FALSE(controller()->GetEnabled());
-  EXPECT_FALSE(test_client()->docked_magnifier_enabled());
 }
 
 // Tests that the workareas of displays are adjusted properly when the Docked
@@ -500,7 +437,8 @@
   const auto root_windows = Shell::GetAllRootWindows();
   ASSERT_EQ(1u, root_windows.size());
 
-  text_input_helper_.CreateAndShowTextInputView(gfx::Rect(500, 400, 80, 80));
+  MagnifierTextInputTestHelper text_input_helper;
+  text_input_helper.CreateAndShowTextInputView(gfx::Rect(500, 400, 80, 80));
 
   // Enable the docked magnifier.
   controller()->SetEnabled(true);
@@ -510,14 +448,14 @@
   EXPECT_FLOAT_EQ(scale1, controller()->GetScale());
 
   // Focus on the text input field.
-  text_input_helper_.FocusOnTextInputView();
+  text_input_helper.FocusOnTextInputView();
 
   // The text input caret center point will be our point of interest. When it
   // goes through the magnifier layer transform, it should end up being in the
   // center of the viewport.
   const ui::Layer* magnifier_layer =
       controller()->GetViewportMagnifierLayerForTesting();
-  gfx::Point caret_center(text_input_helper_.GetCaretBounds().CenterPoint());
+  gfx::Point caret_center(text_input_helper.GetCaretBounds().CenterPoint());
   magnifier_layer->transform().TransformPoint(&caret_center);
   const views::Widget* viewport_widget =
       controller()->GetViewportWidgetForTesting();
@@ -529,12 +467,48 @@
   // transformed caret center should always go to the viewport center.
   GetEventGenerator().PressKey(ui::VKEY_A, 0);
   GetEventGenerator().ReleaseKey(ui::VKEY_A, 0);
-  gfx::Point new_caret_center(
-      text_input_helper_.GetCaretBounds().CenterPoint());
+  gfx::Point new_caret_center(text_input_helper.GetCaretBounds().CenterPoint());
   magnifier_layer->transform().TransformPoint(&new_caret_center);
   EXPECT_EQ(new_caret_center, viewport_center);
 }
 
+TEST_F(DockedMagnifierTest, FocusChangeEvents) {
+  UpdateDisplay("600x900");
+  const auto root_windows = Shell::GetAllRootWindows();
+  ASSERT_EQ(1u, root_windows.size());
+
+  MagnifierFocusTestHelper focus_test_helper;
+  focus_test_helper.CreateAndShowFocusTestView(gfx::Point(70, 500));
+
+  // Enable the docked magnifier.
+  controller()->SetEnabled(true);
+  const float scale = 2.0f;
+  controller()->SetScale(scale);
+  EXPECT_TRUE(controller()->GetEnabled());
+  EXPECT_FLOAT_EQ(scale, controller()->GetScale());
+
+  // Focus on the first button and expect the magnifier to be centered around
+  // its center.
+  focus_test_helper.FocusFirstButton();
+  const ui::Layer* magnifier_layer =
+      controller()->GetViewportMagnifierLayerForTesting();
+  gfx::Point button_1_center(
+      focus_test_helper.GetFirstButtonBoundsInRoot().CenterPoint());
+  magnifier_layer->transform().TransformPoint(&button_1_center);
+  const views::Widget* viewport_widget =
+      controller()->GetViewportWidgetForTesting();
+  const gfx::Point viewport_center(
+      viewport_widget->GetWindowBoundsInScreen().CenterPoint());
+  EXPECT_EQ(button_1_center, viewport_center);
+
+  // Similarly if we focus on the second button.
+  focus_test_helper.FocusSecondButton();
+  gfx::Point button_2_center(
+      focus_test_helper.GetSecondButtonBoundsInRoot().CenterPoint());
+  magnifier_layer->transform().TransformPoint(&button_2_center);
+  EXPECT_EQ(button_2_center, viewport_center);
+}
+
 // Tests that viewport layer is inverted properly when the status of the High
 // Contrast mode changes.
 TEST_F(DockedMagnifierTest, HighContrastMode) {
diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc
index 0b0b3b09..e4b01b2 100644
--- a/ash/magnifier/magnification_controller.cc
+++ b/ash/magnifier/magnification_controller.cc
@@ -225,6 +225,13 @@
   return gfx::ToEnclosingRect(GetWindowRectDIP(scale_));
 }
 
+void MagnificationController::CenterOnPoint(const gfx::Point& point_in_screen) {
+  gfx::Point point_in_root = point_in_screen;
+  ::wm::ConvertPointFromScreen(root_window_, &point_in_root);
+
+  MoveMagnifierWindowCenterPoint(point_in_root);
+}
+
 void MagnificationController::HandleFocusedNodeChanged(
     bool is_editable_node,
     const gfx::Rect& node_bounds_in_screen) {
@@ -271,6 +278,61 @@
   root_window_->AddObserver(this);
 }
 
+void MagnificationController::OnCaretBoundsChanged(
+    const ui::TextInputClient* client) {
+  // caret bounds in screen coordinates.
+  const gfx::Rect caret_bounds = client->GetCaretBounds();
+  // Note: OnCaretBoundsChanged could be fired OnTextInputTypeChanged during
+  // which the caret position is not set a meaning position, and we do not
+  // need to adjust the view port position based on the bogus caret position.
+  // This is only a transition period, the caret position will be fixed upon
+  // focusing right after.
+  if (caret_bounds.width() == 0 && caret_bounds.height() == 0)
+    return;
+
+  gfx::Point new_caret_point = caret_bounds.CenterPoint();
+  // |caret_point_| in |root_window_| coordinates.
+  ::wm::ConvertPointFromScreen(root_window_, &new_caret_point);
+
+  // When the caret point was not actually changed, nothing should happen.
+  // OnCaretBoundsChanged could be fired on every event that may change the
+  // caret bounds, in particular a window creation/movement, that may not result
+  // in an actual movement.
+  if (new_caret_point == caret_point_)
+    return;
+  caret_point_ = new_caret_point;
+
+  // If the feature for centering the text input focus is disabled, the
+  // magnifier window will be moved to follow the focus with a panning margin.
+  if (!KeepFocusCentered()) {
+    // Visible window_rect in |root_window_| coordinates.
+    const gfx::Rect visible_window_rect = GetViewportRect();
+    const int panning_margin = kCaretPanningMargin / scale_;
+    MoveMagnifierWindowFollowPoint(caret_point_, panning_margin, panning_margin,
+                                   visible_window_rect.width() / 2,
+                                   visible_window_rect.height() / 2);
+    return;
+  }
+
+  // Move the magnifier window to center the focus with a little delay.
+  // In Gmail compose window, when user types a blank space, it will insert
+  // a non-breaking space(NBSP). NBSP will be replaced with a blank space
+  // character when user types a non-blank space character later, which causes
+  // OnCaretBoundsChanged be called twice. The first call moves the caret back
+  // to the character position just before NBSP, replaces the NBSP with blank
+  // space plus the new character, then the second call will move caret to the
+  // position after the new character. In order to avoid the magnifier window
+  // being moved back and forth with these two OnCaretBoundsChanged events, we
+  // defer moving magnifier window until the |move_magnifier_timer_| fires,
+  // when the caret settles eventually.
+  move_magnifier_timer_.Stop();
+  move_magnifier_timer_.Start(
+      FROM_HERE,
+      base::TimeDelta::FromMilliseconds(
+          disable_move_magnifier_delay_ ? 0 : kMoveMagnifierDelayInMs),
+      this, &MagnificationController::OnMoveMagnifierTimer);
+}
+
 void MagnificationController::OnImplicitAnimationsCompleted() {
   if (!is_on_animation_)
     return;
@@ -453,6 +515,10 @@
     // Jump back to exactly 1.0 if we are just a tiny bit zoomed in.
     if (scale_ < kMinMagnifiedScaleThreshold) {
       SetScale(kNonMagnifiedScale, true /* animate */);
+    } else {
+      // Store current magnifier scale in pref. We don't need to call this if we
+      // call SetScale (the above case) as SetScale does this.
+      Shell::Get()->accessibility_delegate()->SaveScreenMagnifierScale(scale_);
     }
   }
 
@@ -484,61 +550,6 @@
   return ui::EVENT_REWRITE_REWRITTEN;
 }
 
-void MagnificationController::OnCaretBoundsChanged(
-    const ui::TextInputClient* client) {
-  // caret bounds in screen coordinates.
-  const gfx::Rect caret_bounds = client->GetCaretBounds();
-  // Note: OnCaretBoundsChanged could be fired OnTextInputTypeChanged during
-  // which the caret position is not set a meaning position, and we do not
-  // need to adjust the view port position based on the bogus caret position.
-  // This is only a transition period, the caret position will be fixed upon
-  // focusing right after.
-  if (caret_bounds.width() == 0 && caret_bounds.height() == 0)
-    return;
-
-  gfx::Point new_caret_point = caret_bounds.CenterPoint();
-  // |caret_point_| in |root_window_| coordinates.
-  ::wm::ConvertPointFromScreen(root_window_, &new_caret_point);
-
-  // When the caret point was not actually changed, nothing should happen.
-  // OnCaretBoundsChanged could be fired on every event that may change the
-  // caret bounds, in particular a window creation/movement, that may not result
-  // in an actual movement.
-  if (new_caret_point == caret_point_)
-    return;
-  caret_point_ = new_caret_point;
-
-  // If the feature for centering the text input focus is disabled, the
-  // magnifier window will be moved to follow the focus with a panning margin.
-  if (!KeepFocusCentered()) {
-    // Visible window_rect in |root_window_| coordinates.
-    const gfx::Rect visible_window_rect = GetViewportRect();
-    const int panning_margin = kCaretPanningMargin / scale_;
-    MoveMagnifierWindowFollowPoint(caret_point_, panning_margin, panning_margin,
-                                   visible_window_rect.width() / 2,
-                                   visible_window_rect.height() / 2);
-    return;
-  }
-
-  // Move the magnifier window to center the focus with a little delay.
-  // In Gmail compose window, when user types a blank space, it will insert
-  // a non-breaking space(NBSP). NBSP will be replaced with a blank space
-  // character when user types a non-blank space character later, which causes
-  // OnCaretBoundsChanged be called twice. The first call moves the caret back
-  // to the character position just before NBSP, replaces the NBSP with blank
-  // space plus the new character, then the second call will move caret to the
-  // position after the new character. In order to avoid the magnifier window
-  // being moved back and forth with these two OnCaretBoundsChanged events, we
-  // defer moving magnifier window until the |move_magnifier_timer_| fires,
-  // when the caret settles eventually.
-  move_magnifier_timer_.Stop();
-  move_magnifier_timer_.Start(
-      FROM_HERE,
-      base::TimeDelta::FromMilliseconds(
-          disable_move_magnifier_delay_ ? 0 : kMoveMagnifierDelayInMs),
-      this, &MagnificationController::OnMoveMagnifierTimer);
-}
-
 bool MagnificationController::Redraw(const gfx::PointF& position,
                                      float scale,
                                      bool animate) {
diff --git a/ash/magnifier/magnification_controller.h b/ash/magnifier/magnification_controller.h
index 8f5cfeb..bc72d1f8 100644
--- a/ash/magnifier/magnification_controller.h
+++ b/ash/magnifier/magnification_controller.h
@@ -95,7 +95,11 @@
   // window coordinates.
   gfx::Rect GetViewportRect() const;
 
-  // Follows the focus on web page for non-editable controls.
+  // Centers the viewport around the given point in screen coordinates.
+  void CenterOnPoint(const gfx::Point& point_in_screen);
+
+  // Follows the focus on web page for non-editable controls. Called from Chrome
+  // when Fullscreen magnifier feature is enabled.
   void HandleFocusedNodeChanged(bool is_editable_node,
                                 const gfx::Rect& node_bounds_in_screen);
 
@@ -106,6 +110,14 @@
   void SwitchTargetRootWindow(aura::Window* new_root_window,
                               bool redraw_original_root);
 
+  // ui::InputMethodObserver:
+  void OnFocus() override {}
+  void OnBlur() override {}
+  void OnCaretBoundsChanged(const ui::TextInputClient* client) override;
+  void OnTextInputStateChanged(const ui::TextInputClient* client) override {}
+  void OnInputMethodDestroyed(const ui::InputMethod* input_method) override {}
+  void OnShowImeIfNeeded() override {}
+
   // Returns the last mouse cursor (or last touched) location.
   gfx::Point GetPointOfInterestForTesting() {
     return point_of_interest_in_root_;
@@ -147,14 +159,6 @@
       const ui::Event& last_event,
       std::unique_ptr<ui::Event>* new_event) override;
 
-  // ui::InputMethodObserver:
-  void OnFocus() override {}
-  void OnBlur() override {}
-  void OnCaretBoundsChanged(const ui::TextInputClient* client) override;
-  void OnTextInputStateChanged(const ui::TextInputClient* client) override {}
-  void OnInputMethodDestroyed(const ui::InputMethod* input_method) override {}
-  void OnShowImeIfNeeded() override {}
-
   // Redraws the magnification window with the given origin position and the
   // given scale. Returns true if the window is changed; otherwise, false.
   // These methods should be called internally just after the scale and/or
diff --git a/ash/magnifier/magnification_controller_unittest.cc b/ash/magnifier/magnification_controller_unittest.cc
index 4dffe9e7..932e09c3 100644
--- a/ash/magnifier/magnification_controller_unittest.cc
+++ b/ash/magnifier/magnification_controller_unittest.cc
@@ -245,6 +245,7 @@
   EXPECT_EQ("450,350", CurrentPointOfInterest());
 }
 
+// TODO(warx): move this test to unit_tests.
 TEST_F(MagnificationControllerTest, FollowFocusChanged) {
   // Enables magnifier and confirm the viewport is at center.
   GetMagnificationController()->SetEnabled(true);
@@ -517,6 +518,30 @@
   EXPECT_EQ("100,300", GetHostMouseLocation());
 }
 
+TEST_F(MagnificationControllerTest, FocusChangeEvents) {
+  MagnifierFocusTestHelper focus_test_helper;
+  focus_test_helper.CreateAndShowFocusTestView(gfx::Point(100, 200));
+
+  // Enables magnifier and confirm the viewport is at center.
+  GetMagnificationController()->SetEnabled(true);
+  EXPECT_EQ(2.0f, GetMagnificationController()->GetScale());
+  EXPECT_EQ("200,150 400x300", GetViewport().ToString());
+  EXPECT_FALSE(GetMagnificationController()->KeepFocusCentered());
+
+  // Focus on the first button and expect the magnifier to be centered around
+  // its center.
+  focus_test_helper.FocusFirstButton();
+  gfx::Point button_1_center(
+      focus_test_helper.GetFirstButtonBoundsInRoot().CenterPoint());
+  EXPECT_EQ(button_1_center, GetViewport().CenterPoint());
+
+  // Similarly if we focus on the second button.
+  focus_test_helper.FocusSecondButton();
+  gfx::Point button_2_center(
+      focus_test_helper.GetSecondButtonBoundsInRoot().CenterPoint());
+  EXPECT_EQ(button_2_center, GetViewport().CenterPoint());
+}
+
 TEST_F(MagnificationControllerTest, FollowTextInputFieldFocus) {
   text_input_helper_.CreateAndShowTextInputView(gfx::Rect(500, 300, 80, 80));
   gfx::Rect text_input_bounds = text_input_helper_.GetTextInputViewBounds();
diff --git a/ash/magnifier/magnifier_test_utils.cc b/ash/magnifier/magnifier_test_utils.cc
index e86edcb..486b71f 100644
--- a/ash/magnifier/magnifier_test_utils.cc
+++ b/ash/magnifier/magnifier_test_utils.cc
@@ -6,6 +6,7 @@
 
 #include "ash/shell.h"
 #include "ui/base/ime/input_method.h"
+#include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/widget/widget.h"
@@ -21,8 +22,61 @@
   return view->GetWidget()->GetNativeWindow()->GetRootWindow();
 }
 
+gfx::Rect GetBoundsInRoot(const gfx::Rect& bounds_in_screen,
+                          views::View* view) {
+  gfx::Rect bounds = bounds_in_screen;
+  ::wm::ConvertRectFromScreen(GetViewRootWindow(view), &bounds);
+  return bounds;
+}
+
 }  // namespace
 
+////////////////////////////////////////////////////////////////////////////////
+// TestFocusView:
+
+// A view that contains two buttons positioned at constant bounds with ability
+// to request focus on either one.
+class TestFocusView : public views::WidgetDelegateView {
+ public:
+  TestFocusView()
+      : button_1_(new views::LabelButton(nullptr, {})),
+        button_2_(new views::LabelButton(nullptr, {})) {
+    button_1_->SetFocusForPlatform();
+    button_2_->SetFocusForPlatform();
+    AddChildView(button_1_);
+    AddChildView(button_2_);
+  }
+
+  ~TestFocusView() override = default;
+
+  gfx::Size CalculatePreferredSize() const override {
+    return MagnifierFocusTestHelper::kTestFocusViewSize;
+  }
+
+  void Layout() override {
+    // Layout the first button at the top of the view.
+    button_1_->SetBounds(0, 0,
+                         MagnifierFocusTestHelper::kTestFocusViewSize.width(),
+                         MagnifierFocusTestHelper::kButtonHeight);
+
+    // And the second at the other end at the bottom of the view.
+    button_2_->SetBounds(0,
+                         MagnifierFocusTestHelper::kTestFocusViewSize.height() -
+                             MagnifierFocusTestHelper::kButtonHeight,
+                         MagnifierFocusTestHelper::kTestFocusViewSize.width(),
+                         MagnifierFocusTestHelper::kButtonHeight);
+  }
+
+  views::LabelButton* button_1_;
+  views::LabelButton* button_2_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestFocusView);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// TestTextInputView:
+
 // A view that contains a single text field for testing text input events.
 class TestTextInputView : public views::WidgetDelegateView {
  public:
@@ -46,6 +100,49 @@
   DISALLOW_COPY_AND_ASSIGN(TestTextInputView);
 };
 
+////////////////////////////////////////////////////////////////////////////////
+// MagnifierFocusTestHelper:
+
+// static
+constexpr int MagnifierFocusTestHelper::kButtonHeight;
+
+// static
+constexpr gfx::Size MagnifierFocusTestHelper::kTestFocusViewSize;
+
+void MagnifierFocusTestHelper::CreateAndShowFocusTestView(
+    const gfx::Point& location) {
+  focus_test_view_ = new TestFocusView;
+  views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
+      focus_test_view_, Shell::GetPrimaryRootWindow(),
+      gfx::Rect(location, MagnifierFocusTestHelper::kTestFocusViewSize));
+  widget->Show();
+}
+
+void MagnifierFocusTestHelper::FocusFirstButton() {
+  DCHECK(focus_test_view_);
+  focus_test_view_->button_1_->RequestFocus();
+}
+
+void MagnifierFocusTestHelper::FocusSecondButton() {
+  DCHECK(focus_test_view_);
+  focus_test_view_->button_2_->RequestFocus();
+}
+
+gfx::Rect MagnifierFocusTestHelper::GetFirstButtonBoundsInRoot() const {
+  DCHECK(focus_test_view_);
+  return GetBoundsInRoot(focus_test_view_->button_1_->GetBoundsInScreen(),
+                         focus_test_view_);
+}
+
+gfx::Rect MagnifierFocusTestHelper::GetSecondButtonBoundsInRoot() const {
+  DCHECK(focus_test_view_);
+  return GetBoundsInRoot(focus_test_view_->button_2_->GetBoundsInScreen(),
+                         focus_test_view_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// MagnifierTextInputTestHelper:
+
 void MagnifierTextInputTestHelper::CreateAndShowTextInputView(
     const gfx::Rect& bounds) {
   CreateAndShowTextInputViewInRoot(bounds, Shell::GetPrimaryRootWindow());
@@ -72,12 +169,9 @@
 }
 
 gfx::Rect MagnifierTextInputTestHelper::GetCaretBounds() {
-  gfx::Rect caret_bounds =
-      GetInputMethod()->GetTextInputClient()->GetCaretBounds();
-  gfx::Point origin = caret_bounds.origin();
-  ::wm::ConvertPointFromScreen(GetViewRootWindow(text_input_view_), &origin);
-  return gfx::Rect(origin.x(), origin.y(), caret_bounds.width(),
-                   caret_bounds.height());
+  return GetBoundsInRoot(
+      GetInputMethod()->GetTextInputClient()->GetCaretBounds(),
+      text_input_view_);
 }
 
 void MagnifierTextInputTestHelper::FocusOnTextInputView() {
diff --git a/ash/magnifier/magnifier_test_utils.h b/ash/magnifier/magnifier_test_utils.h
index 3276ed03..4284fc2 100644
--- a/ash/magnifier/magnifier_test_utils.h
+++ b/ash/magnifier/magnifier_test_utils.h
@@ -6,12 +6,14 @@
 #define ASH_MAGNIFIER_MAGNIFIER_TEST_UTILS_H_
 
 #include "base/macros.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace aura {
 class Window;
 }  // namespace aura
 
 namespace gfx {
+class Point;
 class Rect;
 }  // namespace gfx
 
@@ -21,9 +23,39 @@
 
 namespace ash {
 
+class TestFocusView;
 class TestTextInputView;
 
 // Defines a test helper for magnifiers unit tests that wants to verify their
+// behaviors in response to focus change events.
+class MagnifierFocusTestHelper {
+ public:
+  MagnifierFocusTestHelper() = default;
+  ~MagnifierFocusTestHelper() = default;
+
+  static constexpr int kButtonHeight = 20;
+  static constexpr gfx::Size kTestFocusViewSize{300, 200};
+
+  // Creates a view at |location| in the primary root window with size =
+  // |kTestFocusViewSize|. The view has two buttons, the first is positioned at
+  // the top of the view and the second at the bottom of the view. Both bottons
+  // have width = the width of |kTestFocusViewSize|, and height =
+  // |kButtonHeight|.
+  void CreateAndShowFocusTestView(const gfx::Point& location);
+
+  void FocusFirstButton();
+  void FocusSecondButton();
+
+  gfx::Rect GetFirstButtonBoundsInRoot() const;
+  gfx::Rect GetSecondButtonBoundsInRoot() const;
+
+ private:
+  TestFocusView* focus_test_view_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(MagnifierFocusTestHelper);
+};
+
+// Defines a test helper for magnifiers unit tests that wants to verify their
 // behaviors in response to text fields input and focus events.
 class MagnifierTextInputTestHelper {
  public:
diff --git a/ash/public/interfaces/docked_magnifier_controller.mojom b/ash/public/interfaces/docked_magnifier_controller.mojom
index c347ce6ca..c373adbe 100644
--- a/ash/public/interfaces/docked_magnifier_controller.mojom
+++ b/ash/public/interfaces/docked_magnifier_controller.mojom
@@ -9,21 +9,10 @@
 // Used by a client (e.g. Chrome) to notify ash of focus change events of nodes
 // in webpages.
 interface DockedMagnifierController {
-  // Sets the client that will be notified with status changes of the Docked
-  // Magnifier.
-  SetClient(DockedMagnifierClient client);
-
   // Requests that the Docked Magnifier centers its viewport around this given
   // screen point. This can be used by a client (e.g. Chrome) to notify ash of
-  // focus change events in e.g. webpages. Note that ash observes the focus
-  // change events of the text input carets in editable nodes by itself.
+  // focus change events in e.g. webpages when feature is enabled. Note that ash
+  // observes the focus change events of the text input carets in editable nodes
+  // by itself.
   CenterOnPoint(gfx.mojom.Point point_in_screen);
 };
-
-// Used by ash to notify a client (e.g. Chrome) of changes in the Docked
-// Magnifier enabled status. This relieves clients from observing changes in the
-// active user profile and the associated prefs.
-interface DockedMagnifierClient {
-  // Notifies the client with the new enabled status of the Docked Magnifier.
-  OnEnabledStatusChanged(bool enabled);
-};
\ No newline at end of file
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd
index 786edc425..91535e0 100644
--- a/ash/resources/ash_resources.grd
+++ b/ash/resources/ash_resources.grd
@@ -19,9 +19,6 @@
       <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_LEFT" file="common/window_header_shade_left_inactive.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_RIGHT" file="common/window_header_shade_right_inactive.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_TOP" file="common/window_header_shade_top_inactive.png" />
-
-      <!-- Crostini terminal images -->
-      <structure type="chrome_scaled_image" name="IDR_LOGO_CROSTINI_TERMINAL" file="cros/crostini/logo_crostini_terminal.png" />
     </structures>
   </release>
 </grit>
diff --git a/ash/rotator/screen_rotation_animator.cc b/ash/rotator/screen_rotation_animator.cc
index e3fb871..6fbf822a 100644
--- a/ash/rotator/screen_rotation_animator.cc
+++ b/ash/rotator/screen_rotation_animator.cc
@@ -115,7 +115,7 @@
     display::Display::Rotation new_rotation,
     const display::Display& display) {
   gfx::Transform inverse;
-  CHECK(CreateRotationTransform(old_rotation, new_rotation, display)
+  CHECK(CreateRotationTransform(old_rotation, new_rotation, display.bounds())
             .GetInverse(&inverse));
   return inverse;
 }
diff --git a/ash/utility/transformer_util.cc b/ash/utility/transformer_util.cc
index e5a2e37..8eb4a22 100644
--- a/ash/utility/transformer_util.cc
+++ b/ash/utility/transformer_util.cc
@@ -25,22 +25,22 @@
 
 gfx::Transform CreateRotationTransform(display::Display::Rotation old_rotation,
                                        display::Display::Rotation new_rotation,
-                                       const display::Display& display) {
+                                       const gfx::Rect& rect_to_rotate) {
   const int rotation_angle = 90 * (((new_rotation - old_rotation) + 4) % 4);
   gfx::Transform rotate;
   switch (rotation_angle) {
     case 0:
       break;
     case 90:
-      rotate.Translate(display.bounds().height(), 0);
+      rotate.Translate(rect_to_rotate.height(), 0);
       rotate.Rotate(90);
       break;
     case 180:
-      rotate.Translate(display.bounds().width(), display.bounds().height());
+      rotate.Translate(rect_to_rotate.width(), rect_to_rotate.height());
       rotate.Rotate(180);
       break;
     case 270:
-      rotate.Translate(0, display.bounds().width());
+      rotate.Translate(0, rect_to_rotate.width());
       rotate.Rotate(270);
       break;
   }
diff --git a/ash/utility/transformer_util.h b/ash/utility/transformer_util.h
index d75c5fa..bd1bd75 100644
--- a/ash/utility/transformer_util.h
+++ b/ash/utility/transformer_util.h
@@ -14,12 +14,12 @@
 
 namespace ash {
 
-// Creates rotation transform from |old_rotation| to |new_rotation| based on the
-// |display| info.
+// Creates rotation transform that rotates the |rect_to_rotate| from
+// |old_rotation| to |new_rotation|.
 ASH_EXPORT gfx::Transform CreateRotationTransform(
     display::Display::Rotation old_rotation,
     display::Display::Rotation new_rotation,
-    const display::Display& display);
+    const gfx::Rect& rect_to_rotate);
 
 }  // namespace ash
 
diff --git a/base/base_switches.cc b/base/base_switches.cc
index 62e6d3dc..7ce7380 100644
--- a/base/base_switches.cc
+++ b/base/base_switches.cc
@@ -24,25 +24,6 @@
 // Comma-separated list of feature names to enable. See also kDisableFeatures.
 const char kEnableFeatures[] = "enable-features";
 
-// Makes memory allocators keep track of their allocations and context, so a
-// detailed breakdown of memory usage can be presented in chrome://tracing when
-// the memory-infra category is enabled.
-const char kEnableHeapProfiling[]           = "enable-heap-profiling";
-
-// Report pseudo allocation traces. Pseudo traces are derived from currently
-// active trace events.
-const char kEnableHeapProfilingModePseudo[] = "";
-
-// Report native (walk the stack) allocation traces. By default pseudo stacks
-// derived from trace events are reported.
-const char kEnableHeapProfilingModeNative[] = "native";
-
-// Report per-task heap usage and churn in the task profiler.
-// Does not keep track of individual allocations unlike the default and native
-// mode. Keeps only track of summarized churn stats in the task profiler
-// (chrome://profiler).
-const char kEnableHeapProfilingTaskProfiler[] = "task-profiler";
-
 // Generates full memory crash dump.
 const char kFullMemoryCrashReport[]         = "full-memory-crash-report";
 
diff --git a/base/base_switches.h b/base/base_switches.h
index a444f09b..3425e6f 100644
--- a/base/base_switches.h
+++ b/base/base_switches.h
@@ -17,10 +17,6 @@
 extern const char kDisableLowEndDeviceMode[];
 extern const char kEnableCrashReporter[];
 extern const char kEnableFeatures[];
-extern const char kEnableHeapProfiling[];
-extern const char kEnableHeapProfilingModePseudo[];
-extern const char kEnableHeapProfilingModeNative[];
-extern const char kEnableHeapProfilingTaskProfiler[];
 extern const char kEnableLowEndDeviceMode[];
 extern const char kForceFieldTrials[];
 extern const char kFullMemoryCrashReport[];
diff --git a/base/containers/flat_map.h b/base/containers/flat_map.h
index dd0788e..2214ec3 100644
--- a/base/containers/flat_map.h
+++ b/base/containers/flat_map.h
@@ -210,9 +210,9 @@
   //
   // Assume that swap invalidates iterators and references.
 
-  void swap(flat_map& other);
+  void swap(flat_map& other) noexcept;
 
-  friend void swap(flat_map& lhs, flat_map& rhs) { lhs.swap(rhs); }
+  friend void swap(flat_map& lhs, flat_map& rhs) noexcept { lhs.swap(rhs); }
 };
 
 // ----------------------------------------------------------------------------
@@ -287,7 +287,7 @@
 // General operations.
 
 template <class Key, class Mapped, class Compare>
-void flat_map<Key, Mapped, Compare>::swap(flat_map& other) {
+void flat_map<Key, Mapped, Compare>::swap(flat_map& other) noexcept {
   tree::swap(other);
 }
 
diff --git a/base/containers/flat_tree.h b/base/containers/flat_tree.h
index 5b421accf..7856e24 100644
--- a/base/containers/flat_tree.h
+++ b/base/containers/flat_tree.h
@@ -140,7 +140,7 @@
             const key_compare& comp = key_compare());
 
   flat_tree(const flat_tree&);
-  flat_tree(flat_tree&&);
+  flat_tree(flat_tree&&) noexcept = default;
 
   flat_tree(std::vector<value_type> items,
             FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES,
@@ -301,7 +301,7 @@
   // and lexicograhpical_compare(). If the underlying container type is changed,
   // this code may need to be modified.
 
-  void swap(flat_tree& other);
+  void swap(flat_tree& other) noexcept;
 
   friend bool operator==(const flat_tree& lhs, const flat_tree& rhs) {
     return lhs.impl_.body_ == rhs.impl_.body_;
@@ -327,7 +327,7 @@
     return !(lhs > rhs);
   }
 
-  friend void swap(flat_tree& lhs, flat_tree& rhs) { lhs.swap(rhs); }
+  friend void swap(flat_tree& lhs, flat_tree& rhs) noexcept { lhs.swap(rhs); }
 
  protected:
   // Emplaces a new item into the tree that is known not to be in it. This
@@ -520,10 +520,6 @@
     const flat_tree&) = default;
 
 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
-flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) =
-    default;
-
-template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
     std::vector<value_type> items,
     FlatContainerDupes dupe_handling,
@@ -934,7 +930,7 @@
 
 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::swap(
-    flat_tree& other) {
+    flat_tree& other) noexcept {
   std::swap(impl_, other.impl_);
 }
 
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.h b/base/trace_event/heap_profiler_allocation_context_tracker.h
index 9bd656d..da03b7f6 100644
--- a/base/trace_event/heap_profiler_allocation_context_tracker.h
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.h
@@ -15,11 +15,25 @@
 namespace base {
 namespace trace_event {
 
-// The allocation context tracker keeps track of thread-local context for heap
-// profiling. It includes a pseudo stack of trace events. On every allocation
-// the tracker provides a snapshot of its context in the form of an
-// |AllocationContext| that is to be stored together with the allocation
-// details.
+// AllocationContextTracker is a thread-local object. Its main purpose is to
+// keep track of a pseudo stack of trace events. Chrome has been instrumented
+// with lots of `TRACE_EVENT` macros. These trace events push their name to a
+// thread-local stack when they go into scope, and pop when they go out of
+// scope, if all of the following conditions have been met:
+//
+//  * A trace is being recorded.
+//  * The category of the event is enabled in the trace config.
+//  * Heap profiling is enabled (with the `--enable-heap-profiling` flag).
+//
+// This means that allocations that occur before tracing is started will not
+// have backtrace information in their context.
+//
+// AllocationContextTracker also keeps track of some thread state not related to
+// trace events. See |AllocationContext|.
+//
+// A thread-local instance of the context tracker is initialized lazily when it
+// is first accessed. This might be because a trace event pushed or popped, or
+// because `GetContextSnapshot()` was called when an allocation occurred
 class BASE_EXPORT AllocationContextTracker {
  public:
   enum class CaptureMode : int32_t {
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 7f35a92..f6cc832 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -206,44 +206,6 @@
   g_memory_dump_manager_for_testing = nullptr;
 }
 
-// static
-HeapProfilingMode MemoryDumpManager::GetHeapProfilingModeFromCommandLine() {
-  if (!CommandLine::InitializedForCurrentProcess() ||
-      !CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableHeapProfiling)) {
-    return kHeapProfilingModeDisabled;
-  }
-#if BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
-  std::string profiling_mode =
-      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          switches::kEnableHeapProfiling);
-  if (profiling_mode == switches::kEnableHeapProfilingTaskProfiler)
-    return kHeapProfilingModeTaskProfiler;
-  if (profiling_mode == switches::kEnableHeapProfilingModePseudo)
-    return kHeapProfilingModePseudo;
-  if (profiling_mode == switches::kEnableHeapProfilingModeNative)
-    return kHeapProfilingModeNative;
-#endif  // BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
-  return kHeapProfilingModeInvalid;
-}
-
-void MemoryDumpManager::EnableHeapProfilingIfNeeded() {
-#if BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
-  HeapProfilingMode profiling_mode = GetHeapProfilingModeFromCommandLine();
-  if (IsHeapProfilingModeEnabled(profiling_mode)) {
-    EnableHeapProfiling(profiling_mode);
-  } else {
-    if (profiling_mode == kHeapProfilingModeInvalid) {
-      // Heap profiling is misconfigured, disable it permanently.
-      EnableHeapProfiling(kHeapProfilingModeDisabled);
-    }
-  }
-#else
-  // Heap profiling is unsupported, disable it permanently.
-  EnableHeapProfiling(kHeapProfilingModeDisabled);
-#endif  // BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
-}
-
 bool MemoryDumpManager::EnableHeapProfiling(HeapProfilingMode profiling_mode) {
   AutoLock lock(lock_);
 #if BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
@@ -341,7 +303,6 @@
     request_dump_function_ = request_dump_function;
     is_coordinator_ = is_coordinator;
   }
-  EnableHeapProfilingIfNeeded();
 
 // Enable the core dump providers.
 #if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index d6237fd..072a7d6 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -131,15 +131,6 @@
   void CreateProcessDump(const MemoryDumpRequestArgs& args,
                          const ProcessMemoryDumpCallback& callback);
 
-  // Returns the heap profiling mode configured on the command-line, if any.
-  // If heap profiling is configured but not supported by this binary, or if an
-  // invalid mode is specified, then kHeapProfilingInvalid is returned.
-  static HeapProfilingMode GetHeapProfilingModeFromCommandLine();
-
-  // Enable heap profiling if supported, and kEnableHeapProfiling command line
-  // is specified.
-  void EnableHeapProfilingIfNeeded();
-
   // Enable heap profiling with specified |profiling_mode|.
   // Use kHeapProfilingModeDisabled to disable, but it can't be re-enabled then.
   // Returns true if mode has been *changed* to the desired |profiling_mode|.
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index de98f1d..e92045ed 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -961,54 +961,6 @@
 }
 #endif  //  BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
 
-TEST_F(MemoryDumpManagerTest, EnableHeapProfilingIfNeeded) {
-  MockMemoryDumpProvider mdp1;
-  MemoryDumpProvider::Options supported_options;
-  supported_options.supports_heap_profiling = true;
-  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), supported_options);
-
-  // Should be noop.
-  mdm_->EnableHeapProfilingIfNeeded();
-  ASSERT_EQ(AllocationContextTracker::CaptureMode::DISABLED,
-            AllocationContextTracker::capture_mode());
-  mdm_->EnableHeapProfilingIfNeeded();
-  ASSERT_EQ(AllocationContextTracker::CaptureMode::DISABLED,
-            AllocationContextTracker::capture_mode());
-
-#if BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
-  testing::InSequence sequence;
-  EXPECT_CALL(mdp1, OnHeapProfilingEnabled(true)).Times(1);
-  EXPECT_CALL(mdp1, OnHeapProfilingEnabled(false)).Times(1);
-
-  CommandLine* cmdline = CommandLine::ForCurrentProcess();
-  cmdline->AppendSwitchASCII(switches::kEnableHeapProfiling, "");
-  mdm_->EnableHeapProfilingIfNeeded();
-  RunLoop().RunUntilIdle();
-  ASSERT_EQ(AllocationContextTracker::CaptureMode::PSEUDO_STACK,
-            AllocationContextTracker::capture_mode());
-  EXPECT_TRUE(mdm_->EnableHeapProfiling(kHeapProfilingModeDisabled));
-  RunLoop().RunUntilIdle();
-  ASSERT_EQ(AllocationContextTracker::CaptureMode::DISABLED,
-            AllocationContextTracker::capture_mode());
-  EXPECT_FALSE(mdm_->EnableHeapProfiling(kHeapProfilingModeBackground));
-  ASSERT_EQ(AllocationContextTracker::CaptureMode::DISABLED,
-            AllocationContextTracker::capture_mode());
-#endif  //  BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
-}
-
-TEST_F(MemoryDumpManagerTest, EnableHeapProfilingIfNeededUnsupported) {
-#if BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
-  ASSERT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModeDisabled);
-  CommandLine* cmdline = CommandLine::ForCurrentProcess();
-  cmdline->AppendSwitchASCII(switches::kEnableHeapProfiling, "unsupported");
-  mdm_->EnableHeapProfilingIfNeeded();
-  EXPECT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModeInvalid);
-#else
-  mdm_->EnableHeapProfilingIfNeeded();
-  EXPECT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModeInvalid);
-#endif  //  BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
-}
-
 // Mock MDP class that tests if the number of OnMemoryDump() calls are expected.
 // It is implemented without gmocks since EXPECT_CALL implementation is slow
 // when there are 1000s of instances, as required in
diff --git a/build/fuchsia/sdk.sha1 b/build/fuchsia/sdk.sha1
index b279f1e..02edeb5d 100644
--- a/build/fuchsia/sdk.sha1
+++ b/build/fuchsia/sdk.sha1
@@ -1 +1 @@
-3a1662dfbcb3ad44bbc10a70c7424da462c4ba0d
+4ff493298d2c801c30489dff4786321d7f698031
\ No newline at end of file
diff --git a/cc/paint/BUILD.gn b/cc/paint/BUILD.gn
index 535acba..ed7ce8e7 100644
--- a/cc/paint/BUILD.gn
+++ b/cc/paint/BUILD.gn
@@ -67,6 +67,8 @@
     "paint_typeface.h",
     "paint_typeface_transfer_cache_entry.cc",
     "paint_typeface_transfer_cache_entry.h",
+    "path_transfer_cache_entry.cc",
+    "path_transfer_cache_entry.h",
     "raw_memory_transfer_cache_entry.cc",
     "raw_memory_transfer_cache_entry.h",
     "record_paint_canvas.cc",
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
index 2e7dbe0..b997a58 100644
--- a/cc/paint/paint_op_reader.cc
+++ b/cc/paint/paint_op_reader.cc
@@ -14,6 +14,7 @@
 #include "cc/paint/paint_op_buffer.h"
 #include "cc/paint/paint_shader.h"
 #include "cc/paint/paint_typeface_transfer_cache_entry.h"
+#include "cc/paint/path_transfer_cache_entry.h"
 #include "cc/paint/transfer_cache_deserialize_helper.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "third_party/skia/include/core/SkRRect.h"
@@ -213,21 +214,17 @@
 }
 
 void PaintOpReader::Read(SkPath* path) {
-  AlignMemory(4);
+  uint32_t transfer_cache_entry_id;
+  ReadSimple(&transfer_cache_entry_id);
   if (!valid_)
     return;
-
-  // This is assumed safe from TOCTOU violations as the SkPath deserializing
-  // function uses an SkRBuffer which reads each piece of memory once much
-  // like PaintOpReader does.  Additionally, paths are later validated in
-  // PaintOpBuffer.
-  size_t read_bytes =
-      path->readFromMemory(const_cast<const char*>(memory_), remaining_bytes_);
-  if (!read_bytes)
-    SetInvalid();
-
-  memory_ += read_bytes;
-  remaining_bytes_ -= read_bytes;
+  auto* entry = transfer_cache_->GetEntryAs<ServicePathTransferCacheEntry>(
+      transfer_cache_entry_id);
+  if (entry) {
+    *path = entry->path();
+  } else {
+    valid_ = false;
+  }
 }
 
 void PaintOpReader::Read(PaintFlags* flags) {
diff --git a/cc/paint/paint_op_writer.cc b/cc/paint/paint_op_writer.cc
index 697a9ea..6d40039 100644
--- a/cc/paint/paint_op_writer.cc
+++ b/cc/paint/paint_op_writer.cc
@@ -11,6 +11,7 @@
 #include "cc/paint/paint_op_buffer_serializer.h"
 #include "cc/paint/paint_shader.h"
 #include "cc/paint/paint_typeface_transfer_cache_entry.h"
+#include "cc/paint/path_transfer_cache_entry.h"
 #include "cc/paint/transfer_cache_serialize_helper.h"
 #include "third_party/skia/include/core/SkSerialProcs.h"
 #include "third_party/skia/include/core/SkTextBlob.h"
@@ -169,16 +170,13 @@
 }
 
 void PaintOpWriter::Write(const SkPath& path) {
-  AlignMemory(4);
-  size_t bytes = path.writeToMemory(nullptr);
-  EnsureBytes(bytes);
-  if (!valid_)
-    return;
-
-  size_t bytes_written = path.writeToMemory(memory_);
-  DCHECK_LE(bytes_written, bytes);
-  memory_ += bytes;
-  remaining_bytes_ -= bytes;
+  auto id = path.getGenerationID();
+  auto locked = transfer_cache_->LockEntry(TransferCacheEntryType::kPath, id);
+  if (!locked) {
+    transfer_cache_->CreateEntry(ClientPathTransferCacheEntry(path));
+    transfer_cache_->AssertLocked(TransferCacheEntryType::kPath, id);
+  }
+  Write(id);
 }
 
 void PaintOpWriter::Write(const PaintFlags& flags) {
diff --git a/cc/paint/path_transfer_cache_entry.cc b/cc/paint/path_transfer_cache_entry.cc
new file mode 100644
index 0000000..c149010
--- /dev/null
+++ b/cc/paint/path_transfer_cache_entry.cc
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/path_transfer_cache_entry.h"
+
+namespace cc {
+
+ClientPathTransferCacheEntry::ClientPathTransferCacheEntry(const SkPath& path)
+    : path_(path) {
+  size_ = path_.writeToMemory(nullptr);
+}
+
+ClientPathTransferCacheEntry::~ClientPathTransferCacheEntry() = default;
+
+uint32_t ClientPathTransferCacheEntry::Id() const {
+  return path_.getGenerationID();
+}
+
+size_t ClientPathTransferCacheEntry::SerializedSize() const {
+  return size_;
+}
+
+bool ClientPathTransferCacheEntry::Serialize(base::span<uint8_t> data) const {
+  DCHECK_EQ(data.size(), size_);
+
+  size_t bytes_written = path_.writeToMemory(data.data());
+  CHECK_LE(bytes_written, size_);
+  return true;
+}
+
+ServicePathTransferCacheEntry::ServicePathTransferCacheEntry() = default;
+
+ServicePathTransferCacheEntry::~ServicePathTransferCacheEntry() = default;
+
+size_t ServicePathTransferCacheEntry::CachedSize() const {
+  return size_;
+}
+
+bool ServicePathTransferCacheEntry::Deserialize(
+    GrContext* context,
+    base::span<const uint8_t> data) {
+  size_t read_bytes = path_.readFromMemory(data.data(), data.size());
+  // Invalid path.
+  if (read_bytes == 0)
+    return false;
+  if (read_bytes > data.size())
+    return false;
+  size_ = read_bytes;
+
+  return true;
+}
+
+}  // namespace cc
diff --git a/cc/paint/path_transfer_cache_entry.h b/cc/paint/path_transfer_cache_entry.h
new file mode 100644
index 0000000..b1282e3c
--- /dev/null
+++ b/cc/paint/path_transfer_cache_entry.h
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_PATH_TRANSFER_CACHE_ENTRY_H_
+#define CC_PAINT_PATH_TRANSFER_CACHE_ENTRY_H_
+
+#include "base/containers/span.h"
+#include "cc/paint/paint_export.h"
+#include "cc/paint/transfer_cache_entry.h"
+#include "third_party/skia/include/core/SkPath.h"
+
+namespace cc {
+
+class CC_PAINT_EXPORT ClientPathTransferCacheEntry
+    : public ClientTransferCacheEntryBase<TransferCacheEntryType::kPath> {
+ public:
+  explicit ClientPathTransferCacheEntry(const SkPath& path);
+  ~ClientPathTransferCacheEntry() final;
+  uint32_t Id() const final;
+  size_t SerializedSize() const final;
+  bool Serialize(base::span<uint8_t> data) const final;
+
+ private:
+  SkPath path_;
+  size_t size_ = 0u;
+};
+
+class CC_PAINT_EXPORT ServicePathTransferCacheEntry
+    : public ServiceTransferCacheEntryBase<TransferCacheEntryType::kPath> {
+ public:
+  ServicePathTransferCacheEntry();
+  ~ServicePathTransferCacheEntry() final;
+  size_t CachedSize() const final;
+  bool Deserialize(GrContext* context, base::span<const uint8_t> data) final;
+
+  const SkPath& path() const { return path_; }
+
+ private:
+  SkPath path_;
+  size_t size_ = 0;
+};
+
+}  // namespace cc
+
+#endif  // CC_PAINT_PATH_TRANSFER_CACHE_ENTRY_H_
diff --git a/cc/paint/transfer_cache_entry.cc b/cc/paint/transfer_cache_entry.cc
index 46252c18..66c9622 100644
--- a/cc/paint/transfer_cache_entry.cc
+++ b/cc/paint/transfer_cache_entry.cc
@@ -10,6 +10,7 @@
 #include "cc/paint/color_space_transfer_cache_entry.h"
 #include "cc/paint/image_transfer_cache_entry.h"
 #include "cc/paint/paint_typeface_transfer_cache_entry.h"
+#include "cc/paint/path_transfer_cache_entry.h"
 #include "cc/paint/raw_memory_transfer_cache_entry.h"
 
 namespace cc {
@@ -25,6 +26,8 @@
       return std::make_unique<ServicePaintTypefaceTransferCacheEntry>();
     case TransferCacheEntryType::kColorSpace:
       return std::make_unique<ServiceColorSpaceTransferCacheEntry>();
+    case TransferCacheEntryType::kPath:
+      return std::make_unique<ServicePathTransferCacheEntry>();
   }
 
   return nullptr;
diff --git a/cc/paint/transfer_cache_entry.h b/cc/paint/transfer_cache_entry.h
index 9ecde14a..dca7b96e 100644
--- a/cc/paint/transfer_cache_entry.h
+++ b/cc/paint/transfer_cache_entry.h
@@ -24,8 +24,9 @@
   kImage,
   kPaintTypeface,
   kColorSpace,
+  kPath,
   // Add new entries above this line, make sure to update kLast.
-  kLast = kColorSpace,
+  kLast = kPath,
 };
 
 // An interface used on the client to serialize a transfer cache entry
diff --git a/cc/tiles/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc
index 648f171..6a52e91 100644
--- a/cc/tiles/software_image_decode_cache.cc
+++ b/cc/tiles/software_image_decode_cache.cc
@@ -554,7 +554,21 @@
       std::max(lifetime_max_items_in_cache_, decoded_images_.size());
   for (auto it = decoded_images_.rbegin();
        decoded_images_.size() > limit && it != decoded_images_.rend();) {
-    EraseCacheEntry(&it);
+    if (it->second->ref_count != 0) {
+      ++it;
+      continue;
+    }
+
+    const CacheKey& key = it->first;
+    auto vector_it = frame_key_to_image_keys_.find(key.frame_key());
+    auto item_it =
+        std::find(vector_it->second.begin(), vector_it->second.end(), key);
+    DCHECK(item_it != vector_it->second.end());
+    vector_it->second.erase(item_it);
+    if (vector_it->second.empty())
+      frame_key_to_image_keys_.erase(vector_it);
+
+    it = decoded_images_.Erase(it);
   }
 }
 
@@ -659,86 +673,12 @@
 SoftwareImageDecodeCache::CacheEntry* SoftwareImageDecodeCache::AddCacheEntry(
     const CacheKey& key) {
   lock_.AssertAcquired();
-
   frame_key_to_image_keys_[key.frame_key()].push_back(key);
-
-  PaintImage::ContentId content_id = key.frame_key().content_id();
-  content_id_to_cache_keys_[content_id].insert(key);
-  ContentIdSet& content_ids_for_stable_id =
-      stable_id_to_content_ids_[key.stable_id()];
-  content_ids_for_stable_id.insert(content_id);
-
   auto it = decoded_images_.Put(key, std::make_unique<CacheEntry>());
   it->second.get()->mark_cached();
-
-  // If we have more than two content ids for this stable id, then try to erase
-  // all images for all content ids except for the most recent two (and also
-  // |key|'s content id, in case it is not one of the most recent two).
-  if (content_ids_for_stable_id.size() > 2) {
-    ContentIdSet content_ids_to_remove = content_ids_for_stable_id;
-    content_ids_to_remove.erase(*content_ids_to_remove.rbegin());
-    content_ids_to_remove.erase(*content_ids_to_remove.rbegin());
-    content_ids_to_remove.erase(content_id);
-    for (auto content_id_to_erase : content_ids_to_remove) {
-      CacheKeySet cache_keys_to_remove =
-          content_id_to_cache_keys_[content_id_to_erase];
-      for (const CacheKey& key : cache_keys_to_remove) {
-        auto found = decoded_images_.Peek(key);
-        DCHECK(found != decoded_images_.end());
-        auto found_reversed = std::make_reverse_iterator(found);
-        EraseCacheEntry(&found_reversed);
-      }
-    }
-  }
-
   return it->second.get();
 }
 
-void SoftwareImageDecodeCache::EraseCacheEntry(
-    ImageMRUCache::reverse_iterator* it) {
-  if ((*it)->second->ref_count != 0) {
-    ++(*it);
-    return;
-  }
-  const CacheKey& key = (*it)->first;
-  PaintImage::ContentId content_id = key.frame_key().content_id();
-  PaintImage::Id stable_id = key.stable_id();
-
-  // Remove from |content_id_to_cache_keys_|.
-  auto found_cache_key_set = content_id_to_cache_keys_.find(content_id);
-  DCHECK(found_cache_key_set != content_id_to_cache_keys_.end());
-  found_cache_key_set->second.erase(key);
-  // If this erases the last entry for |content_id|, then...
-  if (found_cache_key_set->second.empty()) {
-    // Erase |content_id| from |content_id_to_cache_keys_|.
-    content_id_to_cache_keys_.erase(found_cache_key_set);
-    // Erase |content_id| from |stable_id_to_content_ids_[stable_id]|.
-    auto found_content_id_set = stable_id_to_content_ids_.find(stable_id);
-    DCHECK(found_content_id_set != stable_id_to_content_ids_.end());
-    auto found_content_id = found_content_id_set->second.find(content_id);
-    DCHECK(found_content_id != found_content_id_set->second.end());
-    found_content_id_set->second.erase(found_content_id);
-    // If that empties |stable_id_to_content_ids_[stable_id]|, then erase
-    // |stable_id| from |stable_id_to_content_ids_|.
-    if (found_content_id_set->second.empty()) {
-      stable_id_to_content_ids_.erase(found_content_id_set);
-    }
-  }
-
-  // Remove from |frame_key_to_image_keys_|.
-  auto vector_it = frame_key_to_image_keys_.find(key.frame_key());
-  auto item_it =
-      std::find(vector_it->second.begin(), vector_it->second.end(), key);
-  DCHECK(item_it != vector_it->second.end());
-  vector_it->second.erase(item_it);
-  if (vector_it->second.empty())
-    frame_key_to_image_keys_.erase(vector_it);
-
-  // Remove from the MRU cache.
-  *it = decoded_images_.Erase(*it);
-  return;
-}
-
 // MemoryBudget ----------------------------------------------------------------
 SoftwareImageDecodeCache::MemoryBudget::MemoryBudget(size_t limit_bytes)
     : limit_bytes_(limit_bytes), current_usage_bytes_(0u) {}
diff --git a/cc/tiles/software_image_decode_cache.h b/cc/tiles/software_image_decode_cache.h
index 5b0534f..0fa379c2 100644
--- a/cc/tiles/software_image_decode_cache.h
+++ b/cc/tiles/software_image_decode_cache.h
@@ -8,9 +8,7 @@
 #include <stdint.h>
 
 #include <memory>
-#include <set>
 #include <unordered_map>
-#include <unordered_set>
 
 #include "base/containers/mru_cache.h"
 #include "base/memory/memory_coordinator_client.h"
@@ -93,8 +91,6 @@
 
   using ImageMRUCache = base::
       HashingMRUCache<CacheKey, std::unique_ptr<CacheEntry>, CacheKeyHash>;
-  using ContentIdSet = std::set<PaintImage::ContentId>;
-  using CacheKeySet = std::unordered_set<CacheKey, CacheKeyHash>;
 
   // Actually decode the image. Note that this function can (and should) be
   // called with no lock acquired, since it can do a lot of work. Note that it
@@ -126,10 +122,6 @@
                                            DecodeTaskType type);
 
   CacheEntry* AddCacheEntry(const CacheKey& key);
-  // If the entry at |*it| is not in use, erase it and update |*it| to point to
-  // the next entry. If unable to erase the entry, update |*it| to point to the
-  // next entry.
-  void EraseCacheEntry(ImageMRUCache::reverse_iterator* it);
 
   void DecodeImageIfNecessary(const CacheKey& key,
                               const PaintImage& paint_image,
@@ -148,11 +140,6 @@
   // Decoded images and ref counts (predecode path).
   ImageMRUCache decoded_images_;
 
-  // Additional tracking of all entries in |decoded_images_| by static id and
-  // by content id. Updated only in AddCacheEntry and EraseCacheEntry.
-  std::map<PaintImage::Id, ContentIdSet> stable_id_to_content_ids_;
-  std::map<PaintImage::ContentId, CacheKeySet> content_id_to_cache_keys_;
-
   // A map of PaintImage::FrameKey to the ImageKeys for cached decodes of this
   // PaintImage.
   std::unordered_map<PaintImage::FrameKey,
diff --git a/cc/tiles/software_image_decode_cache_unittest.cc b/cc/tiles/software_image_decode_cache_unittest.cc
index 58fc5073..c9f8c5a 100644
--- a/cc/tiles/software_image_decode_cache_unittest.cc
+++ b/cc/tiles/software_image_decode_cache_unittest.cc
@@ -1742,7 +1742,9 @@
   cache.DrawWithImageFinished(draw_image, decoded_draw_image);
 }
 
-TEST(SoftwareImageDecodeCacheTest, ContentIdCaching) {
+// TODO(ccameron): Re-enable this when the root cause of crashes is discovered.
+// https://crbug.com/791828
+TEST(SoftwareImageDecodeCacheTest, DISABLED_ContentIdCaching) {
   TestSoftwareImageDecodeCache cache;
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 33324a6..e09e525 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -1558,6 +1558,11 @@
     const ResourcePool::InUsePoolResource& resource =
         tile->draw_info().GetResource();
 
+    // Update requirements first so that if the tile has become required
+    // it will force a redraw.
+    if (pending_tile_requirements_dirty_)
+      tile->tiling()->UpdateRequiredStatesOnTile(tile);
+
     if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY ||
         raster_buffer_provider_->IsResourceReadyToDraw(resource)) {
       tile->draw_info().set_resource_ready_for_draw();
@@ -1569,8 +1574,6 @@
     // TODO(ericrk): If a tile in our list no longer has valid tile priorities,
     // it may still report that it is required, and unnecessarily delay
     // activation. crbug.com/687265
-    if (pending_tile_requirements_dirty_)
-      tile->tiling()->UpdateRequiredStatesOnTile(tile);
     if (tile->required_for_activation())
       required_for_activation.push_back(&resource);
     if (tile->required_for_draw())
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 8c9a5f4..67b0a31 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -2291,7 +2291,6 @@
               run_loop.Quit();
               return 1;
             }));
-    host_impl()->tile_manager()->DidModifyTilePriorities();
     host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
     run_loop.Run();
   }
@@ -2321,7 +2320,6 @@
   // will cause a test failure.
   base::RunLoop run_loop;
 
-  host_impl()->tile_manager()->DidModifyTilePriorities();
   host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
   EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate())
       .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
@@ -2356,7 +2354,6 @@
               run_loop.Quit();
               return 1;
             }));
-    host_impl()->tile_manager()->DidModifyTilePriorities();
     host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
     run_loop.Run();
   }
@@ -2386,7 +2383,6 @@
   // will cause a test failure.
   base::RunLoop run_loop;
 
-  host_impl()->tile_manager()->DidModifyTilePriorities();
   host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
   EXPECT_CALL(MockHostImpl(), NotifyReadyToDraw())
       .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
@@ -2401,7 +2397,6 @@
   SetupTreesWithPendingTreeTiles();
 
   base::RunLoop run_loop;
-  host_impl()->tile_manager()->DidModifyTilePriorities();
   host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
   EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate())
       .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
@@ -2413,6 +2408,92 @@
   EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToActivate());
 }
 
+TEST_F(TileManagerReadyToDrawTest, TilePrioritiesUpdated) {
+  // Use smoothness as that's a mode in which we wait on resources to be
+  // ready instead of marking them ready immediately.
+  host_impl()->SetTreePriority(SMOOTHNESS_TAKES_PRIORITY);
+  gfx::Size very_small(1, 1);
+  host_impl()->SetViewportSize(very_small);
+
+  gfx::Size layer_bounds(1000, 1000);
+  SetupDefaultTrees(layer_bounds);
+
+  // Run until all tile tasks are complete, but don't let any draw callbacks
+  // finish.
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(MockHostImpl(), NotifyAllTileTasksCompleted())
+        .WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); }));
+
+    // Until we activate our ready to draw callback, treat all resources as not
+    // ready to draw.
+    EXPECT_CALL(*mock_raster_buffer_provider(),
+                IsResourceReadyToDraw(testing::_))
+        .WillRepeatedly(Return(false));
+    EXPECT_CALL(*mock_raster_buffer_provider(), SetReadyToDrawCallback(_, _, _))
+        .WillRepeatedly(Return(1));
+    host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+    run_loop.Run();
+  }
+
+  // Inspect the current state of tiles in this world of cpu done but gpu
+  // not ready yet.
+  size_t orig_num_required = 0;
+  size_t orig_num_prepaint = 0;
+  std::vector<Tile*> prepaint_tiles;
+  for (auto* tile : host_impl()->tile_manager()->AllTilesForTesting()) {
+    if (tile->draw_info().has_resource()) {
+      if (tile->is_prepaint()) {
+        orig_num_prepaint++;
+        prepaint_tiles.push_back(tile);
+      } else {
+        orig_num_required++;
+      }
+    }
+  }
+
+  // Verify that there exist some prepaint tiles here.
+  EXPECT_GT(orig_num_prepaint, 0u);
+  EXPECT_GT(orig_num_required, 0u);
+
+  host_impl()->SetViewportSize(layer_bounds);
+  host_impl()->active_tree()->UpdateDrawProperties();
+  host_impl()->pending_tree()->UpdateDrawProperties();
+
+  // Rerun prepare tiles.
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(MockHostImpl(), NotifyAllTileTasksCompleted())
+        .WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); }));
+    host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+    run_loop.Run();
+  }
+
+  // Make sure tiles priorities are updated.
+  size_t final_num_required = 0;
+  size_t final_num_prepaint = 0;
+  bool found_one_prepaint_to_required_transition = false;
+  for (auto* tile : host_impl()->tile_manager()->AllTilesForTesting()) {
+    if (tile->draw_info().has_resource()) {
+      if (tile->is_prepaint()) {
+        final_num_prepaint++;
+      } else {
+        final_num_required++;
+        if (std::find(prepaint_tiles.begin(), prepaint_tiles.end(), tile) !=
+            prepaint_tiles.end()) {
+          found_one_prepaint_to_required_transition = true;
+        }
+      }
+    }
+  }
+
+  // Tile priorities should be updated and we should have more required
+  // and fewer prepaint now that the viewport has changed.
+  EXPECT_GT(final_num_required, orig_num_required);
+  EXPECT_LT(final_num_prepaint, orig_num_prepaint);
+  EXPECT_TRUE(found_one_prepaint_to_required_transition);
+}
+
 void UpdateVisibleRect(FakePictureLayerImpl* layer,
                        const gfx::Rect visible_rect) {
   PictureLayerTilingSet* tiling_set = layer->tilings();
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 32cc59dc..1cb74744 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1449,6 +1449,7 @@
 void LayerTreeHostImpl::DidModifyTilePriorities() {
   // Mark priorities as dirty and schedule a PrepareTiles().
   tile_priorities_dirty_ = true;
+  tile_manager_.DidModifyTilePriorities();
   client_->SetNeedsPrepareTilesOnImplThread();
 }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index aa8893231..b0bd7def0 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=68
 MINOR=0
-BUILD=3402
+BUILD=3405
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
index 89900ed..3164f27 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -399,16 +399,6 @@
     }
 
     @Override
-    public boolean shouldHideAndroidBrowserControls() {
-        // Account for the Chrome Home bottom sheet when making this decision. If the bottom sheet
-        // is being used, Contextual Search will show in place of the toolbar. This means that the
-        // Android view needs to be hidden immediately when the Contextual Search bar starts
-        // peeking.
-        return (mActivity != null && mActivity.getBottomSheet() != null && isShowing())
-                || super.shouldHideAndroidBrowserControls();
-    }
-
-    @Override
     protected boolean doesMatchFullWidthCriteria(float containerWidth) {
         if (!mOverrideIsFullWidthSizePanelForTesting && mActivity != null
                 && mActivity.getBottomSheet() != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
index ebae316..b0f800d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
@@ -67,6 +67,9 @@
     /** Whether composited UI is currently showing (such as Contextual Search). */
     private boolean mIsCompositedUIShowing;
 
+    /** Whether the bottom sheet is temporarily suppressed. */
+    private boolean mIsSuppressed;
+
     /**
      * Build a new controller of the bottom sheet.
      * @param tabModelSelector A tab model selector to track events on tabs open in the browser.
@@ -141,11 +144,10 @@
             public void onSceneChange(Layout layout) {
                 // If the tab did not change, reshow the existing content. Once the tab actually
                 // changes, existing content and requests will be cleared.
-                if (canShowInLayout(layout) && mWasShownForCurrentTab && !mBottomSheet.isSheetOpen()
-                        && mBottomSheet.getCurrentSheetContent() != null) {
-                    mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true);
+                if (canShowInLayout(layout)) {
+                    unsuppressSheet();
                 } else if (!canShowInLayout(layout)) {
-                    mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_HIDDEN, false);
+                    suppressSheet(StateChangeReason.COMPOSITED_UI);
                 }
             }
         });
@@ -187,29 +189,19 @@
         // TODO(mdjones): This should be changed to a generic OverlayPanel observer.
         if (contextualSearchManager != null) {
             contextualSearchManager.addObserver(new ContextualSearchObserver() {
-                /** Whether the bottom sheet was showing prior to contextual search appearing. */
-                private boolean mWasSheetShowing;
-
                 @Override
                 public void onShowContextualSearch(
                         @Nullable GSAContextDisplaySelection selectionContext) {
                     // Contextual Search can call this method more than once per show event.
                     if (mIsCompositedUIShowing) return;
-                    mWasSheetShowing = mBottomSheet.getSheetState() == BottomSheet.SHEET_STATE_PEEK;
                     mIsCompositedUIShowing = true;
-                    mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_HIDDEN, false,
-                            BottomSheet.StateChangeReason.COMPOSITED_UI);
+                    suppressSheet(StateChangeReason.COMPOSITED_UI);
                 }
 
                 @Override
                 public void onHideContextualSearch() {
                     mIsCompositedUIShowing = false;
-                    if (mBottomSheet.getCurrentSheetContent() != null && mWasSheetShowing) {
-                        mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true);
-                    } else {
-                        showNextContent();
-                    }
-                    mWasSheetShowing = false;
+                    unsuppressSheet();
                 }
             });
         }
@@ -220,6 +212,35 @@
     }
 
     /**
+     * Temporarily suppress the bottom sheet while other UI is showing. This will not itself change
+     * the content displayed by the sheet.
+     * @param reason The reason the sheet was suppressed.
+     */
+    private void suppressSheet(@StateChangeReason int reason) {
+        mIsSuppressed = true;
+        mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_HIDDEN, false, reason);
+    }
+
+    /**
+     * Unsuppress the bottom sheet. This may or may not affect the sheet depending on the state of
+     * the browser (i.e. the tab switcher may be showing).
+     */
+    private void unsuppressSheet() {
+        if (!mIsSuppressed || !canShowInLayout(mLayoutManager.getActiveLayout())
+                || !mWasShownForCurrentTab || isOtherUIObscuring()) {
+            return;
+        }
+        mIsSuppressed = false;
+
+        if (mBottomSheet.getCurrentSheetContent() != null) {
+            mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true);
+        } else {
+            // In the event the previous content was hidden, try to show the next one.
+            showNextContent();
+        }
+    }
+
+    /**
      * @return The {@link BottomSheet} controlled by this class.
      */
     public BottomSheet getBottomSheet() {
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index bbdccf2e..32870e3 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-68.0.3401.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-68.0.3402.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 902a7fdd..486087ee 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -129,9 +129,15 @@
   </message>
 
   <!-- MultiDevice setup dialog. -->
-  <message name="IDS_MULTIDEVICE_SETUP_DIALOG_TITLE" desc="Title for the MultiDevice setup dialog, which allows users to enable features which involve communication between multiple devices (e.g., a Chromebook and a phone).">
+  <message name="IDS_MULTIDEVICE_SETUP_DIALOG_TITLE" desc="Title for the MultiDevice setup dialog, which allows users to enable features which involve communication between multiple devices (e.g., a Chromebook and a phone)." translateable="false">
     MultiDevice Setup
   </message>
+  <message name="IDS_MULTIDEVICE_SETUP_ACCEPT_LABEL" desc="Label for button to accept conditions and begin MultiDevice setup workflow.">
+    Accept
+  </message>
+  <message name="IDS_MULTIDEVICE_SETUP_TRY_AGAIN_LABEL" desc="Label for button to retry setup upon failure.">
+    Try again
+  </message>
 
   <!-- File Manager -->
   <message name="IDS_FILE_SYSTEM_PROVIDER_UNRESPONSIVE_WARNING" desc="A warning shown in a notification that an operation is taking longer than expected.">
@@ -1299,6 +1305,9 @@
   <message name="IDS_FILE_BROWSER_FAILED_SPACE_INFO" desc="Menu item, saying that FileBrowser is failed to retrieve space information.">
     Failed to retrieve space info
   </message>
+  <message name="IDS_FILE_BROWSER_SEE_MENU_FOR_ACTIONS" desc="Text to be used by screen reader to indicate users that there are more options on the action bar.">
+    More options available on the action bar. Press Alt + A to focus the action bar.
+  </message>
 
 <!-- Common for Audio player and Media player -->
   <message name="IDS_MEDIA_PLAYER_PLAY_BUTTON_LABEL" desc="Label for the Play button of media players (audio player / video player).">
@@ -3595,7 +3604,7 @@
     Install critical update
   </message>
   <message name="IDS_ENCRYPTION_MIGRATION_READY_DESCRIPTION" desc="Description shown in encryption migration screen, which asks the user to install an OS update.">
-    To download and use Android apps, first you need to install this required update. While your Your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> is updating, you can’t use it. After installation completes, your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> will restart.
+    To download and use Android apps, first you need to install this required update. While your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> is updating, you can’t use it. After installation completes, your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> will restart.
   </message>
   <message name="IDS_ENCRYPTION_MIGRATION_MIGRATING_TITLE" desc="Title shown in encryption migration screen when the migration is ongoing.">
     Installing OS update
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index c98b318..dbe7888 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4884,11 +4884,6 @@
         usage statistics
       </message>
 
-      <!-- Unimplemented Flags Infobar-->
-      <message name="IDS_UNIMPLEMENTED_FLAGS_WARNING_MESSAGE" desc="Message shown when a command-line flag is used that is not implemented by this build. [Keep it short so it fits in the infobar.]">
-        <ph name="BAD_FLAG">$1<ex>--enable-heap-profiling</ex></ph> is not implemented in this build
-      </message>
-
       <!-- Bad Flags Infobar-->
       <message name="IDS_BAD_FLAGS_WARNING_MESSAGE" desc="Message shown when an unsupported command-line flag is used. [Keep it short so it fits in the infobar.]">
         You are using an unsupported command-line flag: <ph name="BAD_FLAG">$1<ex>--no-sandbox</ex></ph>. Stability and security will suffer.
diff --git a/chrome/app/theme/chrome_unscaled_resources.grd b/chrome/app/theme/chrome_unscaled_resources.grd
index 383d4821..9b89ae3b 100644
--- a/chrome/app/theme/chrome_unscaled_resources.grd
+++ b/chrome/app/theme/chrome_unscaled_resources.grd
@@ -111,6 +111,11 @@
         <include name="IDR_APPS_FOLDER_OVERLAY_128" file="mac/apps_folder_overlay_128.png" type="BINDATA" />
         <include name="IDR_APPS_FOLDER_OVERLAY_512" file="mac/apps_folder_overlay_512.png" type="BINDATA" />
       </if>
+      <if expr="chromeos">
+        <!-- Crostini icons -->
+        <include name="IDR_LOGO_CROSTINI_TERMINAL" file="crostini/logo_crostini_terminal.png" type="BINDATA" />
+        <include name="IDR_LOGO_CROSTINI_DEFAULT" file="crostini/logo_crostini_default.png" type="BINDATA" />
+      </if>
     </includes>
   </release>
 </grit>
diff --git a/chrome/app/theme/crostini/logo_crostini_default.png b/chrome/app/theme/crostini/logo_crostini_default.png
new file mode 100644
index 0000000..6c78bef
--- /dev/null
+++ b/chrome/app/theme/crostini/logo_crostini_default.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/crostini/logo_crostini_terminal.png b/chrome/app/theme/crostini/logo_crostini_terminal.png
similarity index 100%
rename from ash/resources/default_100_percent/cros/crostini/logo_crostini_terminal.png
rename to chrome/app/theme/crostini/logo_crostini_terminal.png
Binary files differ
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 8bf20a2..c4062ea 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -967,16 +967,6 @@
       arraysize(kPersistentMenuItemEnabled), nullptr}};
 #endif  // OS_ANDROID
 
-const FeatureEntry::Choice kEnableHeapProfilingChoices[] = {
-    {flags_ui::kGenericExperimentChoiceDisabled, "", ""},
-    {flag_descriptions::kEnableHeapProfilingModePseudo,
-     switches::kEnableHeapProfiling, switches::kEnableHeapProfilingModePseudo},
-    {flag_descriptions::kEnableHeapProfilingModeNative,
-     switches::kEnableHeapProfiling, switches::kEnableHeapProfilingModeNative},
-    {flag_descriptions::kEnableHeapProfilingTaskProfiler,
-     switches::kEnableHeapProfiling,
-     switches::kEnableHeapProfilingTaskProfiler}};
-
 const FeatureEntry::Choice kEnableOutOfProcessHeapProfilingChoices[] = {
     {flags_ui::kGenericExperimentChoiceDisabled, "", ""},
     {flag_descriptions::kEnableOutOfProcessHeapProfilingModeMinimal,
@@ -3196,10 +3186,6 @@
      flag_descriptions::kSamplingHeapProfilerDescription, kOsAll,
      SINGLE_VALUE_TYPE(switches::kSamplingHeapProfiler)},
 
-    {"enable-heap-profiling", flag_descriptions::kEnableHeapProfilingName,
-     flag_descriptions::kEnableHeapProfilingDescription, kOsAll,
-     MULTI_VALUE_TYPE(kEnableHeapProfilingChoices)},
-
     {"memlog", flag_descriptions::kEnableOutOfProcessHeapProfilingName,
      flag_descriptions::kEnableOutOfProcessHeapProfilingDescription, kOsAll,
      MULTI_VALUE_TYPE(kEnableOutOfProcessHeapProfilingChoices)},
diff --git a/chrome/browser/app_controller_mac.h b/chrome/browser/app_controller_mac.h
index adf019c..f843d1f 100644
--- a/chrome/browser/app_controller_mac.h
+++ b/chrome/browser/app_controller_mac.h
@@ -182,6 +182,10 @@
 // different models of application lifetime.
 bool IsOpeningNewWindow();
 
+// Create a guest profile if one is needed. Afterwards, even if the profile
+// already existed, notify the AppController of the profile in use.
+void CreateGuestProfileIfNeeded();
+
 }  // namespace app_controller_mac
 
 #endif  // CHROME_BROWSER_APP_CONTROLLER_MAC_H_
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 17e4527..7602fe5 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -1716,10 +1716,29 @@
 
 //---------------------------------------------------------------------------
 
+namespace {
+
+void UpdateProfileInUse(Profile* profile, Profile::CreateStatus status) {
+  if (status == Profile::CREATE_STATUS_INITIALIZED) {
+    AppController* controller =
+        base::mac::ObjCCastStrict<AppController>([NSApp delegate]);
+    [controller windowChangedToProfile:profile];
+  }
+}
+
+}  // namespace
+
 namespace app_controller_mac {
 
 bool IsOpeningNewWindow() {
   return g_is_opening_new_window;
 }
 
+void CreateGuestProfileIfNeeded() {
+  g_browser_process->profile_manager()->CreateProfileAsync(
+      ProfileManager::GetGuestProfilePath(),
+      base::BindRepeating(&UpdateProfileInUse), base::string16(), std::string(),
+      std::string());
+}
+
 }  // namespace app_controller_mac
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 9b41510f..78e6f3e 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -4729,3 +4729,21 @@
       &cookie_is_correct));
   EXPECT_TRUE(cookie_is_correct);
 }
+
+// Sends an auto-resize message to the RenderWidgetHost and ensures that the
+// auto-resize transaction is handled and produces a single response message
+// from guest to embedder.
+IN_PROC_BROWSER_TEST_P(WebViewTest, AutoResizeMessages) {
+  LoadAppWithGuest("web_view/simple");
+  content::WebContents* embedder = GetEmbedderWebContents();
+  content::WebContents* guest = GetGuestWebContents();
+  bool is_guest =
+      !base::FeatureList::IsEnabled(::features::kGuestViewCrossProcessFrames);
+
+  // Helper function as this test requires inspecting a number of content::
+  // internal objects.
+  EXPECT_TRUE(content::TestChildOrGuestAutoresize(
+      is_guest,
+      embedder->GetRenderWidgetHostView()->GetRenderWidgetHost()->GetProcess(),
+      guest->GetRenderWidgetHostView()->GetRenderWidgetHost()));
+}
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index f390d84..52949a95 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -8,9 +8,6 @@
   </outputs>
   <release seq="1">
     <structures>
-      <if expr="enable_extensions">
-        <structure name="IDR_EXTENSIONS_HTML" file="resources\extensions\extensions.html" flattenhtml="true" type="chrome_html" />
-      </if>
       <if expr="chromeos">
         <structure name="IDR_FIRST_RUN_HTML" file="resources\chromeos\first_run\first_run.html" flattenhtml="true" type="chrome_html"/>
         <structure name="IDR_FIRST_RUN_JS" file="resources\chromeos\first_run\first_run.js" flattenhtml="true" type="chrome_html" />
@@ -171,11 +168,6 @@
           </else>
         </if>
       </if>
-      <if expr="enable_extensions">
-        <include name="IDR_EXTENSION_COMMAND_LIST_JS" file="resources\extensions\extension_command_list.js" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_EXTENSION_LIST_JS" file="resources\extensions\extension_list.js" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_EXTENSIONS_JS" file="resources\extensions\extensions.js" flattenhtml="true" type="BINDATA" />
-      </if>
       <include name="IDR_FEEDBACK_MANIFEST" file="resources\feedback\manifest.json" type="BINDATA" />
       <if expr="is_android">
         <include name="IDR_OFFLINE_INTERNALS_HTML" file="resources\offline_pages\offline_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 08f752f2..e60e3c5 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -509,6 +509,8 @@
     "crostini/crostini_registry_service.h",
     "crostini/crostini_registry_service_factory.cc",
     "crostini/crostini_registry_service_factory.h",
+    "crostini/crostini_util.cc",
+    "crostini/crostini_util.h",
     "cryptauth/chrome_cryptauth_service.cc",
     "cryptauth/chrome_cryptauth_service.h",
     "cryptauth/chrome_cryptauth_service_factory.cc",
@@ -549,8 +551,6 @@
     "display/output_protection_delegate.h",
     "display/quirks_manager_delegate_impl.cc",
     "display/quirks_manager_delegate_impl.h",
-    "docked_magnifier/docked_magnifier_client.cc",
-    "docked_magnifier/docked_magnifier_client.h",
     "drive/debug_info_collector.cc",
     "drive/debug_info_collector.h",
     "drive/download_handler.cc",
@@ -1835,7 +1835,6 @@
     "../metrics/perf/random_selector_unittest.cc",
     "../policy/default_geolocation_policy_handler_unittest.cc",
     "../ui/browser_finder_chromeos_unittest.cc",
-    "accessibility/magnification_manager_unittest.cc",
     "accessibility/select_to_speak_event_handler_unittest.cc",
     "accessibility/spoken_feedback_event_rewriter_unittest.cc",
     "app_mode/startup_app_launcher_unittest.cc",
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager.cc b/chrome/browser/chromeos/accessibility/magnification_manager.cc
index b972efb5..a902d2d6 100644
--- a/chrome/browser/chromeos/accessibility/magnification_manager.cc
+++ b/chrome/browser/chromeos/accessibility/magnification_manager.cc
@@ -8,7 +8,9 @@
 #include <memory>
 
 #include "ash/magnifier/magnification_controller.h"
+#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
+#include "ash/public/interfaces/constants.mojom.h"
 #include "ash/shell.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
@@ -22,6 +24,8 @@
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace chromeos {
 
@@ -48,7 +52,7 @@
 }
 
 bool MagnificationManager::IsMagnifierEnabled() const {
-  return enabled_;
+  return fullscreen_magnifier_enabled_;
 }
 
 void MagnificationManager::SetMagnifierEnabled(bool enabled) {
@@ -87,6 +91,18 @@
                  content::NotificationService::AllSources());
   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
                  content::NotificationService::AllSources());
+  // TODO(warx): observe focus changed in page notification when either
+  // fullscreen magnifier or docked magnifier is enabled.
+  registrar_.Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
+                 content::NotificationService::AllSources());
+
+  // Connect to ash's DockedMagnifierController interface.
+  if (ash::features::IsDockedMagnifierEnabled()) {
+    content::ServiceManagerConnection::GetForProcess()
+        ->GetConnector()
+        ->BindInterface(ash::mojom::kServiceName,
+                        &docked_magnifier_controller_);
+  }
 }
 
 MagnificationManager::~MagnificationManager() {
@@ -122,10 +138,7 @@
       break;
     }
     case content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE: {
-      content::FocusedNodeDetails* node_details =
-          content::Details<content::FocusedNodeDetails>(details).ptr();
-      ash::Shell::Get()->magnification_controller()->HandleFocusedNodeChanged(
-          node_details->is_editable_node, node_details->node_bounds_in_screen);
+      HandleFocusChangedInPage(details);
       break;
     }
   }
@@ -168,13 +181,12 @@
   // even if |enabled| is unchanged. Only if |enabled| is false and the
   // magnifier is already disabled, we are sure that we don't need to reflect
   // the new settings right now because the magnifier keeps disabled.
-  if (!enabled && !enabled_)
+  if (!enabled && !fullscreen_magnifier_enabled_)
     return;
 
-  enabled_ = enabled;
+  fullscreen_magnifier_enabled_ = enabled;
 
-  ash::Shell::Get()->magnification_controller()->SetEnabled(enabled_);
-  MonitorFocusInPageChange();
+  ash::Shell::Get()->magnification_controller()->SetEnabled(enabled);
 }
 
 void MagnificationManager::SetMagnifierKeepFocusCenteredInternal(
@@ -221,7 +233,7 @@
   }
 
   AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER,
-                                          enabled_);
+                                          fullscreen_magnifier_enabled_);
 
   if (!AccessibilityManager::Get())
     return;
@@ -230,16 +242,36 @@
     ash::Shell::Get()->UpdateCursorCompositingEnabled();
 }
 
-void MagnificationManager::MonitorFocusInPageChange() {
-  if (enabled_ && !observing_focus_change_in_page_) {
-    registrar_.Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
-                   content::NotificationService::AllSources());
-    observing_focus_change_in_page_ = true;
-  } else if (!enabled_ && observing_focus_change_in_page_) {
-    registrar_.Remove(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
-                      content::NotificationService::AllSources());
-    observing_focus_change_in_page_ = false;
+void MagnificationManager::HandleFocusChangedInPage(
+    const content::NotificationDetails& details) {
+  const bool docked_magnifier_enabled =
+      ash::features::IsDockedMagnifierEnabled() && profile_ &&
+      profile_->GetPrefs()->GetBoolean(ash::prefs::kDockedMagnifierEnabled);
+  if (!fullscreen_magnifier_enabled_ && !docked_magnifier_enabled)
+    return;
+
+  content::FocusedNodeDetails* node_details =
+      content::Details<content::FocusedNodeDetails>(details).ptr();
+  // Ash uses the InputMethod of the window tree host to observe text input
+  // caret bounds changes, which works for both the native UI as well as
+  // webpages. We don't need to notify it of editable nodes in this case.
+  if (node_details->is_editable_node)
+    return;
+
+  const gfx::Rect& bounds_in_screen = node_details->node_bounds_in_screen;
+  if (bounds_in_screen.IsEmpty())
+    return;
+
+  // Fullscreen magnifier and docked magnifier are mutually exclusive.
+  if (fullscreen_magnifier_enabled_) {
+    ash::Shell::Get()->magnification_controller()->HandleFocusedNodeChanged(
+        node_details->is_editable_node, node_details->node_bounds_in_screen);
+    return;
   }
+  DCHECK(docked_magnifier_enabled);
+  // Called when docked magnifier feature is enabled to avoid unnecessary
+  // mojo IPC to ash.
+  docked_magnifier_controller_->CenterOnPoint(bounds_in_screen.CenterPoint());
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager.h b/chrome/browser/chromeos/accessibility/magnification_manager.h
index 5ac5b87..c6ab3ff0 100644
--- a/chrome/browser/chromeos/accessibility/magnification_manager.h
+++ b/chrome/browser/chromeos/accessibility/magnification_manager.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_MAGNIFICATION_MANAGER_H_
 #define CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_MAGNIFICATION_MANAGER_H_
 
+#include "ash/public/interfaces/docked_magnifier_controller.mojom.h"
 #include "base/macros.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/notification_observer.h"
@@ -15,14 +16,18 @@
 
 namespace chromeos {
 
-// MagnificationManager controls the full screen magnifier from chrome-browser
-// side (not ash side).
+// MagnificationManager controls the Fullscreen and Docked magnifier from
+// chrome-browser side (not ash side).
 //
-// MagnificationManager does:
+// MagnificationManager does below for Fullscreen magnifier:
+// TODO(warx): Move to ash.
 //   - Watch logged-in. Changes the behavior between the login screen and user
 //     desktop.
 //   - Watch change of the pref. When the pref changes, the setting of the
 //     magnifier will interlock with it.
+//
+// MagnificationManager also observes focus changed in page and calls Ash when
+// either Fullscreen or Docked magnifier is enabled.
 class MagnificationManager
     : public content::NotificationObserver,
       public user_manager::UserManager::UserSessionStateObserver {
@@ -36,16 +41,16 @@
   // Returns the existing instance. If there is no instance, returns NULL.
   static MagnificationManager* Get();
 
-  // Returns if the screen magnifier is enabled.
+  // Returns if the Fullscreen magnifier is enabled.
   bool IsMagnifierEnabled() const;
 
-  // Enables the screen magnifier.
+  // Enables the Fullscreen magnifier.
   void SetMagnifierEnabled(bool enabled);
 
-  // Saves the magnifier scale to the pref.
+  // Saves the Fullscreen magnifier scale to the pref.
   void SaveScreenMagnifierScale(double scale);
 
-  // Loads the magnifier scale from the pref.
+  // Loads the Fullscreen magnifier scale from the pref.
   double GetSavedScreenMagnifierScale() const;
 
   void SetProfileForTest(Profile* profile);
@@ -69,20 +74,23 @@
   void SetMagnifierScaleInternal(double scale);
   void UpdateMagnifierFromPrefs();
 
-  void MonitorFocusInPageChange();
+  // Called when received content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE.
+  void HandleFocusChangedInPage(const content::NotificationDetails& details);
 
   Profile* profile_ = nullptr;
 
-  bool enabled_ = false;
+  bool fullscreen_magnifier_enabled_ = false;
   bool keep_focus_centered_ = false;
   double scale_ = 0.0;
-  bool observing_focus_change_in_page_ = false;
 
   content::NotificationRegistrar registrar_;
   std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
   std::unique_ptr<user_manager::ScopedUserSessionStateObserver>
       session_state_observer_;
 
+  // Ash's mojom::DockedMagnifierController used to request Ash's a11y feature.
+  ash::mojom::DockedMagnifierControllerPtr docked_magnifier_controller_;
+
   DISALLOW_COPY_AND_ASSIGN(MagnificationManager);
 };
 
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager_unittest.cc b/chrome/browser/chromeos/accessibility/magnification_manager_unittest.cc
deleted file mode 100644
index 37c8587..0000000
--- a/chrome/browser/chromeos/accessibility/magnification_manager_unittest.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
-
-#include "ash/public/cpp/accessibility_types.h"
-#include "ash/test/ash_test_base.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/prefs/pref_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromeos {
-namespace {
-
-void EnableMagnifier() {
-  return MagnificationManager::Get()->SetMagnifierEnabled(true);
-}
-
-void DisableMagnifier() {
-  return MagnificationManager::Get()->SetMagnifierEnabled(false);
-}
-
-bool IsMagnifierEnabled() {
-  return MagnificationManager::Get()->IsMagnifierEnabled();
-}
-
-}  // namespace
-
-class MagnificationManagerTest : public ash::AshTestBase {
- public:
-  MagnificationManagerTest() = default;
-  ~MagnificationManagerTest() override = default;
-
-  void SetUp() override {
-    ash::AshTestBase::SetUp();
-    MagnificationManager::Initialize();
-    ASSERT_TRUE(MagnificationManager::Get());
-    MagnificationManager::Get()->SetProfileForTest(&profile_);
-  }
-
-  void TearDown() override {
-    MagnificationManager::Shutdown();
-    ash::AshTestBase::TearDown();
-  }
-
-  TestingProfile profile_;
-};
-
-TEST_F(MagnificationManagerTest, EnableDisable) {
-  // Set full screen magnifier, and confirm the status is set successfully.
-  EnableMagnifier();
-  EXPECT_TRUE(IsMagnifierEnabled());
-
-  // Disables magnifier, and confirm the status is set successfully.
-  DisableMagnifier();
-  EXPECT_FALSE(IsMagnifierEnabled());
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 435e9e8..ca1132d 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -220,8 +220,7 @@
     network_portal_detector::SetNetworkPortalDetector(
         new NetworkPortalDetectorImpl(
             g_browser_process->system_network_context_manager()
-                ->GetURLLoaderFactory(),
-            true));
+                ->GetURLLoaderFactory()));
   }
 }
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index ac7420b..a0da72e 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -9,10 +9,10 @@
 #include "base/sys_info.h"
 #include "base/task_scheduler/post_task.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/component_updater/cros_component_installer.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/app_list/crostini/crostini_util.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chromeos/dbus/concierge_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -40,6 +40,12 @@
   return container_username.substr(0, container_username.find('@'));
 }
 
+std::string CryptohomeIdForProfile(Profile* profile) {
+  std::string id = chromeos::ProfileHelper::GetUserIdHashFromProfile(profile);
+  // Empty id means we're running in a test.
+  return id.empty() ? "test" : id;
+}
+
 class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> {
  public:
   CrostiniRestarter(std::string vm_name,
@@ -51,15 +57,51 @@
         cryptohome_id_(std::move(cryptohome_id)),
         container_name_(std::move(container_name)),
         container_username_(std::move(container_username)),
-        callback_(std::move(callback)) {}
+        callback_(std::move(callback)),
+        restart_id_(next_restart_id_) {
+    restarter_map_[next_restart_id_++] = base::WrapRefCounted(this);
+  }
 
   void Restart() {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    g_browser_process->platform_part()->cros_component_manager()->Load(
-        "cros-termina",
-        component_updater::CrOSComponentManager::MountPolicy::kMount,
-        base::BindOnce(&CrostiniRestarter::InstallImageLoaderFinished,
-                       base::WrapRefCounted(this)));
+    if (is_aborted_)
+      return;
+    auto* cros_component_manager =
+        g_browser_process->platform_part()->cros_component_manager();
+    if (cros_component_manager) {
+      g_browser_process->platform_part()->cros_component_manager()->Load(
+          "cros-termina",
+          component_updater::CrOSComponentManager::MountPolicy::kMount,
+          base::BindOnce(&CrostiniRestarter::InstallImageLoaderFinished,
+                         base::WrapRefCounted(this)));
+    } else {
+      // Running in test.
+      InstallImageLoaderFinishedOnUIThread(
+          component_updater::CrOSComponentManager::Error::NONE,
+          base::FilePath());
+    }
+  }
+
+  void AddObserver(CrostiniManager::RestartObserver* observer) {
+    observer_list_.AddObserver(observer);
+  }
+
+  CrostiniManager::RestartId GetRestartId() { return restart_id_; }
+
+  static void Abort(CrostiniManager::RestartId restart_id) {
+    auto it = restarter_map_.find(restart_id);
+    if (it != restarter_map_.end()) {
+      it->second->is_aborted_ = true;
+      restarter_map_.erase(it);
+    }
+  }
+
+  void UnrefAndRunCallback(ConciergeClientResult result) {
+    auto it = restarter_map_.find(restart_id_);
+    if (it != restarter_map_.end()) {
+      restarter_map_.erase(it);
+    }
+    std::move(callback_).Run(result);
   }
 
  private:
@@ -76,6 +118,8 @@
       component_updater::CrOSComponentManager::Error error,
       const base::FilePath& result) {
     DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+    if (restarter->is_aborted_)
+      return;
     content::BrowserThread::PostTask(
         content::BrowserThread::UI, FROM_HERE,
         base::BindOnce(&CrostiniRestarter::InstallImageLoaderFinishedOnUIThread,
@@ -85,11 +129,21 @@
   void InstallImageLoaderFinishedOnUIThread(
       component_updater::CrOSComponentManager::Error error,
       const base::FilePath& result) {
-    if (error != component_updater::CrOSComponentManager::Error::NONE) {
+    ConciergeClientResult client_result =
+        error == component_updater::CrOSComponentManager::Error::NONE
+            ? ConciergeClientResult::SUCCESS
+            : ConciergeClientResult::CONTAINER_START_FAILED;
+    // Tell observers.
+    for (auto& observer : observer_list_) {
+      observer.OnComponentLoaded(client_result);
+    }
+    if (is_aborted_)
+      return;
+    if (client_result != ConciergeClientResult::SUCCESS) {
       LOG(ERROR)
           << "Failed to install the cros-termina component with error code: "
           << static_cast<int>(error);
-      std::move(callback_).Run(ConciergeClientResult::CONTAINER_START_FAILED);
+      UnrefAndRunCallback(client_result);
       return;
     }
     CrostiniManager::GetInstance()->StartVmConcierge(
@@ -98,9 +152,18 @@
 
   void ConciergeStarted(bool is_started) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    ConciergeClientResult client_result =
+        is_started ? ConciergeClientResult::SUCCESS
+                   : ConciergeClientResult::CONTAINER_START_FAILED;
+    // Tell observers.
+    for (auto& observer : observer_list_) {
+      observer.OnConciergeStarted(client_result);
+    }
+    if (is_aborted_)
+      return;
     if (!is_started) {
       LOG(ERROR) << "Failed to start Concierge service.";
-      std::move(callback_).Run(ConciergeClientResult::CONTAINER_START_FAILED);
+      UnrefAndRunCallback(client_result);
       return;
     }
     CrostiniManager::GetInstance()->CreateDiskImage(
@@ -112,9 +175,15 @@
   void CreateDiskImageFinished(ConciergeClientResult result,
                                const base::FilePath& result_path) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    // Tell observers.
+    for (auto& observer : observer_list_) {
+      observer.OnDiskImageCreated(result);
+    }
+    if (is_aborted_)
+      return;
     if (result != ConciergeClientResult::SUCCESS) {
       LOG(ERROR) << "Failed to create disk image.";
-      std::move(callback_).Run(result);
+      UnrefAndRunCallback(result);
       return;
     }
     CrostiniManager::GetInstance()->StartTerminaVm(
@@ -124,9 +193,15 @@
 
   void StartTerminaVmFinished(ConciergeClientResult result) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    // Tell observers.
+    for (auto& observer : observer_list_) {
+      observer.OnVmStarted(result);
+    }
+    if (is_aborted_)
+      return;
     if (result != ConciergeClientResult::SUCCESS) {
       LOG(ERROR) << "Failed to Start Termina VM.";
-      std::move(callback_).Run(result);
+      UnrefAndRunCallback(result);
       return;
     }
     CrostiniManager::GetInstance()->StartContainer(
@@ -139,7 +214,9 @@
     if (result != ConciergeClientResult::SUCCESS) {
       LOG(ERROR) << "Failed to start container.";
     }
-    std::move(callback_).Run(result);
+    if (is_aborted_)
+      return;
+    UnrefAndRunCallback(result);
   }
 
   std::string vm_name_;
@@ -147,8 +224,19 @@
   std::string container_name_;
   std::string container_username_;
   CrostiniManager::RestartCrostiniCallback callback_;
+  base::ObserverList<CrostiniManager::RestartObserver> observer_list_;
+  CrostiniManager::RestartId restart_id_;
+  bool is_aborted_ = false;
+
+  static CrostiniManager::RestartId next_restart_id_;
+  static std::map<CrostiniManager::RestartId, scoped_refptr<CrostiniRestarter>>
+      restarter_map_;
 };
 
+CrostiniManager::RestartId CrostiniRestarter::next_restart_id_ = 0;
+std::map<CrostiniManager::RestartId, scoped_refptr<CrostiniRestarter>>
+    CrostiniRestarter::restarter_map_;
+
 }  // namespace
 
 // static
@@ -439,20 +527,29 @@
   OpenApplicationWindow(launch_params, vsh_in_crosh_url);
 }
 
-void CrostiniManager::RestartCrostini(Profile* profile,
-                                      std::string vm_name,
-                                      std::string container_name,
-                                      RestartCrostiniCallback callback) {
+CrostiniManager::RestartId CrostiniManager::RestartCrostini(
+    Profile* profile,
+    std::string vm_name,
+    std::string container_name,
+    RestartCrostiniCallback callback,
+    RestartObserver* observer) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  std::string cryptohome_id = chromeos::ProfileHelper::Get()
-                                  ->GetUserByProfile(profile)
-                                  ->username_hash();
+  std::string cryptohome_id = CryptohomeIdForProfile(profile);
   std::string container_username = ContainerUserNameForProfile(profile);
 
   auto crostini_restarter = base::MakeRefCounted<CrostiniRestarter>(
       std::move(vm_name), std::move(cryptohome_id), std::move(container_name),
       std::move(container_username), std::move(callback));
+  if (observer) {
+    crostini_restarter->AddObserver(observer);
+  }
   crostini_restarter->Restart();
+  return crostini_restarter->GetRestartId();
+}
+
+void CrostiniManager::AbortRestartCrostini(
+    CrostiniManager::RestartId restart_id) {
+  CrostiniRestarter::Abort(restart_id);
 }
 
 void CrostiniManager::OnCreateDiskImage(
@@ -591,7 +688,6 @@
         ConciergeClientResult::LAUNCH_CONTAINER_APPLICATION_FAILED);
     return;
   }
-
   std::move(callback).Run(ConciergeClientResult::SUCCESS);
 }
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index e50290d..26745073 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -65,6 +65,15 @@
   using RestartCrostiniCallback =
       base::OnceCallback<void(ConciergeClientResult result)>;
 
+  // Observer class for the Crostini restart flow.
+  class RestartObserver {
+   public:
+    virtual void OnComponentLoaded(ConciergeClientResult result) = 0;
+    virtual void OnConciergeStarted(ConciergeClientResult result) = 0;
+    virtual void OnDiskImageCreated(ConciergeClientResult result) = 0;
+    virtual void OnVmStarted(ConciergeClientResult result) = 0;
+  };
+
   // Checks if the cros-termina component is installed.
   static bool IsCrosTerminaInstalled();
 
@@ -127,8 +136,6 @@
   // Asynchronously launches an app as specified by its desktop file id.
   // |callback| is called with SUCCESS when the relevant process is started
   // or LAUNCH_CONTAINER_APPLICATION_FAILED if there was an error somewhere.
-  //
-  // TODO(nverne): Start the VM and Container if not already running.
   void LaunchContainerApplication(std::string vm_name,
                                   std::string container_name,
                                   std::string desktop_file_id,
@@ -140,10 +147,17 @@
                                const std::string& vm_name,
                                const std::string& container_name);
 
-  void RestartCrostini(Profile* profile,
-                       std::string vm_name,
-                       std::string container_name,
-                       RestartCrostiniCallback callback);
+  using RestartId = int;
+  static const RestartId kUninitializedRestartId = -1;
+  // Runs all the steps required to restart the given crostini vm and container.
+  // The optional |observer| tracks progress.
+  RestartId RestartCrostini(Profile* profile,
+                            std::string vm_name,
+                            std::string container_name,
+                            RestartCrostiniCallback callback,
+                            RestartObserver* observer = nullptr);
+
+  void AbortRestartCrostini(RestartId id);
 
   // ConciergeClient::Observer:
   void OnContainerStarted(
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index 46ebc23..afc411dc 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -7,8 +7,10 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
+#include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_concierge_client.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace crostini {
@@ -21,79 +23,77 @@
 
 class CrostiniManagerTest : public testing::Test {
  public:
-  void CreateDiskImageClientErrorCallback(
-      base::OnceClosure closure,
-      crostini::ConciergeClientResult result,
-      const base::FilePath& file_path) {
+  void CreateDiskImageClientErrorCallback(base::OnceClosure closure,
+                                          ConciergeClientResult result,
+                                          const base::FilePath& file_path) {
     EXPECT_FALSE(fake_concierge_client_->create_disk_image_called());
-    EXPECT_EQ(result, crostini::ConciergeClientResult::CLIENT_ERROR);
+    EXPECT_EQ(result, ConciergeClientResult::CLIENT_ERROR);
     std::move(closure).Run();
   }
 
-  void DestroyDiskImageClientErrorCallback(
-      base::OnceClosure closure,
-      crostini::ConciergeClientResult result) {
+  void DestroyDiskImageClientErrorCallback(base::OnceClosure closure,
+                                           ConciergeClientResult result) {
     EXPECT_FALSE(fake_concierge_client_->destroy_disk_image_called());
-    EXPECT_EQ(result, crostini::ConciergeClientResult::CLIENT_ERROR);
+    EXPECT_EQ(result, ConciergeClientResult::CLIENT_ERROR);
     std::move(closure).Run();
   }
 
-  void StartTerminaVmClientErrorCallback(
-      base::OnceClosure closure,
-      crostini::ConciergeClientResult result) {
+  void StartTerminaVmClientErrorCallback(base::OnceClosure closure,
+                                         ConciergeClientResult result) {
     EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
-    EXPECT_EQ(result, crostini::ConciergeClientResult::CLIENT_ERROR);
+    EXPECT_EQ(result, ConciergeClientResult::CLIENT_ERROR);
     std::move(closure).Run();
   }
 
   void StopVmClientErrorCallback(base::OnceClosure closure,
-                                 crostini::ConciergeClientResult result) {
+                                 ConciergeClientResult result) {
     EXPECT_FALSE(fake_concierge_client_->stop_vm_called());
-    EXPECT_EQ(result, crostini::ConciergeClientResult::CLIENT_ERROR);
+    EXPECT_EQ(result, ConciergeClientResult::CLIENT_ERROR);
     std::move(closure).Run();
   }
 
-  void StartContainerClientErrorCallback(
-      base::OnceClosure closure,
-      crostini::ConciergeClientResult result) {
+  void StartContainerClientErrorCallback(base::OnceClosure closure,
+                                         ConciergeClientResult result) {
     EXPECT_FALSE(fake_concierge_client_->start_container_called());
-    EXPECT_EQ(result, crostini::ConciergeClientResult::CLIENT_ERROR);
+    EXPECT_EQ(result, ConciergeClientResult::CLIENT_ERROR);
     std::move(closure).Run();
   }
 
   void CreateDiskImageSuccessCallback(base::OnceClosure closure,
-                                      crostini::ConciergeClientResult result,
+                                      ConciergeClientResult result,
                                       const base::FilePath& file_path) {
     EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
     std::move(closure).Run();
   }
 
   void DestroyDiskImageSuccessCallback(base::OnceClosure closure,
-                                       crostini::ConciergeClientResult result) {
+                                       ConciergeClientResult result) {
     EXPECT_TRUE(fake_concierge_client_->destroy_disk_image_called());
     std::move(closure).Run();
   }
 
   void StartTerminaVmSuccessCallback(base::OnceClosure closure,
-                                     crostini::ConciergeClientResult result) {
+                                     ConciergeClientResult result) {
     EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
     std::move(closure).Run();
   }
 
   void StopVmSuccessCallback(base::OnceClosure closure,
-                             crostini::ConciergeClientResult result) {
+                             ConciergeClientResult result) {
     EXPECT_TRUE(fake_concierge_client_->stop_vm_called());
     std::move(closure).Run();
   }
 
   void StartContainerSuccessCallback(base::OnceClosure closure,
-                                     crostini::ConciergeClientResult result) {
+                                     ConciergeClientResult result) {
     EXPECT_TRUE(fake_concierge_client_->start_container_called());
     std::move(closure).Run();
   }
 
   CrostiniManagerTest()
-      : fake_concierge_client_(new chromeos::FakeConciergeClient()) {
+      : fake_concierge_client_(new chromeos::FakeConciergeClient()),
+        scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::UI) {
     chromeos::DBusThreadManager::GetSetterForTesting()->SetConciergeClient(
         base::WrapUnique(fake_concierge_client_));
     chromeos::DBusThreadManager::Initialize();
@@ -112,7 +112,7 @@
 TEST_F(CrostiniManagerTest, CreateDiskImageNameError) {
   const base::FilePath& disk_path = base::FilePath("");
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->CreateDiskImage(
+  CrostiniManager::GetInstance()->CreateDiskImage(
       "i_dont_know_what_cryptohome_id_is", disk_path,
       vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT,
       base::BindOnce(&CrostiniManagerTest::CreateDiskImageClientErrorCallback,
@@ -123,7 +123,7 @@
 TEST_F(CrostiniManagerTest, CreateDiskImageCryptohomeError) {
   const base::FilePath& disk_path = base::FilePath(kVmName);
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->CreateDiskImage(
+  CrostiniManager::GetInstance()->CreateDiskImage(
       "", disk_path, vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT,
       base::BindOnce(&CrostiniManagerTest::CreateDiskImageClientErrorCallback,
                      base::Unretained(this), loop.QuitClosure()));
@@ -133,7 +133,7 @@
 TEST_F(CrostiniManagerTest, CreateDiskImageStorageLocationError) {
   const base::FilePath& disk_path = base::FilePath(kVmName);
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->CreateDiskImage(
+  CrostiniManager::GetInstance()->CreateDiskImage(
       "i_dont_know_what_cryptohome_id_is", disk_path,
       vm_tools::concierge::StorageLocation_INT_MIN_SENTINEL_DO_NOT_USE_,
       base::BindOnce(&CrostiniManagerTest::CreateDiskImageClientErrorCallback,
@@ -144,7 +144,7 @@
 TEST_F(CrostiniManagerTest, CreateDiskImageSuccess) {
   const base::FilePath& disk_path = base::FilePath(kVmName);
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->CreateDiskImage(
+  CrostiniManager::GetInstance()->CreateDiskImage(
       "i_dont_know_what_cryptohome_id_is", disk_path,
       vm_tools::concierge::STORAGE_CRYPTOHOME_DOWNLOADS,
       base::BindOnce(&CrostiniManagerTest::CreateDiskImageSuccessCallback,
@@ -155,7 +155,7 @@
 TEST_F(CrostiniManagerTest, DestroyDiskImageNameError) {
   const base::FilePath& disk_path = base::FilePath("");
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->DestroyDiskImage(
+  CrostiniManager::GetInstance()->DestroyDiskImage(
       "i_dont_know_what_cryptohome_id_is", disk_path,
       vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT,
       base::BindOnce(&CrostiniManagerTest::DestroyDiskImageClientErrorCallback,
@@ -166,7 +166,7 @@
 TEST_F(CrostiniManagerTest, DestroyDiskImageCryptohomeError) {
   const base::FilePath& disk_path = base::FilePath(kVmName);
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->DestroyDiskImage(
+  CrostiniManager::GetInstance()->DestroyDiskImage(
       "", disk_path, vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT,
       base::BindOnce(&CrostiniManagerTest::DestroyDiskImageClientErrorCallback,
                      base::Unretained(this), loop.QuitClosure()));
@@ -176,7 +176,7 @@
 TEST_F(CrostiniManagerTest, DestroyDiskImageStorageLocationError) {
   const base::FilePath& disk_path = base::FilePath(kVmName);
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->DestroyDiskImage(
+  CrostiniManager::GetInstance()->DestroyDiskImage(
       "i_dont_know_what_cryptohome_id_is", disk_path,
       vm_tools::concierge::StorageLocation_INT_MIN_SENTINEL_DO_NOT_USE_,
       base::BindOnce(&CrostiniManagerTest::DestroyDiskImageClientErrorCallback,
@@ -187,7 +187,7 @@
 TEST_F(CrostiniManagerTest, DestroyDiskImageSuccess) {
   const base::FilePath& disk_path = base::FilePath(kVmName);
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->DestroyDiskImage(
+  CrostiniManager::GetInstance()->DestroyDiskImage(
       "i_dont_know_what_cryptohome_id_is", disk_path,
       vm_tools::concierge::STORAGE_CRYPTOHOME_DOWNLOADS,
       base::BindOnce(&CrostiniManagerTest::DestroyDiskImageSuccessCallback,
@@ -198,7 +198,7 @@
 TEST_F(CrostiniManagerTest, StartTerminaVmNameError) {
   const base::FilePath& disk_path = base::FilePath(kVmName);
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->StartTerminaVm(
+  CrostiniManager::GetInstance()->StartTerminaVm(
       "", disk_path,
       base::BindOnce(&CrostiniManagerTest::StartTerminaVmClientErrorCallback,
                      base::Unretained(this), loop.QuitClosure()));
@@ -208,7 +208,7 @@
 TEST_F(CrostiniManagerTest, StartTerminaVmDiskPathError) {
   const base::FilePath& disk_path = base::FilePath();
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->StartTerminaVm(
+  CrostiniManager::GetInstance()->StartTerminaVm(
       kVmName, disk_path,
       base::BindOnce(&CrostiniManagerTest::StartTerminaVmClientErrorCallback,
                      base::Unretained(this), loop.QuitClosure()));
@@ -218,7 +218,7 @@
 TEST_F(CrostiniManagerTest, StartTerminaVmSuccess) {
   const base::FilePath& disk_path = base::FilePath(kVmName);
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->StartTerminaVm(
+  CrostiniManager::GetInstance()->StartTerminaVm(
       kVmName, disk_path,
       base::BindOnce(&CrostiniManagerTest::StartTerminaVmSuccessCallback,
                      base::Unretained(this), loop.QuitClosure()));
@@ -227,7 +227,7 @@
 
 TEST_F(CrostiniManagerTest, StopVmNameError) {
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->StopVm(
+  CrostiniManager::GetInstance()->StopVm(
       "", base::BindOnce(&CrostiniManagerTest::StopVmClientErrorCallback,
                          base::Unretained(this), loop.QuitClosure()));
   loop.Run();
@@ -235,7 +235,7 @@
 
 TEST_F(CrostiniManagerTest, StopVmSuccess) {
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->StopVm(
+  CrostiniManager::GetInstance()->StopVm(
       kVmName, base::BindOnce(&CrostiniManagerTest::StopVmSuccessCallback,
                               base::Unretained(this), loop.QuitClosure()));
   loop.Run();
@@ -243,7 +243,7 @@
 
 TEST_F(CrostiniManagerTest, StartContainerVmNameError) {
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->StartContainer(
+  CrostiniManager::GetInstance()->StartContainer(
       "", kContainerName, kContainerUserName,
       base::BindOnce(&CrostiniManagerTest::StartContainerClientErrorCallback,
                      base::Unretained(this), loop.QuitClosure()));
@@ -252,7 +252,7 @@
 
 TEST_F(CrostiniManagerTest, StartContainerContainerNameError) {
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->StartContainer(
+  CrostiniManager::GetInstance()->StartContainer(
       kVmName, "", kContainerUserName,
       base::BindOnce(&CrostiniManagerTest::StartContainerClientErrorCallback,
                      base::Unretained(this), loop.QuitClosure()));
@@ -261,7 +261,7 @@
 
 TEST_F(CrostiniManagerTest, StartContainerContainerUserNameError) {
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->StartContainer(
+  CrostiniManager::GetInstance()->StartContainer(
       kVmName, kContainerName, "",
       base::BindOnce(&CrostiniManagerTest::StartContainerClientErrorCallback,
                      base::Unretained(this), loop.QuitClosure()));
@@ -271,7 +271,7 @@
 TEST_F(CrostiniManagerTest, StartContainerSignalNotConnectedError) {
   base::RunLoop loop;
   fake_concierge_client_->set_container_started_signal_connected(false);
-  crostini::CrostiniManager::GetInstance()->StartContainer(
+  CrostiniManager::GetInstance()->StartContainer(
       kVmName, kContainerName, kContainerUserName,
       base::BindOnce(&CrostiniManagerTest::StartContainerClientErrorCallback,
                      base::Unretained(this), loop.QuitClosure()));
@@ -280,11 +280,143 @@
 
 TEST_F(CrostiniManagerTest, StartContainerSuccess) {
   base::RunLoop loop;
-  crostini::CrostiniManager::GetInstance()->StartContainer(
+  CrostiniManager::GetInstance()->StartContainer(
       kVmName, kContainerName, kContainerUserName,
       base::BindOnce(&CrostiniManagerTest::StartContainerSuccessCallback,
                      base::Unretained(this), loop.QuitClosure()));
   loop.Run();
 }
 
+class CrostiniManagerRestartTest : public CrostiniManagerTest,
+                                   public CrostiniManager::RestartObserver {
+ public:
+  CrostiniManagerRestartTest()
+      : test_browser_thread_bundle_(
+            content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
+
+  void SetUp() override {
+    loop_ = std::make_unique<base::RunLoop>();
+    profile_ = std::make_unique<TestingProfile>();
+  }
+
+  void RestartCrostiniCallback(base::OnceClosure closure,
+                               ConciergeClientResult result) {
+    restart_crostini_callback_called_ = true;
+    std::move(closure).Run();
+  }
+
+  // CrostiniManager::RestartObserver
+  void OnComponentLoaded(ConciergeClientResult result) override {
+    if (abort_on_component_loaded_) {
+      Abort();
+    }
+  }
+
+  void OnConciergeStarted(ConciergeClientResult result) override {
+    if (abort_on_concierge_started_) {
+      Abort();
+    }
+  }
+
+  void OnDiskImageCreated(ConciergeClientResult result) override {
+    if (abort_on_disk_image_created_) {
+      Abort();
+    }
+  }
+
+  void OnVmStarted(ConciergeClientResult result) override {
+    if (abort_on_vm_started_) {
+      Abort();
+    }
+  }
+
+ protected:
+  void Abort() {
+    CrostiniManager::GetInstance()->AbortRestartCrostini(restart_id_);
+    loop_->Quit();
+  }
+
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
+
+  CrostiniManager::RestartId restart_id_ =
+      CrostiniManager::kUninitializedRestartId;
+  bool abort_on_component_loaded_ = false;
+  bool abort_on_concierge_started_ = false;
+  bool abort_on_disk_image_created_ = false;
+  bool abort_on_vm_started_ = false;
+  bool restart_crostini_callback_called_ = false;
+  std::unique_ptr<base::RunLoop>
+      loop_;  // loop_ must be created on the UI thread.
+  std::unique_ptr<TestingProfile> profile_;
+};
+
+TEST_F(CrostiniManagerRestartTest, RestartSuccess) {
+  restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
+      profile_.get(), kVmName, kContainerName,
+      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
+                     base::Unretained(this), loop_->QuitClosure()),
+      this);
+  loop_->Run();
+  EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
+  EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
+  EXPECT_TRUE(fake_concierge_client_->start_container_called());
+  EXPECT_TRUE(restart_crostini_callback_called_);
+}
+
+TEST_F(CrostiniManagerRestartTest, AbortOnComponentLoaded) {
+  abort_on_component_loaded_ = true;
+  restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
+      profile_.get(), kVmName, kContainerName,
+      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
+                     base::Unretained(this), loop_->QuitClosure()),
+      this);
+  loop_->Run();
+  EXPECT_FALSE(fake_concierge_client_->create_disk_image_called());
+  EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
+  EXPECT_FALSE(fake_concierge_client_->start_container_called());
+  EXPECT_FALSE(restart_crostini_callback_called_);
+}
+
+TEST_F(CrostiniManagerRestartTest, AbortOnConciergeStarted) {
+  abort_on_concierge_started_ = true;
+  restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
+      profile_.get(), kVmName, kContainerName,
+      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
+                     base::Unretained(this), loop_->QuitClosure()),
+      this);
+  loop_->Run();
+  EXPECT_FALSE(fake_concierge_client_->create_disk_image_called());
+  EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
+  EXPECT_FALSE(fake_concierge_client_->start_container_called());
+  EXPECT_FALSE(restart_crostini_callback_called_);
+}
+
+TEST_F(CrostiniManagerRestartTest, AbortOnDiskImageCreated) {
+  abort_on_disk_image_created_ = true;
+  restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
+      profile_.get(), kVmName, kContainerName,
+      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
+                     base::Unretained(this), loop_->QuitClosure()),
+      this);
+  loop_->Run();
+  EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
+  EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
+  EXPECT_FALSE(fake_concierge_client_->start_container_called());
+  EXPECT_FALSE(restart_crostini_callback_called_);
+}
+
+TEST_F(CrostiniManagerRestartTest, AbortOnVmStarted) {
+  abort_on_vm_started_ = true;
+  restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
+      profile_.get(), kVmName, kContainerName,
+      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
+                     base::Unretained(this), loop_->QuitClosure()),
+      this);
+  loop_->Run();
+  EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
+  EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
+  EXPECT_FALSE(fake_concierge_client_->start_container_called());
+  EXPECT_FALSE(restart_crostini_callback_called_);
+}
+
 }  // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service.cc b/chrome/browser/chromeos/crostini/crostini_registry_service.cc
index 4b53852..966b376 100644
--- a/chrome/browser/chromeos/crostini/crostini_registry_service.cc
+++ b/chrome/browser/chromeos/crostini/crostini_registry_service.cc
@@ -4,8 +4,10 @@
 
 #include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
 
+#include "base/strings/string_util.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/dbus/vm_applications/apps.pb.h"
 #include "components/crx_file/id_util.h"
@@ -20,6 +22,16 @@
 
 namespace {
 
+// Prefixes of the ApplicationId set on exo windows.
+constexpr char kArcWindowAppIdPrefix[] = "org.chromium.arc";
+constexpr char kCrostiniWindowAppIdPrefix[] = "org.chromium.termina.";
+// This comes after kCrostiniWindowAppIdPrefix
+constexpr char kWMClassPrefix[] = "wmclass.";
+
+// This prefix is used when generating the crostini app list id, and used as a
+// prefix when generating shelf ids for windows we couldn't match to an app.
+constexpr char kCrostiniAppIdPrefix[] = "crostini:";
+
 constexpr char kCrostiniRegistryPref[] = "crostini.registry";
 
 // Keys for the Dictionary stored in prefs for each app.
@@ -31,8 +43,6 @@
 constexpr char kAppNameKey[] = "name";
 constexpr char kAppNoDisplayKey[] = "no_display";
 
-constexpr char kCrostiniAppIdPrefix[] = "crostini:";
-
 std::string GenerateAppId(const std::string& desktop_file_id,
                           const std::string& vm_name,
                           const std::string& container_name) {
@@ -125,6 +135,68 @@
 
 CrostiniRegistryService::~CrostiniRegistryService() = default;
 
+std::string CrostiniRegistryService::GetCrostiniShelfAppId(
+    const std::string& window_app_id,
+    const std::string* window_startup_id) {
+  if (base::StartsWith(window_app_id, kArcWindowAppIdPrefix,
+                       base::CompareCase::SENSITIVE))
+    return std::string();
+
+  // TODO(timloh): We should:
+  // - Use and store startup notify values so we can check against it.
+  // - Store StartUpWMClass values and give these priority over matching the
+  // desktop file id for non-wayland apps
+
+  base::StringPiece key;
+  if (base::StartsWith(window_app_id, kCrostiniWindowAppIdPrefix,
+                       base::CompareCase::SENSITIVE)) {
+    base::StringPiece suffix(
+        window_app_id.begin() + strlen(kCrostiniWindowAppIdPrefix),
+        window_app_id.end());
+
+    // If we don't have an id to match to a desktop file, just return the window
+    // app id, which is already prefixed.
+    if (!base::StartsWith(suffix, kWMClassPrefix, base::CompareCase::SENSITIVE))
+      return kCrostiniAppIdPrefix + window_app_id;
+    key = suffix.substr(strlen(kWMClassPrefix));
+  } else {
+    key = window_app_id;
+  }
+
+  std::string result;
+  const base::DictionaryValue* apps =
+      prefs_->GetDictionary(kCrostiniRegistryPref);
+  for (const auto& item : apps->DictItems()) {
+    const std::string& desktop_file_id =
+        item.second
+            .FindKeyOfType(kAppDesktopFileIdKey, base::Value::Type::STRING)
+            ->GetString();
+    if (!EqualsCaseInsensitiveASCII(key, desktop_file_id))
+      continue;
+
+    if (!result.empty())
+      return kCrostiniAppIdPrefix + window_app_id;
+    result = item.first;
+  }
+
+  if (!result.empty())
+    return result;
+  return kCrostiniAppIdPrefix + window_app_id;
+}
+
+bool CrostiniRegistryService::IsCrostiniShelfAppId(
+    const std::string& shelf_app_id) {
+  if (base::StartsWith(shelf_app_id, kCrostiniAppIdPrefix,
+                       base::CompareCase::SENSITIVE))
+    return true;
+  // TODO(timloh): Return true for the default Terminal app.
+  // TODO(timloh): We need to handle desktop files that have been removed.
+  // For example, running windows with a no-longer-valid app id will try to
+  // use the ExtensionContextMenuModel.
+  return prefs_->GetDictionary(kCrostiniRegistryPref)->FindKey(shelf_app_id) !=
+         nullptr;
+}
+
 std::vector<std::string> CrostiniRegistryService::GetRegisteredAppIds() const {
   const base::DictionaryValue* apps =
       prefs_->GetDictionary(kCrostiniRegistryPref);
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service.h b/chrome/browser/chromeos/crostini/crostini_registry_service.h
index dddefc8..09fbde7 100644
--- a/chrome/browser/chromeos/crostini/crostini_registry_service.h
+++ b/chrome/browser/chromeos/crostini/crostini_registry_service.h
@@ -31,6 +31,25 @@
 // the VM isn't running. The registrations here correspond to .desktop files,
 // which are detailed in the spec:
 // https://www.freedesktop.org/wiki/Specifications/desktop-entry-spec/
+
+// This class deals with several types of IDs, including:
+// 1) Desktop File IDs (desktop_file_id):
+//    - As per the desktop entry spec.
+// 2) Crostini App List Ids (app_id):
+//    - Valid extensions ids for apps stored in the registry, derived from the
+//    desktop file id, vm name, and container name.
+//    - The default Terminal app is a special case app list item, without an
+//    entry in the registry.
+// 3) Exo Window App Ids (window_app_id):
+//    - Retrieved from exo::ShellSurface::GetApplicationId()
+//    - For Wayland apps, this is the surface class of the app
+//    - For X apps, this is of the form org.chromium.termina.wmclass.foo when
+//    WM_CLASS is set to foo, or otherwise some string prefixed by
+//    "org.chromium.termina." when WM_CLASS is not set.
+// 4) Shelf App Ids (shelf_app_id):
+//    - Used in ash::ShelfID::app_id
+//    - Either a Window App Id prefixed by "crostini:" or a Crostini App Id.
+//    - For pinned apps, this is a Crostini App Id.
 class CrostiniRegistryService : public KeyedService {
  public:
   struct Registration {
@@ -80,6 +99,20 @@
   explicit CrostiniRegistryService(Profile* profile);
   ~CrostiniRegistryService() override;
 
+  // Returns a shelf app id for an exo window id.
+  //
+  // If the given window app id is not for Crostini (i.e. Arc++), returns an
+  // empty string. If we can uniquely identify a registry entry, returns the
+  // crostini app id for that. Otherwise, returns the |window_app_id|, possibly
+  // prefixed "org.chromium.termina.wayland." if it was not already prefixed.
+  //
+  // As the window app id is derived from fields set by the app itself, it is
+  // possible for an app to masquerade as a different app.
+  std::string GetCrostiniShelfAppId(const std::string& window_app_id,
+                                    const std::string* window_startup_id);
+  // Returns whether the app_id is a Crostini app id.
+  bool IsCrostiniShelfAppId(const std::string& shelf_app_id);
+
   std::vector<std::string> GetRegisteredAppIds() const;
 
   // Return null if |app_id| is not found in the registry.
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc b/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc
index 739571e..55faa2e 100644
--- a/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc
@@ -65,6 +65,10 @@
     return app_list;
   }
 
+  std::string WindowIdForWMClass(const std::string& wm_class) {
+    return "org.chromium.termina.wmclass." + wm_class;
+  }
+
   CrostiniRegistryService* service() { return service_.get(); }
 
  private:
@@ -177,4 +181,40 @@
               testing::UnorderedElementsAre(app_id_1, app_id_3, new_app_id));
 }
 
+TEST_F(CrostiniRegistryServiceTest, GetCrostiniAppIdNoStartupID) {
+  ApplicationList app_list = BasicAppList("app", "vm", "container");
+  *app_list.add_apps() = BasicApp("cool.app");
+  *app_list.add_apps() = BasicApp("super");
+  service()->UpdateApplicationList(app_list);
+
+  service()->UpdateApplicationList(BasicAppList("super", "vm 2", "container"));
+
+  EXPECT_THAT(service()->GetRegisteredAppIds(), testing::SizeIs(4));
+
+  EXPECT_EQ(
+      service()->GetCrostiniShelfAppId(WindowIdForWMClass("App"), nullptr),
+      GenerateAppId("app", "vm", "container"));
+  EXPECT_EQ(
+      service()->GetCrostiniShelfAppId(WindowIdForWMClass("cool.app"), nullptr),
+      GenerateAppId("cool.app", "vm", "container"));
+
+  EXPECT_EQ(
+      service()->GetCrostiniShelfAppId(WindowIdForWMClass("super"), nullptr),
+      "crostini:" + WindowIdForWMClass("super"));
+  EXPECT_EQ(service()->GetCrostiniShelfAppId(
+                "org.chromium.termina.wmclientleader.1234", nullptr),
+            "crostini:org.chromium.termina.wmclientleader.1234");
+  EXPECT_EQ(service()->GetCrostiniShelfAppId("org.chromium.termina.xid.654321",
+                                             nullptr),
+            "crostini:org.chromium.termina.xid.654321");
+
+  EXPECT_EQ(service()->GetCrostiniShelfAppId("cool.app", nullptr),
+            GenerateAppId("cool.app", "vm", "container"));
+  EXPECT_EQ(service()->GetCrostiniShelfAppId("fancy.app", nullptr),
+            "crostini:fancy.app");
+
+  EXPECT_EQ(service()->GetCrostiniShelfAppId("org.chromium.arc.h", nullptr),
+            std::string());
+}
+
 }  // namespace crostini
diff --git a/chrome/browser/ui/app_list/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc
similarity index 62%
rename from chrome/browser/ui/app_list/crostini/crostini_util.cc
rename to chrome/browser/chromeos/crostini/crostini_util.cc
index 67a6f22..2bf467c2 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_util.cc
+++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -2,19 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/app_list/crostini/crostini_util.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 
 #include "base/feature_list.h"
 #include "chrome/browser/chromeos/virtual_machines/virtual_machines_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_features.h"
 
-namespace {
-
-constexpr char kCrostiniAppIdPrefix[] = "crostini:";
-
-}  // namespace
-
 bool IsCrostiniAllowed() {
   return virtual_machines::AreVirtualMachinesAllowedByVersionAndChannel() &&
          virtual_machines::AreVirtualMachinesAllowedByPolicy();
@@ -32,13 +26,3 @@
 bool IsCrostiniRunning() {
   return false;
 }
-
-std::string CreateCrostiniAppId(const std::string& window_app_id) {
-  DCHECK(!IsCrostiniAppId(window_app_id));
-  return kCrostiniAppIdPrefix + window_app_id;
-}
-
-bool IsCrostiniAppId(const std::string& app_id) {
-  return strncmp(app_id.c_str(), kCrostiniAppIdPrefix,
-                 sizeof(kCrostiniAppIdPrefix) - 1) == 0;
-}
diff --git a/chrome/browser/ui/app_list/crostini/crostini_util.h b/chrome/browser/chromeos/crostini/crostini_util.h
similarity index 62%
rename from chrome/browser/ui/app_list/crostini/crostini_util.h
rename to chrome/browser/chromeos/crostini/crostini_util.h
index 9125f56..849d66df7 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_util.h
+++ b/chrome/browser/chromeos/crostini/crostini_util.h
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_APP_LIST_CROSTINI_CROSTINI_UTIL_H_
-#define CHROME_BROWSER_UI_APP_LIST_CROSTINI_CROSTINI_UTIL_H_
-
-#include <string>
+#ifndef CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_UTIL_H_
+#define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_UTIL_H_
 
 // Returns true if crostini is allowed to run.
 // Otherwise, returns false, e.g. if crostini is not available on the device,
@@ -15,15 +13,9 @@
 // Returns true if crostini UI can be shown. Implies crostini is allowed to run.
 bool IsExperimentalCrostiniUIAvailable();
 
-// Returns a Crostini app ID from a Aura window app ID.
-std::string CreateCrostiniAppId(const std::string& window_app_id);
-
-// Returns true if the app_id is a Crostini app ID.
-bool IsCrostiniAppId(const std::string& app_id);
-
 constexpr char kCrostiniDefaultVmName[] = "termina";
 constexpr char kCrostiniDefaultContainerName[] = "penguin";
 constexpr char kCrostiniCroshBuiltinAppId[] =
     "nkoccljplnhpfnfiajclkommnmllphnl";
 
-#endif  // CHROME_BROWSER_UI_APP_LIST_CROSTINI_CROSTINI_UTIL_H_
+#endif  // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_UTIL_H_
diff --git a/chrome/browser/chromeos/docked_magnifier/docked_magnifier_client.cc b/chrome/browser/chromeos/docked_magnifier/docked_magnifier_client.cc
deleted file mode 100644
index 743f697..0000000
--- a/chrome/browser/chromeos/docked_magnifier/docked_magnifier_client.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/docked_magnifier/docked_magnifier_client.h"
-
-#include "ash/public/interfaces/constants.mojom.h"
-#include "content/public/browser/focused_node_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/common/service_manager_connection.h"
-#include "services/service_manager/public/cpp/connector.h"
-
-DockedMagnifierClient::DockedMagnifierClient() : binding_(this) {}
-
-DockedMagnifierClient::~DockedMagnifierClient() {}
-
-void DockedMagnifierClient::Start() {
-  if (!docked_magnifier_controller_) {
-    service_manager::Connector* connector =
-        content::ServiceManagerConnection::GetForProcess()->GetConnector();
-    connector->BindInterface(ash::mojom::kServiceName,
-                             &docked_magnifier_controller_);
-  }
-  ash::mojom::DockedMagnifierClientPtr client;
-  binding_.Bind(mojo::MakeRequest(&client));
-  docked_magnifier_controller_->SetClient(std::move(client));
-}
-
-void DockedMagnifierClient::OnEnabledStatusChanged(bool enabled) {
-  if (enabled == observing_focus_changes_)
-    return;
-
-  observing_focus_changes_ = enabled;
-  if (enabled) {
-    registrar_.Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
-                   content::NotificationService::AllSources());
-  } else {
-    registrar_.Remove(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
-                      content::NotificationService::AllSources());
-  }
-}
-
-void DockedMagnifierClient::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(type, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE);
-
-  content::FocusedNodeDetails* node_details =
-      content::Details<content::FocusedNodeDetails>(details).ptr();
-  // Ash uses the InputMethod of the window tree host to observe text input
-  // caret bounds changes, which works for both the native UI as well as
-  // webpages. We don't need to notify it of editable nodes in this case.
-  if (node_details->is_editable_node)
-    return;
-
-  const gfx::Rect& bounds_in_screen = node_details->node_bounds_in_screen;
-  if (bounds_in_screen.IsEmpty())
-    return;
-
-  docked_magnifier_controller_->CenterOnPoint(bounds_in_screen.CenterPoint());
-}
diff --git a/chrome/browser/chromeos/docked_magnifier/docked_magnifier_client.h b/chrome/browser/chromeos/docked_magnifier/docked_magnifier_client.h
deleted file mode 100644
index f8cfb053..0000000
--- a/chrome/browser/chromeos/docked_magnifier/docked_magnifier_client.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_DOCKED_MAGNIFIER_DOCKED_MAGNIFIER_CLIENT_H_
-#define CHROME_BROWSER_CHROMEOS_DOCKED_MAGNIFIER_DOCKED_MAGNIFIER_CLIENT_H_
-
-#include <memory>
-
-#include "ash/public/interfaces/docked_magnifier_controller.mojom.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-// Observes focus change events for nodes in webpages and notifies the Docked
-// Magnifier with these events.
-class DockedMagnifierClient : public ash::mojom::DockedMagnifierClient,
-                              public content::NotificationObserver {
- public:
-  DockedMagnifierClient();
-  ~DockedMagnifierClient() override;
-
-  void Start();
-
-  // ash::mojom::DockedMagnifierClient:
-  void OnEnabledStatusChanged(bool enabled) override;
-
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
- private:
-  ash::mojom::DockedMagnifierControllerPtr docked_magnifier_controller_;
-  mojo::Binding<ash::mojom::DockedMagnifierClient> binding_;
-
-  content::NotificationRegistrar registrar_;
-
-  bool observing_focus_changes_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(DockedMagnifierClient);
-};
-
-#endif  // CHROME_BROWSER_CHROMEOS_DOCKED_MAGNIFIER_DOCKED_MAGNIFIER_CLIENT_H_
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index 66c19524..8a424bd2 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -770,6 +770,7 @@
   SET_STRING("ZIP_TARGET_EXISTS_ERROR",
              IDS_FILE_BROWSER_ZIP_TARGET_EXISTS_ERROR);
   SET_STRING("ZIP_UNEXPECTED_ERROR", IDS_FILE_BROWSER_ZIP_UNEXPECTED_ERROR);
+  SET_STRING("SEE_MENU_FOR_ACTIONS", IDS_FILE_BROWSER_SEE_MENU_FOR_ACTIONS);
 #undef SET_STRING
 
   dict->SetBoolean("PDF_VIEW_ENABLED",
diff --git a/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc b/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc
index 119a3b0..a037a37a 100644
--- a/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/audio_player_browsertest.cc
@@ -6,19 +6,20 @@
 
 namespace file_manager {
 
-template <GuestMode M>
+template <GuestMode MODE>
 class AudioPlayerBrowserTestBase : public FileManagerBrowserTestBase {
  public:
-  GuestMode GetGuestModeParam() const override { return M; }
+  GuestMode GetGuestModeParam() const override { return MODE; }
+
   const char* GetTestCaseNameParam() const override {
     return test_case_name_.c_str();
   }
 
- protected:
   const char* GetTestManifestName() const override {
     return "audio_player_test_manifest.json";
   }
 
+ protected:
   void set_test_case_name(const std::string& name) { test_case_name_ = name; }
 
  private:
@@ -29,15 +30,7 @@
 typedef AudioPlayerBrowserTestBase<IN_GUEST_MODE>
     AudioPlayerBrowserTestInGuestMode;
 
-// http://crbug.com/508949
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_OpenAudioOnDownloads DISABLED_OpenAudioOnDownloads
-#else
-// TODO(yamaguchi): Enable after removing root cause of the test flakiness.
-// http://crbug.com/804413.
-#define MAYBE_OpenAudioOnDownloads DISABLED_OpenAudioOnDownloads
-#endif
-IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, MAYBE_OpenAudioOnDownloads) {
+IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, OpenAudioOnDownloads) {
   set_test_case_name("openAudioOnDownloads");
   StartTest();
 }
@@ -48,50 +41,22 @@
   StartTest();
 }
 
-// http://crbug.com/508949
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_OpenAudioOnDrive DISABLED_OpenAudioOnDrive
-#else
-// TODO(yamaguchi): Enable after removing root cause of the test flakiness.
-// http://crbug.com/804413.
-#define MAYBE_OpenAudioOnDrive DISABLED_OpenAudioOnDrive
-#endif
-IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, MAYBE_OpenAudioOnDrive) {
+IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, OpenAudioOnDrive) {
   set_test_case_name("openAudioOnDrive");
   StartTest();
 }
 
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_TogglePlayState DISABLED_TogglePlayState
-#else
-// TODO(yamaguchi): Enable after removing root cause of the test flakiness.
-// http://crbug.com/804413.
-#define MAYBE_TogglePlayState DISABLED_TogglePlayState
-#endif
-IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, MAYBE_TogglePlayState) {
+IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, TogglePlayState) {
   set_test_case_name("togglePlayState");
   StartTest();
 }
 
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_ChangeVolumeLevel DISABLED_ChangeVolumeLevel
-#else
-// TODO(yamaguchi): Enable after removing root cause of the test flakiness.
-// http://crbug.com/804413.
-#define MAYBE_ChangeVolumeLevel DISABLED_ChangeVolumeLevel
-#endif
-IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, MAYBE_ChangeVolumeLevel) {
+IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, ChangeVolumeLevel) {
   set_test_case_name("changeVolumeLevel");
   StartTest();
 }
 
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_ChangeTracks DISABLED_ChangeTracks
-#else
-// Also disable because of flakyness. http://crbug.com/618198
-#define MAYBE_ChangeTracks DISABLED_ChangeTracks
-#endif
-IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, MAYBE_ChangeTracks) {
+IN_PROC_BROWSER_TEST_F(AudioPlayerBrowserTest, ChangeTracks) {
   set_test_case_name("changeTracks");
   StartTest();
 }
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 3fb2bf8..446c947 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -130,9 +130,8 @@
                       TestParameter(NOT_IN_GUEST_MODE, "imageOpenDownloads"),
                       TestParameter(NOT_IN_GUEST_MODE, "imageOpenDrive")));
 
-// Flaky: crbug.com/715963
 WRAPPED_INSTANTIATE_TEST_CASE_P(
-    DISABLED_CreateNewFolder,
+    CreateNewFolder,
     FileManagerBrowserTest,
     ::testing::Values(
         TestParameter(NOT_IN_GUEST_MODE, "createNewFolderAfterSelectFile"),
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 4b75729d..aee67a2 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -578,7 +578,7 @@
 }
 
 void FileManagerBrowserTestBase::StartTest() {
-  LOG(INFO) << "FileManagerBrowserTest::StartTest " << GetTestManifestName();
+  LOG(INFO) << "FileManagerBrowserTest::StartTest " << GetTestCaseNameParam();
   InstallExtension(
       base::FilePath(FILE_PATH_LITERAL("ui/file_manager/integration_tests")),
       GetTestManifestName());
diff --git a/chrome/browser/chromeos/file_manager/video_player_browsertest.cc b/chrome/browser/chromeos/file_manager/video_player_browsertest.cc
index 53e304e..d8d236a 100644
--- a/chrome/browser/chromeos/file_manager/video_player_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/video_player_browsertest.cc
@@ -8,25 +8,26 @@
 
 namespace file_manager {
 
-template <GuestMode M>
+template <GuestMode MODE>
 class VideoPlayerBrowserTestBase : public FileManagerBrowserTestBase {
  public:
-  GuestMode GetGuestModeParam() const override { return M; }
-  const char* GetTestCaseNameParam() const override {
-    return test_case_name_.c_str();
-  }
-
- protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(
         chromeos::switches::kEnableVideoPlayerChromecastSupport);
     FileManagerBrowserTestBase::SetUpCommandLine(command_line);
   }
 
+  GuestMode GetGuestModeParam() const override { return MODE; }
+
+  const char* GetTestCaseNameParam() const override {
+    return test_case_name_.c_str();
+  }
+
   const char* GetTestManifestName() const override {
     return "video_player_test_manifest.json";
   }
 
+ protected:
   void set_test_case_name(const std::string& name) { test_case_name_ = name; }
 
  private:
@@ -37,10 +38,7 @@
 typedef VideoPlayerBrowserTestBase<IN_GUEST_MODE>
     VideoPlayerBrowserTestInGuestMode;
 
-// TODO(yamaguchi): Enable after removing root cause of the test flakiness.
-// http://crbug.com/804413.
-IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest,
-                       DISABLED_OpenSingleVideoOnDownloads) {
+IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest, OpenSingleVideoOnDownloads) {
   set_test_case_name("openSingleVideoOnDownloads");
   StartTest();
 }
@@ -51,40 +49,17 @@
   StartTest();
 }
 
-// MEMORY_SANITIZER: http://crbug.com/508949
-// CHROME_OS: http://crbug.com/688568
-#if defined(MEMORY_SANITIZER) || defined(OS_CHROMEOS)
-#define MAYBE_OpenSingleVideoOnDrive DISABLED_OpenSingleVideoOnDrive
-#else
-#define MAYBE_OpenSingleVideoOnDrive OpenSingleVideoOnDrive
-#endif
-IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest, MAYBE_OpenSingleVideoOnDrive) {
+IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest, OpenSingleVideoOnDrive) {
   set_test_case_name("openSingleVideoOnDrive");
   StartTest();
 }
 
-// http://crbug.com/508949
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_CheckInitialElements DISABLED_CheckInitialElements
-#else
-#define MAYBE_CheckInitialElements CheckInitialElements
-#endif
-// TODO(yamaguchi):Enable after removing root cause of the test flakiness.
-// https://crbug.com/804413.
-IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest, DISABLED_CheckInitialElements) {
+IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest, CheckInitialElements) {
   set_test_case_name("checkInitialElements");
   StartTest();
 }
 
-// http://crbug.com/508949
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_ClickControlButtons DISABLED_ClickControlButtons
-#else
-#define MAYBE_ClickControlButtons ClickControlButtons
-#endif
-// TODO(yamaguchi):Enable after removing root cause of the test flakiness.
-// https://crbug.com/804413.
-IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest, DISABLED_ClickControlButtons) {
+IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest, ClickControlButtons) {
   set_test_case_name("clickControlButtons");
   StartTest();
 }
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
index 451a014..1272914 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
@@ -113,7 +113,8 @@
 
   // Make sure gears are in motion in the background.
   auto_enrollment_controller_->Start();
-  network_portal_detector::GetInstance()->StartDetectionIfIdle();
+  network_portal_detector::GetInstance()->StartPortalDetection(
+      false /* force */);
 }
 
 void AutoEnrollmentCheckScreen::Hide() {}
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index 9401723..1da60d1 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -54,7 +54,6 @@
 #include "chromeos/login/auth/authenticator.h"
 #include "chromeos/login/auth/authpolicy_login_helper.h"
 #include "chromeos/login/auth/extended_authenticator.h"
-#include "chromeos/network/portal_detector/network_portal_detector.h"
 #include "components/password_manager/core/browser/hash_password_manager.h"
 #include "components/session_manager/core/session_manager.h"
 #include "components/signin/core/browser/signin_manager.h"
@@ -516,8 +515,6 @@
     VLOG(1) << "Calling session manager's StopSession D-Bus method";
     DBusThreadManager::Get()->GetSessionManagerClient()->StopSession();
   }
-  // Close captive portal window and clear signin profile.
-  network_portal_detector::GetInstance()->OnLockScreenRequest();
 }
 
 // static
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc
index bf2d334..5cbf5557c 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -357,10 +357,10 @@
       is_first_detection_notification_) {
     is_first_detection_notification_ = false;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            base::IgnoreResult(&NetworkPortalDetector::StartDetectionIfIdle),
-            base::Unretained(network_portal_detector::GetInstance())));
+        FROM_HERE, base::BindOnce([]() {
+          network_portal_detector::GetInstance()->StartPortalDetection(
+              false /* force */);
+        }));
     return;
   }
   is_first_detection_notification_ = false;
diff --git a/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc b/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
index 0399bf52..75bc8c8 100644
--- a/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
+++ b/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
@@ -74,6 +74,7 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
     command_line->AppendSwitch(chromeos::switches::kLoginManager);
+    command_line->AppendSwitch(chromeos::switches::kDisableHIDDetectionOnOOBE);
   }
 
   void SetUpOnMainThread() override {
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.cc b/chrome/browser/chromeos/net/network_portal_detector_impl.cc
index b4a3989..ad904b9 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl.cc
@@ -16,7 +16,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/net/network_portal_notification_controller.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_profile_client.h"
@@ -211,8 +210,7 @@
     NetworkPortalDetectorImpl::kDelaySinceShillPortalForUMA;
 
 NetworkPortalDetectorImpl::NetworkPortalDetectorImpl(
-    network::mojom::URLLoaderFactory* loader_factory,
-    bool create_notification_controller)
+    network::mojom::URLLoaderFactory* loader_factory)
     : strategy_(PortalDetectorStrategy::CreateById(
           PortalDetectorStrategy::STRATEGY_ID_LOGIN_SCREEN,
           this)),
@@ -228,21 +226,13 @@
     portal_test_url_ = GURL(CaptivePortalDetector::kDefaultURL);
   }
 
-  if (create_notification_controller) {
-    notification_controller_.reset(
-        new NetworkPortalNotificationController(this));
-    notification_controller_->set_retry_detection_callback(
-        base::Bind(&NetworkPortalDetectorImpl::RetryDetection,
-                   weak_factory_.GetWeakPtr()));
-  }
-
   registrar_.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED,
                  content::NotificationService::AllSources());
   registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED,
                  content::NotificationService::AllSources());
 
   NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
-  StartDetectionIfIdle();
+  StartPortalDetection(false /* force */);
 }
 
 NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() {
@@ -259,6 +249,8 @@
     NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
                                                                    FROM_HERE);
   }
+  for (auto& observer : observers_)
+    observer.OnShutdown();
 }
 
 void NetworkPortalDetectorImpl::AddObserver(Observer* observer) {
@@ -315,9 +307,12 @@
   return it->second;
 }
 
-bool NetworkPortalDetectorImpl::StartDetectionIfIdle() {
-  if (!is_idle())
-    return false;
+bool NetworkPortalDetectorImpl::StartPortalDetection(bool force) {
+  if (!is_idle()) {
+    if (!force)
+      return false;
+    StopDetection();
+  }
   StartDetection();
   return true;
 }
@@ -327,13 +322,7 @@
   if (id == strategy_->Id())
     return;
   strategy_ = PortalDetectorStrategy::CreateById(id, this);
-  StopDetection();
-  StartDetectionIfIdle();
-}
-
-void NetworkPortalDetectorImpl::OnLockScreenRequest() {
-  if (notification_controller_)
-    notification_controller_->CloseDialog();
+  StartPortalDetection(true /* force */);
 }
 
 void NetworkPortalDetectorImpl::DefaultNetworkChanged(
@@ -442,11 +431,6 @@
   ResetStrategyAndCounters();
 }
 
-void NetworkPortalDetectorImpl::RetryDetection() {
-  StopDetection();
-  StartDetection();
-}
-
 void NetworkPortalDetectorImpl::ScheduleAttempt(const base::TimeDelta& delay) {
   DCHECK(is_idle());
 
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.h b/chrome/browser/chromeos/net/network_portal_detector_impl.h
index 3740b158..3ffa9bd 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl.h
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl.h
@@ -41,7 +41,6 @@
 
 namespace chromeos {
 
-class NetworkPortalNotificationController;
 class NetworkState;
 
 // This class handles all notifications about network changes from
@@ -57,8 +56,8 @@
   static constexpr base::TimeDelta kDelaySinceShillPortalForUMA =
       base::TimeDelta::FromSeconds(60);
 
-  NetworkPortalDetectorImpl(network::mojom::URLLoaderFactory* loader_factory,
-                            bool create_notification_controller);
+  explicit NetworkPortalDetectorImpl(
+      network::mojom::URLLoaderFactory* loader_factory);
   ~NetworkPortalDetectorImpl() override;
 
   // Set the URL to be tested for portal state.
@@ -130,9 +129,8 @@
   CaptivePortalState GetCaptivePortalState(const std::string& guid) override;
   bool IsEnabled() override;
   void Enable(bool start_detection) override;
-  bool StartDetectionIfIdle() override;
+  bool StartPortalDetection(bool force) override;
   void SetStrategy(PortalDetectorStrategy::StrategyId id) override;
-  void OnLockScreenRequest() override;
 
   // NetworkStateHandlerObserver implementation:
   void DefaultNetworkChanged(const NetworkState* network) override;
@@ -262,14 +260,8 @@
   // Number of detection attempts in a row with NO RESPONSE result.
   int no_response_result_count_ = 0;
 
-  // Must be declared before |notification_controller_| as
-  // ~NetworkPortalNotificationController() calls
-  // NetworkPortalDetectorImpl::RemoveObserver() which uses this.
   SEQUENCE_CHECKER(sequence_checker_);
 
-  // UI notification controller about captive portal state.
-  std::unique_ptr<NetworkPortalNotificationController> notification_controller_;
-
   content::NotificationRegistrar registrar_;
 
   // Test time ticks used by unit tests.
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc b/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc
index f3221ee..6b0df851 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/location.h"
@@ -75,7 +77,7 @@
       : LoginManagerTest(false),
         test_account_id_(
             AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId)),
-        network_portal_detector_(NULL) {}
+        network_portal_detector_(nullptr) {}
 
   ~NetworkPortalDetectorImplBrowserTest() override {}
 
@@ -85,11 +87,8 @@
     ShillServiceClient::TestInterface* service_test =
         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
     service_test->ClearServices();
-    service_test->AddService(kWifiServicePath,
-                             kWifiGuid,
-                             "wifi",
-                             shill::kTypeEthernet,
-                             shill::kStateIdle,
+    service_test->AddService(kWifiServicePath, kWifiGuid, "wifi",
+                             shill::kTypeEthernet, shill::kStateIdle,
                              true /* add_to_visible */);
     DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
         dbus::ObjectPath(kWifiServicePath), shill::kStateProperty,
@@ -99,16 +98,24 @@
     display_service_ = std::make_unique<NotificationDisplayServiceTester>(
         chromeos::ProfileHelper::GetSigninProfile());
 
-    network_portal_detector_ = new NetworkPortalDetectorImpl(
-        test_loader_factory(), true /* create_notification_controller */);
+    network_portal_detector_ =
+        new NetworkPortalDetectorImpl(test_loader_factory());
+    // Takes ownership of |network_portal_detector_|:
     network_portal_detector::InitializeForTesting(network_portal_detector_);
     network_portal_detector_->Enable(false /* start_detection */);
     set_detector(network_portal_detector_->captive_portal_detector_.get());
     PortalDetectorStrategy::set_delay_till_next_attempt_for_testing(
         base::TimeDelta());
+    network_portal_notification_controller_ =
+        std::make_unique<NetworkPortalNotificationController>(
+            network_portal_detector_);
     base::RunLoop().RunUntilIdle();
   }
 
+  void TearDownOnMainThread() override {
+    network_portal_notification_controller_.reset();
+  }
+
   void RestartDetection() {
     network_portal_detector_->StopDetection();
     network_portal_detector_->StartDetection();
@@ -120,13 +127,11 @@
   }
 
   void SetIgnoreNoNetworkForTesting() {
-    network_portal_detector_->notification_controller_
-        ->SetIgnoreNoNetworkForTesting();
+    network_portal_notification_controller_->SetIgnoreNoNetworkForTesting();
   }
 
   const NetworkPortalWebDialog* GetDialog() const {
-    return network_portal_detector_->notification_controller_
-        ->GetDialogForTesting();
+    return network_portal_notification_controller_->GetDialogForTesting();
   }
 
  protected:
@@ -136,6 +141,8 @@
 
  private:
   NetworkPortalDetectorImpl* network_portal_detector_;
+  std::unique_ptr<NetworkPortalNotificationController>
+      network_portal_notification_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetectorImplBrowserTest);
 };
@@ -152,9 +159,9 @@
   typedef NetworkPortalNotificationController Controller;
 
   EnumHistogramChecker ui_checker(
-      kNotificationMetric, Controller::NOTIFICATION_METRIC_COUNT, NULL);
+      kNotificationMetric, Controller::NOTIFICATION_METRIC_COUNT, nullptr);
   EnumHistogramChecker action_checker(
-      kUserActionMetric, Controller::USER_ACTION_METRIC_COUNT, NULL);
+      kUserActionMetric, Controller::USER_ACTION_METRIC_COUNT, nullptr);
 
   LoginUser(test_account_id_);
   content::RunAllPendingInMessageLoop();
@@ -167,7 +174,7 @@
   // No notification until portal detection is completed.
   EXPECT_FALSE(display_service_->GetNotification(kNotificationId));
   RestartDetection();
-  CompleteURLFetch(net::OK, 200, NULL);
+  CompleteURLFetch(net::OK, 200, nullptr);
 
   // Check that wifi is marked as behind the portal and that notification
   // is displayed.
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
index fa32d900..577fe864 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
@@ -106,7 +106,7 @@
     EXPECT_TRUE(user_manager::UserManager::Get()->GetPrimaryUser());
 
     network_portal_detector_.reset(
-        new NetworkPortalDetectorImpl(test_loader_factory(), false));
+        new NetworkPortalDetectorImpl(test_loader_factory()));
     network_portal_detector_->Enable(false);
 
     set_detector(network_portal_detector_->captive_portal_detector_.get());
@@ -171,8 +171,8 @@
     return network_portal_detector()->state();
   }
 
-  bool start_detection_if_idle() {
-    return network_portal_detector()->StartDetectionIfIdle();
+  bool StartPortalDetection(bool force) {
+    return network_portal_detector()->StartPortalDetection(force);
   }
 
   void enable_error_screen_strategy() {
@@ -857,7 +857,7 @@
   // First portal detection attempts determines ONLINE state.
   SetConnected(kStubWireless1);
   ASSERT_EQ(State::STATE_CHECKING_FOR_PORTAL, state());
-  ASSERT_FALSE(start_detection_if_idle());
+  ASSERT_FALSE(StartPortalDetection(false /* force */));
 
   CompleteURLFetch(net::OK, 204, nullptr);
 
diff --git a/chrome/browser/chromeos/net/network_portal_detector_test_impl.cc b/chrome/browser/chromeos/net/network_portal_detector_test_impl.cc
index cfaa5c55..a70886e 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_test_impl.cc
+++ b/chrome/browser/chromeos/net/network_portal_detector_test_impl.cc
@@ -13,6 +13,8 @@
 }
 
 NetworkPortalDetectorTestImpl::~NetworkPortalDetectorTestImpl() {
+  for (auto& observer : observers_)
+    observer.OnShutdown();
 }
 
 void NetworkPortalDetectorTestImpl::SetDefaultNetworkForTesting(
@@ -86,7 +88,7 @@
 void NetworkPortalDetectorTestImpl::Enable(bool start_detection) {
 }
 
-bool NetworkPortalDetectorTestImpl::StartDetectionIfIdle() {
+bool NetworkPortalDetectorTestImpl::StartPortalDetection(bool force) {
   return false;
 }
 
@@ -95,7 +97,4 @@
   strategy_id_ = id;
 }
 
-void NetworkPortalDetectorTestImpl::OnLockScreenRequest() {
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_portal_detector_test_impl.h b/chrome/browser/chromeos/net/network_portal_detector_test_impl.h
index 8701d5d4..a532ee78 100644
--- a/chrome/browser/chromeos/net/network_portal_detector_test_impl.h
+++ b/chrome/browser/chromeos/net/network_portal_detector_test_impl.h
@@ -34,10 +34,8 @@
       const std::string& service_path) override;
   bool IsEnabled() override;
   void Enable(bool start_detection) override;
-  bool StartDetectionIfIdle() override;
-
+  bool StartPortalDetection(bool force) override;
   void SetStrategy(PortalDetectorStrategy::StrategyId id) override;
-  void OnLockScreenRequest() override;
 
   PortalDetectorStrategy::StrategyId strategy_id() const {
     return strategy_id_;
diff --git a/chrome/browser/chromeos/net/network_portal_notification_controller.cc b/chrome/browser/chromeos/net/network_portal_notification_controller.cc
index 86b4ecc6..c83cb4c 100644
--- a/chrome/browser/chromeos/net/network_portal_notification_controller.cc
+++ b/chrome/browser/chromeos/net/network_portal_notification_controller.cc
@@ -42,6 +42,7 @@
 #include "chromeos/network/network_type_pattern.h"
 #include "components/captive_portal/captive_portal_detector.h"
 #include "components/prefs/pref_service.h"
+#include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user_manager.h"
 #include "extensions/browser/api/networking_config/networking_config_service.h"
 #include "extensions/browser/api/networking_config/networking_config_service_factory.h"
@@ -227,17 +228,23 @@
 NetworkPortalNotificationController::NetworkPortalNotificationController(
     NetworkPortalDetector* network_portal_detector)
     : network_portal_detector_(network_portal_detector), weak_factory_(this) {
-  if (NetworkHandler::IsInitialized()) {  // NULL for unit tests.
+  if (NetworkHandler::IsInitialized()) {  // May be false in tests.
     NetworkHandler::Get()->network_state_handler()->AddObserver(this,
                                                                 FROM_HERE);
   }
-  if (network_portal_detector_)
+  if (network_portal_detector_) {  // May be null in tests.
     network_portal_detector_->AddObserver(this);
+    DCHECK(session_manager::SessionManager::Get());
+    session_manager::SessionManager::Get()->AddObserver(this);
+  }
 }
 
 NetworkPortalNotificationController::~NetworkPortalNotificationController() {
-  if (network_portal_detector_)
+  if (network_portal_detector_) {
+    if (session_manager::SessionManager::Get())
+      session_manager::SessionManager::Get()->RemoveObserver(this);
     network_portal_detector_->RemoveObserver(this);
+  }
   if (NetworkHandler::IsInitialized()) {
     NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
                                                                    FROM_HERE);
@@ -302,6 +309,19 @@
       NetworkPortalNotificationController::NOTIFICATION_METRIC_COUNT);
 }
 
+void NetworkPortalNotificationController::OnShutdown() {
+  CloseDialog();
+  network_portal_detector_->RemoveObserver(this);
+  network_portal_detector_ = nullptr;
+}
+
+void NetworkPortalNotificationController::OnSessionStateChanged() {
+  session_manager::SessionState state =
+      session_manager::SessionManager::Get()->session_state();
+  if (state == session_manager::SessionState::LOCKED)
+    CloseDialog();
+}
+
 void NetworkPortalNotificationController::ShowDialog() {
   if (dialog_)
     return;
@@ -424,8 +444,8 @@
 }
 
 void NetworkPortalNotificationController::OnExtensionFinishedAuthentication() {
-  if (!retry_detection_callback_.is_null())
-    retry_detection_callback_.Run();
+  if (network_portal_detector_)
+    network_portal_detector_->StartPortalDetection(true /* force */);
 }
 
 void NetworkPortalNotificationController::SetIgnoreNoNetworkForTesting() {
diff --git a/chrome/browser/chromeos/net/network_portal_notification_controller.h b/chrome/browser/chromeos/net/network_portal_notification_controller.h
index 93e02a5..30bacf6 100644
--- a/chrome/browser/chromeos/net/network_portal_notification_controller.h
+++ b/chrome/browser/chromeos/net/network_portal_notification_controller.h
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chromeos/network/network_state_handler_observer.h"
 #include "chromeos/network/portal_detector/network_portal_detector.h"
+#include "components/session_manager/core/session_manager_observer.h"
 #include "ui/message_center/public/cpp/notification.h"
 
 namespace extensions {
@@ -28,7 +29,8 @@
 // captive portal.
 class NetworkPortalNotificationController
     : public NetworkStateHandlerObserver,
-      public NetworkPortalDetector::Observer {
+      public NetworkPortalDetector::Observer,
+      public session_manager::SessionManagerObserver {
  public:
   // The values of these metrics are being used for UMA gathering, so it is
   // important that they don't change between releases.
@@ -61,16 +63,6 @@
       NetworkPortalDetector* network_portal_dectector);
   ~NetworkPortalNotificationController() override;
 
-  // |retry_detection_callback| will be called if the controller learns about a
-  // potential change of the captive portal (e.g. if an extension notifies about
-  // a finished authentication).
-  // |retry_detection_callback| will not be called after this controller is
-  // destroyed.
-  void set_retry_detection_callback(
-      const base::Closure& retry_detection_callback) {
-    retry_detection_callback_ = retry_detection_callback;
-  }
-
   // Creates NetworkPortalWebDialog.
   void ShowDialog();
 
@@ -124,6 +116,10 @@
   void OnPortalDetectionCompleted(
       const NetworkState* network,
       const NetworkPortalDetector::CaptivePortalState& state) override;
+  void OnShutdown() override;
+
+  // session_manager::SessionManagerObserver:
+  void OnSessionStateChanged() override;
 
   // Last network guid for which notification was displayed.
   std::string last_network_guid_;
@@ -137,10 +133,6 @@
   // Do not close Portal Login dialog on "No network" error in browser tests.
   bool ignore_no_network_for_testing_ = false;
 
-  // This is called if the controller learns about a potential change of the
-  // captive portal.
-  base::Closure retry_detection_callback_;
-
   base::WeakPtrFactory<NetworkPortalNotificationController> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkPortalNotificationController);
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
index c32cd09..409a659 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
@@ -600,37 +600,16 @@
   if (str->empty()) {
     *str = GetIconUrlFromImage(
         ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-            is_app ? IDR_APP_DEFAULT_ICON : IDR_EXTENSION_DEFAULT_ICON),
-        is_greyscale);
+            is_app ? IDR_APP_DEFAULT_ICON : IDR_EXTENSION_DEFAULT_ICON));
   }
 
   return *str;
 }
 
 std::string ExtensionInfoGenerator::GetIconUrlFromImage(
-    const gfx::Image& image,
-    bool should_greyscale) {
-  // Ignore |should_greyscale| if MD Extensions are enabled.
-  // TODO(dpapad): Remove should_greyscale logic once non-MD Extensions UI is
-  // removed.
-  should_greyscale =
-      should_greyscale &&
-      !base::FeatureList::IsEnabled(features::kMaterialDesignExtensions);
-
+    const gfx::Image& image) {
   scoped_refptr<base::RefCountedMemory> data;
-  if (should_greyscale) {
-    color_utils::HSL shift = {-1, 0, 0.6};
-    const SkBitmap* bitmap = image.ToSkBitmap();
-    DCHECK(bitmap);
-    SkBitmap grey = SkBitmapOperations::CreateHSLShiftedBitmap(*bitmap, shift);
-    scoped_refptr<base::RefCountedBytes> image_bytes(
-        new base::RefCountedBytes());
-    gfx::PNGCodec::EncodeBGRASkBitmap(grey, false, &image_bytes->data());
-    data = image_bytes;
-  } else {
-    data = image.As1xPNGBytes();
-  }
-
+  data = image.As1xPNGBytes();
   std::string base_64;
   base::Base64Encode(base::StringPiece(data->front_as<char>(), data->size()),
                      &base_64);
@@ -642,8 +621,7 @@
     std::unique_ptr<developer::ExtensionInfo> info,
     const gfx::Image& icon) {
   if (!icon.IsEmpty()) {
-    info->icon_url = GetIconUrlFromImage(
-        icon, info->state != developer::EXTENSION_STATE_ENABLED);
+    info->icon_url = GetIconUrlFromImage(icon);
   } else {
     bool is_app =
         info->type == developer::EXTENSION_TYPE_HOSTED_APP ||
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.h b/chrome/browser/extensions/api/developer_private/extension_info_generator.h
index 8fb11cc..84628f8 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator.h
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.h
@@ -69,9 +69,8 @@
   // Returns the icon url for the default icon to use.
   const std::string& GetDefaultIconUrl(bool is_app, bool is_disabled);
 
-  // Returns an icon url from the given image, optionally applying a greyscale.
-  std::string GetIconUrlFromImage(const gfx::Image& image,
-                                  bool should_greyscale);
+  // Returns an icon url from the given image.
+  std::string GetIconUrlFromImage(const gfx::Image& image);
 
   // Various systems, cached for convenience.
   content::BrowserContext* browser_context_;
diff --git a/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
index 6181698..99964e18 100644
--- a/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
+++ b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
@@ -242,34 +242,28 @@
     FileSystemDelegate::FilesSelectedCallback files_selected_callback,
     base::OnceClosure file_selection_canceled_callback) {
   const Extension* extension = extension_function->extension();
-  content::WebContents* web_contents = nullptr;
+  content::WebContents* web_contents =
+      extension_function->GetSenderWebContents();
+
+  if (!web_contents)
+    return false;
 
   // TODO(asargent/benwells) - As a short term remediation for
   // crbug.com/179010 we're adding the ability for a whitelisted extension to
   // use this API since chrome.fileBrowserHandler.selectFile is ChromeOS-only.
   // Eventually we'd like a better solution and likely this code will go back
   // to being platform-app only.
-  if (extension->is_platform_app()) {
-    content::WebContents* candidate = content::WebContents::FromRenderFrameHost(
-        extension_function->render_frame_host());
-    // Make sure there is an app window associated with the web contents.
-    if (AppWindowRegistry::Get(extension_function->browser_context())
-            ->GetAppWindowForWebContents(candidate)) {
-      web_contents = candidate;
-    }
-  } else {
-    // TODO(michaelpg): As a workaround for crbug.com/736930, allow this to work
-    // from a background page by using the the extended
-    // GetAssociatedWebContentsDeprecated() function provided by
-    // ChromeExtensionFunctionDetails. This is safe because only whitelisted
-    // extensions can access the chrome.fileSystem API; platform apps cannot
-    // open the file picker from a background page.
-    web_contents = ChromeExtensionFunctionDetails(extension_function.get())
-                       .GetAssociatedWebContentsDeprecated();
-  }
 
-  if (!web_contents)
+  // Make sure there is an app window associated with the web contents, so that
+  // platform apps cannot open the file picker from a background page.
+  // TODO(michaelpg): As a workaround for https://crbug.com/736930, allow this
+  // to work from a background page for non-platform apps (which, in practice,
+  // is restricted to whitelisted extensions).
+  if (extension->is_platform_app() &&
+      !AppWindowRegistry::Get(extension_function->browser_context())
+           ->GetAppWindowForWebContents(web_contents)) {
     return false;
+  }
 
   // The file picker will hold a reference to the UIThreadExtensionFunction
   // instance, preventing its destruction (and subsequent sending of the
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_api_util.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_api_util.cc
index c0d399bb..9a0eda7 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_api_util.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_api_util.cc
@@ -51,8 +51,9 @@
   for (const chrome::mojom::MediaStreamInfoPtr& info : metadata->raw_tags) {
     extensions::api::media_galleries::StreamInfo stream_info;
     stream_info.type = std::move(info->type);
-    stream_info.tags.additional_properties.Swap(
-        info->additional_properties.get());
+    base::DictionaryValue* dict_value;
+    info->additional_properties.GetAsDictionary(&dict_value);
+    stream_info.tags.additional_properties.Swap(dict_value);
     extension_metadata.raw_tags.push_back(std::move(stream_info));
   }
 
diff --git a/chrome/browser/extensions/api/networking_config_chromeos_apitest_chromeos.cc b/chrome/browser/extensions/api/networking_config_chromeos_apitest_chromeos.cc
index 2dea3a79..5cdb6dbd6 100644
--- a/chrome/browser/extensions/api/networking_config_chromeos_apitest_chromeos.cc
+++ b/chrome/browser/extensions/api/networking_config_chromeos_apitest_chromeos.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
 #include <string>
 
 #include "base/location.h"
@@ -48,6 +49,9 @@
     : public ExtensionApiTest,
       public captive_portal::CaptivePortalDetectorTestBase {
  public:
+  NetworkingConfigTest() : network_portal_detector_(nullptr) {}
+  ~NetworkingConfigTest() override = default;
+
   void SetUpOnMainThread() override {
     ExtensionApiTest::SetUpOnMainThread();
     content::RunAllPendingInMessageLoop();
@@ -81,12 +85,20 @@
 
     content::RunAllPendingInMessageLoop();
 
-    network_portal_detector_ = new NetworkPortalDetectorImpl(
-        test_loader_factory(), true /* create_notification_controller */);
+    network_portal_detector_ =
+        new NetworkPortalDetectorImpl(test_loader_factory());
+    // Takes ownership of |network_portal_detector_|:
     chromeos::network_portal_detector::InitializeForTesting(
         network_portal_detector_);
     network_portal_detector_->Enable(false /* start_detection */);
     set_detector(network_portal_detector_->captive_portal_detector_.get());
+    network_portal_notification_controller_ =
+        std::make_unique<NetworkPortalNotificationController>(
+            network_portal_detector_);
+  }
+
+  void TearDownOnMainThread() override {
+    network_portal_notification_controller_.reset();
   }
 
   void LoadTestExtension() {
@@ -118,7 +130,9 @@
   }
 
  protected:
-  NetworkPortalDetectorImpl* network_portal_detector_ = nullptr;
+  NetworkPortalDetectorImpl* network_portal_detector_;
+  std::unique_ptr<NetworkPortalNotificationController>
+      network_portal_notification_controller_;
   const extensions::Extension* extension_ = nullptr;
   std::unique_ptr<NotificationDisplayServiceTester> display_service_;
 };
diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
index ed6342e..6be68a53 100644
--- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
+++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
@@ -22,6 +22,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/result_codes.h"
 #include "content/public/common/url_constants.h"
+#include "content/public/test/test_utils.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
@@ -443,17 +444,12 @@
 // Test that when an extension with a background page that has a tab open
 // crashes, the tab stays open, and reloading it reloads the extension.
 // Regression test for issue 71629 and 763808.
-//
-// Disabled on Linux dbg: https://crbug.com/831078.
-// TODO(https://crbug.com/831078): Disable it only when site-per-process is
-// enabled.
-#if !defined(NDEBUG) && defined(OS_LINUX)
-#define MAYBE_ReloadTabsWithBackgroundPage DISABLED_ReloadTabsWithBackgroundPage
-#else
-#define MAYBE_ReloadTabsWithBackgroundPage ReloadTabsWithBackgroundPage
-#endif
 IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
-                       MAYBE_ReloadTabsWithBackgroundPage) {
+                       ReloadTabsWithBackgroundPage) {
+  // TODO(https://crbug.com/831078): Fix the test.
+  if (content::AreAllSitesIsolatedForTesting())
+    return;
+
   TabStripModel* tab_strip = browser()->tab_strip_model();
   const size_t count_before = GetEnabledExtensionCount();
   const size_t crash_count_before = GetTerminatedExtensionCount();
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index be125bb5..ca5cc4f 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -264,6 +264,12 @@
 // Tests whether an extension in an interstitial page can send messages to the
 // background page.
 IN_PROC_BROWSER_TEST_P(MessagingApiTest, MessagingInterstitial) {
+#if defined(OS_WIN)
+  // TODO(https://crbug.com/833429): Intermittent timeouts when run with
+  // --site-per-process on Windows.
+  if (content::AreAllSitesIsolatedForTesting())
+    return;
+#endif
   net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
   https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME);
   ASSERT_TRUE(https_server.Start());
diff --git a/chrome/browser/extensions/lazy_background_page_apitest.cc b/chrome/browser/extensions/lazy_background_page_apitest.cc
index e9dd1845..acaff7d7 100644
--- a/chrome/browser/extensions/lazy_background_page_apitest.cc
+++ b/chrome/browser/extensions/lazy_background_page_apitest.cc
@@ -571,61 +571,6 @@
   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
 
-// Tests that the lazy background page updates the chrome://extensions page
-// when it is destroyed.
-IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, UpdateExtensionsPage) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {} /* enabled */, {features::kMaterialDesignExtensions} /* disabled */);
-
-  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIExtensionsURL));
-  auto* extensions_page = browser()->tab_strip_model()->GetActiveWebContents();
-
-  ResultCatcher catcher;
-  base::FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page").
-      AppendASCII("wait_for_view");
-  const Extension* extension = LoadExtension(extdir);
-  ASSERT_TRUE(extension);
-  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
-
-  // The extension should've opened a new tab to an extension page.
-  EXPECT_EQ(extension->GetResourceURL("extension_page.html").spec(),
-            browser()->tab_strip_model()->GetActiveWebContents()->
-                GetURL().spec());
-
-  // Lazy Background Page still exists, because the extension created a new tab
-  // to an extension page.
-  EXPECT_TRUE(IsBackgroundPageAlive(last_loaded_extension_id()));
-
-  // Close the new tab.
-  LazyBackgroundObserver page_complete;
-  browser()->tab_strip_model()->CloseWebContentsAt(
-      browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
-  page_complete.WaitUntilClosed();
-
-  // Lazy Background Page has been shut down.
-  EXPECT_FALSE(IsBackgroundPageAlive(last_loaded_extension_id()));
-
-  // Updating the extensions page is a process that has back-and-forth
-  // communication (i.e., backend tells extensions page something changed,
-  // extensions page requests updated data, backend responds with updated data,
-  // and so forth). This makes it difficult to know for sure when the page is
-  // done updating, so just try a few times. We limit the total number of
-  // attempts so that a) the test *fails* (instead of times out), and b) we
-  // know we're not making a ridiculous amount of trips to update the page.
-  bool is_inactive = false;
-  int kMaxTries = 10;
-  int num_tries = 0;
-  while (!is_inactive && num_tries++ < kMaxTries) {
-    EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
-        extensions_page,
-        "var ele = document.querySelectorAll('div.active-views');"
-        "window.domAutomationController.send("
-        "    ele[0].innerHTML.search('(Inactive)') > 0);",
-        &is_inactive));
-  }
-}
-
 // Tests that the lazy background page will be unloaded if the onSuspend event
 // handler calls an API function such as chrome.storage.local.set().
 // See: http://crbug.com/296834
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 06bdc647..ee67644 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -429,12 +429,6 @@
 const char kEnableHDRDescription[] =
     "Enables HDR support on compatible displays.";
 
-const char kEnableHeapProfilingName[] = "Heap profiling";
-const char kEnableHeapProfilingDescription[] = "Enables heap profiling.";
-const char kEnableHeapProfilingModePseudo[] = "Enabled (pseudo mode)";
-const char kEnableHeapProfilingModeNative[] = "Enabled (native mode)";
-const char kEnableHeapProfilingTaskProfiler[] = "Enabled (task mode)";
-
 const char kEnableHttpFormWarningName[] =
     "Show in-form warnings for sensitive fields when the top-level page is not "
     "HTTPS";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 01c1c67..8e93553 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -295,12 +295,6 @@
 extern const char kEnableHDRName[];
 extern const char kEnableHDRDescription[];
 
-extern const char kEnableHeapProfilingName[];
-extern const char kEnableHeapProfilingDescription[];
-extern const char kEnableHeapProfilingModePseudo[];
-extern const char kEnableHeapProfilingModeNative[];
-extern const char kEnableHeapProfilingTaskProfiler[];
-
 extern const char kEnableHttpFormWarningName[];
 extern const char kEnableHttpFormWarningDescription[];
 
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 2b6baf9..dd7af3a4 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -1448,68 +1448,6 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(PolicyTest, DeveloperToolsDisabledExtensionsDevMode) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {} /* enabled */, {features::kMaterialDesignExtensions} /* disabled */);
-
-  // Verifies that when DeveloperToolsDisabled policy is set, the "dev mode"
-  // in chrome://extensions-frame is actively turned off and the checkbox
-  // is disabled.
-  // Note: We don't test the indicator as it is tested in the policy pref test
-  // for kDeveloperToolsDisabled.
-
-  // This test currently depends on the following assumptions about the webui:
-  // (1) The ID of the checkbox to toggle dev mode
-  const char toggle_dev_mode_accessor_js[] =
-      "document.getElementById('toggle-dev-on')";
-  // (2) The ID of the dev controls containing element
-  const char dev_controls_accessor_js[] =
-      "document.getElementById('dev-controls')";
-  // (3) the fact that dev-controls is displayed/hidden using its height attr
-  const char dev_controls_visibility_check_js[] =
-      "parseFloat(document.getElementById('dev-controls').style.height) > 0";
-
-  // Navigate to the extensions frame and enabled "Developer mode"
-  ui_test_utils::NavigateToURL(browser(),
-                               GURL(chrome::kChromeUIExtensionsFrameURL));
-
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_TRUE(content::ExecuteScript(
-      contents, base::StringPrintf("domAutomationController.send(%s.click());",
-                                   toggle_dev_mode_accessor_js)));
-
-  WaitForExtensionsDevModeControlsVisibility(contents,
-                                             dev_controls_accessor_js,
-                                             dev_controls_visibility_check_js,
-                                             true);
-
-  // Disable devtools via policy.
-  PolicyMap policies;
-  policies.Set(key::kDeveloperToolsDisabled, POLICY_LEVEL_MANDATORY,
-               POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
-               std::make_unique<base::Value>(true), nullptr);
-  UpdateProviderPolicy(policies);
-
-  // Expect devcontrols to be hidden now...
-  WaitForExtensionsDevModeControlsVisibility(contents,
-                                             dev_controls_accessor_js,
-                                             dev_controls_visibility_check_js,
-                                             false);
-
-  // ... and checkbox is not disabled
-  bool is_toggle_dev_mode_checkbox_enabled = false;
-  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
-      contents,
-      base::StringPrintf(
-          "domAutomationController.send(!%s.hasAttribute('disabled'))",
-          toggle_dev_mode_accessor_js),
-      &is_toggle_dev_mode_checkbox_enabled));
-  EXPECT_FALSE(is_toggle_dev_mode_checkbox_enabled);
-}
-
-// TODO(dpapad): Remove the "_MD" suffix once the non-MD test is deleted.
-IN_PROC_BROWSER_TEST_F(PolicyTest, DeveloperToolsDisabledExtensionsDevMode_MD) {
   // Verifies that when DeveloperToolsDisabled policy is set, the "dev mode"
   // in chrome://extensions is actively turned off and the checkbox
   // is disabled.
diff --git a/chrome/browser/policy/site_isolation_policy_browsertest.cc b/chrome/browser/policy/site_isolation_policy_browsertest.cc
index 4714df07..e7f249f 100644
--- a/chrome/browser/policy/site_isolation_policy_browsertest.cc
+++ b/chrome/browser/policy/site_isolation_policy_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/macros.h"
+#include "build/build_config.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -124,7 +125,9 @@
     // the call to the base setup method because setting the Site Isolation
     // policy is indistinguishable from setting the the command line flag
     // directly.
-    are_sites_isolated_for_testing_ = content::AreAllSitesIsolatedForTesting();
+    are_sites_isolated_for_testing_ =
+        !base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kDisableSiteIsolationTrials);
 
     // We setup the policy here, because the policy must be 'live' before the
     // renderer is created, since the value for this policy is passed to the
@@ -226,7 +229,15 @@
   CheckExpectations(expectations, arraysize(expectations));
 }
 
-IN_PROC_BROWSER_TEST_F(SiteIsolationPolicyBrowserTest, NoPolicyNoTrialsFlags) {
+// https://crbug.com/833423: The test is incompatible with the
+// not_site_per_process_browser_tests step on the trybots.
+#if defined(OS_LINUX)
+#define MAYBE_NoPolicyNoTrialsFlags DISABLED_NoPolicyNoTrialsFlags
+#else
+#define MAYBE_NoPolicyNoTrialsFlags NoPolicyNoTrialsFlags
+#endif
+IN_PROC_BROWSER_TEST_F(SiteIsolationPolicyBrowserTest,
+                       MAYBE_NoPolicyNoTrialsFlags) {
   ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kDisableSiteIsolationTrials));
 }
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc
index bf64784..d03b2815 100644
--- a/chrome/browser/push_messaging/push_messaging_browsertest.cc
+++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -1725,7 +1725,14 @@
 
 // Push subscriptions used to be non-InstanceID GCM registrations. Still need
 // to be able to unsubscribe these, even though new ones are no longer created.
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, LegacyUnsubscribeSuccess) {
+// Flaky on some Win and Linux buildbots.  See crbug.com/835382.
+#if defined(OS_WIN) || defined(OS_LINUX)
+#define MAYBE_LegacyUnsubscribeSuccess DISABLED_LegacyUnsubscribeSuccess
+#else
+#define MAYBE_LegacyUnsubscribeSuccess LegacyUnsubscribeSuccess
+#endif
+IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+                       MAYBE_LegacyUnsubscribeSuccess) {
   std::string script_result;
 
   std::string subscription_id1;
diff --git a/chrome/browser/resource_coordinator/resource_coordinator_render_process_probe_browsertest.cc b/chrome/browser/resource_coordinator/resource_coordinator_render_process_probe_browsertest.cc
index 081686fb..1c27a39 100644
--- a/chrome/browser/resource_coordinator/resource_coordinator_render_process_probe_browsertest.cc
+++ b/chrome/browser/resource_coordinator/resource_coordinator_render_process_probe_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/resource_coordinator/resource_coordinator_render_process_probe.h"
 #include "chrome/browser/ui/browser.h"
@@ -82,6 +83,12 @@
 
 IN_PROC_BROWSER_TEST_F(ResourceCoordinatorRenderProcessProbeBrowserTest,
                        TrackAndMeasureActiveRenderProcesses) {
+#if defined(OS_WIN)
+  // TODO(https://crbug.com/833430): Spare-RPH-related failures when run with
+  // --site-per-process on Windows.
+  if (content::AreAllSitesIsolatedForTesting())
+    return;
+#endif
   // Ensure that the |resource_coordinator| service is enabled.
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures({features::kGlobalResourceCoordinator,
diff --git a/chrome/browser/resources/chromeos/arc_support/background.js b/chrome/browser/resources/chromeos/arc_support/background.js
index 040ecfd..fc9371f 100644
--- a/chrome/browser/resources/chromeos/arc_support/background.js
+++ b/chrome/browser/resources/chromeos/arc_support/background.js
@@ -991,6 +991,12 @@
     overlayWebview.addEventListener('contentload', function() {
       overlay.classList.remove('overlay-loading');
     });
+    overlayWebview.addContentScripts([{
+      name: 'postProcess',
+      matches: ['https://support.google.com/*'],
+      css: {files: ['overlay.css']},
+      run_at: 'document_end'
+    }]);
 
     focusManager = new appWindow.contentWindow.ArcOptInFocusManager();
     focusManager.initialize();
diff --git a/chrome/browser/resources/chromeos/arc_support/overlay.css b/chrome/browser/resources/chromeos/arc_support/overlay.css
new file mode 100644
index 0000000..cff4f363
--- /dev/null
+++ b/chrome/browser/resources/chromeos/arc_support/overlay.css
@@ -0,0 +1,11 @@
+/* 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. */
+
+/* Hide header for help articles that contains sign-in button, link to apps and
+   search bar. Also hide div of class promotion-container that has link to
+   YouTube */
+.hcfe .promotion-container,
+.hcfe > header {
+  display: none;
+}
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index 99412e0f..d3a8c99 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -108,7 +108,7 @@
       <p>After2</p>
       <p>After3</p>
     </div>
-    <div id="live" aria-live="polite"></div>
+    <div id="live" aria-live="assertive"></div>
     <div id="delete" role="button">Delete</div>
     <script>
       document.getElementById('delete').addEventListener('click', function() {
@@ -1343,7 +1343,7 @@
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(function(root) {/*!
     <div><input value="test" type="text"></input></div>
-    <div id="live" aria-live="polite"></div>
+    <div id="live" aria-live="assertive"></div>
     <script>
       const input = document.querySelector('input');
       const [div, live] = document.querySelectorAll('div');
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js
index a227302..8838b3b3 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js
@@ -15,6 +15,7 @@
 var RoleType = chrome.automation.RoleType;
 var TreeChange = chrome.automation.TreeChange;
 var TreeChangeObserverFilter = chrome.automation.TreeChangeObserverFilter;
+var TreeChangeType = chrome.automation.TreeChangeType;
 
 /**
  * ChromeVox2 live region handler.
@@ -43,6 +44,13 @@
    * @private
    */
   this.liveRegionNodeSet_ = new WeakSet();
+
+  /**
+   * A list of nodes that have changed as part of one atomic tree update.
+   * @private {!Array}
+   */
+  this.changedNodes_ = [];
+
   chrome.automation.addTreeChangeObserver(
       TreeChangeObserverFilter.LIVE_REGION_TREE_CHANGES,
       this.onTreeChange.bind(this));
@@ -105,15 +113,39 @@
     var all = relevant.indexOf('all') >= 0;
 
     if (all ||
-        (additions && (type == 'nodeCreated' || type == 'subtreeCreated'))) {
-      this.outputLiveRegionChange_(node, null);
+        (additions &&
+         (type == TreeChangeType.NODE_CREATED ||
+          type == TreeChangeType.SUBTREE_CREATED))) {
+      this.queueLiveRegionChange_(node);
     }
 
-    if (all || (text && type == 'textChanged'))
-      this.outputLiveRegionChange_(node, null);
+    if (all || (text && type == TreeChangeType.TEXT_CHANGED))
+      this.queueLiveRegionChange_(node);
 
-    if (all || (removals && type == 'nodeRemoved'))
+    if (all || (removals && type == TreeChangeType.NODE_REMOVED))
       this.outputLiveRegionChange_(node, '@live_regions_removed');
+
+    if (type == TreeChangeType.SUBTREE_UPDATE_END)
+      this.processQueuedTreeChanges_();
+  },
+
+  /**
+   * @param {!AutomationNode} node
+   * @private
+   */
+  queueLiveRegionChange_: function(node) {
+    this.changedNodes_.push(node);
+  },
+
+  /**
+   * @private
+   */
+  processQueuedTreeChanges_: function() {
+    this.liveRegionNodeSet_ = new WeakSet();
+    this.changedNodes_.forEach(function(node) {
+      this.outputLiveRegionChange_(node, null);
+    }.bind(this));
+    this.changedNodes_ = [];
   },
 
   /**
@@ -129,10 +161,6 @@
     if (node.containerLiveBusy)
       return;
 
-    var delta = new Date() - this.lastLiveRegionTime_;
-    if (delta > LiveRegions.LIVE_REGION_MIN_SAME_NODE_MS)
-      this.liveRegionNodeSet_ = new WeakSet();
-
     while (node.containerLiveAtomic && !node.liveAtomic && node.parent)
       node = node.parent;
 
@@ -158,15 +186,15 @@
     // Queue live regions coming from background tabs.
     var webView = AutomationUtil.getTopLevelRoot(node);
     webView = webView ? webView.parent : null;
-    var forceQueueForBackgroundedLiveRegion =
-        !webView || !webView.state.focused;
+    var forceQueue = !webView || !webView.state.focused ||
+        node.containerLiveStatus == 'polite';
 
     // Enqueue live region updates that were received at approximately
     // the same time, otherwise flush previous live region updates.
     var queueTime = LiveRegions.LIVE_REGION_QUEUE_TIME_MS;
     var currentTime = new Date();
     var delta = currentTime - this.lastLiveRegionTime_;
-    if (delta > queueTime && !forceQueueForBackgroundedLiveRegion)
+    if (delta > queueTime && !forceQueue)
       output.withQueueMode(cvox.QueueMode.CATEGORY_FLUSH);
     else
       output.withQueueMode(cvox.QueueMode.QUEUE);
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions_test.extjs
index 5e90a7f5..518a750 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions_test.extjs
@@ -23,6 +23,7 @@
   /** @override */
   setUp: function() {
     window.RoleType = chrome.automation.RoleType;
+    window.TreeChangeType = chrome.automation.TreeChangeType;
   },
 
   /**
@@ -52,7 +53,7 @@
   this.runWithLoadedTree(
     function() {/*!
       <h1>Document with live region</h1>
-      <p id="live" aria-live="polite"></p>
+      <p id="live" aria-live="assertive"></p>
       <button id="go">Go</button>
       <script>
         document.getElementById('go').addEventListener('click', function() {
@@ -73,7 +74,7 @@
   this.runWithLoadedTree(
     function() {/*!
       <h1>Document with live region</h1>
-      <p id="live" aria-live="polite" aria-relevant="removals">Hello, world</p>
+      <p id="live" aria-live="assertive" aria-relevant="removals">Hello, world</p>
       <button id="go">Go</button>
       <script>
         document.getElementById('go').addEventListener('click', function() {
@@ -95,7 +96,7 @@
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(
     function() {/*!
-      <div id="live" aria-live="polite" aria-atomic="true">
+      <div id="live" aria-live="assertive" aria-atomic="true">
         <div></div><div>Bravo</div><div></div>
       </div>
       <button id="go">Go</button>
@@ -120,7 +121,7 @@
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(
     function() {/*!
-      <h1 aria-atomic="true" id="live"aria-live="polite">foo</h1>
+      <h1 aria-atomic="true" id="live"aria-live="assertive">foo</h1>
       <button id="go">go</button>
       <script>
         document.getElementById('go').addEventListener('click', function(e) {
@@ -146,7 +147,7 @@
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(
     function() {/*!
-      <div id="live" aria-live="polite">
+      <div id="live" aria-live="assertive">
         <img id="img" src="#" alt="Before">
       </div>
       <button id="go">Go</button>
@@ -169,7 +170,7 @@
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(
     function() {/*!
-      <div id="live" aria-live="polite"></div>
+      <div id="live" aria-live="assertive"></div>
       <button id="go">Go</button>
       <button id="focus">Focus</button>
       <script>
@@ -194,7 +195,7 @@
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(
     function() {/*!
-      <div id="live" aria-live="polite"></div>
+      <div id="live" aria-live="assertive"></div>
       <button id="go">Go</button>
       <button id="focus">Focus</button>
       <script>
@@ -222,8 +223,8 @@
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(
     function() {/*!
-      <div id="live1" aria-live="polite"></div>
-      <div id="live2" aria-live="polite"></div>
+      <div id="live1" aria-live="assertive"></div>
+      <div id="live2" aria-live="assertive"></div>
       <button id="go">Go</button>
       <button id="focus">Focus</button>
       <script>
@@ -249,7 +250,7 @@
   this.runWithLoadedTree(function() {/*!
     <p>start</p>
     <button>first</button>
-    <div role="button" id="live" aria-live="polite">
+    <div role="button" id="live" aria-live="assertive">
       hello!
     </div>
     <script>
@@ -272,3 +273,33 @@
     mockFeedback.replay();
   });
 });
+
+TEST_F('LiveRegionsTest', 'SimulateTreeChanges', function() {
+  var mockFeedback = this.createMockFeedback();
+  this.runWithLoadedTree(function() {/*!
+    <button></button>
+    <div aria-live="assertive">
+      <p>hello</p><p>there</p>
+    </div>
+  */},
+  function(root) {
+    var live = new LiveRegions(ChromeVoxState.instance);
+    var t1, t2;
+    [t1, t2] = root.findAll({role: RoleType.STATIC_TEXT});
+    mockFeedback.call(function() {
+          live.onTreeChange({type: TreeChangeType.TEXT_CHANGED, target: t2});
+          live.onTreeChange({type: TreeChangeType.SUBTREE_UPDATE_END, target: t2});
+        })
+        .expectNextSpeechUtteranceIsNot('hello')
+        .expectSpeech('there')
+        .clearPendingOutput()
+        mockFeedback.call(function() {
+          live.onTreeChange({type: TreeChangeType.TEXT_CHANGED, target: t1});
+          live.onTreeChange({type: TreeChangeType.TEXT_CHANGED, target: t2});
+          live.onTreeChange({type: TreeChangeType.SUBTREE_UPDATE_END, target: t2});
+        })
+        .expectSpeech('hello')
+        .expectSpeech('there');
+    mockFeedback.replay();
+  });
+});
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
index f72794d..c77a14ce 100644
--- a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
+++ b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
@@ -97,6 +97,12 @@
       overlayUrl.addEventListener('contentload', function() {
         overlayUrl.classList.remove('overlay-loading');
       });
+      overlayUrl.addContentScripts([{
+        name: 'postProcess',
+        matches: ['https://support.google.com/*'],
+        css: {files: ['overlay.css']},
+        run_at: 'document_end'
+      }]);
 
       // Update the screen size after setup layout.
       if (Oobe.getInstance().currentScreen === this)
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/button_bar.html b/chrome/browser/resources/chromeos/multidevice_setup/button_bar.html
new file mode 100644
index 0000000..7db0578
--- /dev/null
+++ b/chrome/browser/resources/chromeos/multidevice_setup/button_bar.html
@@ -0,0 +1,37 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="i18n_setup.html">
+
+
+<dom-module id="button-bar">
+  <template>
+    <style include="paper-button-style cr-shared-style">
+      :host {
+        display: flex;
+        justify-content: flex-end;
+      }
+
+      paper-button {
+        text-transform: none;
+      }
+    </style>
+    <paper-button
+        id="backward"
+        on-tap="onBackwardButtonTapped_"
+        class="cancel-button"
+        hidden$="[[!backwardButtonText]]">
+      [[backwardButtonText]]
+    </paper-button>
+    <paper-button
+        id="forward"
+        on-tap="onForwardButtonTapped_"
+        class="action-button"
+        hidden$="[[!forwardButtonText]]">
+      [[forwardButtonText]]
+    </paper-button>
+  </template>
+  <script src="button_bar.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/button_bar.js b/chrome/browser/resources/chromeos/multidevice_setup/button_bar.js
new file mode 100644
index 0000000..85d76c56
--- /dev/null
+++ b/chrome/browser/resources/chromeos/multidevice_setup/button_bar.js
@@ -0,0 +1,41 @@
+// 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.
+
+/**
+ * DOM Element containing (page-dependent) navigation buttons for the
+ * MultiDevice Setup WebUI.
+ */
+Polymer({
+  is: 'button-bar',
+
+  properties: {
+    /**
+     *  Translated text to display on the forward-naviation button.
+     *
+     *  Undefined if the visible page has no forward-navigation button.
+     *
+     *  @type {string|undefined}
+     */
+    forwardButtonText: String,
+
+    /**
+     *  Translated text to display on the backward-naviation button.
+     *
+     *  Undefined if the visible page has no backward-navigation button.
+     *
+     *  @type {string|undefined}
+     */
+    backwardButtonText: String,
+  },
+
+  /** @private */
+  onForwardButtonTapped_: function() {
+    this.fire('forward-navigation-requested');
+  },
+
+  /** @private */
+  onBackwardButtonTapped_: function() {
+    this.fire('backward-navigation-requested');
+  },
+});
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/button_navigation_behavior.html b/chrome/browser/resources/chromeos/multidevice_setup/button_navigation_behavior.html
index 931808b..1a749867 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/button_navigation_behavior.html
+++ b/chrome/browser/resources/chromeos/multidevice_setup/button_navigation_behavior.html
@@ -1,3 +1,4 @@
 <link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
 
 <script src="button_navigation_behavior.js"></script>
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/button_navigation_behavior.js b/chrome/browser/resources/chromeos/multidevice_setup/button_navigation_behavior.js
index 3d56bf9..85b5ac2 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/button_navigation_behavior.js
+++ b/chrome/browser/resources/chromeos/multidevice_setup/button_navigation_behavior.js
@@ -3,12 +3,67 @@
 // found in the LICENSE file.
 
 /** @polymerBehavior */
-const ButtonNavigationBehavior = {
+const ButtonNavigationBehaviorImpl = {
   properties: {
-    /** @type {string|undefined} */
-    forwardButtonText: String,
+    /**
+     *  ID for forward button label, which must be translated for display.
+     *
+     *  Undefined if the visible page has no forward-navigation button.
+     *
+     *  @type {string|undefined}
+     */
+    forwardButtonTextId: String,
 
-    /** @type {string|undefined} */
-    backwardButtonText: String,
+    /**
+     *  ID for backward button label, which must be translated for display.
+     *
+     *  Undefined if the visible page has no backward-navigation button.
+     *
+     *  @type {string|undefined}
+     */
+    backwardButtonTextId: String,
+
+    /**
+     *  Translated text to display on the forward-naviation button.
+     *
+     *  Undefined if the visible page has no forward-navigation button.
+     *
+     *  @type {string|undefined}
+     */
+    forwardButtonText: {
+      type: String,
+      computed: 'computeButtonText_(forwardButtonTextId)',
+    },
+
+    /**
+     *  Translated text to display on the backward-naviation button.
+     *
+     *  Undefined if the visible page has no backward-navigation button.
+     *
+     *  @type {string|undefined}
+     */
+    backwardButtonText: {
+      type: String,
+      computed: 'computeButtonText_(backwardButtonTextId)',
+    },
+  },
+
+  /**
+   * @param {string} buttonTextId Key for the localized string to appear on a
+   *     button.
+   * @return {string|undefined} The localized string corresponding to the key
+   *     buttonTextId. Return value is undefined if buttonTextId is not a key
+   *     for any localized string. Note: this includes the case in which
+   *     buttonTextId is undefined.
+   * @private
+   */
+  computeButtonText_(buttonTextId) {
+    return this.i18nExists(buttonTextId) ? this.i18n(buttonTextId) : undefined;
   },
 };
+
+/** @polymerBehavior */
+const ButtonNavigationBehavior = [
+  I18nBehavior,
+  ButtonNavigationBehaviorImpl,
+];
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/compiled_resources2.gyp b/chrome/browser/resources/chromeos/multidevice_setup/compiled_resources2.gyp
index af3b93cc..4fa64d95 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/compiled_resources2.gyp
+++ b/chrome/browser/resources/chromeos/multidevice_setup/compiled_resources2.gyp
@@ -1,43 +1,62 @@
-# 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.
+#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.
 {
-  'targets': [
+  'targets' : [
     {
-      'target_name': 'button_navigation_behavior',
-      'dependencies': [],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+      'target_name' : 'button_bar',
+      'dependencies' : [],
+      'includes' :
+          ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
 
     {
-      'target_name': 'multidevice_setup',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+      'target_name' : 'button_navigation_behavior',
+      'dependencies' : [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
-        'button_navigation_behavior',
-        'setup_failed_page',
-        'setup_succeeded_page',
-        'start_setup_page',
       ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+      'includes' :
+          ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
 
     {
-      'target_name': 'setup_failed_page',
-      'dependencies': ['button_navigation_behavior'],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+      'target_name' : 'multidevice_setup',
+      'dependencies' : [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+        'button_bar',
+        'start_setup_page',
+        'setup_succeeded_page',
+        'setup_failed_page',
+      ],
+      'includes' :
+          ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
 
     {
-      'target_name': 'setup_succeeded_page',
-      'dependencies': ['button_navigation_behavior'],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+      'target_name' : 'setup_failed_page',
+      'dependencies' : [
+        'button_navigation_behavior',
+      ],
+      'includes' :
+          ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
 
     {
-      'target_name': 'start_setup_page',
-      'dependencies': ['button_navigation_behavior'],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+      'target_name' : 'setup_succeeded_page',
+      'dependencies' : [
+        'button_navigation_behavior',
+      ],
+      'includes' :
+          ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+
+    {
+      'target_name' : 'start_setup_page',
+      'dependencies' : [
+        'button_navigation_behavior',
+      ],
+      'includes' :
+          ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
   ],
 }
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/i18n_setup.html b/chrome/browser/resources/chromeos/multidevice_setup/i18n_setup.html
new file mode 100644
index 0000000..b1bc3de
--- /dev/null
+++ b/chrome/browser/resources/chromeos/multidevice_setup/i18n_setup.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/load_time_data.html">
+
+<script src="strings.js"></script>
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup.html b/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup.html
index c12690dd..2a0752b7 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup.html
+++ b/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup.html
@@ -2,6 +2,7 @@
 
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
+<link rel="import" href="button_bar.html">
 <link rel="import" href="button_navigation_behavior.html">
 <link rel="import" href="setting_up_page.html">
 <link rel="import" href="setup_failed_page.html">
@@ -10,14 +11,19 @@
 
 <dom-module id="multidevice-setup">
   <template>
-    <iron-pages id="pages" attr-for-selected="is"
-        selected="[[visiblePageName_]]" selected-item="{{visiblePage_}}">
+    <iron-pages
+        id="pages"
+        attr-for-selected="is"
+        selected="[[visiblePageName_]]"
+        selected-item="{{visiblePage_}}">
       <setup-failed-page></setup-failed-page>
       <setup-succeeded-page></setup-succeeded-page>
       <start-setup-page></start-setup-page>
     </iron-pages>
-    <div>Forward Button: [[visiblePage_.forwardButtonText]]</div>
-    <div>Backward Button: [[visiblePage_.backwardButtonText]]</div>
+    <button-bar
+        forward-button-text="[[visiblePage_.forwardButtonText]]"
+        backward-button-text="[[visiblePage_.backwardButtonText]]">
+    </button-bar>
   </template>
   <script src="multidevice_setup.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup.js b/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup.js
index f4f40a07..a7265e6 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup.js
+++ b/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup.js
@@ -2,67 +2,105 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/** @polymer */
-Polymer({
-  is: 'multidevice-setup',
+cr.define('multidevice_setup', function() {
+  /** @enum {string} */
+  const PageName = {
+    FAILURE: 'setup-failed-page',
+    SUCCESS: 'setup-succeeded-page',
+    START: 'start-setup-page',
+  };
 
-  properties: {
-    /**
-     * Array of objects representing all available MultiDevice hosts. Each
-     * object contains the name of the device type (e.g. "Pixel XL") and its
-     * Device ID.
-     *
-     * @private
-     * @type {Array<{name: string, id: string}>}
-     */
-    devices_: Array,
+  const MultiDeviceSetup = Polymer({
+    is: 'multidevice-setup',
 
-    /**
-     * Element name of the currently visible page.
-     *
-     * @private
-     * @type {string}
-     */
-    visiblePageName_: {
-      type: String,
-      value: 'start-setup-page',
+    properties: {
+      /**
+       * Array of objects representing all available MultiDevice hosts. Each
+       * object contains the name of the device type (e.g. "Pixel XL") and its
+       * Device ID.
+       *
+       * @private {Array<{name: string, id: string}>}
+       */
+      devices_: Array,
+
+      /**
+       * Element name of the currently visible page.
+       *
+       * @private {!PageName}
+       */
+      visiblePageName_: {
+        type: String,
+        value: PageName.START,
+      },
+
+      /**
+       * DOM Element corresponding to the visible page.
+       *
+       * @private {!StartSetupPageElement|!SetupSucceededPageElement|
+       *           !SetupFailedPageElement}
+       */
+      visiblePage_: {
+        type: Object,
+        // Note: This notification is for testing purposes.
+        notify: true,
+      },
+
+      /**
+       * Device ID for the currently selected host device.
+       *
+       * Undefined if the no list of potential hosts has been received from mojo
+       * service.
+       *
+       * @private {string|undefined}
+       */
+      selectedDeviceId_: String,
     },
 
-    /**
-     * DOM Element corresponding to the visible page.
-     *
-     * @private
-     * @type {!SetupFailedPageElement|!SetupSucceededPageElement|
-     *        !StartSetupPageElement}
-     */
-    visiblePage_: Object,
+    listeners: {
+      'forward-navigation-requested': 'onForwardNavigationRequested_',
+      'backward-navigation-requested': 'onBackwardNavigationRequested_',
+    },
 
-    /**
-     *  Device ID for the currently selected host device.
-     *
-     *  Undefined if the no list of potential hosts has been received from
-     *  CryptAuth.
-     *
-     *  @private
-     *  @type {string|undefined}
-     */
-    selectedDeviceId_: String,
-  },
+    // Instance methods
 
-  listeners: {
-    'forward-navigation-requested': 'onForwardNavigationRequested_',
-    'backward-navigation-requested': 'onBackwardNavigationRequested_',
-  },
+    closeUi_: function() {
+      // TODO(jordynass): Implement closing UI.
+      console.log('Closing WebUI');
+      // This method is just for testing that the method was called
+      this.fire('ui-closed');
+    },
 
-  // Event handling callbacks
+    // Event handling callbacks
 
-  /** @private */
-  onForwardNavigationRequested_: function() {
-    // TODO(jordynass): Put in page specific logic as each page is implemented.
-  },
+    /** @private */
+    onForwardNavigationRequested_: function() {
+      switch (this.visiblePageName_) {
+        case PageName.FAILURE:
+          this.visiblePageName_ = PageName.START;
+          break;
+        case PageName.SUCCESS:
+          this.closeUi_();
+          break;
+        case PageName.START:
+          // TODO(jordynass): Once mojo API is complete, this should call
+          // SetBetterTogetherHost(selectedDeviceId)
+          console.log('Calling SetBetterTogetherHost(selectedDeviceId)');
+      }
+    },
 
-  /** @private */
-  onBackwardNavigationRequested_: function() {
-    // TODO(jordynass): Put in page specific logic as each page is implemented.
-  },
+    /** @private */
+    onBackwardNavigationRequested_: function() {
+      switch (this.visiblePageName_) {
+        case PageName.FAILURE:
+          this.closeUi_();
+          break;
+        case PageName.START:
+          this.closeUi_();
+      }
+    },
+  });
+
+  return {
+    MultiDeviceSetup: MultiDeviceSetup,
+  };
 });
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_resources.grd b/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_resources.grd
index aeeb1307..a10e30a 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_resources.grd
+++ b/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_resources.grd
@@ -12,12 +12,21 @@
   </outputs>
   <release seq="1">
     <structures>
+      <structure name="IDR_MULTIDEVICE_SETUP_BUTTON_BAR_HTML"
+                 file="button_bar.html"
+                 type="chrome_html" />
+      <structure name="IDR_MULTIDEVICE_SETUP_BUTTON_BAR_JS"
+                 file="button_bar.js"
+                 type="chrome_html" />
       <structure name="IDR_MULTIDEVICE_SETUP_BUTTON_NAVIGATION_BEHAVIOR_HTML"
                  file="button_navigation_behavior.html"
                  type="chrome_html" />
       <structure name="IDR_MULTIDEVICE_SETUP_BUTTON_NAVIGATION_BEHAVIOR_JS"
                  file="button_navigation_behavior.js"
                  type="chrome_html" />
+      <structure name="IDR_MULTIDEVICE_SETUP_I18N_SETUP_HTML"
+                 file="i18n_setup.html"
+                 type="chrome_html" />
       <structure name="IDR_MULTIDEVICE_SETUP_MULTIDEVICE_SETUP_DIALOG_HTML"
                  file="multidevice_setup_dialog.html"
                  flattenhtml="true"
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/setup_failed_page.html b/chrome/browser/resources/chromeos/multidevice_setup/setup_failed_page.html
index 210c172..f8ecec6 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/setup_failed_page.html
+++ b/chrome/browser/resources/chromeos/multidevice_setup/setup_failed_page.html
@@ -5,7 +5,7 @@
 
 <dom-module id="setup-failed-page">
   <template>
-    Setup Failed Placeholder Text
+    --------------Setup Failed Placeholder Text--------------
   </template>
   <script src="setup_failed_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/setup_failed_page.js b/chrome/browser/resources/chromeos/multidevice_setup/setup_failed_page.js
index 6eb5b503..1c88f612 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/setup_failed_page.js
+++ b/chrome/browser/resources/chromeos/multidevice_setup/setup_failed_page.js
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/** @polymer */
 Polymer({
   is: 'setup-failed-page',
 
@@ -10,17 +9,17 @@
     /**
      * Overriden from ButtonNavigationBehavior
      */
-    forwardButtonText: {
+    forwardButtonTextId: {
       type: String,
-      value: 'Try again',
+      value: 'tryAgain',
     },
 
     /**
      * Overriden from ButtonNavigationBehavior
      */
-    backwardButtonText: {
+    backwardButtonTextId: {
       type: String,
-      value: 'Cancel',
+      value: 'cancel',
     },
   },
 
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/setup_succeeded_page.html b/chrome/browser/resources/chromeos/multidevice_setup/setup_succeeded_page.html
index 34fac6f6e..d45962c 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/setup_succeeded_page.html
+++ b/chrome/browser/resources/chromeos/multidevice_setup/setup_succeeded_page.html
@@ -5,7 +5,7 @@
 
 <dom-module id="setup-succeeded-page">
   <template>
-    Setup Succeeded Placeholder Text
+    --------------Setup Succeeded Placeholder Text--------------
   </template>
   <script src="setup_succeeded_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/setup_succeeded_page.js b/chrome/browser/resources/chromeos/multidevice_setup/setup_succeeded_page.js
index 039b105..b116d70 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/setup_succeeded_page.js
+++ b/chrome/browser/resources/chromeos/multidevice_setup/setup_succeeded_page.js
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/** @polymer */
 Polymer({
   is: 'setup-succeeded-page',
 
@@ -10,9 +9,9 @@
     /**
      * Overriden from ButtonNavigationBehavior
      */
-    forwardButtonText: {
+    forwardButtonTextId: {
       type: String,
-      value: 'Done',
+      value: 'done',
     },
   },
 
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/start_setup_page.html b/chrome/browser/resources/chromeos/multidevice_setup/start_setup_page.html
index e6135ff..9aab421 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/start_setup_page.html
+++ b/chrome/browser/resources/chromeos/multidevice_setup/start_setup_page.html
@@ -5,7 +5,7 @@
 
 <dom-module id="start-setup-page">
   <template>
-    Start Setup Placeholder Text
+    --------------Start Setup Placeholder Text--------------
   </template>
   <script src="start_setup_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/start_setup_page.js b/chrome/browser/resources/chromeos/multidevice_setup/start_setup_page.js
index ed6de3c..1d199a8 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/start_setup_page.js
+++ b/chrome/browser/resources/chromeos/multidevice_setup/start_setup_page.js
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/** @polymer */
 Polymer({
   is: 'start-setup-page',
 
@@ -10,17 +9,17 @@
     /**
      * Overriden from ButtonNavigationBehavior
      */
-    forwardButtonText: {
+    forwardButtonTextId: {
       type: String,
-      value: 'Accept',
+      value: 'accept',
     },
 
     /**
      * Overriden from ButtonNavigationBehavior
      */
-    backwardButtonText: {
+    backwardButtonTextId: {
       type: String,
-      value: 'Cancel',
+      value: 'cancel',
     },
   },
 
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index fccd3d7..e5765f69 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -88,6 +88,7 @@
         <include name="IDR_FIRST_RUN_DIALOG_ICON_256" file="chromeos/first_run/app/icon/256.png" type="BINDATA" />
         <include name="IDR_ARC_SUPPORT_BACKGROUND_JS" file="chromeos/arc_support/background.js" flattenhtml="true" type="BINDATA" />
         <include name="IDR_ARC_SUPPORT_MAIN_CSS" file="chromeos/arc_support/main.css" type="BINDATA" />
+        <include name="IDR_ARC_SUPPORT_OVERLAY_CSS" file="chromeos/arc_support/overlay.css" type="BINDATA" />
         <include name="IDR_ARC_SUPPORT_PLAYSTORE_CSS" file="chromeos/arc_support/playstore.css" type="BINDATA" />
         <include name="IDR_ARC_SUPPORT_PLAYSTORE_JS" file="chromeos/arc_support/playstore.js" type="BINDATA" />
         <include name="IDR_ARC_SUPPORT_PLAYSTORE_LOGO" file="chromeos/arc_support/icon/playstore.svg" type="BINDATA" />
diff --git a/chrome/browser/resources/extensions/OWNERS b/chrome/browser/resources/extensions/OWNERS
deleted file mode 100644
index 9f96570..0000000
--- a/chrome/browser/resources/extensions/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-finnur@chromium.org
-rdevlin.cronin@chromium.org
-
-# TEAM: extensions-dev@chromium.org
-# COMPONENT: Platform>Extensions
diff --git a/chrome/browser/resources/extensions/apps_developer_tools_promo_48.png b/chrome/browser/resources/extensions/apps_developer_tools_promo_48.png
deleted file mode 100644
index 462bc9a..0000000
--- a/chrome/browser/resources/extensions/apps_developer_tools_promo_48.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/extensions/chromeos/kiosk_app_disable_bailout_confirm.html b/chrome/browser/resources/extensions/chromeos/kiosk_app_disable_bailout_confirm.html
deleted file mode 100644
index d6137cf..0000000
--- a/chrome/browser/resources/extensions/chromeos/kiosk_app_disable_bailout_confirm.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<div id="kiosk-disable-bailout-confirm-overlay" class="page">
-  <div class="close-button"></div>
-  <div class="content-area">
-    <p id="kiosk-disable-bailout-warning-bold">
-      $i18n{kioskDisableBailoutShortcutWarningBold}
-    </p>
-    <p>$i18n{kioskDisableBailoutShortcutWarning}</p>
-  </div>
-  <div class="action-area">
-    <div class="button-strip">
-      <button id="kiosk-disable-bailout-cancel-button">
-        $i18n{kioskDisableBailoutShortcutCancel}
-      </button>
-      <button id="kiosk-disable-bailout-confirm-button">
-        $i18n{kioskDisableBailoutShortcutConfirm}
-      </button>
-    </div>
-  </div>
-</div>
diff --git a/chrome/browser/resources/extensions/chromeos/kiosk_app_disable_bailout_confirm.js b/chrome/browser/resources/extensions/chromeos/kiosk_app_disable_bailout_confirm.js
deleted file mode 100644
index 89c628b3..0000000
--- a/chrome/browser/resources/extensions/chromeos/kiosk_app_disable_bailout_confirm.js
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('extensions', function() {
-  /**
-   * A confirmation overlay for disabling kiosk app bailout shortcut.
-   * @constructor
-   */
-  function KioskDisableBailoutConfirm() {
-  }
-
-  cr.addSingletonGetter(KioskDisableBailoutConfirm);
-
-  KioskDisableBailoutConfirm.prototype = {
-    /**
-     * Initialize the page.
-     */
-    initialize: function() {
-      var overlay = $('kiosk-disable-bailout-confirm-overlay');
-      cr.ui.overlay.setupOverlay(overlay);
-      cr.ui.overlay.globalInitialization();
-      overlay.addEventListener('cancelOverlay', this.handleCancel);
-
-      var el = $('kiosk-disable-bailout-shortcut');
-      el.addEventListener('change', this.handleDisableBailoutShortcutChange_);
-
-      $('kiosk-disable-bailout-confirm-button').onclick = function(e) {
-        extensions.ExtensionSettings.showOverlay($('kiosk-apps-page'));
-        chrome.send('setDisableBailoutShortcut', [true]);
-      };
-      $('kiosk-disable-bailout-cancel-button').onclick = this.handleCancel;
-    },
-
-    /** Handles overlay being canceled. */
-    handleCancel: function() {
-      extensions.ExtensionSettings.showOverlay($('kiosk-apps-page'));
-      $('kiosk-disable-bailout-shortcut').checked = false;
-    },
-
-    /**
-     * Custom change handler for the disable bailout shortcut checkbox.
-     * It blocks the underlying pref being changed and brings up confirmation
-     * alert to user.
-     * @private
-     */
-    handleDisableBailoutShortcutChange_: function() {
-      // Just set the pref if user un-checks the box.
-      if (!$('kiosk-disable-bailout-shortcut').checked) {
-        chrome.send('setDisableBailoutShortcut', [false]);
-        return false;
-      }
-
-      // Otherwise, show the confirmation overlay.
-      extensions.ExtensionSettings.showOverlay($(
-          'kiosk-disable-bailout-confirm-overlay'));
-      return true;
-    }
-  };
-
-  // Export
-  return {
-    KioskDisableBailoutConfirm: KioskDisableBailoutConfirm
-  };
-});
-
diff --git a/chrome/browser/resources/extensions/chromeos/kiosk_app_list.js b/chrome/browser/resources/extensions/chromeos/kiosk_app_list.js
deleted file mode 100644
index d9278409..0000000
--- a/chrome/browser/resources/extensions/chromeos/kiosk_app_list.js
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * The type of the app data object. The definition is based on
- * chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc:
- *     PopulateAppDict()
- * @typedef {{id: string,
- *            name: string,
- *            iconURL: string,
- *            autoLaunch: boolean,
- *            isLoading: boolean}}
- */
-var AppDict;
-
-cr.define('extensions', function() {
-  /** @const */ var List = cr.ui.List;
-  /** @const */ var ListItem = cr.ui.ListItem;
-  /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
-
-  /**
-   * Creates a list for showing kiosk apps.
-   * @constructor
-   * @extends {cr.ui.List}
-   */
-  var KioskAppList = cr.ui.define('list');
-
-  KioskAppList.prototype = {
-    __proto__: List.prototype,
-
-    /**
-     * True if auto launch feature can be configured.
-     * @type {?boolean}
-     */
-    autoLaunchEnabled_: false,
-
-    /** @override */
-    createItem: function(app) {
-      var item = new KioskAppListItem();
-      item.data = app;
-      item.autoLaunchEnabled = this.autoLaunchEnabled_;
-      return item;
-    },
-
-    /**
-     * Sets auto launch enabled flag.
-     * @param {boolean} enabled True if auto launch should be enabled.
-     */
-    setAutoLaunchEnabled: function(enabled) {
-      this.autoLaunchEnabled_ = enabled;
-    },
-
-    /**
-     * Loads the given list of apps.
-     * @param {!Array<!Object>} apps An array of app info objects.
-     */
-    setApps: function(apps) {
-      this.dataModel = new ArrayDataModel(apps);
-    },
-
-    /**
-     * Updates the given app.
-     * @param {!AppDict} app An app info object.
-     */
-    updateApp: function(app) {
-      for (var i = 0; i < this.items.length; ++i) {
-        if (this.items[i].data.id == app.id) {
-          this.items[i].data = app;
-          break;
-        }
-      }
-    }
-  };
-
-  /**
-   * Creates a list item for a kiosk app.
-   * @constructor
-   * @extends {cr.ui.ListItem}
-   */
-  var KioskAppListItem = cr.ui.define(function() {
-    var el = $('kiosk-app-list-item-template').cloneNode(true);
-    el.removeAttribute('id');
-    el.hidden = false;
-    return el;
-  });
-
-  KioskAppListItem.prototype = {
-    __proto__: ListItem.prototype,
-
-    /**
-     * Data object to hold app info.
-     * @type {Object}
-     * @private
-     */
-    data_: null,
-
-    get data() {
-      assert(this.data_);
-      return this.data_;
-    },
-
-    set data(data) {
-      this.data_ = data;
-      this.redraw();
-    },
-
-    set autoLaunchEnabled(enabled) {
-      this.querySelector('.enable-auto-launch-button').hidden = !enabled;
-      this.querySelector('.disable-auto-launch-button').hidden = !enabled;
-    },
-
-    /**
-     * Getter for the icon element.
-     * @type {Element}
-     */
-    get icon() {
-      return this.querySelector('.kiosk-app-icon');
-    },
-
-    /**
-     * Getter for the name element.
-     * @type {Element}
-     */
-    get name() {
-      return this.querySelector('.kiosk-app-name');
-    },
-
-    /**
-     * Getter for the status text element.
-     * @type {Element}
-     */
-    get status() {
-      return this.querySelector('.kiosk-app-status');
-    },
-
-    /** @override */
-    decorate: function() {
-      ListItem.prototype.decorate.call(this);
-
-      var sendMessageWithId = function(msg) {
-        return function() {
-          chrome.send(msg, [this.data.id]);
-        }.bind(this);
-      }.bind(this);
-
-      this.querySelector('.enable-auto-launch-button').onclick =
-        sendMessageWithId('enableKioskAutoLaunch');
-      this.querySelector('.disable-auto-launch-button').onclick =
-        sendMessageWithId('disableKioskAutoLaunch');
-      this.querySelector('.row-delete-button').onclick =
-          sendMessageWithId('removeKioskApp');
-    },
-
-    /**
-     * Updates UI from app info data.
-     */
-    redraw: function() {
-      this.icon.classList.toggle('spinner', this.data.isLoading);
-      this.icon.style.backgroundImage = 'url(' + this.data.iconURL + ')';
-
-      this.name.textContent = this.data.name || this.data.id;
-      this.status.textContent = this.data.autoLaunch ?
-          loadTimeData.getString('autoLaunch') : '';
-
-      this.autoLaunch = this.data.autoLaunch;
-    }
-  };
-
-  /**
-   * True if the app represented by this item will auto launch.
-   */
-  cr.defineProperty(KioskAppListItem, 'autoLaunch', cr.PropertyKind.BOOL_ATTR);
-
-  // Export
-  return {
-    KioskAppList: KioskAppList
-  };
-});
diff --git a/chrome/browser/resources/extensions/chromeos/kiosk_apps.css b/chrome/browser/resources/extensions/chromeos/kiosk_apps.css
deleted file mode 100644
index e16c782..0000000
--- a/chrome/browser/resources/extensions/chromeos/kiosk_apps.css
+++ /dev/null
@@ -1,155 +0,0 @@
-/* Copyright 2013 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-#kiosk-apps-page .checkbox {
-  display: block;
-}
-
-#kiosk-app-list {
-  border: 1px solid lightgrey;
-  height: 200px;
-  margin-bottom: 5px;
-}
-
-#kiosk-app-list > * {
-  -webkit-box-align: center;
-  box-sizing: border-box;
-  display: -webkit-box;
-  height: 32px;
-}
-
-/* TODO(xiyuan): The .row-delete-button rules probably should live somewhere
- * else and be shared with options.css */
-list .row-delete-button {
-  background-color: transparent;
-  background-image: -webkit-image-set(
-      url(../../../../../ui/resources/default_100_percent/close_2.png) 1x,
-      url(../../../../../ui/resources/default_200_percent/close_2.png) 2x);
-  border: none;
-  display: block;
-  height: 16px;
-  opacity: 1;
-  transition: 150ms opacity;
-  width: 16px;
-}
-
-list > *:not(:hover):not([selected]):not([lead]) .row-delete-button,
-list:not([has-element-focus]) > *:not(:hover):not([selected])
-    .row-delete-button,
-list[disabled] .row-delete-button,
-list .row-delete-button[disabled] {
-  opacity: 0;
-  pointer-events: none;
-}
-
-list .row-delete-button:hover {
-  background-image: -webkit-image-set(
-      url(../../../../../ui/resources/default_100_percent/close_2_hover.png)
-          1x,
-      url(../../../../../ui/resources/default_200_percent/close_2_hover.png)
-          2x);
-}
-
-list .row-delete-button:active {
-  background-image: -webkit-image-set(
-      url(../../../../../ui/resources/default_100_percent/close_2_pressed.png)
-          1x,
-      url(../../../../../ui/resources/default_200_percent/close_2_pressed.png)
-          2x);
-}
-
-.controlled-setting-with-label > input:disabled + span label {
-  color: #999;
-}
-
-#kiosk-app-id-edit-row {
-  -webkit-justify-content: space-between;
-  display: -webkit-flex;
-  width: 510px;
-}
-
-#kiosk-app-id-edit,
-#kiosk-app-add {
-  display: block;
-}
-
-#kiosk-app-id-edit {
-  -webkit-flex-grow: 1;
-  -webkit-margin-end: 10px;
-}
-
-#kiosk-apps-error-banner {
-  background-color: rgb(223, 165, 165);
-  margin: 2px 0;
-  opacity: 0;
-  padding: 5px;
-  transition: opacity 150ms;
-  visibility: hidden;
-  white-space: nowrap;
-  width: 100%;
-}
-
-#kiosk-apps-error-banner.visible {
-  opacity: 1;
-  visibility: visible;
-}
-
-.kiosk-app-list-item {
-  white-space: nowrap;
-}
-
-.kiosk-app-list-item .space-filler {
-  -webkit-box-flex: 1;
-}
-
-.kiosk-app-icon,
-.kiosk-app-name,
-.kiosk-app-status {
-  display: inline-block;
-  vertical-align: middle;
-}
-
-.kiosk-app-icon {
-  background-size: 100%;
-  height: 16px;
-  width: 16px;
-}
-
-.kiosk-app-icon.spinner {
-  background-image: url(chrome://resources/images/throbber_small.svg)
-      !important;
-}
-
-.kiosk-app-name,
-.kiosk-app-status {
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
-.kiosk-app-name {
-  max-width: 250px;
-}
-
-.kiosk-app-status {
-  -webkit-margin-start: 8px;
-  max-width: 120px;
-}
-
-.disable-auto-launch-button,
-.enable-auto-launch-button {
-  display: none;
-}
-
-.kiosk-app-list-item[auto-launch]:hover .disable-auto-launch-button,
-.kiosk-app-list-item:not([auto-launch]):hover .enable-auto-launch-button {
-  display: inline-block;
-}
-
-#kiosk-disable-bailout-confirm-overlay {
-  width: 250px
-}
-
-#kiosk-disable-bailout-warning-bold {
-  font-weight: bold;
-}
diff --git a/chrome/browser/resources/extensions/chromeos/kiosk_apps.html b/chrome/browser/resources/extensions/chromeos/kiosk_apps.html
deleted file mode 100644
index 0056e78..0000000
--- a/chrome/browser/resources/extensions/chromeos/kiosk_apps.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<div id="kiosk-apps-page" class="page">
-  <div class="close-button"></div>
-  <h1>$i18n{kioskOverlayTitle}</h1>
-  <div class="content-area">
-    <div class="option">
-      <list id="kiosk-app-list"></list>
-      <div id="kiosk-apps-error-banner">
-        <span class="kiosk-app-name"></span>
-        <span class="kiosk-app-status">$i18n{invalidApp}</span>
-      </div>
-      <label for="kiosk-app-id-edit">
-        <span>$i18n{addKioskApp}</span>
-      </label>
-      <div id="kiosk-app-id-edit-row">
-        <input id="kiosk-app-id-edit" type="text"
-            i18n-values="placeholder:kioskAppIdEditHint">
-        <button id="kiosk-app-add">$i18n{add}</button>
-      </div>
-      <div class="checkbox">
-        <span class="controlled-setting-with-label">
-          <input id="kiosk-disable-bailout-shortcut" type="checkbox">
-          <span>
-            <label for="kiosk-disable-bailout-shortcut">
-              $i18n{kioskDiableBailoutShortcutLabel}
-            </label>
-          </span>
-        </span>
-      </div>
-    </div>
-  </div>
-  <div class="action-area">
-    <div class="button-strip">
-      <button id="kiosk-options-overlay-confirm">$i18n{done}</button>
-    </div>
-  </div>
-
-  <div id="kiosk-app-list-item-template" class="kiosk-app-list-item" hidden>
-    <div class="content">
-      <span class="kiosk-app-icon"></span>
-      <span class="kiosk-app-name"></span>
-      <span class="kiosk-app-status"></span>
-    </div>
-    <div class="space-filler"></div>
-    <button class="enable-auto-launch-button">
-      $i18n{enableAutoLaunchButton}
-    </button>
-    <button class="disable-auto-launch-button">
-      $i18n{disableAutoLaunchButton}
-    </button>
-    <button class="raw-button custom-appearance row-delete-button">
-    </button>
-  </div>
-</div>
diff --git a/chrome/browser/resources/extensions/chromeos/kiosk_apps.js b/chrome/browser/resources/extensions/chromeos/kiosk_apps.js
deleted file mode 100644
index 3052f55..0000000
--- a/chrome/browser/resources/extensions/chromeos/kiosk_apps.js
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('extensions', function() {
-  /**
-   * Encapsulated handling of ChromeOS kiosk apps options page.
-   * @constructor
-   */
-  function KioskAppsOverlay() {
-  }
-
-  cr.addSingletonGetter(KioskAppsOverlay);
-
-  KioskAppsOverlay.prototype = {
-    /**
-     * Clear error timer id.
-     * @type {?number}
-     */
-    clearErrorTimer_: null,
-
-    /** @private {WebUIListenerTracker} */
-    listenerTracker_: null,
-
-    /**
-     * Initialize the page.
-     */
-    initialize: function() {
-      this.listenerTracker_ = new WebUIListenerTracker();
-
-      cr.sendWithPromise('initializeKioskAppSettings')
-          .then(KioskAppsOverlay.enableKiosk);
-
-      extensions.KioskAppList.decorate($('kiosk-app-list'));
-
-      var overlay = $('kiosk-apps-page');
-      cr.ui.overlay.setupOverlay(overlay);
-      cr.ui.overlay.globalInitialization();
-      overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
-
-      $('kiosk-options-overlay-confirm').onclick =
-          this.handleDismiss_.bind(this);
-      $('kiosk-app-id-edit').addEventListener('keypress',
-          this.handleAppIdInputKeyPressed_.bind(this));
-      $('kiosk-app-add').onclick = this.handleAddButtonClick_.bind(this);
-    },
-
-    /*
-     * Invoked when the page is shown.
-     */
-    didShowPage: function() {
-      this.listenerTracker_.add(
-          'kiosk-app-settings-changed', KioskAppsOverlay.setSettings);
-      this.listenerTracker_.add(
-          'kiosk-app-updated', KioskAppsOverlay.updateApp);
-      this.listenerTracker_.add('kiosk-app-error', KioskAppsOverlay.showError);
-
-      cr.sendWithPromise('getKioskAppSettings')
-          .then(KioskAppsOverlay.setSettings);
-      $('kiosk-app-id-edit').focus();
-    },
-
-    /**
-     * Shows error for given app name/id and schedules it to cleared.
-     * @param {!string} appName App name/id to show in error banner.
-     */
-    showError: function(appName) {
-      var errorBanner = $('kiosk-apps-error-banner');
-      var appNameElement = errorBanner.querySelector('.kiosk-app-name');
-      appNameElement.textContent = appName;
-      errorBanner.classList.add('visible');
-
-      if (this.clearErrorTimer_)
-        window.clearTimeout(this.clearErrorTimer_);
-
-      // Sets a timer to clear out error banner after 5 seconds.
-      this.clearErrorTimer_ = window.setTimeout(function() {
-        errorBanner.classList.remove('visible');
-        this.clearErrorTimer_ = null;
-      }.bind(this), 5000);
-    },
-
-    /**
-     * Handles keypressed event in the app id input element.
-     * @private
-     */
-    handleAppIdInputKeyPressed_: function(e) {
-      if (e.key == 'Enter' && e.target.value)
-        this.handleAddButtonClick_();
-    },
-
-    /**
-     * Handles click event on the add button.
-     * @private
-     */
-    handleAddButtonClick_: function() {
-      var appId = $('kiosk-app-id-edit').value;
-      if (!appId)
-        return;
-
-      chrome.send('addKioskApp', [appId]);
-      $('kiosk-app-id-edit').value = '';
-    },
-
-    /**
-     * Handles the overlay being dismissed.
-     * @private
-     */
-    handleDismiss_: function() {
-      this.handleAddButtonClick_();
-      extensions.ExtensionSettings.showOverlay(null);
-      this.listenerTracker_.removeAll();
-    }
-  };
-
-  /**
-   * Sets apps to be displayed in kiosk-app-list.
-   * @param {!Object<{apps: !Array<AppDict>, disableBailout: boolean,
-   *     hasAutoLaunchApp: boolean}>} settings An object containing an array of
-   *     app info objects and disable bailout shortcut flag.
-   */
-  KioskAppsOverlay.setSettings = function(settings) {
-    /** @type {extensions.KioskAppList} */ ($('kiosk-app-list'))
-        .setApps(settings.apps);
-    $('kiosk-disable-bailout-shortcut').checked = settings.disableBailout;
-    $('kiosk-disable-bailout-shortcut').disabled = !settings.hasAutoLaunchApp;
-  };
-
-  /**
-   * Update an app in kiosk-app-list.
-   * @param {!AppDict} app App info to be updated.
-   */
-  KioskAppsOverlay.updateApp = function(app) {
-    /** @type {extensions.KioskAppList} */ ($('kiosk-app-list')).updateApp(app);
-  };
-
-  /**
-   * Shows error for given app name/id.
-   * @param {!string} appName App name/id to show in error banner.
-   */
-  KioskAppsOverlay.showError = function(appName) {
-    KioskAppsOverlay.getInstance().showError(appName);
-  };
-
-  /**
-   * Enables consumer kiosk.
-   * @param {!{kioskEnabled: boolean, autoLaunchEnabled: boolean}} params
-   */
-  KioskAppsOverlay.enableKiosk = function(params) {
-    $('add-kiosk-app').hidden = !params.kioskEnabled;
-    $('kiosk-disable-bailout-shortcut').parentNode.hidden =
-        !params.autoLaunchEnabled;
-    /** @type {extensions.KioskAppList} */ ($('kiosk-app-list'))
-        .setAutoLaunchEnabled(params.autoLaunchEnabled);
-  };
-
-  // Export
-  return {
-    KioskAppsOverlay: KioskAppsOverlay
-  };
-});
-
-// <include src="kiosk_app_list.js">
-// <include src="kiosk_app_disable_bailout_confirm.js">
diff --git a/chrome/browser/resources/extensions/compiled_resources2.gyp b/chrome/browser/resources/extensions/compiled_resources2.gyp
deleted file mode 100644
index 060505c..0000000
--- a/chrome/browser/resources/extensions/compiled_resources2.gyp
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
-  'targets': [
-    {
-      'target_name': 'extensions',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:webui_listener_tracker',
-      ],
-      'variables': {
-        'script_args': ['--custom_sources'],
-        'source_files': [
-          '<(DEPTH)/ui/webui/resources/js/promise_resolver.js',
-          '<(DEPTH)/ui/webui/resources/js/load_time_data.js',
-          '<(DEPTH)/ui/webui/resources/js/parse_html_subset.js',
-          '<(DEPTH)/ui/webui/resources/js/cr.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/array_data_model.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/list.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js',
-          'extension_loader.js',
-          '<(DEPTH)/ui/webui/resources/js/util.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/focus_manager.js',
-          'extension_focus_manager.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/list_item.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/focus_row.js',
-          'extension_options_overlay.js',
-          '<(DEPTH)/third_party/closure_compiler/externs/management.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/list_selection_controller.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/alert_overlay.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/bubble.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/focus_grid.js',
-          'chromeos/kiosk_apps.js',
-          '<(DEPTH)/ui/webui/resources/js/assert.js',
-          'extension_commands_overlay.js',
-          'extensions.js',
-          'extension_list.js',
-          'chromeos/kiosk_app_disable_bailout_confirm.js',
-          'focus_row.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/bubble_button.js',
-          '<(DEPTH)/third_party/closure_compiler/externs/chrome_send.js',
-          '<(DEPTH)/third_party/jstemplate/util.js',
-          'extension_error.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui.js',
-          '<(DEPTH)/ui/webui/resources/js/event_tracker.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/overlay.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/drag_wrapper.js',
-          'extension_code.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/event_target.js',
-          '<(DEPTH)/third_party/jstemplate/jsevalcontext.js',
-          'extension_command_list.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/controlled_indicator.js',
-          'extension_error_overlay.js',
-          '../md_extensions/drag_and_drop_handler.js',
-          '<(DEPTH)/ui/webui/resources/js/cr/ui/list_selection_model.js',
-          '<(DEPTH)/third_party/jstemplate/jstemplate.js',
-          'chromeos/kiosk_app_list.js',
-          '<(DEPTH)/third_party/closure_compiler/externs/developer_private.js',
-          '../md_extensions/shortcut_util.js',
-          'pack_extension_overlay.js',
-        ],
-      },
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    }
-  ]
-}
diff --git a/chrome/browser/resources/extensions/extension_code.js b/chrome/browser/resources/extensions/extension_code.js
deleted file mode 100644
index fd99783..0000000
--- a/chrome/browser/resources/extensions/extension_code.js
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @typedef {{afterHighlight: string,
- *            beforeHighlight: string,
- *            highlight: string,
- *            message: string}}
- */
-var ExtensionHighlight;
-
-cr.define('extensions', function() {
-  'use strict';
-
-  /**
-   * ExtensionCode is an element which displays code in a styled div, and is
-   * designed to highlight errors.
-   * @constructor
-   * @extends {HTMLDivElement}
-   */
-  function ExtensionCode(div) {
-    div.__proto__ = ExtensionCode.prototype;
-    return div;
-  }
-
-  ExtensionCode.prototype = {
-    __proto__: HTMLDivElement.prototype,
-
-    /**
-     * Populate the content area of the code div with the given code. This will
-     * highlight the erroneous section (if any).
-     * @param {?ExtensionHighlight} code The 'highlight' strings represent the
-     *     three portions of the file's content to display - the portion which
-     *     is most relevant and should be emphasized (highlight), and the parts
-     *     both before and after this portion. The title is the error message,
-     *     which will be the mouseover hint for the highlighted region. These
-     *     may be empty.
-     *  @param {string} emptyMessage The message to display if the code
-     *     object is empty (e.g., 'could not load code').
-     */
-    populate: function(code, emptyMessage) {
-      // Clear any remnant content, so we don't have multiple code listed.
-      this.clear();
-
-      // If there's no code, then display an appropriate message.
-      if (!code ||
-          (!code.highlight && !code.beforeHighlight && !code.afterHighlight)) {
-        var span = document.createElement('span');
-        span.classList.add('extension-code-empty');
-        span.textContent = emptyMessage;
-        this.appendChild(span);
-        return;
-      }
-
-      var sourceDiv = document.createElement('div');
-      sourceDiv.classList.add('extension-code-source');
-      this.appendChild(sourceDiv);
-
-      var lineCount = 0;
-      var createSpan = function(source, isHighlighted) {
-        lineCount += source.split('\n').length - 1;
-        var span = document.createElement('span');
-        span.className = isHighlighted ? 'extension-code-highlighted-source' :
-                                         'extension-code-normal-source';
-        span.textContent = source;
-        return span;
-      };
-
-      if (code.beforeHighlight)
-        sourceDiv.appendChild(createSpan(code.beforeHighlight, false));
-
-      if (code.highlight) {
-        var highlightSpan = createSpan(code.highlight, true);
-        highlightSpan.title = code.message;
-        sourceDiv.appendChild(highlightSpan);
-      }
-
-      if (code.afterHighlight)
-        sourceDiv.appendChild(createSpan(code.afterHighlight, false));
-
-      // Make the line numbers. This should be the number of line breaks + 1
-      // (the last line doesn't break, but should still be numbered).
-      var content = '';
-      for (var i = 1; i < lineCount + 1; ++i)
-        content += i + '\n';
-      var span = document.createElement('span');
-      span.textContent = content;
-
-      var linesDiv = document.createElement('div');
-      linesDiv.classList.add('extension-code-line-numbers');
-      linesDiv.appendChild(span);
-      this.insertBefore(linesDiv, this.firstChild);
-    },
-
-    /**
-     * Clears the content of the element.
-     */
-    clear: function() {
-      while (this.firstChild)
-        this.removeChild(this.firstChild);
-    },
-
-    /**
-     * Scrolls to the error, if there is one. This cannot be called when the
-     * div is hidden.
-     */
-    scrollToError: function() {
-      var errorSpan = this.querySelector('.extension-code-highlighted-source');
-      if (errorSpan)
-        this.scrollTop = errorSpan.offsetTop - this.clientHeight / 2;
-    }
-  };
-
-  // Export
-  return {
-    ExtensionCode: ExtensionCode
-  };
-});
diff --git a/chrome/browser/resources/extensions/extension_command_list.js b/chrome/browser/resources/extensions/extension_command_list.js
deleted file mode 100644
index 1aa48e3..0000000
--- a/chrome/browser/resources/extensions/extension_command_list.js
+++ /dev/null
@@ -1,425 +0,0 @@
-// Copyright (c) 2012 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 src="../md_extensions/shortcut_util.js">
-
-cr.define('extensions', function() {
-  'use strict';
-
-  /**
-   * Creates a new list of extension commands.
-   * @param {HTMLDivElement} div
-   * @constructor
-   * @extends {HTMLDivElement}
-   */
-  function ExtensionCommandList(div) {
-    div.__proto__ = ExtensionCommandList.prototype;
-    return div;
-  }
-
-  ExtensionCommandList.prototype = {
-    __proto__: HTMLDivElement.prototype,
-
-    /**
-     * While capturing, this records the current (last) keyboard event generated
-     * by the user. Will be |null| after capture and during capture when no
-     * keyboard event has been generated.
-     * @type {KeyboardEvent}.
-     * @private
-     */
-    currentKeyEvent_: null,
-
-    /**
-     * While capturing, this keeps track of the previous selection so we can
-     * revert back to if no valid assignment is made during capture.
-     * @type {string}.
-     * @private
-     */
-    oldValue_: '',
-
-    /**
-     * While capturing, this keeps track of which element the user asked to
-     * change.
-     * @type {HTMLElement}.
-     * @private
-     */
-    capturingElement_: null,
-
-    /**
-     * Updates the extensions data for the overlay.
-     * @param {!Array<chrome.developerPrivate.ExtensionInfo>} data The extension
-     *     data.
-     */
-    setData: function(data) {
-      /** @private {!Array<chrome.developerPrivate.ExtensionInfo>} */
-      this.data_ = data;
-
-      this.textContent = '';
-
-      // Iterate over the extension data and add each item to the list.
-      this.data_.forEach(this.createNodeForExtension_.bind(this));
-    },
-
-    /**
-     * Synthesizes and initializes an HTML element for the extension command
-     * metadata given in |extension|.
-     * @param {chrome.developerPrivate.ExtensionInfo} extension A dictionary of
-     *     extension metadata.
-     * @private
-     */
-    createNodeForExtension_: function(extension) {
-      if (extension.commands.length == 0 ||
-          extension.state == chrome.developerPrivate.ExtensionState.DISABLED)
-        return;
-
-      var template = $('template-collection-extension-commands').querySelector(
-          '.extension-command-list-extension-item-wrapper');
-      var node = template.cloneNode(true);
-
-      var title = node.querySelector('.extension-title');
-      title.textContent = extension.name;
-
-      this.appendChild(node);
-
-      // Iterate over the commands data within the extension and add each item
-      // to the list.
-      extension.commands.forEach(
-          this.createNodeForCommand_.bind(this, extension.id));
-    },
-
-    /**
-     * Synthesizes and initializes an HTML element for the extension command
-     * metadata given in |command|.
-     * @param {string} extensionId The associated extension's id.
-     * @param {chrome.developerPrivate.Command} command A dictionary of
-     *     extension command metadata.
-     * @private
-     */
-    createNodeForCommand_: function(extensionId, command) {
-      var template = $('template-collection-extension-commands').querySelector(
-          '.extension-command-list-command-item-wrapper');
-      var node = template.cloneNode(true);
-      node.id = this.createElementId_('command', extensionId, command.name);
-
-      var description = node.querySelector('.command-description');
-      description.textContent = command.description;
-
-      var shortcutNode = node.querySelector('.command-shortcut-text');
-      shortcutNode.addEventListener('mouseup',
-                                    this.startCapture_.bind(this));
-      shortcutNode.addEventListener('focus', this.handleFocus_.bind(this));
-      shortcutNode.addEventListener('blur', this.handleBlur_.bind(this));
-      shortcutNode.addEventListener('keydown', this.handleKeyDown_.bind(this));
-      shortcutNode.addEventListener('keyup', this.handleKeyUp_.bind(this));
-      if (!command.isActive) {
-        shortcutNode.textContent =
-            loadTimeData.getString('extensionCommandsInactive');
-
-        var commandShortcut = node.querySelector('.command-shortcut');
-        commandShortcut.classList.add('inactive-keybinding');
-      } else {
-        shortcutNode.textContent = command.keybinding;
-      }
-
-      var commandClear = node.querySelector('.command-clear');
-      commandClear.id = this.createElementId_(
-          'clear', extensionId, command.name);
-      commandClear.title = loadTimeData.getString('extensionCommandsDelete');
-      commandClear.addEventListener('click', this.handleClear_.bind(this));
-
-      var select = node.querySelector('.command-scope');
-      select.id = this.createElementId_(
-          'setCommandScope', extensionId, command.name);
-      select.hidden = false;
-      // Add the 'In Chrome' option.
-      var option = document.createElement('option');
-      option.textContent = loadTimeData.getString('extensionCommandsRegular');
-      select.appendChild(option);
-      if (command.isExtensionAction || !command.isActive) {
-        // Extension actions cannot be global, so we might as well disable the
-        // combo box, to signify that, and if the command is inactive, it
-        // doesn't make sense to allow the user to adjust the scope.
-        select.disabled = true;
-      } else {
-        // Add the 'Global' option.
-        option = document.createElement('option');
-        option.textContent = loadTimeData.getString('extensionCommandsGlobal');
-        select.appendChild(option);
-        select.selectedIndex =
-            command.scope == chrome.developerPrivate.CommandScope.GLOBAL ?
-                1 : 0;
-
-        select.addEventListener(
-            'change', this.handleSetCommandScope_.bind(this));
-      }
-
-      this.appendChild(node);
-    },
-
-    /**
-     * Starts keystroke capture to determine which key to use for a particular
-     * extension command.
-     * @param {Event} event The keyboard event to consider.
-     * @private
-     */
-    startCapture_: function(event) {
-      if (this.capturingElement_)
-        return;  // Already capturing.
-
-      chrome.developerPrivate.setShortcutHandlingSuspended(true);
-
-      var shortcutNode = event.target;
-      this.oldValue_ = shortcutNode.textContent;
-      shortcutNode.textContent =
-          loadTimeData.getString('extensionCommandsStartTyping');
-      shortcutNode.parentElement.classList.add('capturing');
-
-      var commandClear =
-          shortcutNode.parentElement.querySelector('.command-clear');
-      commandClear.hidden = true;
-
-      this.capturingElement_ = /** @type {HTMLElement} */(event.target);
-    },
-
-    /**
-     * Ends keystroke capture and either restores the old value or (if valid
-     * value) sets the new value as active..
-     * @param {Event} event The keyboard event to consider.
-     * @private
-     */
-    endCapture_: function(event) {
-      if (!this.capturingElement_)
-        return;  // Not capturing.
-
-      chrome.developerPrivate.setShortcutHandlingSuspended(false);
-
-      var shortcutNode = this.capturingElement_;
-      var commandShortcut = shortcutNode.parentElement;
-
-      commandShortcut.classList.remove('capturing');
-      commandShortcut.classList.remove('contains-chars');
-
-      // When the capture ends, the user may have not given a complete and valid
-      // input (or even no input at all). Only a valid key event followed by a
-      // valid key combination will cause a shortcut selection to be activated.
-      // If no valid selection was made, however, revert back to what the
-      // textbox had before to indicate that the shortcut registration was
-      // canceled.
-      if (!this.currentKeyEvent_ ||
-          !extensions.isValidKeyCode(this.currentKeyEvent_.keyCode))
-        shortcutNode.textContent = this.oldValue_;
-
-      var commandClear = commandShortcut.querySelector('.command-clear');
-      if (this.oldValue_ == '') {
-        commandShortcut.classList.remove('clearable');
-        commandClear.hidden = true;
-      } else {
-        commandShortcut.classList.add('clearable');
-        commandClear.hidden = false;
-      }
-
-      this.oldValue_ = '';
-      this.capturingElement_ = null;
-      this.currentKeyEvent_ = null;
-    },
-
-    /**
-     * Handles focus event and adds visual indication for active shortcut.
-     * @param {Event} event to consider.
-     * @private
-     */
-    handleFocus_: function(event) {
-      var commandShortcut = event.target.parentElement;
-      commandShortcut.classList.add('focused');
-    },
-
-    /**
-     * Handles lost focus event and removes visual indication of active shortcut
-     * also stops capturing on focus lost.
-     * @param {Event} event to consider.
-     * @private
-     */
-    handleBlur_: function(event) {
-      this.endCapture_(event);
-      var commandShortcut = event.target.parentElement;
-      commandShortcut.classList.remove('focused');
-    },
-
-    /**
-     * The KeyDown handler.
-     * @param {Event} event The keyboard event to consider.
-     * @private
-     */
-    handleKeyDown_: function(event) {
-      event = /** @type {KeyboardEvent} */(event);
-      if (event.keyCode == extensions.Key.Escape) {
-        if (!this.capturingElement_) {
-          // If we're not currently capturing, allow escape to propagate (so it
-          // can close the overflow).
-          return;
-        }
-        // Otherwise, escape cancels capturing.
-        this.endCapture_(event);
-        var parsed = this.parseElementId_('clear',
-            event.target.parentElement.querySelector('.command-clear').id);
-        chrome.developerPrivate.updateExtensionCommand({
-          extensionId: parsed.extensionId,
-          commandName: parsed.commandName,
-          keybinding: ''
-        });
-        event.preventDefault();
-        event.stopPropagation();
-        return;
-      }
-      if (event.keyCode == extensions.Key.Tab) {
-        // Allow tab propagation for keyboard navigation.
-        return;
-      }
-
-      if (!this.capturingElement_)
-        this.startCapture_(event);
-
-      this.handleKey_(event);
-    },
-
-    /**
-     * The KeyUp handler.
-     * @param {Event} event The keyboard event to consider.
-     * @private
-     */
-    handleKeyUp_: function(event) {
-      event = /** @type {KeyboardEvent} */(event);
-      if (event.keyCode == extensions.Key.Tab ||
-          event.keyCode == extensions.Key.Escape) {
-        // We need to allow tab propagation for keyboard navigation, and escapes
-        // are fully handled in handleKeyDown.
-        return;
-      }
-
-      // We want to make it easy to change from Ctrl+Shift+ to just Ctrl+ by
-      // releasing Shift, but we also don't want it to be easy to lose for
-      // example Ctrl+Shift+F to Ctrl+ just because you didn't release Ctrl
-      // as fast as the other two keys. Therefore, we process KeyUp until you
-      // have a valid combination and then stop processing it (meaning that once
-      // you have a valid combination, we won't change it until the next
-      // KeyDown message arrives).
-      if (!this.currentKeyEvent_ ||
-          !extensions.isValidKeyCode(this.currentKeyEvent_.keyCode)) {
-        if (!event.ctrlKey && !event.altKey ||
-            ((cr.isMac || cr.isChromeOS) && !event.metaKey)) {
-          // If neither Ctrl nor Alt is pressed then it is not a valid shortcut.
-          // That means we're back at the starting point so we should restart
-          // capture.
-          this.endCapture_(event);
-          this.startCapture_(event);
-        } else {
-          this.handleKey_(event);
-        }
-      }
-    },
-
-    /**
-     * A general key handler (used for both KeyDown and KeyUp).
-     * @param {KeyboardEvent} event The keyboard event to consider.
-     * @private
-     */
-    handleKey_: function(event) {
-      // While capturing, we prevent all events from bubbling, to prevent
-      // shortcuts lacking the right modifier (F3 for example) from activating
-      // and ending capture prematurely.
-      event.preventDefault();
-      event.stopPropagation();
-
-      if (!extensions.hasValidModifiers(event))
-        return;
-
-      var shortcutNode = this.capturingElement_;
-      var keystroke = extensions.keystrokeToString(event);
-      shortcutNode.textContent = keystroke;
-      event.target.classList.add('contains-chars');
-      this.currentKeyEvent_ = event;
-
-      if (extensions.isValidKeyCode(event.keyCode)) {
-        var node = event.target;
-        while (node && !node.id)
-          node = node.parentElement;
-
-        this.oldValue_ = keystroke;  // Forget what the old value was.
-        var parsed = this.parseElementId_('command', node.id);
-
-        // Ending the capture must occur before calling
-        // setExtensionCommandShortcut to ensure the shortcut is set.
-        this.endCapture_(event);
-        chrome.developerPrivate.updateExtensionCommand(
-            {extensionId: parsed.extensionId,
-             commandName: parsed.commandName,
-             keybinding: keystroke});
-      }
-    },
-
-    /**
-     * A handler for the delete command button.
-     * @param {Event} event The mouse event to consider.
-     * @private
-     */
-    handleClear_: function(event) {
-      var parsed = this.parseElementId_('clear', event.target.id);
-      chrome.developerPrivate.updateExtensionCommand(
-          {extensionId: parsed.extensionId,
-           commandName: parsed.commandName,
-           keybinding: ''});
-    },
-
-    /**
-     * A handler for the setting the scope of the command.
-     * @param {Event} event The mouse event to consider.
-     * @private
-     */
-    handleSetCommandScope_: function(event) {
-      var parsed = this.parseElementId_('setCommandScope', event.target.id);
-      var element =
-          $('setCommandScope-' + parsed.extensionId + '-' + parsed.commandName);
-      var scope = element.selectedIndex == 1 ?
-          chrome.developerPrivate.CommandScope.GLOBAL :
-          chrome.developerPrivate.CommandScope.CHROME;
-      chrome.developerPrivate.updateExtensionCommand(
-          {extensionId: parsed.extensionId,
-           commandName: parsed.commandName,
-           scope: scope});
-    },
-
-    /**
-     * A utility function to create a unique element id based on a namespace,
-     * extension id and a command name.
-     * @param {string} namespace   The namespace to prepend the id with.
-     * @param {string} extensionId The extension ID to use in the id.
-     * @param {string} commandName The command name to append the id with.
-     * @private
-     */
-    createElementId_: function(namespace, extensionId, commandName) {
-      return namespace + '-' + extensionId + '-' + commandName;
-    },
-
-    /**
-     * A utility function to parse a unique element id based on a namespace,
-     * extension id and a command name.
-     * @param {string} namespace   The namespace to prepend the id with.
-     * @param {string} id          The id to parse.
-     * @return {{extensionId: string, commandName: string}} The parsed id.
-     * @private
-     */
-    parseElementId_: function(namespace, id) {
-      var kExtensionIdLength = 32;
-      return {
-        extensionId: id.substring(namespace.length + 1,
-                                  namespace.length + 1 + kExtensionIdLength),
-        commandName: id.substring(namespace.length + 1 + kExtensionIdLength + 1)
-      };
-    },
-  };
-
-  return {
-    ExtensionCommandList: ExtensionCommandList
-  };
-});
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.css b/chrome/browser/resources/extensions/extension_commands_overlay.css
deleted file mode 100644
index 407a256..0000000
--- a/chrome/browser/resources/extensions/extension_commands_overlay.css
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Copyright (c) 2012 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. */
-
-.extension-command-list-command-item-wrapper {
-  margin-left: 12px;
-}
-
-.command-title {
-  display: inline-block;
-  margin-top: 1em;
-}
-
-.command-container {
-  -webkit-box-orient: horizontal;
-  display: -webkit-box;
-  width: 450px;
-}
-
-.command-description {
-  -webkit-box-flex: 1;
-  display: -webkit-box;
-  margin-top: 0.5em;
-  min-height: 2em;
-}
-
-.command-shortcut-container {
-  display: -webkit-box;
-  margin-top: 0.25em;
-  min-height: 2em;
-}
-
-.command-shortcut {
-  border: solid 1px #BFBFBF;
-  border-radius: 2px;
-  color: rgb(48, 57, 66);
-  display: inline-block;
-  height: 1.4em;
-  min-width: 12.5em;
-  padding: 3px 0 1px 4px;
-}
-
-.command-shortcut-text {
-  display: inline-block;
-  height: 1.4em;
-  min-width: 11em;
-  outline: none;
-}
-
-.focused {
-  border: solid 1px rgb(140, 147, 255);
-}
-
-.clearable {
-  background: white;
-}
-
-.command-clear {
-  float: right;
-  margin-top: 1px;
-}
-
-.command-scope {
-  margin-left: 0.25em;
-  margin-top: 0.24em;
-}
-
-.capturing {
-  background: rgb(243, 244, 255);
-  border: solid 1px rgb(140, 147, 255);
-  color: #999;
-}
-
-.contains-chars {
-  color: rgb(48, 57, 66);
-}
-
-.inactive-keybinding {
-  color: #999;
-}
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.html b/chrome/browser/resources/extensions/extension_commands_overlay.html
deleted file mode 100644
index ad6c248..0000000
--- a/chrome/browser/resources/extensions/extension_commands_overlay.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!--
- * Copyright (c) 2012 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.
--->
-<div id="extension-commands-overlay" class="page">
-  <div class="close-button"></div>
-  <h1>$i18n{extensionCommandsOverlay}</h1>
-  <div class="content-area">
-    <div id="extension-command-list"
-         class="empty-extension-commands-list"></div>
-    <div id="no-commands" hidden>
-      <span id="no-extensions-commands-message">
-        $i18n{extensionCommandsEmpty}
-      </span>
-    </div>
-  </div>
-  <div class="action-area">
-    <div class="action-area-right">
-      <div class="button-strip">
-        <button id="extension-commands-dismiss">$i18n{ok}</button>
-      </div>
-    </div>
-  </div>
-</div>
-
-<div id="template-collection-extension-commands" hidden>
-  <div class="extension-command-list-extension-item-wrapper">
-    <div class="extension-command-list-extension-item">
-      <div class="extension-command-extension-details">
-        <div>
-          <span class="extension-title command-title"></span>
-          <div class="command-details"></div>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <div class="extension-command-list-command-item-wrapper">
-    <div class="extension-command-list-command-item">
-      <div class="extension-command-details">
-        <div class="command-container">
-          <span class="command-description"></span>
-          <span class="command-shortcut-container"
-              ><span class="command-shortcut clearable"
-                  ><img class="command-clear"
-                        src="chrome://theme/IDR_EXTENSION_COMMAND_CLOSE"
-                  ><span class="command-shortcut-text" tabindex="0"
-              ></span></span></span>
-          <select class="command-scope" hidden></select>
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.js b/chrome/browser/resources/extensions/extension_commands_overlay.js
deleted file mode 100644
index 443440b2..0000000
--- a/chrome/browser/resources/extensions/extension_commands_overlay.js
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2012 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 src="extension_command_list.js">
-
-cr.define('extensions', function() {
-  'use strict';
-
-  // The Extension Commands list object that will be used to show the commands
-  // on the page.
-  var ExtensionCommandList = extensions.ExtensionCommandList;
-
-  /**
-   * ExtensionCommandsOverlay class
-   * Encapsulated handling of the 'Extension Commands' overlay page.
-   * @constructor
-   */
-  function ExtensionCommandsOverlay() {
-  }
-
-  cr.addSingletonGetter(ExtensionCommandsOverlay);
-
-  ExtensionCommandsOverlay.prototype = {
-    /**
-     * Initialize the page.
-     */
-    initializePage: function() {
-      var overlay = $('overlay');
-      cr.ui.overlay.setupOverlay(overlay);
-      cr.ui.overlay.globalInitialization();
-      overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
-
-      this.extensionCommandList_ = new ExtensionCommandList(
-          /**@type {HTMLDivElement} */($('extension-command-list')));
-
-      $('extension-commands-dismiss').addEventListener('click', function() {
-        cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
-      });
-
-      // The ExtensionList will update us with its data, so we don't need to
-      // handle that here.
-    },
-
-    /**
-     * Handles a click on the dismiss button.
-     * @param {Event} e The click event.
-     */
-    handleDismiss_: function(e) {
-      extensions.ExtensionSettings.showOverlay(null);
-    },
-  };
-
-  /**
-   * Called by the dom_ui_ to re-populate the page with data representing
-   * the current state of extension commands.
-   * @param {!Array<chrome.developerPrivate.ExtensionInfo>} extensionsData
-   */
-  ExtensionCommandsOverlay.updateExtensionsData = function(extensionsData) {
-    var overlay = ExtensionCommandsOverlay.getInstance();
-    overlay.extensionCommandList_.setData(extensionsData);
-
-    var hasAnyCommands = false;
-    for (var i = 0; i < extensionsData.length; ++i) {
-      if (extensionsData[i].commands.length > 0) {
-        hasAnyCommands = true;
-        break;
-      }
-    }
-
-    // Make sure the config link is visible, since there are commands to show
-    // and potentially configure.
-    document.querySelector('.extension-commands-config').hidden =
-        !hasAnyCommands;
-
-    $('no-commands').hidden = hasAnyCommands;
-    overlay.extensionCommandList_.classList.toggle(
-        'empty-extension-commands-list', !hasAnyCommands);
-  };
-
-  // Export
-  return {
-    ExtensionCommandsOverlay: ExtensionCommandsOverlay
-  };
-});
diff --git a/chrome/browser/resources/extensions/extension_error.css b/chrome/browser/resources/extensions/extension_error.css
deleted file mode 100644
index 79ee0ab3..0000000
--- a/chrome/browser/resources/extensions/extension_error.css
+++ /dev/null
@@ -1,111 +0,0 @@
-/* Copyright 2013 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-.extension-error-list-heading {
-  align-content: flex-start;
-  display: flex;
-  flex-direction: row;
-  justify-content: space-between;
-  padding: 3px;
-}
-
-.extension-error-list-heading span {
-  font-weight: bold;
-}
-
-.extension-error-list a {
-  cursor: pointer;
-}
-
-.extension-error-list-contents {
-  -webkit-padding-start: 0;
-  cursor: pointer;
-  list-style-type: none;
-  margin-bottom: 0;
-  margin-top: 0;
-}
-
-#no-errors-span {
-  -webkit-margin-start: 10px;
-}
-
-.extension-error-list-contents.scrollable {
-  overflow-y: auto;
-}
-
-.extension-error-list-contents .extension-error-metadata:hover {
-  background-color: #eee;
-}
-
-.extension-error-list-contents
-    .extension-error-metadata.extension-error-active {
-  background-color: rgba(0, 100, 255, 0.1);
-}
-
-.extension-error-metadata {
-  -webkit-padding-end: 1px;
-  -webkit-padding-start: 3px;
-  display: flex;
-  flex-direction: row;
-}
-
-.extension-error-icon {
-  -webkit-margin-end: 3px;
-  height: 15px;
-  width: 15px;
-}
-
-.extension-error-message {
-  -webkit-margin-end: 15px;
-  flex: 1;
-  margin-bottom: 0;
-  margin-top: 0;
-  overflow: hidden;
-}
-
-.extension-error-metadata {
-  align-items: center;
-  display: flex;
-}
-
-.extension-error-metadata > .error-delete-button {
-  -webkit-appearance: none;
-  background: url(chrome://theme/IDR_CLOSE_DIALOG) center no-repeat;
-  border: none;
-  height: 14px;
-  opacity: 0.6;
-  width: 14px;
-}
-
-.extension-error-metadata > .error-delete-button:hover {
-  opacity: 0.8;
-}
-
-.extension-error-metadata > .error-delete-button:active {
-  opacity: 1.0;
-}
-
-.extension-error-severity-info .extension-error-message {
-  color: #333;
-}
-.extension-error-severity-info .extension-error-icon,
-.extension-error-info-icon {
-  content: url(extension_error_severity_info.png);
-}
-
-.extension-error-severity-warning .extension-error-message {
-  color: rgba(250, 145, 0, 255);
-}
-.extension-error-severity-warning .extension-error-icon,
-.extension-error-warning-icon {
-  content: url(extension_error_severity_warning.png);
-}
-
-.extension-error-severity-fatal .extension-error-message {
-  color: rgba(200, 50, 50, 255);
-}
-.extension-error-severity-fatal .extension-error-icon,
-.extension-error-fatal-icon {
-  content: url(extension_error_severity_fatal.png);
-}
diff --git a/chrome/browser/resources/extensions/extension_error.html b/chrome/browser/resources/extensions/extension_error.html
deleted file mode 100644
index ad294bb..0000000
--- a/chrome/browser/resources/extensions/extension_error.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-Copyright 2013 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be found
-in the LICENSE file.
--->
-<div id="template-collection-extension-error" hidden>
-  <div class="extension-error-list">
-    <div class="extension-error-list-heading">
-      <span>$i18n{extensionErrorHeading}</span>
-      <a id="extension-error-list-clear" is="action-link">
-        $i18n{extensionErrorClearAll}
-      </a>
-    </div>
-    <ul class="extension-error-list-contents"></ul>
-    <span id="no-errors-span" hidden>$i18n{extensionErrorNoErrors}</span>
-  </div>
-  <li class="extension-error-metadata">
-    <p class="extension-error-message" tabindex="0"></p>
-    <button class="custom-appearance error-delete-button"></button>
-  </li>
-</div>
diff --git a/chrome/browser/resources/extensions/extension_error.js b/chrome/browser/resources/extensions/extension_error.js
deleted file mode 100644
index 6d619c29..0000000
--- a/chrome/browser/resources/extensions/extension_error.js
+++ /dev/null
@@ -1,376 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('extensions', function() {
-  'use strict';
-
-  /**
-   * Clone a template within the extension error template collection.
-   * @param {string} templateName The class name of the template to clone.
-   * @return {HTMLElement} The clone of the template.
-   */
-  function cloneTemplate(templateName) {
-    return /** @type {HTMLElement} */($('template-collection-extension-error').
-        querySelector('.' + templateName).cloneNode(true));
-  }
-
-  /**
-   * Checks that an Extension ID follows the proper format (i.e., is 32
-   * characters long, is lowercase, and contains letters in the range [a, p]).
-   * @param {string} id The Extension ID to test.
-   * @return {boolean} Whether or not the ID is valid.
-   */
-  function idIsValid(id) {
-    return /^[a-p]{32}$/.test(id);
-  }
-
-  /**
-   * @param {!Array<(ManifestError|RuntimeError)>} errors
-   * @param {number} id
-   * @return {number} The index of the error with |id|, or -1 if not found.
-   */
-  function findErrorById(errors, id) {
-    for (var i = 0; i < errors.length; ++i) {
-      if (errors[i].id == id)
-        return i;
-    }
-    return -1;
-  }
-
-  /**
-   * Creates a new ExtensionError HTMLElement; this is used to show a
-   * notification to the user when an error is caused by an extension.
-   * @param {(RuntimeError|ManifestError)} error The error the element should
-   *     represent.
-   * @constructor
-   * @extends {HTMLElement}
-   */
-  function ExtensionError(error) {
-    var div = cloneTemplate('extension-error-metadata');
-    div.__proto__ = ExtensionError.prototype;
-    div.decorate(error);
-    return div;
-  }
-
-  ExtensionError.prototype = {
-    __proto__: HTMLElement.prototype,
-
-    /**
-     * @param {(RuntimeError|ManifestError)} error The error the element should
-     *     represent.
-     * @private
-     */
-    decorate: function(error) {
-      /**
-       * The backing error.
-       * @type {(ManifestError|RuntimeError)}
-       */
-      this.error = error;
-      var iconAltTextKey = 'extensionLogLevelWarn';
-
-      // Add an additional class for the severity level.
-      if (error.type == chrome.developerPrivate.ErrorType.RUNTIME) {
-        switch (error.severity) {
-          case chrome.developerPrivate.ErrorLevel.LOG:
-            this.classList.add('extension-error-severity-info');
-            iconAltTextKey = 'extensionLogLevelInfo';
-            break;
-          case chrome.developerPrivate.ErrorLevel.WARN:
-            this.classList.add('extension-error-severity-warning');
-            break;
-          case chrome.developerPrivate.ErrorLevel.ERROR:
-            this.classList.add('extension-error-severity-fatal');
-            iconAltTextKey = 'extensionLogLevelError';
-            break;
-          default:
-            assertNotReached();
-        }
-      } else {
-        // We classify manifest errors as "warnings".
-        this.classList.add('extension-error-severity-warning');
-      }
-
-      var iconNode = document.createElement('img');
-      iconNode.className = 'extension-error-icon';
-      iconNode.alt = loadTimeData.getString(iconAltTextKey);
-      this.insertBefore(iconNode, this.firstChild);
-
-      var messageSpan = this.querySelector('.extension-error-message');
-      messageSpan.textContent = error.message;
-
-      var deleteButton = this.querySelector('.error-delete-button');
-      deleteButton.addEventListener('click', function(e) {
-        this.dispatchEvent(
-            new CustomEvent('deleteExtensionError',
-                            {bubbles: true, detail: this.error}));
-      }.bind(this));
-
-      this.addEventListener('click', function(e) {
-        if (e.target != deleteButton)
-          this.requestActive_();
-      }.bind(this));
-
-      this.addEventListener('keydown', function(e) {
-        if (e.key == 'Enter' && e.target != deleteButton)
-          this.requestActive_();
-      });
-    },
-
-    /**
-     * Bubble up an event to request to become active.
-     * @private
-     */
-    requestActive_: function() {
-      this.dispatchEvent(
-          new CustomEvent('highlightExtensionError',
-                          {bubbles: true, detail: this.error}));
-    },
-  };
-
-  /**
-   * A variable length list of runtime or manifest errors for a given extension.
-   * @param {Array<(RuntimeError|ManifestError)>} errors The list of extension
-   *     errors with which to populate the list.
-   * @param {string} extensionId The id of the extension.
-   * @constructor
-   * @extends {HTMLDivElement}
-   */
-  function ExtensionErrorList(errors, extensionId) {
-    var div = cloneTemplate('extension-error-list');
-    div.__proto__ = ExtensionErrorList.prototype;
-    div.extensionId_ = extensionId;
-    div.decorate(errors);
-    return div;
-  }
-
-  /**
-   * @param {!Element} root
-   * @param {?Element} boundary
-   * @constructor
-   * @extends {cr.ui.FocusRow}
-   */
-  ExtensionErrorList.FocusRow = function(root, boundary) {
-    cr.ui.FocusRow.call(this, root, boundary);
-
-    this.addItem('message', '.extension-error-message');
-    this.addItem('delete', '.error-delete-button');
-  };
-
-  ExtensionErrorList.FocusRow.prototype = {
-    __proto__: cr.ui.FocusRow.prototype,
-  };
-
-  ExtensionErrorList.prototype = {
-    __proto__: HTMLDivElement.prototype,
-
-    /**
-     * Initializes the extension error list.
-     * @param {Array<(RuntimeError|ManifestError)>} errors The list of errors.
-     */
-    decorate: function(errors) {
-      /** @private {!Array<(ManifestError|RuntimeError)>} */
-      this.errors_ = [];
-
-      /** @private {!cr.ui.FocusGrid} */
-      this.focusGrid_ = new cr.ui.FocusGrid();
-
-      /** @private {Element} */
-      this.listContents_ = this.querySelector('.extension-error-list-contents');
-
-      errors.forEach(this.addError_, this);
-
-      this.focusGrid_.ensureRowActive();
-
-      this.addEventListener('highlightExtensionError', function(e) {
-        this.setActiveErrorNode_(e.target);
-      });
-      this.addEventListener('deleteExtensionError', function(e) {
-        this.removeError_(e.detail);
-      });
-
-      this.querySelector('#extension-error-list-clear').addEventListener(
-          'click', function(e) {
-        this.clear(true);
-      }.bind(this));
-
-      /**
-       * The callback for the extension changed event.
-       * @private {function(chrome.developerPrivate.EventData):void}
-       */
-      this.onItemStateChangedListener_ = function(data) {
-        var type = chrome.developerPrivate.EventType;
-        if ((data.event_type == type.ERRORS_REMOVED ||
-             data.event_type == type.ERROR_ADDED) &&
-            data.extensionInfo.id == this.extensionId_) {
-          var newErrors = data.extensionInfo.runtimeErrors.concat(
-              data.extensionInfo.manifestErrors);
-          this.updateErrors_(newErrors);
-        }
-      }.bind(this);
-
-      chrome.developerPrivate.onItemStateChanged.addListener(
-          this.onItemStateChangedListener_);
-
-      /**
-       * The active error element in the list.
-       * @private {?}
-       */
-      this.activeError_ = null;
-
-      this.setActiveError(0);
-    },
-
-    /**
-     * Adds an error to the list.
-     * @param {(RuntimeError|ManifestError)} error The error to add.
-     * @private
-     */
-    addError_: function(error) {
-      this.querySelector('#no-errors-span').hidden = true;
-      this.errors_.push(error);
-
-      var extensionError = new ExtensionError(error);
-      this.listContents_.appendChild(extensionError);
-
-      this.focusGrid_.addRow(
-          new ExtensionErrorList.FocusRow(extensionError, this.listContents_));
-    },
-
-    /**
-     * Removes an error from the list.
-     * @param {(RuntimeError|ManifestError)} error The error to remove.
-     * @private
-     */
-    removeError_: function(error) {
-      var index = 0;
-      for (; index < this.errors_.length; ++index) {
-        if (this.errors_[index].id == error.id)
-          break;
-      }
-      assert(index != this.errors_.length);
-      var errorList = this.querySelector('.extension-error-list-contents');
-
-      var wasActive =
-          this.activeError_ && this.activeError_.error.id == error.id;
-
-      this.errors_.splice(index, 1);
-      var listElement = errorList.children[index];
-
-      var focusRow = this.focusGrid_.getRowForRoot(listElement);
-      this.focusGrid_.removeRow(focusRow);
-      this.focusGrid_.ensureRowActive();
-      focusRow.destroy();
-
-      // TODO(dbeam): in a world where this UI is actually used, we should
-      // probably move the focus before removing |listElement|.
-      listElement.parentNode.removeChild(listElement);
-
-      if (wasActive) {
-        index = Math.min(index, this.errors_.length - 1);
-        this.setActiveError(index);  // Gracefully handles the -1 case.
-      }
-
-      chrome.developerPrivate.deleteExtensionErrors({
-        extensionId: error.extensionId,
-        errorIds: [error.id]
-      });
-
-      if (this.errors_.length == 0)
-        this.querySelector('#no-errors-span').hidden = false;
-    },
-
-    /**
-     * Updates the list of errors.
-     * @param {!Array<(ManifestError|RuntimeError)>} newErrors The new list of
-     *     errors.
-     * @private
-     */
-    updateErrors_: function(newErrors) {
-      this.errors_.forEach(function(error) {
-        if (findErrorById(newErrors, error.id) == -1)
-          this.removeError_(error);
-      }, this);
-      newErrors.forEach(function(error) {
-        var index = findErrorById(this.errors_, error.id);
-        if (index == -1)
-          this.addError_(error);
-        else
-          this.errors_[index] = error;  // Update the existing reference.
-      }, this);
-    },
-
-    /**
-     * Called when the list is being removed.
-     */
-    onRemoved: function() {
-      chrome.developerPrivate.onItemStateChanged.removeListener(
-          this.onItemStateChangedListener_);
-      this.clear(false);
-    },
-
-    /**
-     * Sets the active error in the list.
-     * @param {number} index The index to set to be active.
-     */
-    setActiveError: function(index) {
-      var errorList = this.querySelector('.extension-error-list-contents');
-      var item = errorList.children[index];
-      this.setActiveErrorNode_(
-          item ? item.querySelector('.extension-error-metadata') : null);
-      var node = null;
-      if (index >= 0 && index < errorList.children.length) {
-        node = errorList.children[index].querySelector(
-                   '.extension-error-metadata');
-      }
-      this.setActiveErrorNode_(node);
-    },
-
-    /**
-     * Clears the list of all errors.
-     * @param {boolean} deleteErrors Whether or not the errors should be deleted
-     *     on the backend.
-     */
-    clear: function(deleteErrors) {
-      if (this.errors_.length == 0)
-        return;
-
-      if (deleteErrors) {
-        var ids = this.errors_.map(function(error) { return error.id; });
-        chrome.developerPrivate.deleteExtensionErrors({
-          extensionId: this.extensionId_,
-          errorIds: ids
-        });
-      }
-
-      this.setActiveErrorNode_(null);
-      this.errors_.length = 0;
-      var errorList = this.querySelector('.extension-error-list-contents');
-      while (errorList.firstChild)
-        errorList.removeChild(errorList.firstChild);
-    },
-
-    /**
-     * Sets the active error in the list.
-     * @param {?} node The error to make active.
-     * @private
-     */
-    setActiveErrorNode_: function(node) {
-      if (this.activeError_)
-        this.activeError_.classList.remove('extension-error-active');
-
-      if (node)
-        node.classList.add('extension-error-active');
-
-      this.activeError_ = node;
-
-      this.dispatchEvent(
-          new CustomEvent('activeExtensionErrorChanged',
-                          {bubbles: true, detail: node ? node.error : null}));
-    },
-  };
-
-  return {
-    ExtensionErrorList: ExtensionErrorList
-  };
-});
diff --git a/chrome/browser/resources/extensions/extension_error_overlay.css b/chrome/browser/resources/extensions/extension_error_overlay.css
deleted file mode 100644
index 9100707..0000000
--- a/chrome/browser/resources/extensions/extension_error_overlay.css
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Copyright 2013 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-#extension-error-overlay {
-  max-width: 100%;
-}
-
-#extension-error-overlay .content-area {
-  display: flex;
-  flex-direction: column;
-}
-
-#extension-error-overlay .extension-error-list {
-  border: 1px solid #ccc;
-  margin-bottom: 3px;
-  min-height: 48px;
-  overflow-y: auto;
-}
-
-.extension-error-overlay-runtime-content {
-  flex: none;
-}
-
-#extension-error-overlay .extension-code-highlighted-source {
-  background-color: rgba(255, 195, 200, 255);
-}
-
-#extension-error-overlay-code {
-  font-size: 1.2em;
-  margin-bottom: 10px;
-}
-
-#extension-error-overlay .extension-code-source {
-  color: #555;
-}
-
-.extension-error-overlay-context {
-  font-size: 1.1em;
-  margin-bottom: 10px;
-}
-
-.extension-error-overlay-stack-trace-list {
-  list-style-type: none;
-  padding: 0;
-}
-
-.extension-error-overlay-stack-trace summary {
-  cursor: pointer;
-  font-size: 1.1em;
-  outline: none;
-}
-
-.extension-error-overlay-stack-trace summary::-webkit-details-marker {
-  font-size: 1em;
-}
-
-.extension-error-overlay-stack-trace-list li {
-  -webkit-padding-start: 10px;
-  background-color: white;
-  cursor: pointer;
-  padding-bottom: 6px;
-  padding-top: 6px;
-}
-
-.extension-error-overlay-stack-trace-list li:hover {
-  background-color: #eee;
-}
-
-.extension-error-overlay-stack-trace-list li.extension-error-active {
-  background-color: rgba(0, 100, 255, 0.1);
-}
diff --git a/chrome/browser/resources/extensions/extension_error_overlay.html b/chrome/browser/resources/extensions/extension_error_overlay.html
deleted file mode 100644
index 2becd7ce..0000000
--- a/chrome/browser/resources/extensions/extension_error_overlay.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!--
-Copyright 2013 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be found
-in the LICENSE file.
--->
-
-<div id="template-collection-extension-error-overlay" hidden>
-  <div class="extension-error-overlay-runtime-content">
-    <div class="extension-error-overlay-context">
-      <span>$i18n{extensionErrorOverlayContextUrl}</span>
-      <span class="extension-error-overlay-context-url"></span>
-    </div>
-    <details class="extension-error-overlay-stack-trace">
-      <summary>$i18n{extensionErrorOverlayStackTrace}</summary>
-      <ul class="extension-error-overlay-stack-trace-list"></ul>
-    </details>
-  </div>
-</div>
-
-<div id="extension-error-overlay" class="page">
-  <div class="close-button"></div>
-  <h1 class="extension-error-overlay-title"></h1>
-  <div class="content-area">
-    <div class="extension-error-list"></div>
-    <div id="extension-error-overlay-code" class="extension-code"></div>
-  </div>
-  <div class="action-area">
-    <div class="action-area-right">
-      <div class="button-strip">
-        <button id="extension-error-overlay-dismiss">
-          $i18n{extensionErrorOverlayDone}
-        </button>
-        <button id="extension-error-overlay-devtools-button" hidden>
-          $i18n{extensionErrorOverlayLaunchDevtools}
-        </button>
-      </div>
-    </div>
-  </div>
-</div>
diff --git a/chrome/browser/resources/extensions/extension_error_overlay.js b/chrome/browser/resources/extensions/extension_error_overlay.js
deleted file mode 100644
index c8d6948b..0000000
--- a/chrome/browser/resources/extensions/extension_error_overlay.js
+++ /dev/null
@@ -1,502 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-/** @typedef {chrome.developerPrivate.RuntimeError} */
-var RuntimeError;
-/** @typedef {chrome.developerPrivate.ManifestError} */
-var ManifestError;
-
-cr.define('extensions', function() {
-  'use strict';
-
-  /**
-   * Clear all the content of a given element.
-   * @param {HTMLElement} element The element to be cleared.
-   */
-  function clearElement(element) {
-    while (element.firstChild)
-      element.removeChild(element.firstChild);
-  }
-
-  /**
-   * Get the url relative to the main extension url. If the url is
-   * unassociated with the extension, this will be the full url.
-   * @param {string} url The url to make relative.
-   * @param {string} extensionUrl The url for the extension resources, in the
-   *     form "chrome-etxension://<extension_id>/".
-   * @return {string} The url relative to the host.
-   */
-  function getRelativeUrl(url, extensionUrl) {
-    return url.substring(0, extensionUrl.length) == extensionUrl ?
-        url.substring(extensionUrl.length) : url;
-  }
-
-  /**
-   * The RuntimeErrorContent manages all content specifically associated with
-   * runtime errors; this includes stack frames and the context url.
-   * @constructor
-   * @extends {HTMLDivElement}
-   */
-  function RuntimeErrorContent() {
-    var contentArea = $('template-collection-extension-error-overlay').
-        querySelector('.extension-error-overlay-runtime-content').
-        cloneNode(true);
-    contentArea.__proto__ = RuntimeErrorContent.prototype;
-    /** @type {RuntimeErrorContent} */ (contentArea).init();
-    return contentArea;
-  }
-
-  /**
-   * The name of the "active" class specific to extension errors (so as to
-   * not conflict with other rules).
-   * @type {string}
-   * @const
-   */
-  RuntimeErrorContent.ACTIVE_CLASS_NAME = 'extension-error-active';
-
-  /**
-   * Determine whether or not we should display the url to the user. We don't
-   * want to include any of our own code in stack traces.
-   * @param {string} url The url in question.
-   * @return {boolean} True if the url should be displayed, and false
-   *     otherwise (i.e., if it is an internal script).
-   */
-  RuntimeErrorContent.shouldDisplayForUrl = function(url) {
-    // All our internal scripts are in the 'extensions::' namespace.
-    return !/^extensions::/.test(url);
-  };
-
-  RuntimeErrorContent.prototype = {
-    __proto__: HTMLDivElement.prototype,
-
-    /**
-     * The underlying error whose details are being displayed.
-     * @type {?(RuntimeError|ManifestError)}
-     * @private
-     */
-    error_: null,
-
-    /**
-     * The URL associated with this extension, i.e. chrome-extension://<id>/.
-     * @type {?string}
-     * @private
-     */
-    extensionUrl_: null,
-
-    /**
-     * The node of the stack trace which is currently active.
-     * @type {?HTMLElement}
-     * @private
-     */
-    currentFrameNode_: null,
-
-    /**
-     * Initialize the RuntimeErrorContent for the first time.
-     */
-    init: function() {
-      /**
-       * The stack trace element in the overlay.
-       * @type {HTMLElement}
-       * @private
-       */
-      this.stackTrace_ = /** @type {HTMLElement} */(
-          this.querySelector('.extension-error-overlay-stack-trace-list'));
-      assert(this.stackTrace_);
-
-      /**
-       * The context URL element in the overlay.
-       * @type {HTMLElement}
-       * @private
-       */
-      this.contextUrl_ = /** @type {HTMLElement} */(
-          this.querySelector('.extension-error-overlay-context-url'));
-      assert(this.contextUrl_);
-    },
-
-    /**
-     * Sets the error for the content.
-     * @param {(RuntimeError|ManifestError)} error The error whose content
-     *     should be displayed.
-     * @param {string} extensionUrl The URL associated with this extension.
-     */
-    setError: function(error, extensionUrl) {
-      this.clearError();
-
-      this.error_ = error;
-      this.extensionUrl_ = extensionUrl;
-      this.contextUrl_.textContent = error.contextUrl ?
-          getRelativeUrl(error.contextUrl, this.extensionUrl_) :
-          loadTimeData.getString('extensionErrorOverlayContextUnknown');
-      this.initStackTrace_();
-    },
-
-    /**
-     * Wipe content associated with a specific error.
-     */
-    clearError: function() {
-      this.error_ = null;
-      this.extensionUrl_ = null;
-      this.currentFrameNode_ = null;
-      clearElement(this.stackTrace_);
-      this.stackTrace_.hidden = true;
-    },
-
-    /**
-     * Makes |frame| active and deactivates the previously active frame (if
-     * there was one).
-     * @param {HTMLElement} frameNode The frame to activate.
-     * @private
-     */
-    setActiveFrame_: function(frameNode) {
-      if (this.currentFrameNode_) {
-        this.currentFrameNode_.classList.remove(
-            RuntimeErrorContent.ACTIVE_CLASS_NAME);
-      }
-
-      this.currentFrameNode_ = frameNode;
-      this.currentFrameNode_.classList.add(
-          RuntimeErrorContent.ACTIVE_CLASS_NAME);
-    },
-
-    /**
-     * Initialize the stack trace element of the overlay.
-     * @private
-     */
-    initStackTrace_: function() {
-      for (var i = 0; i < this.error_.stackTrace.length; ++i) {
-        var frame = this.error_.stackTrace[i];
-        // Don't include any internal calls (e.g., schemaBindings) in the
-        // stack trace.
-        if (!RuntimeErrorContent.shouldDisplayForUrl(frame.url))
-          continue;
-
-        var frameNode = document.createElement('li');
-        // Attach the index of the frame to which this node refers (since we
-        // may skip some, this isn't a 1-to-1 match).
-        frameNode.indexIntoTrace = i;
-
-        // The description is a human-readable summation of the frame, in the
-        // form "<relative_url>:<line_number> (function)", e.g.
-        // "myfile.js:25 (myFunction)".
-        var description = getRelativeUrl(frame.url,
-            assert(this.extensionUrl_)) + ':' + frame.lineNumber;
-        if (frame.functionName) {
-          var functionName = frame.functionName == '(anonymous function)' ?
-              loadTimeData.getString('extensionErrorOverlayAnonymousFunction') :
-              frame.functionName;
-          description += ' (' + functionName + ')';
-        }
-        frameNode.textContent = description;
-
-        // When the user clicks on a frame in the stack trace, we should
-        // highlight that overlay in the list, display the appropriate source
-        // code with the line highlighted, and link the "Open DevTools" button
-        // with that frame.
-        frameNode.addEventListener('click', function(frame, frameNode, e) {
-          this.setActiveFrame_(frameNode);
-
-          // Request the file source with the section highlighted.
-          extensions.ExtensionErrorOverlay.getInstance().requestFileSource(
-              {extensionId: this.error_.extensionId,
-               message: this.error_.message,
-               pathSuffix: getRelativeUrl(frame.url,
-                                          assert(this.extensionUrl_)),
-               lineNumber: frame.lineNumber});
-        }.bind(this, frame, frameNode));
-
-        this.stackTrace_.appendChild(frameNode);
-      }
-
-      // Set the current stack frame to the first stack frame and show the
-      // trace, if one exists. (We can't just check error.stackTrace, because
-      // it's possible the trace was purely internal, and we don't show
-      // internal frames.)
-      if (this.stackTrace_.children.length > 0) {
-        this.stackTrace_.hidden = false;
-        this.setActiveFrame_(assertInstanceof(this.stackTrace_.firstChild,
-            HTMLElement));
-      }
-    },
-
-    /**
-     * Open the developer tools for the active stack frame.
-     */
-    openDevtools: function() {
-      var stackFrame =
-          this.error_.stackTrace[this.currentFrameNode_.indexIntoTrace];
-
-      chrome.developerPrivate.openDevTools(
-          {renderProcessId: this.error_.renderProcessId || -1,
-           renderViewId: this.error_.renderViewId || -1,
-           url: stackFrame.url,
-           lineNumber: stackFrame.lineNumber || 0,
-           columnNumber: stackFrame.columnNumber || 0});
-    }
-  };
-
-  /**
-   * The ExtensionErrorOverlay will show the contents of a file which pertains
-   * to the ExtensionError; this is either the manifest file (for manifest
-   * errors) or a source file (for runtime errors). If possible, the portion
-   * of the file which caused the error will be highlighted.
-   * @constructor
-   */
-  function ExtensionErrorOverlay() {
-    /**
-     * The content section for runtime errors; this is re-used for all
-     * runtime errors and attached/detached from the overlay as needed.
-     * @type {RuntimeErrorContent}
-     * @private
-     */
-    this.runtimeErrorContent_ = new RuntimeErrorContent();
-  }
-
-  /**
-   * The manifest filename.
-   * @type {string}
-   * @const
-   * @private
-   */
-  ExtensionErrorOverlay.MANIFEST_FILENAME_ = 'manifest.json';
-
-  /**
-   * Determine whether or not chrome can load the source for a given file; this
-   * can only be done if the file belongs to the extension.
-   * @param {string} file The file to load.
-   * @param {string} extensionUrl The url for the extension, in the form
-   *     chrome-extension://<extension-id>/.
-   * @return {boolean} True if the file can be loaded, false otherwise.
-   * @private
-   */
-  ExtensionErrorOverlay.canLoadFileSource = function(file, extensionUrl) {
-    return file.substr(0, extensionUrl.length) == extensionUrl ||
-           file.toLowerCase() == ExtensionErrorOverlay.MANIFEST_FILENAME_;
-  };
-
-  cr.addSingletonGetter(ExtensionErrorOverlay);
-
-  ExtensionErrorOverlay.prototype = {
-    /**
-     * The underlying error whose details are being displayed.
-     * @type {?(RuntimeError|ManifestError)}
-     * @private
-     */
-    selectedError_: null,
-
-    /**
-     * Initialize the page.
-     * @param {function(HTMLDivElement)} showOverlay The function to show or
-     *     hide the ExtensionErrorOverlay; this should take a single parameter
-     *     which is either the overlay Div if the overlay should be displayed,
-     *     or null if the overlay should be hidden.
-     */
-    initializePage: function(showOverlay) {
-      var overlay = $('overlay');
-      cr.ui.overlay.setupOverlay(overlay);
-      cr.ui.overlay.globalInitialization();
-      overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
-
-      $('extension-error-overlay-dismiss').addEventListener('click',
-          function() {
-        cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
-      });
-
-      /**
-       * The element of the full overlay.
-       * @type {HTMLDivElement}
-       * @private
-       */
-      this.overlayDiv_ = /** @type {HTMLDivElement} */(
-          $('extension-error-overlay'));
-
-      /**
-       * The portion of the overlay which shows the code relating to the error
-       * and the corresponding line numbers.
-       * @type {extensions.ExtensionCode}
-       * @private
-       */
-      this.codeDiv_ =
-          new extensions.ExtensionCode($('extension-error-overlay-code'));
-
-      /**
-       * The function to show or hide the ExtensionErrorOverlay.
-       * @param {boolean} isVisible Whether the overlay should be visible.
-       */
-      this.setVisible = function(isVisible) {
-        showOverlay(isVisible ? this.overlayDiv_ : null);
-        if (isVisible)
-          this.codeDiv_.scrollToError();
-      };
-
-      /**
-       * The button to open the developer tools (only available for runtime
-       * errors).
-       * @type {HTMLButtonElement}
-       * @private
-       */
-      this.openDevtoolsButton_ = /** @type {HTMLButtonElement} */(
-          $('extension-error-overlay-devtools-button'));
-      this.openDevtoolsButton_.addEventListener('click', function() {
-          this.runtimeErrorContent_.openDevtools();
-      }.bind(this));
-    },
-
-    /**
-     * Handles a click on the dismiss ("OK" or close) buttons.
-     * @param {Event} e The click event.
-     * @private
-     */
-    handleDismiss_: function(e) {
-      this.setVisible(false);
-
-      // There's a chance that the overlay receives multiple dismiss events; in
-      // this case, handle it gracefully and return (since all necessary work
-      // will already have been done).
-      if (!this.selectedError_)
-        return;
-
-      // Remove all previous content.
-      this.codeDiv_.clear();
-
-      /** @type {extensions.ExtensionErrorList} */ (
-          this.overlayDiv_.querySelector('.extension-error-list'))
-          .onRemoved();
-
-      this.clearRuntimeContent_();
-
-      this.selectedError_ = null;
-    },
-
-    /**
-     * Clears the current content.
-     * @private
-     */
-    clearRuntimeContent_: function() {
-      if (this.runtimeErrorContent_.parentNode) {
-        this.runtimeErrorContent_.parentNode.removeChild(
-            this.runtimeErrorContent_);
-        this.runtimeErrorContent_.clearError();
-      }
-      this.openDevtoolsButton_.hidden = true;
-    },
-
-    /**
-     * Sets the active error for the overlay.
-     * @param {?(ManifestError|RuntimeError)} error The error to make active.
-     * @private
-     */
-    setActiveError_: function(error) {
-      this.selectedError_ = error;
-
-      // If there is no error (this can happen if, e.g., the user deleted all
-      // the errors), then clear the content.
-      if (!error) {
-        this.codeDiv_.populate(
-            null, loadTimeData.getString('extensionErrorNoErrorsCodeMessage'));
-        this.clearRuntimeContent_();
-        return;
-      }
-
-      var extensionUrl = 'chrome-extension://' + error.extensionId + '/';
-      // Set or hide runtime content.
-      if (error.type == chrome.developerPrivate.ErrorType.RUNTIME) {
-        this.runtimeErrorContent_.setError(error, extensionUrl);
-        this.overlayDiv_.querySelector('.content-area').insertBefore(
-            this.runtimeErrorContent_,
-            this.codeDiv_.nextSibling);
-        this.openDevtoolsButton_.hidden = false;
-        this.openDevtoolsButton_.disabled = !error.canInspect;
-      } else {
-        this.clearRuntimeContent_();
-      }
-
-      // Read the file source to populate the code section, or set it to null if
-      // the file is unreadable.
-      if (ExtensionErrorOverlay.canLoadFileSource(error.source, extensionUrl)) {
-        // Use pathname instead of relativeUrl.
-        var requestFileSourceArgs = {extensionId: error.extensionId,
-                                     message: error.message};
-        switch (error.type) {
-          case chrome.developerPrivate.ErrorType.MANIFEST:
-            requestFileSourceArgs.pathSuffix = error.source;
-            requestFileSourceArgs.manifestKey = error.manifestKey;
-            requestFileSourceArgs.manifestSpecific = error.manifestSpecific;
-            break;
-          case chrome.developerPrivate.ErrorType.RUNTIME:
-            // slice(1) because pathname starts with a /.
-            var pathname = new URL(error.source).pathname.slice(1);
-            requestFileSourceArgs.pathSuffix = pathname;
-            requestFileSourceArgs.lineNumber =
-                error.stackTrace && error.stackTrace[0] ?
-                    error.stackTrace[0].lineNumber : 0;
-            break;
-          default:
-            assertNotReached();
-        }
-        this.requestFileSource(requestFileSourceArgs);
-      } else {
-        this.onFileSourceResponse_(null);
-      }
-    },
-
-    /**
-     * Associate an error with the overlay. This will set the error for the
-     * overlay, and, if possible, will populate the code section of the overlay
-     * with the relevant file, load the stack trace, and generate links for
-     * opening devtools (the latter two only happen for runtime errors).
-     * @param {Array<(RuntimeError|ManifestError)>} errors The error to show in
-     *     the overlay.
-     * @param {string} extensionId The id of the extension.
-     * @param {string} extensionName The name of the extension.
-     */
-    setErrorsAndShowOverlay: function(errors, extensionId, extensionName) {
-      document.querySelector(
-          '#extension-error-overlay .extension-error-overlay-title').
-              textContent = extensionName;
-      var errorsDiv = this.overlayDiv_.querySelector('.extension-error-list');
-      var extensionErrors =
-          new extensions.ExtensionErrorList(errors, extensionId);
-      errorsDiv.parentNode.replaceChild(extensionErrors, errorsDiv);
-      extensionErrors.addEventListener('activeExtensionErrorChanged',
-                                       function(e) {
-        this.setActiveError_(e.detail);
-      }.bind(this));
-
-      if (errors.length > 0)
-        this.setActiveError_(errors[0]);
-      this.setVisible(true);
-    },
-
-    /**
-     * Requests a file's source.
-     * @param {chrome.developerPrivate.RequestFileSourceProperties} args The
-     *     arguments for the call.
-     */
-    requestFileSource: function(args) {
-      chrome.developerPrivate.requestFileSource(
-          args, this.onFileSourceResponse_.bind(this));
-    },
-
-    /**
-     * Set the code to be displayed in the code portion of the overlay.
-     * @see ExtensionErrorOverlay.requestFileSourceResponse().
-     * @param {?chrome.developerPrivate.RequestFileSourceResponse} response The
-     *     response from the request file source call, which will be shown as
-     *     code. If |response| is null, then a "Could not display code" message
-     *     will be displayed instead.
-     */
-    onFileSourceResponse_: function(response) {
-      this.codeDiv_.populate(
-          response,  // ExtensionCode can handle a null response.
-          loadTimeData.getString('extensionErrorOverlayNoCodeToDisplay'));
-      this.setVisible(true);
-    },
-  };
-
-  // Export
-  return {
-    ExtensionErrorOverlay: ExtensionErrorOverlay
-  };
-});
diff --git a/chrome/browser/resources/extensions/extension_error_severity_fatal.png b/chrome/browser/resources/extensions/extension_error_severity_fatal.png
deleted file mode 100644
index b53dc2c..0000000
--- a/chrome/browser/resources/extensions/extension_error_severity_fatal.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/extensions/extension_error_severity_info.png b/chrome/browser/resources/extensions/extension_error_severity_info.png
deleted file mode 100644
index 9aba928..0000000
--- a/chrome/browser/resources/extensions/extension_error_severity_info.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/extensions/extension_error_severity_warning.png b/chrome/browser/resources/extensions/extension_error_severity_warning.png
deleted file mode 100644
index d2e3434..0000000
--- a/chrome/browser/resources/extensions/extension_error_severity_warning.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/extensions/extension_focus_manager.js b/chrome/browser/resources/extensions/extension_focus_manager.js
deleted file mode 100644
index 377744ca..0000000
--- a/chrome/browser/resources/extensions/extension_focus_manager.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('extensions', function() {
-  /**
-   * @constructor
-   * @extends {cr.ui.FocusManager}
-   */
-  function ExtensionFocusManager() {}
-
-  cr.addSingletonGetter(ExtensionFocusManager);
-
-  ExtensionFocusManager.prototype = {
-    __proto__: cr.ui.FocusManager.prototype,
-
-    /** @override */
-    getFocusParent: function() {
-      var overlay = extensions.ExtensionSettings.getCurrentOverlay();
-      return overlay || $('extension-settings');
-    },
-  };
-
-  return {
-    ExtensionFocusManager: ExtensionFocusManager,
-  };
-});
diff --git a/chrome/browser/resources/extensions/extension_list.js b/chrome/browser/resources/extensions/extension_list.js
deleted file mode 100644
index 5a2e396e..0000000
--- a/chrome/browser/resources/extensions/extension_list.js
+++ /dev/null
@@ -1,1066 +0,0 @@
-// Copyright (c) 2012 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 src="extension_error.js">
-
-cr.define('extensions', function() {
-  'use strict';
-
-  var ExtensionType = chrome.developerPrivate.ExtensionType;
-
-  /**
-   * @param {string} name The name of the template to clone.
-   * @return {!Element} The freshly cloned template.
-   */
-  function cloneTemplate(name) {
-    var node = $('templates').querySelector('.' + name).cloneNode(true);
-    return assertInstanceof(node, Element);
-  }
-
-  /**
-   * @extends {HTMLElement}
-   * @constructor
-   */
-  function ExtensionWrapper() {
-    var wrapper = cloneTemplate('extension-list-item-wrapper');
-    wrapper.__proto__ = ExtensionWrapper.prototype;
-    wrapper.initialize();
-    return wrapper;
-  }
-
-  ExtensionWrapper.prototype = {
-    __proto__: HTMLElement.prototype,
-
-    initialize: function() {
-      var boundary = $('extension-settings-list');
-      /** @private {!extensions.FocusRow} */
-      this.focusRow_ = new extensions.FocusRow(this, boundary);
-    },
-
-    /** @return {!cr.ui.FocusRow} */
-    getFocusRow: function() {
-      return this.focusRow_;
-    },
-
-    /**
-     * Add an item to the focus row and listen for |eventType| events.
-     * @param {string} focusType A tag used to identify equivalent elements when
-     *     changing focus between rows.
-     * @param {string} query A query to select the element to set up.
-     * @param {string=} opt_eventType The type of event to listen to.
-     * @param {function(Event)=} opt_handler The function that should be called
-     *     by the event.
-     * @private
-     */
-    setupColumn: function(focusType, query, opt_eventType, opt_handler) {
-      assert(this.focusRow_.addItem(focusType, query));
-      if (opt_eventType) {
-        assert(opt_handler);
-        this.querySelector(query).addEventListener(opt_eventType, opt_handler);
-      }
-    },
-  };
-
-  var ExtensionCommandsOverlay = extensions.ExtensionCommandsOverlay;
-
-  /**
-   * Compares two extensions for the order they should appear in the list.
-   * @param {chrome.developerPrivate.ExtensionInfo} a The first extension.
-   * @param {chrome.developerPrivate.ExtensionInfo} b The second extension.
-   * returns {number} -1 if A comes before B, 1 if A comes after B, 0 if equal.
-   */
-  function compareExtensions(a, b) {
-    function compare(x, y) {
-      return x < y ? -1 : (x > y ? 1 : 0);
-    }
-    function compareLocation(x, y) {
-      if (x.location == y.location)
-        return 0;
-      if (x.location == chrome.developerPrivate.Location.UNPACKED)
-        return -1;
-      if (y.location == chrome.developerPrivate.Location.UNPACKED)
-        return 1;
-      return 0;
-    }
-    return compareLocation(a, b) ||
-           compare(a.name.toLowerCase(), b.name.toLowerCase()) ||
-           compare(a.id, b.id);
-  }
-
-  /** @interface */
-  function ExtensionListDelegate() {}
-
-  ExtensionListDelegate.prototype = {
-    /**
-     * Called when the number of extensions in the list has changed.
-     */
-    onExtensionCountChanged: assertNotReached,
-  };
-
-  /**
-   * Creates a new list of extensions.
-   * @param {extensions.ExtensionListDelegate} delegate
-   * @constructor
-   * @extends {HTMLDivElement}
-   */
-  function ExtensionList(delegate) {
-    var div = document.createElement('div');
-    div.__proto__ = ExtensionList.prototype;
-    div.initialize(delegate);
-    return div;
-  }
-
-  ExtensionList.prototype = {
-    __proto__: HTMLDivElement.prototype,
-
-    /**
-     * Indicates whether an embedded options page that was navigated to through
-     * the '?options=' URL query has been shown to the user. This is necessary
-     * to prevent showExtensionNodes_ from opening the options more than once.
-     * @type {boolean}
-     * @private
-     */
-    optionsShown_: false,
-
-    /** @private {!cr.ui.FocusGrid} */
-    focusGrid_: new cr.ui.FocusGrid(),
-
-    /**
-     * Indicates whether an uninstall dialog is being shown to prevent multiple
-     * dialogs from being displayed.
-     * @private {boolean}
-     */
-    uninstallIsShowing_: false,
-
-    /**
-     * Indicates whether a permissions prompt is showing.
-     * @private {boolean}
-     */
-    permissionsPromptIsShowing_: false,
-
-    /**
-     * Whether or not any initial navigation (like scrolling to an extension,
-     * or opening an options page) has occurred.
-     * @private {boolean}
-     */
-    didInitialNavigation_: false,
-
-    /**
-     * Whether or not incognito mode is available.
-     * @private {boolean}
-     */
-    incognitoAvailable_: false,
-
-    /**
-     * Whether or not the app info dialog is enabled.
-     * @private {boolean}
-     */
-    enableAppInfoDialog_: false,
-
-    /**
-     * Initializes the list.
-     * @param {!extensions.ExtensionListDelegate} delegate
-     */
-    initialize: function(delegate) {
-      /** @private {!Array<chrome.developerPrivate.ExtensionInfo>} */
-      this.extensions_ = [];
-
-      /** @private {!extensions.ExtensionListDelegate} */
-      this.delegate_ = delegate;
-
-      this.resetLoadFinished();
-
-      chrome.developerPrivate.onItemStateChanged.addListener(
-          function(eventData) {
-        var EventType = chrome.developerPrivate.EventType;
-        switch (eventData.event_type) {
-          case EventType.VIEW_REGISTERED:
-          case EventType.VIEW_UNREGISTERED:
-          case EventType.INSTALLED:
-          case EventType.LOADED:
-          case EventType.UNLOADED:
-          case EventType.ERROR_ADDED:
-          case EventType.ERRORS_REMOVED:
-          case EventType.PREFS_CHANGED:
-            if (eventData.extensionInfo) {
-              this.updateOrCreateWrapper_(eventData.extensionInfo);
-              this.focusGrid_.ensureRowActive();
-            }
-            break;
-          case EventType.UNINSTALLED:
-            var index = this.getIndexOfExtension_(eventData.item_id);
-            this.extensions_.splice(index, 1);
-            this.removeWrapper_(/**@type {!ExtensionWrapper} */ (
-                getRequiredElement(eventData.item_id)));
-            break;
-          default:
-            assertNotReached();
-        }
-
-        if (eventData.event_type == EventType.UNLOADED)
-          this.hideEmbeddedExtensionOptions_(eventData.item_id);
-
-        if (eventData.event_type == EventType.INSTALLED ||
-            eventData.event_type == EventType.UNINSTALLED) {
-          this.delegate_.onExtensionCountChanged();
-        }
-
-        if (eventData.event_type == EventType.LOADED ||
-            eventData.event_type == EventType.UNLOADED ||
-            eventData.event_type == EventType.PREFS_CHANGED ||
-            eventData.event_type == EventType.UNINSTALLED) {
-          // We update the commands overlay whenever an extension is added or
-          // removed (other updates wouldn't affect command-ly things). We
-          // need both UNLOADED and UNINSTALLED since the UNLOADED event results
-          // in an extension losing active keybindings, and UNINSTALLED can
-          // result in the "Keyboard shortcuts" link being removed.
-          ExtensionCommandsOverlay.updateExtensionsData(this.extensions_);
-        }
-      }.bind(this));
-    },
-
-    /**
-     * Resets the |loadFinished| promise so that it can be used again; this
-     * is useful if the page updates and tests need to wait for it to finish.
-     */
-    resetLoadFinished: function() {
-      /**
-       * |loadFinished| should be used for testing purposes and will be
-       * fulfilled when this list has finished loading the first time.
-       * @type {Promise}
-       * */
-      this.loadFinished = new Promise(function(resolve, reject) {
-        /** @private {function(?)} */
-        this.resolveLoadFinished_ = resolve;
-      }.bind(this));
-    },
-
-    /**
-     * Updates the extensions on the page.
-     * @param {boolean} incognitoAvailable Whether or not incognito is allowed.
-     * @param {boolean} enableAppInfoDialog Whether or not the app info dialog
-     *     is enabled.
-     * @return {Promise} A promise that is resolved once the extensions data is
-     *     fully updated.
-     */
-    updateExtensionsData: function(incognitoAvailable, enableAppInfoDialog) {
-      // If we start to need more information about the extension configuration,
-      // consider passing in the full object from the ExtensionSettings.
-      this.incognitoAvailable_ = incognitoAvailable;
-      this.enableAppInfoDialog_ = enableAppInfoDialog;
-      /** @private {Promise} */
-      this.extensionsUpdated_ = new Promise(function(resolve, reject) {
-        chrome.developerPrivate.getExtensionsInfo(
-            {includeDisabled: true, includeTerminated: true},
-            function(extensions) {
-          // Sort in order of unpacked vs. packed, followed by name, followed by
-          // id.
-          extensions.sort(compareExtensions);
-          this.extensions_ = extensions;
-          this.showExtensionNodes_();
-
-          // We keep the commands overlay's extension info in sync, so that we
-          // don't duplicate the same querying logic there.
-          ExtensionCommandsOverlay.updateExtensionsData(this.extensions_);
-
-          resolve();
-
-          // |resolve| is async so it's necessary to use |then| here in order to
-          // do work after other |then|s have finished. This is important so
-          // elements are visible when these updates happen.
-          this.extensionsUpdated_.then(function() {
-            this.onUpdateFinished_();
-            this.resolveLoadFinished_();
-          }.bind(this));
-        }.bind(this));
-      }.bind(this));
-      return this.extensionsUpdated_;
-    },
-
-    /**
-     * Updates elements that need to be visible in order to update properly.
-     * @private
-     */
-    onUpdateFinished_: function() {
-      // Cannot focus or highlight a extension if there are none, and we should
-      // only scroll to a particular extension or open the options page once.
-      if (this.extensions_.length == 0 || this.didInitialNavigation_)
-        return;
-
-      this.didInitialNavigation_ = true;
-      assert(!this.hidden);
-      assert(!this.parentElement.hidden);
-
-      var idToHighlight = this.getIdQueryParam_();
-      if (idToHighlight) {
-        var wrapper = /** @type {ExtensionWrapper} */ ($(idToHighlight));
-        if (wrapper) {
-          this.scrollToWrapper_(idToHighlight);
-
-          var focusRow = wrapper.getFocusRow();
-          (focusRow.getFirstFocusable('enabled') ||
-           focusRow.getFirstFocusable('remove-enterprise') ||
-           focusRow.getFirstFocusable('website') ||
-           focusRow.getFirstFocusable('details')).focus();
-        }
-      }
-
-      var idToOpenOptions = this.getOptionsQueryParam_();
-      if (idToOpenOptions && $(idToOpenOptions))
-        this.showEmbeddedExtensionOptions_(idToOpenOptions, true);
-    },
-
-    /** @return {number} The number of extensions being displayed. */
-    getNumExtensions: function() {
-      return this.extensions_.length;
-    },
-
-    /**
-     * @param {string} id The id of the extension.
-     * @return {number} The index of the extension with the given id.
-     * @private
-     */
-    getIndexOfExtension_: function(id) {
-      for (var i = 0; i < this.extensions_.length; ++i) {
-        if (this.extensions_[i].id == id)
-          return i;
-      }
-      return -1;
-    },
-
-    getIdQueryParam_: function() {
-      return parseQueryParams(document.location)['id'];
-    },
-
-    getOptionsQueryParam_: function() {
-      return parseQueryParams(document.location)['options'];
-    },
-
-    /**
-     * Creates or updates all extension items from scratch.
-     * @private
-     */
-    showExtensionNodes_: function() {
-      // Any node that is not updated will be removed.
-      var seenIds = [];
-
-      // Iterate over the extension data and add each item to the list.
-      this.extensions_.forEach(function(extension) {
-        seenIds.push(extension.id);
-        this.updateOrCreateWrapper_(extension);
-      }, this);
-      this.focusGrid_.ensureRowActive();
-
-      // Remove extensions that are no longer installed.
-      var wrappers = document.querySelectorAll(
-          '.extension-list-item-wrapper[id]');
-      Array.prototype.forEach.call(wrappers, function(wrapper) {
-        if (seenIds.indexOf(wrapper.id) < 0)
-          this.removeWrapper_(wrapper);
-      }, this);
-    },
-
-    /**
-     * Removes the wrapper from the DOM and updates the focused element if
-     * needed.
-     * @param {!ExtensionWrapper} wrapper
-     * @private
-     */
-    removeWrapper_: function(wrapper) {
-      // If focus is in the wrapper about to be removed, move it first. This
-      // happens when clicking the trash can to remove an extension.
-      if (wrapper.contains(document.activeElement)) {
-        var wrappers = /** @type {NodeList<ExtensionWrapper>}*/ (
-            document.querySelectorAll('.extension-list-item-wrapper[id]'));
-        var index = Array.prototype.indexOf.call(wrappers, wrapper);
-        assert(index != -1);
-        var focusableWrapper = wrappers[index + 1] || wrappers[index - 1];
-        if (focusableWrapper) {
-          var newFocusRow = focusableWrapper.getFocusRow();
-          newFocusRow.getEquivalentElement(document.activeElement).focus();
-        }
-      }
-
-      var focusRow = wrapper.getFocusRow();
-      this.focusGrid_.removeRow(focusRow);
-      this.focusGrid_.ensureRowActive();
-      focusRow.destroy();
-
-      wrapper.parentNode.removeChild(wrapper);
-    },
-
-    /**
-     * Scrolls the page down to the extension node with the given id.
-     * @param {string} extensionId The id of the extension to scroll to.
-     * @private
-     */
-    scrollToWrapper_: function(extensionId) {
-      // Scroll offset should be calculated slightly higher than the actual
-      // offset of the element being scrolled to, so that it ends up not all
-      // the way at the top. That way it is clear that there are more elements
-      // above the element being scrolled to.
-      var wrapper = $(extensionId);
-      var scrollFudge = 1.2;
-      var scrollTop = wrapper.offsetTop - scrollFudge * wrapper.clientHeight;
-      setScrollTopForDocument(document, scrollTop);
-    },
-
-    /**
-     * Synthesizes and initializes an HTML element for the extension metadata
-     * given in |extension|.
-     * @param {!chrome.developerPrivate.ExtensionInfo} extension A dictionary
-     *     of extension metadata.
-     * @param {?Element} nextWrapper The newly created wrapper will be inserted
-     *     before |nextWrapper| if non-null (else it will be appended to the
-     *     wrapper list).
-     * @private
-     */
-    createWrapper_: function(extension, nextWrapper) {
-      var wrapper = new ExtensionWrapper;
-      wrapper.id = extension.id;
-
-      // The 'Permissions' link.
-      wrapper.setupColumn('details', '.permissions-link', 'click', function(e) {
-        if (!this.permissionsPromptIsShowing_) {
-          chrome.developerPrivate.showPermissionsDialog(extension.id,
-                                                        function() {
-            this.permissionsPromptIsShowing_ = false;
-          }.bind(this));
-          this.permissionsPromptIsShowing_ = true;
-        }
-        e.preventDefault();
-      });
-
-      wrapper.setupColumn('options', '.options-button', 'click', function(e) {
-        this.showEmbeddedExtensionOptions_(extension.id, false);
-        e.preventDefault();
-      }.bind(this));
-
-      // The 'Options' button or link, depending on its behaviour.
-      // Set an href to get the correct mouse-over appearance (link,
-      // footer) - but the actual link opening is done through developerPrivate
-      // API with a preventDefault().
-      wrapper.querySelector('.options-link').href =
-          extension.optionsPage ? extension.optionsPage.url : '';
-      wrapper.setupColumn('options', '.options-link', 'click', function(e) {
-        chrome.developerPrivate.showOptions(extension.id);
-        e.preventDefault();
-      });
-
-      // The 'View in Web Store/View Web Site' link.
-      wrapper.setupColumn('website', '.site-link');
-
-      // The 'Launch' link.
-      wrapper.setupColumn('launch', '.launch-link', 'click', function(e) {
-        chrome.management.launchApp(extension.id);
-      });
-
-      // The 'Reload' link.
-      wrapper.setupColumn('localReload', '.reload-link', 'click', function(e) {
-        chrome.developerPrivate.reload(extension.id, {failQuietly: true});
-      });
-
-      wrapper.setupColumn('errors', '.errors-link', 'click', function(e) {
-        var extensionId = extension.id;
-        assert(this.extensions_.length > 0);
-        var newEx = this.extensions_.filter(function(e) {
-          return e.id == extensionId;
-        })[0];
-        var errors = newEx.manifestErrors.concat(newEx.runtimeErrors);
-        extensions.ExtensionErrorOverlay.getInstance().setErrorsAndShowOverlay(
-            errors, extensionId, newEx.name);
-      }.bind(this));
-
-      wrapper.setupColumn('suspiciousLearnMore',
-                          '.suspicious-install-message .learn-more-link');
-
-      // The path, if provided by unpacked extension.
-      wrapper.setupColumn('loadPath', '.load-path a:first-of-type', 'click',
-                          function(e) {
-        chrome.developerPrivate.showPath(extension.id);
-        e.preventDefault();
-      });
-
-      // The 'allow in incognito' checkbox.
-      wrapper.setupColumn('incognito', '.incognito-control input', 'change',
-                          function(e) {
-        var butterBar = wrapper.querySelector('.butter-bar');
-        var checked = e.target.checked;
-        butterBar.hidden = !checked ||
-            extension.type == ExtensionType.HOSTED_APP;
-        chrome.developerPrivate.updateExtensionConfiguration({
-          extensionId: extension.id,
-          incognitoAccess: e.target.checked
-        });
-      }.bind(this));
-
-      // The 'collect errors' checkbox. This should only be visible if the
-      // error console is enabled - we can detect this by the existence of the
-      // |errorCollectionEnabled| property.
-      wrapper.setupColumn('collectErrors', '.error-collection-control input',
-          'change', function(e) {
-        chrome.developerPrivate.updateExtensionConfiguration({
-          extensionId: extension.id,
-          errorCollection: e.target.checked
-        });
-      });
-
-      // The 'allow on all urls' checkbox. This should only be visible if
-      // active script restrictions are enabled. If they are not enabled, no
-      // extensions should want all urls.
-      wrapper.setupColumn('allUrls', '.all-urls-control input', 'click',
-                          function(e) {
-        chrome.developerPrivate.updateExtensionConfiguration({
-          extensionId: extension.id,
-          runOnAllUrls: e.target.checked
-        });
-      });
-
-      // The 'allow file:// access' checkbox.
-      wrapper.setupColumn('localUrls', '.file-access-control input', 'click',
-                          function(e) {
-        chrome.developerPrivate.updateExtensionConfiguration({
-          extensionId: extension.id,
-          fileAccess: e.target.checked
-        });
-      });
-
-      // The 'Reload' terminated link.
-      wrapper.setupColumn('terminatedReload', '.terminated-reload-link',
-                          'click', function(e) {
-        chrome.developerPrivate.reload(extension.id, {failQuietly: true});
-      });
-
-      // The 'Repair' corrupted link.
-      wrapper.setupColumn('repair', '.corrupted-repair-button', 'click',
-                          function(e) {
-        chrome.developerPrivate.repairExtension(extension.id);
-      });
-
-      // The 'Enabled' checkbox.
-      wrapper.setupColumn('enabled', '.enable-checkbox input', 'click',
-                          function(e) {
-        var checked = e.target.checked;
-        // TODO(devlin): What should we do if this fails? Ideally we want to
-        // show some kind of error or feedback to the user if this fails.
-        chrome.management.setEnabled(extension.id, checked);
-
-        // This may seem counter-intuitive (to not set/clear the checkmark)
-        // but this page will be updated asynchronously if the extension
-        // becomes enabled/disabled. It also might not become enabled or
-        // disabled, because the user might e.g. get prompted when enabling
-        // and choose not to.
-        e.preventDefault();
-      });
-
-      // 'Remove' button.
-      var trash = cloneTemplate('trash');
-      trash.title = loadTimeData.getString('extensionUninstall');
-
-      wrapper.querySelector('.enable-controls').appendChild(trash);
-
-      wrapper.setupColumn('remove-enterprise', '.trash', 'click', function(e) {
-        trash.classList.add('open');
-        trash.classList.toggle('mouse-clicked', e.detail > 0);
-        if (this.uninstallIsShowing_)
-          return;
-        this.uninstallIsShowing_ = true;
-        chrome.management.uninstall(extension.id,
-                                    {showConfirmDialog: true},
-                                    function() {
-          // TODO(devlin): What should we do if the uninstall fails?
-          this.uninstallIsShowing_ = false;
-
-          if (trash.classList.contains('mouse-clicked'))
-            trash.blur();
-
-          if (chrome.runtime.lastError) {
-            // The uninstall failed (e.g. a cancel). Allow the trash to close.
-            trash.classList.remove('open');
-          } else {
-            // Leave the trash open if the uninstall succeded. Otherwise it can
-            // half-close right before it's removed when the DOM is modified.
-          }
-        }.bind(this));
-      }.bind(this));
-
-      // Maintain the order that nodes should be in when creating as well as
-      // when adding only one new wrapper.
-      this.insertBefore(wrapper, nextWrapper);
-      this.updateWrapper_(extension, wrapper);
-
-      var nextRow = this.focusGrid_.getRowForRoot(nextWrapper);  // May be null.
-      this.focusGrid_.addRowBefore(wrapper.getFocusRow(), nextRow);
-    },
-
-    /**
-     * Updates an HTML element for the extension metadata given in |extension|.
-     * @param {!chrome.developerPrivate.ExtensionInfo} extension A dictionary of
-     *     extension metadata.
-     * @param {!ExtensionWrapper} wrapper The extension wrapper element to
-     *     update.
-     * @private
-     */
-    updateWrapper_: function(extension, wrapper) {
-      var isActive =
-          extension.state == chrome.developerPrivate.ExtensionState.ENABLED;
-      wrapper.classList.toggle('inactive-extension', !isActive);
-      wrapper.classList.remove('controlled', 'may-not-remove');
-
-      if (extension.controlledInfo) {
-        wrapper.classList.add('controlled');
-      } else if (!extension.userMayModify ||
-                 extension.mustRemainInstalled ||
-                 extension.dependentExtensions.length > 0) {
-        wrapper.classList.add('may-not-remove');
-      }
-
-      var item = wrapper.querySelector('.extension-list-item');
-      item.style.backgroundImage = 'url(' + extension.iconUrl + ')';
-
-      this.setText_(wrapper, '.extension-title', extension.name);
-      this.setText_(wrapper, '.extension-version', extension.version);
-      this.setText_(wrapper, '.location-text', extension.locationText || '');
-      this.setText_(wrapper, '.blacklist-text', extension.blacklistText || '');
-      this.setText_(wrapper, '.extension-description', extension.description);
-
-      // The 'allow in incognito' checkbox.
-      this.updateVisibility_(wrapper, '.incognito-control',
-                             isActive && this.incognitoAvailable_,
-                             function(item) {
-        var incognito = item.querySelector('input');
-        incognito.disabled = !extension.incognitoAccess.isEnabled;
-        incognito.checked = extension.incognitoAccess.isActive;
-      });
-      var showButterBar = isActive &&
-            extension.incognitoAccess.isActive &&
-            extension.type != ExtensionType.HOSTED_APP;
-      // The 'allow in incognito' butter bar.
-      this.updateVisibility_(wrapper, '.butter-bar', showButterBar);
-
-      // The 'collect errors' checkbox. This should only be visible if the
-      // error console is enabled - we can detect this by the existence of the
-      // |errorCollectionEnabled| property.
-      this.updateVisibility_(
-          wrapper, '.error-collection-control',
-          isActive && extension.errorCollection.isEnabled,
-          function(item) {
-        item.querySelector('input').checked =
-            extension.errorCollection.isActive;
-      });
-
-      // The 'allow on all urls' checkbox. This should only be visible if
-      // active script restrictions are enabled. If they are not enabled, no
-      // extensions should want all urls.
-      this.updateVisibility_(
-          wrapper, '.all-urls-control',
-          isActive && extension.runOnAllUrls.isEnabled,
-          function(item) {
-        item.querySelector('input').checked = extension.runOnAllUrls.isActive;
-      });
-
-      // The 'allow file:// access' checkbox.
-      this.updateVisibility_(wrapper, '.file-access-control',
-                             isActive && extension.fileAccess.isEnabled,
-                             function(item) {
-        item.querySelector('input').checked = extension.fileAccess.isActive;
-      });
-
-      // The 'Options' button or link, depending on its behaviour.
-      var optionsEnabled = isActive && !!extension.optionsPage;
-      this.updateVisibility_(wrapper, '.options-link', optionsEnabled &&
-                             extension.optionsPage.openInTab);
-      this.updateVisibility_(wrapper, '.options-button', optionsEnabled &&
-                             !extension.optionsPage.openInTab);
-
-      // The 'View in Web Store/View Web Site' link.
-      var siteLinkEnabled = !!extension.homePage.url &&
-                            !this.enableAppInfoDialog_;
-      this.updateVisibility_(wrapper, '.site-link', siteLinkEnabled,
-                             function(item) {
-        item.href = extension.homePage.url;
-        item.textContent = loadTimeData.getString(
-            extension.homePage.specified ? 'extensionSettingsVisitWebsite' :
-                                           'extensionSettingsVisitWebStore');
-      });
-
-      var isUnpacked =
-          extension.location == chrome.developerPrivate.Location.UNPACKED;
-      // The 'Reload' link.
-      this.updateVisibility_(wrapper, '.reload-link', isActive && isUnpacked);
-
-      // The 'Launch' link.
-      this.updateVisibility_(
-          wrapper, '.launch-link',
-          isUnpacked && extension.type == ExtensionType.PLATFORM_APP &&
-              isActive);
-
-      // The 'Errors' link.
-      var hasErrors = extension.runtimeErrors.length > 0 ||
-          extension.manifestErrors.length > 0;
-      this.updateVisibility_(wrapper, '.errors-link', hasErrors,
-                             function(item) {
-        var Level = chrome.developerPrivate.ErrorLevel;
-
-        var map = {};
-        map[Level.LOG] = {weight: 0, name: 'extension-error-info-icon'};
-        map[Level.WARN] = {weight: 1, name: 'extension-error-warning-icon'};
-        map[Level.ERROR] = {weight: 2, name: 'extension-error-fatal-icon'};
-
-        // Find the highest severity of all the errors; manifest errors all have
-        // a 'warning' level severity.
-        var highestSeverity = extension.runtimeErrors.reduce(
-            function(prev, error) {
-          return map[error.severity].weight > map[prev].weight ?
-              error.severity : prev;
-        }, extension.manifestErrors.length ? Level.WARN : Level.LOG);
-
-        // Adjust the class on the icon.
-        var icon = item.querySelector('.extension-error-icon');
-        // TODO(hcarmona): Populate alt text with a proper description since
-        // this icon conveys the severity of the error. (info, warning, fatal).
-        icon.alt = '';
-        icon.className = 'extension-error-icon';  // Remove other classes.
-        icon.classList.add(map[highestSeverity].name);
-      });
-
-      // The 'Reload' terminated link.
-      var isTerminated =
-          extension.state == chrome.developerPrivate.ExtensionState.TERMINATED;
-      this.updateVisibility_(wrapper, '.terminated-reload-link', isTerminated);
-
-      // The 'Repair' corrupted link.
-      var canRepair = !isTerminated &&
-                      extension.disableReasons.corruptInstall &&
-                      extension.location ==
-                          chrome.developerPrivate.Location.FROM_STORE;
-      this.updateVisibility_(wrapper, '.corrupted-repair-button', canRepair);
-
-      // The 'Enabled' checkbox.
-      var isOK = !isTerminated && !canRepair;
-      this.updateVisibility_(wrapper, '.enable-checkbox', isOK, function(item) {
-        var enableCheckboxDisabled =
-            !extension.userMayModify ||
-            extension.disableReasons.suspiciousInstall ||
-            extension.disableReasons.corruptInstall ||
-            extension.disableReasons.updateRequired ||
-            extension.dependentExtensions.length > 0 ||
-            extension.state ==
-                chrome.developerPrivate.ExtensionState.BLACKLISTED;
-        item.querySelector('input').disabled = enableCheckboxDisabled;
-        item.querySelector('input').checked = isActive;
-      });
-
-      // Indicator for extensions controlled by policy.
-      var controlNode = wrapper.querySelector('.enable-controls');
-      var indicator =
-          controlNode.querySelector('.controlled-extension-indicator');
-      var needsIndicator = isOK && extension.controlledInfo;
-
-      if (needsIndicator && !indicator) {
-        indicator = new cr.ui.ControlledIndicator();
-        indicator.classList.add('controlled-extension-indicator');
-        var ControllerType = chrome.developerPrivate.ControllerType;
-        var controlledByStr = '';
-        switch (extension.controlledInfo.type) {
-          case ControllerType.POLICY:
-            controlledByStr = 'policy';
-            break;
-          case ControllerType.CHILD_CUSTODIAN:
-            controlledByStr = 'child-custodian';
-            break;
-          case ControllerType.SUPERVISED_USER_CUSTODIAN:
-            controlledByStr = 'supervised-user-custodian';
-            break;
-        }
-        indicator.setAttribute('controlled-by', controlledByStr);
-        var text = extension.controlledInfo.text;
-        indicator.setAttribute('text' + controlledByStr, text);
-        indicator.image.setAttribute('aria-label', text);
-        controlNode.appendChild(indicator);
-        wrapper.setupColumn('remove-enterprise', '[controlled-by] div');
-      } else if (!needsIndicator && indicator) {
-        controlNode.removeChild(indicator);
-      }
-
-      // Developer mode ////////////////////////////////////////////////////////
-
-      // First we have the id.
-      var idLabel = wrapper.querySelector('.extension-id');
-      idLabel.textContent = ' ' + extension.id;
-
-      // Then the path, if provided by unpacked extension.
-      this.updateVisibility_(wrapper, '.load-path', isUnpacked,
-                             function(item) {
-        item.querySelector('a:first-of-type').textContent =
-            ' ' + extension.prettifiedPath;
-      });
-
-      // Then the 'managed, cannot uninstall/disable' message.
-      // We would like to hide managed installed message since this
-      // extension is disabled.
-      var isRequired =
-          !extension.userMayModify || extension.mustRemainInstalled;
-      this.updateVisibility_(wrapper, '.managed-message', isRequired &&
-                             !extension.disableReasons.updateRequired);
-
-      // Then the 'This isn't from the webstore, looks suspicious' message.
-      var isSuspicious = extension.disableReasons.suspiciousInstall;
-      this.updateVisibility_(wrapper, '.suspicious-install-message',
-                             !isRequired && isSuspicious);
-
-      // Then the 'This is a corrupt extension' message.
-      this.updateVisibility_(wrapper, '.corrupt-install-message', !isRequired &&
-                             extension.disableReasons.corruptInstall);
-
-      // Then the 'An update required by enterprise policy' message. Note that
-      // a force-installed extension might be disabled due to being outdated
-      // as well.
-      this.updateVisibility_(wrapper, '.update-required-message',
-                             extension.disableReasons.updateRequired);
-
-      // The 'following extensions depend on this extension' list.
-      var hasDependents = extension.dependentExtensions.length > 0;
-      wrapper.classList.toggle('developer-extras', hasDependents);
-      this.updateVisibility_(wrapper, '.dependent-extensions-message',
-                             hasDependents, function(item) {
-        var dependentList = item.querySelector('ul');
-        dependentList.textContent = '';
-        extension.dependentExtensions.forEach(function(dependentExtension) {
-          var depNode = cloneTemplate('dependent-list-item');
-          depNode.querySelector('.dep-extension-title').textContent =
-              dependentExtension.name;
-          depNode.querySelector('.dep-extension-id').textContent =
-              dependentExtension.id;
-          dependentList.appendChild(depNode);
-        }, this);
-      }.bind(this));
-
-      // The active views.
-      this.updateVisibility_(wrapper, '.active-views',
-                             extension.views.length > 0, function(item) {
-        var link = item.querySelector('a');
-
-        // Link needs to be an only child before the list is updated.
-        while (link.nextElementSibling)
-          item.removeChild(link.nextElementSibling);
-
-        // Link needs to be cleaned up if it was used before.
-        link.textContent = '';
-        if (link.clickHandler)
-          link.removeEventListener('click', link.clickHandler);
-
-        extension.views.forEach(function(view, i) {
-          if (view.type == chrome.developerPrivate.ViewType.EXTENSION_DIALOG ||
-              view.type == chrome.developerPrivate.ViewType.EXTENSION_POPUP) {
-            return;
-          }
-          var displayName;
-          if (view.url.startsWith('chrome-extension://')) {
-            var pathOffset = 'chrome-extension://'.length + 32 + 1;
-            displayName = view.url.substring(pathOffset);
-            if (displayName == '_generated_background_page.html')
-              displayName = loadTimeData.getString('backgroundPage');
-          } else {
-            displayName = view.url;
-          }
-          var label = displayName +
-              (view.incognito ?
-                  ' ' + loadTimeData.getString('viewIncognito') : '') +
-              (view.renderProcessId == -1 ?
-                  ' ' + loadTimeData.getString('viewInactive') : '') +
-              (view.isIframe ?
-                  ' ' + loadTimeData.getString('viewIframe') : '');
-          link.textContent = label;
-          link.clickHandler = function(e) {
-            chrome.developerPrivate.openDevTools({
-              extensionId: extension.id,
-              renderProcessId: view.renderProcessId,
-              renderViewId: view.renderViewId,
-              incognito: view.incognito
-            });
-          };
-          link.addEventListener('click', link.clickHandler);
-
-          if (i < extension.views.length - 1) {
-            link = link.cloneNode(true);
-            item.appendChild(link);
-          }
-
-          wrapper.setupColumn('activeView', '.active-views a:last-of-type');
-        });
-      });
-
-      // The extension warnings (describing runtime issues).
-      this.updateVisibility_(wrapper, '.extension-warnings',
-                             extension.runtimeWarnings.length > 0,
-                             function(item) {
-        var warningList = item.querySelector('ul');
-        warningList.textContent = '';
-        extension.runtimeWarnings.forEach(function(warning) {
-          var li = document.createElement('li');
-          warningList.appendChild(li).innerText = warning;
-        });
-      });
-
-      // Install warnings.
-      this.updateVisibility_(wrapper, '.install-warnings',
-                             extension.installWarnings.length > 0,
-                             function(item) {
-        var installWarningList = item.querySelector('ul');
-        installWarningList.textContent = '';
-        if (extension.installWarnings) {
-          extension.installWarnings.forEach(function(warning) {
-            var li = document.createElement('li');
-            li.innerText = warning;
-            installWarningList.appendChild(li);
-          });
-        }
-      });
-
-      if (location.hash.substr(1) == extension.id) {
-        // Scroll beneath the fixed header so that the extension is not
-        // obscured.
-        var topScroll = wrapper.offsetTop - $('page-header').offsetHeight;
-        var pad = parseInt(window.getComputedStyle(wrapper).marginTop, 10);
-        if (!isNaN(pad))
-          topScroll -= pad / 2;
-        setScrollTopForDocument(document, topScroll);
-      }
-    },
-
-    /**
-     * Updates an element's textContent.
-     * @param {Node} node Ancestor of the element specified by |query|.
-     * @param {string} query A query to select an element in |node|.
-     * @param {string} textContent
-     * @private
-     */
-    setText_: function(node, query, textContent) {
-      node.querySelector(query).textContent = textContent;
-    },
-
-    /**
-     * Updates an element's visibility and calls |shownCallback| if it is
-     * visible.
-     * @param {Node} node Ancestor of the element specified by |query|.
-     * @param {string} query A query to select an element in |node|.
-     * @param {boolean} visible Whether the element should be visible or not.
-     * @param {function(Element)=} opt_shownCallback Callback if the element is
-     *     visible. The element passed in will be the element specified by
-     *     |query|.
-     * @private
-     */
-    updateVisibility_: function(node, query, visible, opt_shownCallback) {
-      var element = assertInstanceof(node.querySelector(query), Element);
-      element.hidden = !visible;
-      if (visible && opt_shownCallback)
-        opt_shownCallback(element);
-    },
-
-    /**
-     * Opens the extension options overlay for the extension with the given id.
-     * @param {string} extensionId The id of extension whose options page should
-     *     be displayed.
-     * @param {boolean} scroll Whether the page should scroll to the extension
-     * @private
-     */
-    showEmbeddedExtensionOptions_: function(extensionId, scroll) {
-      if (this.optionsShown_)
-        return;
-
-      // Get the extension from the given id.
-      var extension = this.extensions_.filter(function(extension) {
-        return extension.state ==
-                   chrome.developerPrivate.ExtensionState.ENABLED &&
-               extension.id == extensionId;
-      })[0];
-
-      if (!extension)
-        return;
-
-      if (scroll)
-        this.scrollToWrapper_(extensionId);
-
-      // Add the options query string. Corner case: the 'options' query string
-      // will clobber the 'id' query string if the options link is clicked when
-      // 'id' is in the URL, or if both query strings are in the URL.
-      window.history.replaceState({}, '', '/?options=' + extensionId);
-
-      var overlay = extensions.ExtensionOptionsOverlay.getInstance();
-      var shownCallback = function() {
-        // This overlay doesn't get focused automatically as <extensionoptions>
-        // is created after the overlay is shown.
-        if (cr.ui.FocusOutlineManager.forDocument(document).visible)
-          overlay.setInitialFocus();
-      };
-      overlay.setExtensionAndShow(extensionId, extension.name,
-                                  extension.iconUrl, shownCallback);
-      this.optionsShown_ = true;
-
-      var self = this;
-      $('overlay').addEventListener('cancelOverlay', function f() {
-        self.optionsShown_ = false;
-        $('overlay').removeEventListener('cancelOverlay', f);
-
-        // Remove the options query string.
-        window.history.replaceState({}, '', '/');
-      });
-
-      // TODO(dbeam): why do we need to focus <extensionoptions> before and
-      // after its showing animation? Makes very little sense to me.
-      overlay.setInitialFocus();
-    },
-
-    /**
-     * Hides the extension options overlay for the extension with id
-     * |extensionId|. If there is an overlay showing for a different extension,
-     * nothing happens.
-     * @param {string} extensionId ID of the extension to hide.
-     * @private
-     */
-    hideEmbeddedExtensionOptions_: function(extensionId) {
-      if (!this.optionsShown_)
-        return;
-
-      var overlay = extensions.ExtensionOptionsOverlay.getInstance();
-      if (overlay.getExtensionId() == extensionId)
-        overlay.close();
-    },
-
-    /**
-     * Updates or creates a wrapper for |extension|.
-     * @param {!chrome.developerPrivate.ExtensionInfo} extension The information
-     *     about the extension to update.
-     * @private
-     */
-    updateOrCreateWrapper_: function(extension) {
-      var currIndex = this.getIndexOfExtension_(extension.id);
-      if (currIndex != -1) {
-        // If there is a current version of the extension, update it with the
-        // new version.
-        this.extensions_[currIndex] = extension;
-      } else {
-        // If the extension isn't found, push it back and sort. Technically, we
-        // could optimize by inserting it at the right location, but since this
-        // only happens on extension install, it's not worth it.
-        this.extensions_.push(extension);
-        this.extensions_.sort(compareExtensions);
-      }
-
-      var wrapper = /**@type {ExtensionWrapper} */ ($(extension.id));
-      if (wrapper) {
-        this.updateWrapper_(extension, wrapper);
-      } else {
-        var nextExt = this.extensions_[this.extensions_.indexOf(extension) + 1];
-        this.createWrapper_(extension, nextExt ? $(nextExt.id) : null);
-      }
-    }
-  };
-
-  return {
-    ExtensionList: ExtensionList,
-    ExtensionListDelegate: ExtensionListDelegate
-  };
-});
diff --git a/chrome/browser/resources/extensions/extension_load_error.css b/chrome/browser/resources/extensions/extension_load_error.css
deleted file mode 100644
index 620eed10..0000000
--- a/chrome/browser/resources/extensions/extension_load_error.css
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright 2014 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-#extension-load-error {
-  -webkit-margin-end: 20px;
-  -webkit-padding-end: 3px;
-  -webkit-padding-start: 10px;
-  background-color: rgba(255, 249, 221, 1);
-  border-radius: 7px;
-  display: flex;
-  flex-direction: column;
-  font-size: 1.1em;
-  margin-top: 10px;
-  padding-bottom: 10px;
-}
-
-#extension-load-error h2 {
-  font-size: 14px;
-  font-weight: bold;
-}
-
-#extension-load-error-message {
-  margin-top: 5px;
-}
-
-#extension-load-error-manifest {
-  background-color: rgba(255, 250, 240, 1);
-  margin-bottom: 10px;
-  margin-top: 10px;
-  max-height: 100px;
-}
-
-#extension-load-error-manifest .extension-code-highlighted-source {
-  background-color: pink;
-}
-
-#extension-load-error-controls {
-  align-self: flex-end;
-}
-
-#extension-load-error-additional > span {
-  font-size: 12px;
-  font-weight: bold;
-}
-
-#extension-load-error-additional > li {
-  margin-bottom: 0;
-  margin-top: 3px;
-}
diff --git a/chrome/browser/resources/extensions/extension_load_error.html b/chrome/browser/resources/extensions/extension_load_error.html
deleted file mode 100644
index 8823bfb..0000000
--- a/chrome/browser/resources/extensions/extension_load_error.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!doctype html>
-<!--
-Copyright 2014 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be found
-in the LICENSE file.
--->
-<div id="extension-load-error" hidden>
-  <h2>$i18n{extensionLoadErrorHeading}</h2>
-  <div id="extension-load-error-message">
-    <span>$i18n{extensionLoadErrorMessage}</span>
-    <span id="extension-load-error-path"></span>
-  </div>
-  <span id="extension-load-error-reason"></span>
-  <div id="extension-load-error-manifest" class="extension-code"></div>
-  <div id="extension-load-error-controls">
-    <button id="extension-load-error-retry-button">
-      $i18n{extensionLoadErrorRetry}
-    </button>
-    <button id="extension-load-error-give-up-button">
-      $i18n{extensionLoadErrorGiveUp}
-    </button>
-  </div>
-  <div id="extension-load-error-additional" hidden>
-    <span>$i18n{extensionLoadAdditionalFailures}</span>
-    <ul></ul>
-  </div>
-</div>
diff --git a/chrome/browser/resources/extensions/extension_loader.js b/chrome/browser/resources/extensions/extension_loader.js
deleted file mode 100644
index 5c03d50..0000000
--- a/chrome/browser/resources/extensions/extension_loader.js
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('extensions', function() {
-  'use strict';
-
-  /**
-   * Construct an ExtensionLoadError around the given |div|.
-   * @param {HTMLDivElement} div The HTML div for the extension load error.
-   * @constructor
-   * @extends {HTMLDivElement}
-   */
-  function ExtensionLoadError(div) {
-    div.__proto__ = ExtensionLoadError.prototype;
-    /** @type {ExtensionLoadError} */ (div).init();
-    return div;
-  }
-
-  /**
-   * Construct a Failure.
-   * @param {string} filePath The path to the unpacked extension.
-   * @param {string} error The reason the extension failed to load.
-   * @param {ExtensionHighlight} manifest Three 'highlight' strings in
-   *     |manifest| represent three portions of the file's content to display -
-   *     the portion which is most relevant and should be emphasized
-   *     (highlight), and the parts both before and after this portion. These
-   *     may be empty.
-   * @param {HTMLLIElement} listElement The HTML element used for displaying the
-   *     failure path for the additional failures UI.
-   * @constructor
-   * @extends {HTMLDivElement}
-   */
-  function Failure(filePath, error, manifest, listElement) {
-    this.path = filePath;
-    this.error = error;
-    this.manifest = manifest;
-    this.listElement = listElement;
-  }
-
-  ExtensionLoadError.prototype = {
-    __proto__: HTMLDivElement.prototype,
-
-    /**
-     * Initialize the ExtensionLoadError div.
-     */
-    init: function() {
-      /**
-       * The element which displays the path of the extension.
-       * @type {HTMLElement}
-       * @private
-       */
-      this.path_ = /** @type {HTMLElement} */(
-          this.querySelector('#extension-load-error-path'));
-
-      /**
-       * The element which displays the reason the extension failed to load.
-       * @type {HTMLElement}
-       * @private
-       */
-      this.reason_ = /** @type {HTMLElement} */(
-          this.querySelector('#extension-load-error-reason'));
-
-      /**
-       * The element which displays the manifest code.
-       * @type {extensions.ExtensionCode}
-       * @private
-       */
-      this.manifest_ = new extensions.ExtensionCode(
-          this.querySelector('#extension-load-error-manifest'));
-
-      /**
-       * The element which displays information about additional errors.
-       * @type {HTMLElement}
-       * @private
-       */
-      this.additional_ = /** @type {HTMLUListElement} */(
-          this.querySelector('#extension-load-error-additional'));
-      this.additional_.list = this.additional_.getElementsByTagName('ul')[0];
-
-      /**
-       * An array of Failures for keeping track of multiple active failures.
-       * @type {Array<Failure>}
-       * @private
-       */
-      this.failures_ = [];
-
-      this.querySelector('#extension-load-error-retry-button').addEventListener(
-          'click', function(e) {
-        chrome.send('extensionLoaderRetry');
-        this.remove_();
-      }.bind(this));
-
-      this.querySelector('#extension-load-error-give-up-button').
-          addEventListener('click', function(e) {
-        chrome.send('extensionLoaderIgnoreFailure');
-        this.remove_();
-      }.bind(this));
-
-      chrome.send('extensionLoaderDisplayFailures');
-    },
-
-    /**
-     * Add a failure to failures_ array. If there is already a displayed
-     * failure, display the additional failures element.
-     * @param {Array<Object>} failures Array of failures containing paths,
-     *     errors, and manifests.
-     * @private
-     */
-    add_: function(failures) {
-      // If a failure is already being displayed, unhide the last item.
-      if (this.failures_.length > 0)
-        this.failures_[this.failures_.length - 1].listElement.hidden = false;
-      failures.forEach(function(failure) {
-        var listItem = /** @type {HTMLLIElement} */(
-            document.createElement('li'));
-        listItem.textContent = failure.path;
-        this.additional_.list.appendChild(listItem);
-        this.failures_.push(new Failure(failure.path,
-                                        failure.error,
-                                        failure.manifest,
-                                        listItem));
-      }.bind(this));
-      // Hide the last item because the UI is displaying its information.
-      this.failures_[this.failures_.length - 1].listElement.hidden = true;
-      this.show_();
-    },
-
-    /**
-     * Remove a failure from |failures_| array. If this was the last failure,
-     * hide the error UI.  If this was the last additional failure, hide
-     * the additional failures UI.
-     * @private
-     */
-    remove_: function() {
-      this.additional_.list.removeChild(
-          this.failures_[this.failures_.length - 1].listElement);
-      this.failures_.pop();
-      if (this.failures_.length > 0) {
-        this.failures_[this.failures_.length - 1].listElement.hidden = true;
-        this.show_();
-      } else {
-        this.hidden = true;
-      }
-    },
-
-    /**
-     * Display the load error to the user. The last failure gets its manifest
-     * and error displayed, while additional failures have their path names
-     * displayed in the additional failures element.
-     * @private
-     */
-    show_: function() {
-      assert(this.failures_.length >= 1);
-      var failure = this.failures_[this.failures_.length - 1];
-      this.path_.textContent = failure.path;
-      this.reason_.textContent = failure.error;
-
-      failure.manifest.message = failure.error;
-      this.manifest_.populate(
-          failure.manifest,
-          loadTimeData.getString('extensionLoadCouldNotLoadManifest'));
-      this.hidden = false;
-      this.manifest_.scrollToError();
-
-      this.additional_.hidden = this.failures_.length == 1;
-    }
-  };
-
-  /**
-   * The ExtensionLoader is the class in charge of loading unpacked extensions.
-   * @constructor
-   */
-  function ExtensionLoader() {
-    /**
-     * The ExtensionLoadError to show any errors from loading an unpacked
-     * extension.
-     * @type {ExtensionLoadError}
-     * @private
-     */
-    this.loadError_ = new ExtensionLoadError(
-        /** @type {HTMLDivElement} */($('extension-load-error')));
-  }
-
-  cr.addSingletonGetter(ExtensionLoader);
-
-  ExtensionLoader.prototype = {
-    /**
-     * Whether or not we are currently loading an unpacked extension.
-     * @private {boolean}
-     */
-    isLoading_: false,
-
-    /**
-     * Begin the sequence of loading an unpacked extension. If an error is
-     * encountered, this object will get notified via notifyFailed().
-     */
-    loadUnpacked: function() {
-      if (this.isLoading_)  // Only one running load at a time.
-        return;
-      this.isLoading_ = true;
-      chrome.developerPrivate.loadUnpacked({failQuietly: true}, function() {
-        // Check lastError to avoid the log, but don't do anything with it -
-        // error-handling is done on the C++ side.
-        var lastError = chrome.runtime.lastError;
-        this.isLoading_ = false;
-      }.bind(this));
-    },
-
-    /**
-     * Notify the ExtensionLoader that loading an unpacked extension failed.
-     * Add the failure to failures_ and show the ExtensionLoadError.
-     * @param {Array<Object>} failures Array of failures containing paths,
-     *     errors, and manifests.
-     */
-    notifyFailed: function(failures) {
-      this.loadError_.add_(failures);
-    },
-  };
-
-  /**
-   * A static forwarding function for ExtensionLoader.notifyFailed.
-   * @param {Array<Object>} failures Array of failures containing paths,
-   *     errors, and manifests.
-   * @see ExtensionLoader.notifyFailed
-   */
-  ExtensionLoader.notifyLoadFailed = function(failures) {
-    ExtensionLoader.getInstance().notifyFailed(failures);
-  };
-
-  return {
-    ExtensionLoader: ExtensionLoader
-  };
-});
diff --git a/chrome/browser/resources/extensions/extension_options_overlay.css b/chrome/browser/resources/extensions/extension_options_overlay.css
deleted file mode 100644
index 5492611..0000000
--- a/chrome/browser/resources/extensions/extension_options_overlay.css
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Copyright 2014 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-#extension-options-overlay {
-  overflow: hidden;
-}
-
-#extension-options-overlay-header {
-  align-items: center;
-  border-bottom: solid lightgray 1px;
-  display: flex;
-  position: relative;
-}
-
-#extension-options-overlay-icon {
-  padding: 8px;
-}
-
-#extension-options-overlay-icon {
-  height: 32px;
-  width: 32px;
-}
-
-#extension-options-overlay-title {
-  /* Cancel left padding to line up with the icon. */
-  padding-left: 0;
-}
diff --git a/chrome/browser/resources/extensions/extension_options_overlay.html b/chrome/browser/resources/extensions/extension_options_overlay.html
deleted file mode 100644
index e5ee0b9..0000000
--- a/chrome/browser/resources/extensions/extension_options_overlay.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!--
-Copyright 2014 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be found
-in the LICENSE file.
--->
-<div id="extension-options-overlay" class="page">
-  <div class="close-button"></div>
-  <div id="extension-options-overlay-header">
-    <img id="extension-options-overlay-icon" aria-hidden="true">
-    <h1 id="extension-options-overlay-title"></h1>
-  </div>
-  <div id="extension-options-overlay-guest"></div>
-</div>
diff --git a/chrome/browser/resources/extensions/extension_options_overlay.js b/chrome/browser/resources/extensions/extension_options_overlay.js
deleted file mode 100644
index 73aac3e..0000000
--- a/chrome/browser/resources/extensions/extension_options_overlay.js
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Returns the width of a scrollbar in logical pixels.
-function getScrollbarWidth() {
-  // Create nested divs with scrollbars.
-  var outer = document.createElement('div');
-  outer.style.width = '100px';
-  outer.style.overflow = 'scroll';
-  outer.style.visibility = 'hidden';
-  document.body.appendChild(outer);
-  var inner = document.createElement('div');
-  inner.style.width = '101px';
-  outer.appendChild(inner);
-
-  // The outer div's |clientWidth| and |offsetWidth| differ only by the width of
-  // the vertical scrollbar.
-  var scrollbarWidth = outer.offsetWidth - outer.clientWidth;
-  outer.parentNode.removeChild(outer);
-  return scrollbarWidth;
-}
-
-cr.define('extensions', function() {
-  'use strict';
-
-  /**
-   * The ExtensionOptionsOverlay will show an extension's options page using
-   * an <extensionoptions> element.
-   * @constructor
-   */
-  function ExtensionOptionsOverlay() {}
-
-  cr.addSingletonGetter(ExtensionOptionsOverlay);
-
-  ExtensionOptionsOverlay.prototype = {
-    /**
-     * The function that shows the given element in the overlay.
-     * @type {?function(HTMLDivElement)} Function that receives the element to
-     *     show in the overlay.
-     * @private
-     */
-    showOverlay_: null,
-
-    /**
-     * The id of the extension that this options page display.
-     * @type {string}
-     * @private
-     */
-    extensionId_: '',
-
-    /**
-     * Initialize the page.
-     * @param {function(HTMLDivElement)} showOverlay The function to show or
-     *     hide the ExtensionOptionsOverlay; this should take a single parameter
-     *     which is either the overlay Div if the overlay should be displayed,
-     *     or null if the overlay should be hidden.
-     */
-    initializePage: function(showOverlay) {
-      var overlay = $('overlay');
-
-      cr.ui.overlay.setupOverlay(overlay);
-      cr.ui.overlay.globalInitialization();
-      overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
-
-      this.showOverlay_ = showOverlay;
-    },
-
-    setInitialFocus: function() {
-      this.getExtensionOptions_().focus();
-    },
-
-    /**
-     * @return {?Element}
-     * @private
-     */
-    getExtensionOptions_: function() {
-      return $('extension-options-overlay-guest').querySelector(
-          'extensionoptions');
-    },
-
-    /**
-     * Handles a click on the close button.
-     * @param {Event} event The click event.
-     * @private
-     */
-    handleDismiss_: function(event) {
-      this.setVisible_(false);
-      var extensionoptions = this.getExtensionOptions_();
-      if (extensionoptions)
-        $('extension-options-overlay-guest').removeChild(extensionoptions);
-
-      $('extension-options-overlay-icon').removeAttribute('src');
-    },
-
-    /**
-     * Associate an extension with the overlay and display it.
-     * @param {string} extensionId The id of the extension whose options page
-     *     should be displayed in the overlay.
-     * @param {string} extensionName The name of the extension, which is used
-     *     as the header of the overlay.
-     * @param {string} extensionIcon The URL of the extension's icon.
-     * @param {function():void} shownCallback A function called when
-     *     showing completes.
-     * @suppress {checkTypes}
-     * TODO(vitalyp): remove the suppression after adding
-     * chrome/renderer/resources/extensions/extension_options.js
-     * to dependencies.
-     */
-    setExtensionAndShow: function(extensionId,
-                                  extensionName,
-                                  extensionIcon,
-                                  shownCallback) {
-      var overlay = $('extension-options-overlay');
-      var overlayHeader = $('extension-options-overlay-header');
-      var overlayGuest = $('extension-options-overlay-guest');
-      var overlayStyle = window.getComputedStyle(overlay);
-
-      $('extension-options-overlay-title').textContent = extensionName;
-      $('extension-options-overlay-icon').src = extensionIcon;
-
-      this.setVisible_(true);
-
-      var extensionoptions = new window.ExtensionOptions();
-      extensionoptions.extension = extensionId;
-      this.extensionId_ = extensionId;
-
-      // The <extensionoptions> content's size needs to be restricted to the
-      // bounds of the overlay window. The overlay gives a minWidth and
-      // maxHeight, but the maxHeight does not include our header height (title
-      // and close button), so we need to subtract that to get the maxHeight
-      // for the extension options.
-      var maxHeight = parseInt(overlayStyle.maxHeight, 10) -
-                      overlayHeader.offsetHeight;
-      var minWidth = parseInt(overlayStyle.minWidth, 10);
-
-      extensionoptions.onclose = function() {
-        cr.dispatchSimpleEvent($('overlay'), 'cancelOverlay');
-      }.bind(this);
-
-      // Track the current animation (used to grow/shrink the overlay content),
-      // if any. Preferred size changes can fire more rapidly than the
-      // animation speed, and multiple animations running at the same time has
-      // undesirable effects.
-      var animation = null;
-
-      /**
-       * Resize the overlay if the <extensionoptions> changes preferred size.
-       * @param {{width: number, height: number}} evt
-       */
-      extensionoptions.onpreferredsizechanged = function(evt) {
-        var oldOverlayWidth = parseInt(overlayStyle.width, 10);
-        var oldOverlayHeight = parseInt(overlayStyle.height, 10);
-        var newOverlayWidth = evt.width;
-        // |evt.height| is just the new overlay guest height, and does not
-        // include the overlay header height, so it needs to be added.
-        var newOverlayHeight = evt.height + overlayHeader.offsetHeight;
-
-        // Make room for the vertical scrollbar, if there is one.
-        if (newOverlayHeight > maxHeight) {
-          newOverlayWidth += getScrollbarWidth();
-        }
-
-        // Enforce |minWidth| and |maxHeight|.
-        newOverlayWidth = Math.max(newOverlayWidth, minWidth);
-        newOverlayHeight = Math.min(newOverlayHeight, maxHeight);
-
-        // animationTime is the amount of time in ms that will be used to resize
-        // the overlay. It is calculated by multiplying the pythagorean distance
-        // between old and the new size (in px) with a constant speed of
-        // 0.25 ms/px.
-        var loading = document.documentElement.classList.contains('loading');
-        var animationTime = loading ? 0 :
-            0.25 * Math.sqrt(Math.pow(newOverlayWidth - oldOverlayWidth, 2) +
-                             Math.pow(newOverlayHeight - oldOverlayHeight, 2));
-
-        if (animation)
-          animation.cancel();
-
-        // The header height must be added to the (old and new) preferred
-        // heights to get the full overlay heights.
-        animation = overlay.animate([
-          {width: oldOverlayWidth + 'px', height: oldOverlayHeight + 'px'},
-          {width: newOverlayWidth + 'px', height: newOverlayHeight + 'px'}
-        ], {
-          duration: animationTime,
-          delay: 0
-        });
-
-        animation.onfinish = function(e) {
-          animation = null;
-
-          // The <extensionoptions> element is ready to place back in the
-          // overlay. Make sure that it's sized to take up the full width/height
-          // of the overlay.
-          overlayGuest.style.position = '';
-          overlayGuest.style.left = '';
-          overlayGuest.style.width = newOverlayWidth + 'px';
-          // |newOverlayHeight| includes the header height, so it needs to be
-          // subtracted to get the new guest height.
-          overlayGuest.style.height =
-              (newOverlayHeight - overlayHeader.offsetHeight) + 'px';
-
-          if (shownCallback) {
-            shownCallback();
-            shownCallback = null;
-          }
-        };
-      }.bind(this);
-
-      // Move the <extensionoptions> off screen until the overlay is ready.
-      overlayGuest.style.position = 'fixed';
-      overlayGuest.style.left = window.outerWidth + 'px';
-      // Begin rendering at the default dimensions. This is also necessary to
-      // cancel any width/height set on a previous render.
-      // TODO(kalman): This causes a visual jag where the overlay guest shows
-      // up briefly. It would be better to render this off-screen first, then
-      // swap it in place. See crbug.com/408274.
-      // This may also solve crbug.com/431001 (width is 0 on initial render).
-      overlayGuest.style.width = '';
-      overlayGuest.style.height = '';
-
-      overlayGuest.appendChild(extensionoptions);
-    },
-
-    /**
-     * Dispatches a 'cancelOverlay' event on the $('overlay') element.
-     */
-    close: function() {
-      cr.dispatchSimpleEvent($('overlay'), 'cancelOverlay');
-    },
-
-    /**
-     * Returns extension id that this options page set.
-     * @return {string}
-     */
-    getExtensionId: function() {
-      return this.extensionId_;
-    },
-
-    /**
-     * Toggles the visibility of the ExtensionOptionsOverlay.
-     * @param {boolean} isVisible Whether the overlay should be visible.
-     * @private
-     */
-    setVisible_: function(isVisible) {
-      this.showOverlay_(isVisible ?
-          /** @type {HTMLDivElement} */($('extension-options-overlay')) :
-          null);
-    }
-  };
-
-  // Export
-  return {
-    ExtensionOptionsOverlay: ExtensionOptionsOverlay
-  };
-});
diff --git a/chrome/browser/resources/extensions/extensions.css b/chrome/browser/resources/extensions/extensions.css
deleted file mode 100644
index fd9e4699..0000000
--- a/chrome/browser/resources/extensions/extensions.css
+++ /dev/null
@@ -1,443 +0,0 @@
-/* Copyright (c) 2012 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. */
-
-html.loading * {
-  transition-duration: 0ms !important;
-}
-
-html:not(.focus-outline-visible)
-:enabled:focus:-webkit-any(input[type='checkbox'], input[type='radio']) {
-  /* Cancel border-color for :focus specified in widgets.css. */
-  border-color: rgba(0, 0, 0, 0.25);
-}
-
-.no-scroll {
-  overflow-y: hidden;
-}
-
-#extension-settings.showing-banner {
-  margin-top: 45px;
-}
-
-/* Developer mode */
-
-#dev-controls {
-  -webkit-margin-end: 0;
-  height: 0;
-  overflow: hidden;
-}
-
-#dev-controls.animated {
-  transition: height 150ms;
-}
-
-.dev-mode #dev-controls {
-  border-bottom: 1px solid #eee;
-}
-
-#dev-controls > * {
-  padding: 8px 3px;
-}
-
-#dev-controls .button-container {
-  -webkit-padding-end: 12px;
-  -webkit-padding-start: 12px;
-  display: flex;
-  flex-wrap: wrap;
-}
-
-#dev-controls button {
-  white-space: nowrap;
-}
-
-#dev-controls .button-container button:not(:last-of-type) {
-  -webkit-margin-end: 5px;
-}
-
-#dev-controls-spacer {
-  flex: 1;
-}
-
-.extension-code {
-  border: 1px solid #ccc;
-  display: flex;
-  font-family: monospace;
-  overflow: auto;
-  white-space: pre;
-}
-
-.extension-code > * {
-  padding: 3px;
-}
-
-.extension-code-line-numbers {
-  align-self: flex-start;
-  background-color: rgba(240, 240, 240, 1);
-  border-right: 1px solid #ccc;
-  color: rgba(128, 128, 128, 1);
-  flex-shrink: 0;
-  text-align: right;
-}
-
-.extension-code-empty {
-  background-color: #eee;
-  display: inline-block;
-  line-height: 100px;  /* Vertically centers text and serves as min-height. */
-  text-align: center;
-  width: 100%;
-}
-
-.extension-details > .developer-extras > div,
-.extension-details > .permanent-warnings > div {
-  margin: 5px 0;
-}
-
-.dependent-extensions-message,
-.suspicious-install-message {
-  line-height: 150%;
-}
-
-#page-header {
-  -webkit-padding-start: 23px;
-  left: 0;
-}
-
-[dir='rtl'] #page-header {
-  right: 0;
-}
-
-#page-header > .page-banner > .page-banner-gradient {
-  -webkit-margin-end: 0;
-}
-
-#header-controls {
-  /* Reserve enough space to match .location-text + .trash */
-  min-width: 130px;
-  right: 16px;
-}
-
-html[dir='rtl'] #header-controls {
-  left: 16px;
-  right: auto;
-}
-
-#page-header > h1::after {
-  -webkit-margin-end: 0;
-}
-
-#extension-settings #page-header {
-  /* These values match the .page values. */
-  -webkit-margin-end: 24px;
-  min-width: 576px;
-}
-
-/* Contents */
-
-#extension-settings {
-  max-width: 738px;
-}
-
-#no-extensions-message {
-  font-weight: bold;
-}
-
-#no-extensions {
-  margin-top: 3em;
-}
-
-#suggest-gallery {
-  -webkit-padding-start: 10px;
-}
-
-#footer-section {
-  background: url(chrome://theme/IDR_WEBSTORE_ICON_32) no-repeat left center;
-  background-size: 32px 32px;
-  font-size: 1.25em;
-  margin: 24px 12px 12px 12px;
-}
-
-html[dir=rtl] #footer-section {
-  background: url(chrome://theme/IDR_WEBSTORE_ICON_32) no-repeat right center;
-}
-
-#footer-section > a {
-  -webkit-margin-start: 42px;
-  line-height: 32px;
-}
-
-.extension-list-item-wrapper {
-  margin: 12px 0;
-  padding: 12px;
-}
-
-.extension-list-item {
-  background-repeat: no-repeat;
-  background-size: 48px 48px;
-  display: -webkit-box;
-  min-height: 48px;
-}
-
-.extension-list-item a {
-  -webkit-margin-start: 0.5em;
-  display: inline-block;
-}
-
-html[dir='rtl'] .extension-list-item {
-  background-position-x: 100%;
-}
-
-.extension-title {
-  -webkit-padding-end: 20px;
-  color: rgb(48, 57, 66);
-  display: inline;
-  font-size: 14px;
-  font-weight: 500;
-  user-select: text;
-}
-
-.inactive-extension .extension-title {
-  color: inherit;
-}
-
-.extension-version {
-  -webkit-padding-end: 7px;
-  font-size: 13px;
-  font-weight: 400;
-}
-
-.extension-description,
-.corrupt-install-message {
-  -webkit-padding-end: 5px;
-  font-size: 13px;
-  margin: 5px 0;
-  white-space: normal;
-}
-
-.corrupt-install-message {
-  color: rgb(196, 42, 23);
-}
-
-.action-links {
-  margin-bottom: 0.5em;
-}
-
-.action-links a {
-  -webkit-margin-end: 1em;
-  -webkit-margin-start: 0;
-}
-
-.action-links .errors-link {
-  align-items: center;
-  display: inline-flex;
-  vertical-align: bottom;
-}
-
-.extension-details {
-  -webkit-box-flex: 1;
-  -webkit-padding-end: 7px;
-  -webkit-padding-start: 60px;
-  padding-top: 6px;
-}
-
-.extension-description,
-.extension-version,
-.extension-list-item-wrapper.inactive-extension .extension-details,
-.location-text,
-.blacklist-text,
-.enable-checkbox input:disabled + .enable-checkbox-text {
-  color: rgb(115, 119, 122);
-}
-
-.enable-controls {
-  /* Matches right: position of dev controls toggle. */
-  -webkit-margin-end: 0;
-  position: relative;
-}
-
-.enable-controls > .controlled-setting-indicator {
-  width: 23px;
-}
-
-.enable-controls > .controlled-setting-indicator > div {
-  left: 11px;
-  right: 11px;
-}
-
-/* We use x[is='action-link'] here so that we get higher specifity than the
- * action link rules without resorting to the Dark Side (!IMPORTANT). */
-.terminated-reload-link[is='action-link'],
-.corrupted-repair-button[is='action-link'] {
-  /* Matches width of trash. */
-  -webkit-margin-end: 30px;
-}
-
-.checkbox {
-  display: inline-block;
-}
-
-.enabled-text {
-  font-weight: bold;
-}
-
-.extension-list-item-wrapper.inactive-extension .enabled-text,
-.extension-list-item-wrapper:not(.inactive-extension) .enable-text,
-.extension-list-item-wrapper.inactive-extension .optional-controls,
-.extension-list-item-wrapper.inactive-extension .butter-bar {
-  display: none;
-}
-
-.optional-controls .checkbox {
-  -webkit-margin-end: 12px;
-}
-
-.load-path > span {
-  word-wrap: break-word;
-}
-
-.terminated-reload-link,
-.corrupted-repair-button {
-  display: inline-block;
-  padding-top: 7px;
-}
-
-.install-warnings a {
-  -webkit-margin-start: 0;
-}
-
-.butter-bar,
-.install-warnings,
-.extension-warnings {
-  border-radius: 3px;
-  line-height: 150%;
-  margin: 8px 0;
-  padding: 8px 12px;
-}
-
-.butter-bar {
-  background: rgb(255, 242, 153);
-}
-
-.install-warnings,
-.extension-warnings {
-  background: pink;
-}
-
-.install-warnings ul,
-.extension-warnings ul {
-  margin: 0;
-}
-
-.error-collection-control {
-  -webkit-margin-start: 5px;
-}
-
-#extension-settings:not(.dev-mode) .developer-extras,
-#extension-settings:not(.dev-mode) .error-collection-control {
-  display: none;
-}
-
-#font-measuring-div {
-  /* Remove from the flow and hide. */
-  position: absolute;
-  visibility: hidden;
-}
-
-.extension-commands-config {
-  float: right;
-}
-
-html[dir=rtl] .extension-commands-config {
-  float: left;
-}
-
-/* Overlays */
-
-#overlay {
-  z-index: 5;
-}
-
-#overlay .page:not(.showing) {
-  display: none;
-}
-
-#drop-target-overlay {
-  color: rgb(48, 57, 66);
-  font-size: 18px;
-  text-align: center;
-}
-
-#drop-target-overlay div {
-  margin: 1em;
-}
-
-.location-text,
-.blacklist-text {
-  display: block;
-  width: 100px;
-}
-
-.enable-checkbox {
-  /* Reserve enough space to match .location-text */
-  min-width: 100px;
-}
-
-/* Trash */
-
-#extension-settings .trash {
-  height: 22px;
-  opacity: 0.8;
-  position: relative;
-  right: -8px;
-  top: 6px;
-  transition: opacity 200ms;
-  vertical-align: top;
-}
-
-html[dir='rtl'] #extension-settings .trash {
-  left: -8px;
-  right: auto;
-}
-
-.extension-list-item:not(:hover) .trash:not(:focus) {
-  opacity: 0;
-}
-
-.extension-list-item-wrapper.may-not-remove .trash {
-  visibility: hidden;
-}
-
-/* In case the extension is policy controlled the trash icon must be hidden by
- * setting display:none rather than only setting visibility:hidden to completely
- * remove it from the layout and make space for the controlled indicator.
- * TODO(cschuet): rather than hide always replace it with something meaningful.
- */
-.extension-list-item-wrapper.controlled .trash {
-  display: none;
-}
-
-/* Supervised users */
-
-.page:not(.profile-is-supervised) .profile-is-supervised-banner,
-.profile-is-supervised .more-extensions-link {
-  display: none;
-}
-
-.profile-is-supervised-banner .page-banner-text {
-  background-image: url(../../../../ui/webui/resources/images/warning.svg);
-}
-
-/* Sideload Wipeout */
-
-.sideload-wipeout-learn-more {
-  text-decoration: none;
-}
-
-.sideload-wipeout-banner .page-banner-text {
-  -webkit-padding-start: 8px;
-  background-image: none;
-}
-
-.extension-highlight {
-  background-color: rgba(0, 0, 0, .05);
-}
diff --git a/chrome/browser/resources/extensions/extensions.html b/chrome/browser/resources/extensions/extensions.html
deleted file mode 100644
index 40d6ce3..0000000
--- a/chrome/browser/resources/extensions/extensions.html
+++ /dev/null
@@ -1,283 +0,0 @@
-<!doctype html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}">
-<head>
-<meta charset="utf-8">
-<title>$i18n{extensionSettings}</title>
-
-<link rel="stylesheet" href="extensions.css">
-<link rel="stylesheet" href="extension_commands_overlay.css">
-<link rel="stylesheet" href="extension_error.css">
-<link rel="stylesheet" href="extension_error_overlay.css">
-<link rel="stylesheet" href="extension_load_error.css">
-<link rel="stylesheet" href="extension_options_overlay.css">
-<link rel="stylesheet" href="pack_extension_overlay.css">
-<link rel="stylesheet" href="chrome://resources/css/alert_overlay.css">
-<link rel="stylesheet" href="chrome://resources/css/bubble.css">
-<link rel="stylesheet" href="chrome://resources/css/bubble_button.css">
-<link rel="stylesheet" href="chrome://resources/css/controlled_indicator.css">
-<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
-<link rel="stylesheet" href="chrome://resources/css/overlay.css">
-<link rel="stylesheet" href="chrome://resources/css/spinner.css">
-<link rel="stylesheet" href="chrome://resources/css/trash.css">
-<link rel="stylesheet" href="../uber_shared.css">
-
-<script src="chrome://resources/js/action_link.js"></script>
-<script src="chrome://resources/js/cr.js"></script>
-<script src="chrome://resources/js/event_tracker.js"></script>
-<script src="chrome://resources/js/load_time_data.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script src="chrome://resources/js/cr/ui.js"></script>
-<script src="chrome://resources/js/cr/ui/alert_overlay.js"></script>
-<script src="chrome://resources/js/cr/ui/bubble.js"></script>
-<script src="chrome://resources/js/cr/ui/bubble_button.js"></script>
-<script src="chrome://resources/js/cr/ui/controlled_indicator.js"></script>
-<script src="chrome://resources/js/cr/ui/drag_wrapper.js"></script>
-<script src="chrome://resources/js/cr/ui/focus_manager.js"></script>
-<script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
-<script src="chrome://resources/js/cr/ui/node_utils.js"></script>
-<script src="chrome://resources/js/cr/ui/overlay.js"></script>
-
-<if expr="chromeos">
-<link rel="stylesheet" href="chrome://resources/css/list.css">
-<link rel="stylesheet" href="chromeos/kiosk_apps.css">
-<script src="chrome://resources/js/cr/event_target.js"></script>
-<script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
-<script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
-<script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
-<script src="chrome://resources/js/cr/ui/list_single_selection_model.js">
-</script>
-<script src="chrome://resources/js/cr/ui/list_item.js"></script>
-<script src="chrome://resources/js/cr/ui/list.js"></script>
-<script src="chrome://resources/js/promise_resolver.js"></script>
-<script src="chrome://resources/js/webui_listener_tracker.js"></script>
-</if>
-
-<script src="chrome://extensions/extensions.js"></script>
-</head>
-
-<body>
-
-<div id="overlay" class="overlay" hidden>
-  <include src="extension_commands_overlay.html">
-  <include src="extension_error_overlay.html">
-  <include src="extension_options_overlay.html">
-  <include src="pack_extension_overlay.html">
-  <include src="../../../../ui/webui/resources/html/alert_overlay.html">
-<if expr="chromeos">
-    <include src="chromeos/kiosk_apps.html">
-    <include src="chromeos/kiosk_app_disable_bailout_confirm.html">
-</if>
-  <div id="drop-target-overlay" class="page">
-    <div>$i18n{extensionSettingsInstallDropTarget}</div>
-  </div>
-</div>
-
-<div class="page" id="extension-settings">
-  <header id="page-header">
-    <h1>$i18n{extensionSettings}</h1>
-    <div id="header-controls" class="header-extras">
-      <div id="dev-toggle" class="checkbox">
-        <label>
-          <input id="toggle-dev-on" type="checkbox">
-          <span>$i18n{extensionSettingsDeveloperMode}</span>
-          <span id="dev-toggle-disabled-by-policy-indicator"
-              class="controlled-setting-indicator"></span>
-        </label>
-      </div>
-    </div>
-    <div class="page-banner profile-is-supervised-banner">
-      <div class="page-banner-gradient">
-        <span class="page-banner-text">
-          $i18n{extensionSettingsSupervisedUser}
-        </span>
-      </div>
-    </div>
-  </header>
-  <div id="loading-spinner">
-    <div class="inline-spinner"></div>
-    <span>$i18n{loading}</span>
-  </div>
-  <div id="dev-controls" hidden>
-    <div class="button-container">
-      <button id="load-unpacked">
-        $i18n{extensionSettingsLoadUnpackedButton}
-      </button>
-      <button id="pack-extension">
-        $i18n{extensionSettingsPackButton}
-      </button>
-<if expr="chromeos">
-      <button id="add-kiosk-app" hidden>$i18n{addKioskAppButton}</button>
-</if>
-      <div id="dev-controls-spacer"></div>
-      <button id="update-extensions-now">
-        $i18n{extensionSettingsUpdateButton}
-      </button>
-    </div>
-  </div>
-  <include src="extension_load_error.html">
-  <div id="extension-list-wrapper" hidden>
-    <div id="footer-section">
-      <a target="_blank" class="more-extensions-link"
-          i18n-values="href:extensionSettingsGetMoreExtensionsUrl">
-        $i18n{extensionSettingsGetMoreExtensions}
-      </a>
-      <a is="action-link" class="extension-commands-config" hidden>
-        $i18n{extensionSettingsCommandsLink}
-      </a>
-    </div>
-  </div>
-  <div id="no-extensions" hidden>
-    <span id="no-extensions-message">$i18n{extensionSettingsNoExtensions}</span>
-    <span id="suggest-gallery" class="more-extensions-link"
-        i18n-values=".innerHTML:extensionSettingsSuggestGallery">
-    </span>
-  </div>
-</div>
-
-<span id="font-measuring-div"></span>
-
-<div id="templates" hidden>
-
-  <div class="extension-list-item-wrapper">
-    <div class="extension-list-item">
-      <div class="extension-details">
-        <div>
-          <h2 class="extension-title"></h2>
-          <span class="extension-version"></span>
-        </div>
-        <p class="corrupt-install-message"
-           hidden>$i18n{extensionSettingsCorruptInstall}</p>
-        <p class="extension-description"></p>
-        <div class="action-links">
-          <a is="action-link" class="permissions-link">
-            $i18n{extensionSettingsPermissions}
-          </a>
-          <a is="action-link" class="options-button" hidden>
-            $i18n{extensionSettingsOptions}
-          </a>
-          <a class="options-link" hidden>$i18n{extensionSettingsOptions}</a>
-          <a class="site-link" target="_parent" hidden></a>
-          <a is="action-link" class="launch-link" hidden>
-            $i18n{extensionSettingsLaunch}
-          </a>
-          <a is="action-link" role="button" class="reload-link" hidden>
-            $i18n{extensionSettingsReloadUnpacked}
-          </a>
-          <a is="action-link" role="button" class="errors-link">
-            <img class="extension-error-icon">
-            <span>$i18n{extensionErrorHeading}</span>
-          </a>
-        </div>
-        <div class="permanent-warnings">
-          <div class="extension-warnings" hidden>
-            <span>$i18n{extensionSettingsWarningsTitle}</span>
-            <ul></ul>
-          </div>
-          <div class="suspicious-install-message" hidden>
-            <span>$i18n{extensionSettingsSuspiciousInstall}</span>
-            <a target="_blank" class="learn-more-link" href="#"
-                i18n-values="href:extensionSettingsSuspiciousInstallHelpUrl">
-              $i18n{extensionSettingsLearnMore}
-            </a>
-          </div>
-        </div>
-        <div class="dependent-extensions-message" hidden>
-          <span>$i18n{extensionSettingsDependentExtensions}</span>
-          <ul></ul>
-        </div>
-        <div class="developer-extras">
-          <div>
-            <span>$i18n{extensionSettingsExtensionId}</span>
-            <span class="extension-id"></span>
-          </div>
-          <div class="load-path" hidden>
-            <span>$i18n{extensionSettingsExtensionPath}</span>
-            <a is="action-link"></a>
-          </div>
-          <div class="managed-message" hidden>
-            $i18n{extensionSettingsPolicyControlled}
-          </div>
-          <div class="update-required-message" hidden>
-            $i18n{extensionSettingsUpdateRequiredBePolicy}
-          </div>
-          <div class="active-views" hidden>
-            <span>$i18n{extensionSettingsInspectViews}</span>
-            <a is="action-link"></a>
-          </div>
-          <div class="install-warnings" hidden>
-            <span>$i18n{extensionSettingsInstallWarnings}</span>
-            <ul></ul>
-          </div>
-        </div>
-        <div class="optional-controls">
-          <div class="checkbox">
-            <label class="incognito-control">
-              <input type="checkbox">
-              <span>$i18n{extensionSettingsEnableIncognito}</span>
-            </label>
-          </div>
-          <div class="checkbox error-collection-control" hidden>
-            <label>
-              <input type="checkbox">
-              <span>$i18n{extensionSettingsEnableErrorCollection}</span>
-            </label>
-          </div>
-          <div class="checkbox all-urls-control" hidden>
-            <label>
-              <input type="checkbox">
-              <span>$i18n{extensionSettingsAllowOnAllUrls}</span>
-            </label>
-          </div>
-          <div class="checkbox file-access-control" hidden>
-            <label>
-              <input type="checkbox">
-              <span>$i18n{extensionSettingsAllowFileAccess}</span>
-            </label>
-          </div>
-        </div>
-        <div class="butter-bar"
-            i18n-values=".innerHTML:extensionSettingsIncognitoWarning" hidden>
-        </div>
-      </div>
-      <div class="enable-controls">
-        <a is="action-link" role="button" class="terminated-reload-link" hidden>
-          $i18n{extensionSettingsReloadTerminated}
-        </a>
-        <a is="action-link" role="button" class="corrupted-repair-button"
-            hidden>
-          $i18n{extensionSettingsRepairCorrupted}
-        </a>
-        <div class="checkbox enable-checkbox" hidden><label>
-          <input type="checkbox">
-          <span class="enable-checkbox-text">
-            <span class="enabled-text">$i18n{extensionSettingsEnabled}</span>
-            <span class="enable-text">$i18n{extensionSettingsEnable}</span>
-          </span>
-        </label>
-        <span class="location-text"></span>
-        <span class="blacklist-text"></span>
-        </div>
-      </div>
-    </div>
-  </div>
-  <li class="dependent-list-item">
-    <span class="dep-extension-title"></span>
-    <ul>
-      <li>
-        <span>$i18n{extensionSettingsExtensionId}</span>
-        <span class="dep-extension-id"></span>
-      </li>
-    </ul>
-  </li>
-
-
-  <include src="../../../../ui/webui/resources/html/trash.html">
-  <include src="extension_error.html">
-
-</div>
-
-<script src="chrome://extensions/strings.js"></script>
-<script src="chrome://resources/js/i18n_template.js"></script>
-
-</body>
-</html>
diff --git a/chrome/browser/resources/extensions/extensions.js b/chrome/browser/resources/extensions/extensions.js
deleted file mode 100644
index b3be062..0000000
--- a/chrome/browser/resources/extensions/extensions.js
+++ /dev/null
@@ -1,461 +0,0 @@
-// Copyright (c) 2012 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 src="../../../../ui/webui/resources/js/cr/ui/focus_row.js">
-// <include src="../../../../ui/webui/resources/js/cr/ui/focus_grid.js">
-// <include src="../md_extensions/drag_and_drop_handler.js">
-// <include src="extension_code.js">
-// <include src="extension_commands_overlay.js">
-// <include src="extension_error_overlay.js">
-// <include src="extension_focus_manager.js">
-// <include src="focus_row.js">
-// <include src="extension_list.js">
-// <include src="pack_extension_overlay.js">
-// <include src="extension_loader.js">
-// <include src="extension_options_overlay.js">
-
-// <if expr="chromeos">
-// <include src="chromeos/kiosk_apps.js">
-// </if>
-
-cr.define('extensions', function() {
-  var ExtensionList = extensions.ExtensionList;
-
-  /**
-   * ExtensionSettings class
-   * @class
-   * @constructor
-   * @implements {extensions.ExtensionListDelegate}
-   */
-  function ExtensionSettings() {}
-
-  cr.addSingletonGetter(ExtensionSettings);
-
-  ExtensionSettings.prototype = {
-    /**
-     * The drag-drop wrapper for installing external Extensions, if available.
-     * null if external Extension installation is not available.
-     * @type {cr.ui.DragWrapper}
-     * @private
-     */
-    dragWrapper_: null,
-
-    /**
-     * True if drag-drop is both available and currently enabled - it can be
-     * temporarily disabled while overlays are showing.
-     * @type {boolean}
-     * @private
-     */
-    dragEnabled_: false,
-
-    /**
-     * True if the page has finished the initial load.
-     * @private {boolean}
-     */
-    hasLoaded_: false,
-
-    /**
-     * Perform initial setup.
-     */
-    initialize: function() {
-      this.setLoading_(true);
-      cr.ui.FocusOutlineManager.forDocument(document);
-      measureCheckboxStrings();
-
-      var extensionList = new ExtensionList(this);
-      extensionList.id = 'extension-settings-list';
-      var wrapper = $('extension-list-wrapper');
-      wrapper.insertBefore(extensionList, wrapper.firstChild);
-
-      // Get the initial profile state, and register to be notified of any
-      // future changes.
-      chrome.developerPrivate.getProfileConfiguration(
-          this.update_.bind(this));
-      chrome.developerPrivate.onProfileStateChanged.addListener(
-          this.update_.bind(this));
-
-      var extensionLoader = extensions.ExtensionLoader.getInstance();
-
-      $('toggle-dev-on').addEventListener('change', function(e) {
-        this.updateDevControlsVisibility_(true);
-        chrome.developerPrivate.updateProfileConfiguration(
-            {inDeveloperMode: e.target.checked});
-        var suffix = $('toggle-dev-on').checked ? 'Enabled' : 'Disabled';
-        chrome.send('metricsHandler:recordAction',
-                    ['Options_ToggleDeveloperMode_' + suffix]);
-      }.bind(this));
-
-      window.addEventListener('resize', function() {
-        this.updateDevControlsVisibility_(false);
-      }.bind(this));
-
-      // Set up the three dev mode buttons (load unpacked, pack and update).
-      $('load-unpacked').addEventListener('click', function(e) {
-        chrome.send('metricsHandler:recordAction',
-                    ['Options_LoadUnpackedExtension']);
-        extensionLoader.loadUnpacked();
-      });
-      $('pack-extension').addEventListener('click',
-          this.handlePackExtension_.bind(this));
-      $('update-extensions-now').addEventListener('click',
-          this.handleUpdateExtensionNow_.bind(this));
-
-      var dragTarget = document.documentElement;
-      /** @private {extensions.DragAndDropHandler} */
-      this.dragWrapperHandler_ =
-          new extensions.DragAndDropHandler(true, false, dragTarget);
-      dragTarget.addEventListener('extension-drag-started', function() {
-        ExtensionSettings.showOverlay($('drop-target-overlay'));
-      });
-      dragTarget.addEventListener('extension-drag-ended', function() {
-        var overlay = ExtensionSettings.getCurrentOverlay();
-        if (overlay && overlay.id === 'drop-target-overlay')
-          ExtensionSettings.showOverlay(null);
-      });
-      this.dragWrapper_ =
-          new cr.ui.DragWrapper(dragTarget, this.dragWrapperHandler_);
-
-      extensions.PackExtensionOverlay.getInstance().initializePage();
-
-      // Hook up the configure commands link to the overlay.
-      var link = document.querySelector('.extension-commands-config');
-      link.addEventListener('click',
-          this.handleExtensionCommandsConfig_.bind(this));
-
-      // Initialize the Commands overlay.
-      extensions.ExtensionCommandsOverlay.getInstance().initializePage();
-
-      extensions.ExtensionErrorOverlay.getInstance().initializePage(
-          extensions.ExtensionSettings.showOverlay);
-
-      extensions.ExtensionOptionsOverlay.getInstance().initializePage(
-          extensions.ExtensionSettings.showOverlay);
-
-      // Add user action logging for bottom links.
-      var moreExtensionLink =
-          document.getElementsByClassName('more-extensions-link');
-      for (var i = 0; i < moreExtensionLink.length; i++) {
-        moreExtensionLink[i].addEventListener('click', function(e) {
-          chrome.send('metricsHandler:recordAction',
-                      ['Options_GetMoreExtensions']);
-        });
-      }
-
-      // Initialize the kiosk overlay.
-      if (cr.isChromeOS) {
-        var kioskOverlay = extensions.KioskAppsOverlay.getInstance();
-        kioskOverlay.initialize();
-
-        $('add-kiosk-app').addEventListener('click', function() {
-          ExtensionSettings.showOverlay($('kiosk-apps-page'));
-          kioskOverlay.didShowPage();
-        });
-
-        extensions.KioskDisableBailoutConfirm.getInstance().initialize();
-      }
-
-      cr.ui.overlay.setupOverlay($('drop-target-overlay'));
-      cr.ui.overlay.globalInitialization();
-
-      extensions.ExtensionFocusManager.getInstance().initialize();
-
-      var path = document.location.pathname;
-      if (path.length > 1) {
-        // Skip starting slash and remove trailing slash (if any).
-        var overlayName = path.slice(1).replace(/\/$/, '');
-        if (overlayName == 'configureCommands')
-          this.showExtensionCommandsConfigUi_();
-      }
-    },
-
-    /**
-     * [Re]-Populates the page with data representing the current state of
-     * installed extensions.
-     * @param {chrome.developerPrivate.ProfileInfo} profileInfo
-     * @private
-     */
-    update_: function(profileInfo) {
-      // We only set the page to be loading if we haven't already finished an
-      // initial load, because otherwise the updates are all incremental and
-      // don't need to display the interstitial spinner.
-      if (!this.hasLoaded_)
-        this.setLoading_(true);
-
-      /** @const */
-      var supervised = profileInfo.isSupervised;
-      var developerModeControlledByPolicy =
-          profileInfo.isDeveloperModeControlledByPolicy;
-
-      var pageDiv = $('extension-settings');
-      pageDiv.classList.toggle('profile-is-supervised', supervised);
-      pageDiv.classList.toggle('showing-banner', supervised);
-
-      var devControlsCheckbox = $('toggle-dev-on');
-      devControlsCheckbox.checked = profileInfo.inDeveloperMode;
-      devControlsCheckbox.disabled =
-          supervised || developerModeControlledByPolicy;
-
-      // This is necessary e.g. if developer mode is now disabled by policy
-      // but extension developer tools were visible.
-      this.updateDevControlsVisibility_(false);
-      this.updateDevToggleControlledIndicator_(developerModeControlledByPolicy);
-
-      $('load-unpacked').disabled = !profileInfo.canLoadUnpacked;
-      var extensionList = /** @type {extensions.ExtensionList} */ (
-          $('extension-settings-list'));
-      extensionList.updateExtensionsData(
-          profileInfo.isIncognitoAvailable,
-          profileInfo.appInfoDialogEnabled).then(function() {
-        if (!this.hasLoaded_) {
-          this.hasLoaded_ = true;
-          this.setLoading_(false);
-        }
-        this.onExtensionCountChanged();
-      }.bind(this));
-    },
-
-    /**
-     * Shows or hides the 'controlled by policy' indicator on the dev-toggle
-     * checkbox.
-     * @param {boolean} devModeControlledByPolicy true if the indicator
-     *     should be showing.
-     * @private
-     */
-    updateDevToggleControlledIndicator_: function(devModeControlledByPolicy) {
-      var controlledIndicator = document.querySelector(
-          '#dev-toggle .controlled-setting-indicator');
-
-      if (!(controlledIndicator instanceof cr.ui.ControlledIndicator))
-        cr.ui.ControlledIndicator.decorate(controlledIndicator);
-
-      // We control the visibility of the ControlledIndicator by setting or
-      // removing the 'controlled-by' attribute (see controlled_indicator.css).
-      var isVisible = controlledIndicator.getAttribute('controlled-by');
-      if (devModeControlledByPolicy && !isVisible) {
-        var controlledBy = 'policy';
-        controlledIndicator.setAttribute(
-           'controlled-by', controlledBy);
-        controlledIndicator.setAttribute(
-            'text' + controlledBy,
-            loadTimeData.getString('extensionControlledSettingPolicy'));
-      } else if (!devModeControlledByPolicy && isVisible) {
-        // This hides the element - see above.
-        controlledIndicator.removeAttribute('controlled-by');
-      }
-    },
-
-    /**
-     * Shows the loading spinner and hides elements that shouldn't be visible
-     * while loading.
-     * @param {boolean} isLoading
-     * @private
-     */
-    setLoading_: function(isLoading) {
-      document.documentElement.classList.toggle('loading', isLoading);
-      $('loading-spinner').hidden = !isLoading;
-      $('dev-controls').hidden = isLoading;
-      this.updateDevControlsVisibility_(false);
-
-      // The extension list is already hidden/shown elsewhere and shouldn't be
-      // updated here because it can be hidden if there are no extensions.
-    },
-
-    /**
-     * Handles the Pack Extension button.
-     * @param {Event} e Change event.
-     * @private
-     */
-    handlePackExtension_: function(e) {
-      ExtensionSettings.showOverlay($('pack-extension-overlay'));
-      chrome.send('metricsHandler:recordAction', ['Options_PackExtension']);
-    },
-
-    /**
-     * Shows the Extension Commands configuration UI.
-     * @private
-     */
-    showExtensionCommandsConfigUi_: function() {
-      ExtensionSettings.showOverlay($('extension-commands-overlay'));
-      chrome.send('metricsHandler:recordAction',
-                  ['Options_ExtensionCommands']);
-    },
-
-    /**
-     * Handles the Configure (Extension) Commands link.
-     * @param {Event} e Change event.
-     * @private
-     */
-    handleExtensionCommandsConfig_: function(e) {
-      this.showExtensionCommandsConfigUi_();
-    },
-
-    /**
-     * Handles the Update Extension Now button.
-     * @param {Event} e Change event.
-     * @private
-     */
-    handleUpdateExtensionNow_: function(e) {
-      chrome.developerPrivate.autoUpdate();
-      chrome.send('metricsHandler:recordAction',
-                  ['Options_UpdateExtensions']);
-    },
-
-    /**
-     * Updates the visibility of the developer controls based on whether the
-     * [x] Developer mode checkbox is checked.
-     * @param {boolean} animated Whether to animate any updates.
-     * @private
-     */
-    updateDevControlsVisibility_: function(animated) {
-      var showDevControls = $('toggle-dev-on').checked;
-      $('extension-settings').classList.toggle('dev-mode', showDevControls);
-
-      var devControls = $('dev-controls');
-      devControls.classList.toggle('animated', animated);
-
-      var buttons = devControls.querySelector('.button-container');
-      Array.prototype.forEach.call(buttons.querySelectorAll('a, button'),
-                                   function(control) {
-        control.tabIndex = showDevControls ? 0 : -1;
-      });
-      buttons.setAttribute('aria-hidden', !showDevControls);
-
-      window.requestAnimationFrame(function() {
-        devControls.style.height = !showDevControls ? '' :
-            buttons.offsetHeight + 'px';
-
-        document.dispatchEvent(new Event('devControlsVisibilityUpdated'));
-      }.bind(this));
-    },
-
-    /** @override */
-    onExtensionCountChanged: function() {
-      /** @const */
-      var hasExtensions =
-          /** @type {extensions.ExtensionList} */ ($('extension-settings-list'))
-              .getNumExtensions() != 0;
-      $('no-extensions').hidden = hasExtensions;
-      $('extension-list-wrapper').hidden = !hasExtensions;
-    },
-  };
-
-  /**
-   * Returns the current overlay or null if one does not exist.
-   * @return {Element} The overlay element.
-   */
-  ExtensionSettings.getCurrentOverlay = function() {
-    return document.querySelector('#overlay .page.showing');
-  };
-
-  /**
-   * Sets the given overlay to show. If the overlay is already showing, this is
-   * a no-op; otherwise, hides any currently-showing overlay.
-   * @param {HTMLElement} node The overlay page to show. If null, all overlays
-   *     are hidden.
-   */
-  ExtensionSettings.showOverlay = function(node) {
-    var pageDiv = $('extension-settings');
-    pageDiv.style.width = node ? window.getComputedStyle(pageDiv).width : '';
-    document.body.classList.toggle('no-scroll', !!node);
-
-    var currentlyShowingOverlay = ExtensionSettings.getCurrentOverlay();
-    if (currentlyShowingOverlay) {
-      if (currentlyShowingOverlay == node)  // Already displayed.
-        return;
-      currentlyShowingOverlay.classList.remove('showing');
-    }
-
-    if (node) {
-      var lastFocused;
-
-      var focusOutlineManager = cr.ui.FocusOutlineManager.forDocument(document);
-      if (focusOutlineManager.visible)
-        lastFocused = document.activeElement;
-
-      $('overlay').addEventListener('cancelOverlay', function f() {
-        if (lastFocused && focusOutlineManager.visible)
-          lastFocused.focus();
-
-        $('overlay').removeEventListener('cancelOverlay', f);
-        window.history.replaceState({}, '', '/');
-      });
-      node.classList.add('showing');
-    }
-
-    var pages = document.querySelectorAll('.page');
-    for (var i = 0; i < pages.length; i++) {
-      var hidden = (node != pages[i]) ? 'true' : 'false';
-      pages[i].setAttribute('aria-hidden', hidden);
-    }
-
-    $('overlay').hidden = !node;
-
-    if (node)
-      ExtensionSettings.focusOverlay();
-
-    // If drag-drop for external Extension installation is available, enable
-    // drag-drop when there is any overlay showing other than the usual overlay
-    // shown when drag-drop is started.
-    var settings = ExtensionSettings.getInstance();
-    if (settings.dragWrapper_) {
-      assert(settings.dragWrapperHandler_).dragEnabled =
-          !node || node == $('drop-target-overlay');
-    }
-  };
-
-  ExtensionSettings.focusOverlay = function() {
-    var currentlyShowingOverlay = ExtensionSettings.getCurrentOverlay();
-    assert(currentlyShowingOverlay);
-
-    if (cr.ui.FocusOutlineManager.forDocument(document).visible)
-      cr.ui.setInitialFocus(currentlyShowingOverlay);
-
-    if (!currentlyShowingOverlay.contains(document.activeElement)) {
-      // Make sure focus isn't stuck behind the overlay.
-      document.activeElement.blur();
-    }
-  };
-
-  /**
-   * Utility function to find the width of various UI strings and synchronize
-   * the width of relevant spans. This is crucial for making sure the
-   * Enable/Enabled checkboxes align, as well as the Developer Mode checkbox.
-   */
-  function measureCheckboxStrings() {
-    var trashWidth = 30;
-    var measuringDiv = $('font-measuring-div');
-    measuringDiv.textContent =
-        loadTimeData.getString('extensionSettingsEnabled');
-    measuringDiv.className = 'enabled-text';
-    var pxWidth = measuringDiv.clientWidth + trashWidth;
-    measuringDiv.textContent =
-        loadTimeData.getString('extensionSettingsEnable');
-    measuringDiv.className = 'enable-text';
-    pxWidth = Math.max(measuringDiv.clientWidth + trashWidth, pxWidth);
-    measuringDiv.textContent =
-        loadTimeData.getString('extensionSettingsDeveloperMode');
-    measuringDiv.className = '';
-    pxWidth = Math.max(measuringDiv.clientWidth, pxWidth);
-
-    var style = document.createElement('style');
-    style.type = 'text/css';
-    style.textContent =
-        '.enable-checkbox-text {' +
-        '  min-width: ' + (pxWidth - trashWidth) + 'px;' +
-        '}' +
-        '#dev-toggle span {' +
-        '  min-width: ' + pxWidth + 'px;' +
-        '}';
-    document.querySelector('head').appendChild(style);
-  }
-
-  // Export
-  return {
-    ExtensionSettings: ExtensionSettings
-  };
-});
-
-window.addEventListener('load', function(e) {
-  extensions.ExtensionSettings.getInstance().initialize();
-});
diff --git a/chrome/browser/resources/extensions/focus_row.js b/chrome/browser/resources/extensions/focus_row.js
deleted file mode 100644
index 6022f39..0000000
--- a/chrome/browser/resources/extensions/focus_row.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('extensions', function() {
-  /**
-   * @param {!Element} root
-   * @param {?Element} boundary
-   * @constructor
-   * @extends {cr.ui.FocusRow}
-   */
-  function FocusRow(root, boundary) {
-    cr.ui.FocusRow.call(this, root, boundary);
-  }
-
-  FocusRow.prototype = {
-    __proto__: cr.ui.FocusRow.prototype,
-
-    /** @override */
-    makeActive: function(active) {
-      cr.ui.FocusRow.prototype.makeActive.call(this, active);
-
-      // Only highlight if the row has focus.
-      this.root.classList.toggle('extension-highlight',
-          active && this.root.contains(document.activeElement));
-    },
-  };
-
-  return {FocusRow: FocusRow};
-});
diff --git a/chrome/browser/resources/extensions/pack_extension_overlay.css b/chrome/browser/resources/extensions/pack_extension_overlay.css
deleted file mode 100644
index 74a4b19d..0000000
--- a/chrome/browser/resources/extensions/pack_extension_overlay.css
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Copyright (c) 2012 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. */
-
-.pack-extension-heading {
-  padding-bottom: 5px;
-  width: 520px;
-}
-
-.pack-extension-text-boxes {
-  text-align: right;
-}
-
-.pack-extension-text-area {
-  width: 260px;
-}
-
-<if expr="toolkit_views">
-/* TODO(estade): apply this everywhere. */
-.button-strip {
-  -webkit-box-direction: reverse;
-}
-</if>
diff --git a/chrome/browser/resources/extensions/pack_extension_overlay.html b/chrome/browser/resources/extensions/pack_extension_overlay.html
deleted file mode 100644
index 65572b5..0000000
--- a/chrome/browser/resources/extensions/pack_extension_overlay.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<div id="pack-extension-overlay" class="page">
-  <div class="close-button"></div>
-  <h1>$i18n{packExtensionOverlay}</h1>
-  <div id="cbd-content-area" class="content-area">
-    <div class="pack-extension-heading">$i18n{packExtensionHeading}</div>
-    <div class="pack-extension-text-boxes">
-      <label for="extension-root-dir">$i18n{packExtensionRootDir}</label>
-      <input class="pack-extension-text-area" id="extension-root-dir"
-          type="text">
-      <button id="browse-extension-dir">
-        $i18n{packExtensionBrowseButton}
-      </button>
-    </div>
-    <div class="pack-extension-text-boxes">
-      <label for="extension-private-key">$i18n{packExtensionPrivateKey}</label>
-      <input class="pack-extension-text-area" id="extension-private-key"
-          type="text">
-      <button id="browse-private-key">
-        $i18n{packExtensionBrowseButton}
-      </button>
-    </div>
-  </div>
-  <div class="action-area">
-    <div class="action-area-right">
-      <div class="button-strip">
-        <button id="pack-extension-dismiss">$i18n{cancel}</button>
-        <button id="pack-extension-commit">
-          $i18n{packExtensionCommit}
-        </button>
-      </div>
-    </div>
-  </div>
-</div>
diff --git a/chrome/browser/resources/extensions/pack_extension_overlay.js b/chrome/browser/resources/extensions/pack_extension_overlay.js
deleted file mode 100644
index 63b20a4d..0000000
--- a/chrome/browser/resources/extensions/pack_extension_overlay.js
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('extensions', function() {
-  /**
-   * PackExtensionOverlay class
-   * Encapsulated handling of the 'Pack Extension' overlay page.
-   * @constructor
-   */
-  function PackExtensionOverlay() {
-  }
-
-  cr.addSingletonGetter(PackExtensionOverlay);
-
-  PackExtensionOverlay.prototype = {
-    /**
-     * Initialize the page.
-     */
-    initializePage: function() {
-      var overlay = $('overlay');
-      cr.ui.overlay.setupOverlay(overlay);
-      cr.ui.overlay.globalInitialization();
-      overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
-
-      $('pack-extension-dismiss').addEventListener('click', function() {
-        cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
-      });
-      $('pack-extension-commit').addEventListener('click',
-          this.handleCommit_.bind(this));
-      $('browse-extension-dir').addEventListener('click',
-          this.handleBrowseExtensionDir_.bind(this));
-      $('browse-private-key').addEventListener('click',
-          this.handleBrowsePrivateKey_.bind(this));
-    },
-
-    /**
-     * Handles a click on the dismiss button.
-     * @param {Event} e The click event.
-     */
-    handleDismiss_: function(e) {
-      extensions.ExtensionSettings.showOverlay(null);
-    },
-
-    /**
-     * Handles a click on the pack button.
-     * @param {Event} e The click event.
-     */
-    handleCommit_: function(e) {
-      var extensionPath = $('extension-root-dir').value;
-      var privateKeyPath = $('extension-private-key').value;
-      chrome.developerPrivate.packDirectory(
-          extensionPath, privateKeyPath, 0, this.onPackResponse_.bind(this));
-    },
-
-    /**
-     * Utility function which asks the C++ to show a platform-specific file
-     * select dialog, and set the value property of |node| to the selected path.
-     * @param {chrome.developerPrivate.SelectType} selectType
-     *     The type of selection to use.
-     * @param {chrome.developerPrivate.FileType} fileType
-     *     The type of file to select.
-     * @param {HTMLInputElement} node The node to set the value of.
-     * @private
-     */
-    showFileDialog_: function(selectType, fileType, node) {
-      chrome.developerPrivate.choosePath(selectType, fileType, function(path) {
-        // Last error is set if the user canceled the dialog.
-        if (!chrome.runtime.lastError && path)
-          node.value = path;
-      });
-    },
-
-    /**
-     * Handles the showing of the extension directory browser.
-     * @param {Event} e Change event.
-     * @private
-     */
-    handleBrowseExtensionDir_: function(e) {
-      this.showFileDialog_(
-          chrome.developerPrivate.SelectType.FOLDER,
-          chrome.developerPrivate.FileType.LOAD,
-          /** @type {HTMLInputElement} */ ($('extension-root-dir')));
-    },
-
-    /**
-     * Handles the showing of the extension private key file.
-     * @param {Event} e Change event.
-     * @private
-     */
-    handleBrowsePrivateKey_: function(e) {
-      this.showFileDialog_(
-          chrome.developerPrivate.SelectType.FILE,
-          chrome.developerPrivate.FileType.PEM,
-          /** @type {HTMLInputElement} */ ($('extension-private-key')));
-    },
-
-    /**
-     * Handles a response from a packDirectory call.
-     * @param {chrome.developerPrivate.PackDirectoryResponse} response The
-     *     response of the pack call.
-     * @private
-     */
-    onPackResponse_: function(response) {
-      /** @type {string} */
-      var alertTitle;
-      /** @type {string} */
-      var alertOk;
-      /** @type {string} */
-      var alertCancel;
-      /** @type {function()} */
-      var alertOkCallback;
-      /** @type {function()} */
-      var alertCancelCallback;
-
-      var closeAlert = function() {
-        extensions.ExtensionSettings.showOverlay(null);
-      };
-
-      switch (response.status) {
-        case chrome.developerPrivate.PackStatus.SUCCESS:
-          alertTitle = loadTimeData.getString('packExtensionOverlay');
-          alertOk = loadTimeData.getString('ok');
-          alertOkCallback = closeAlert;
-          // No 'Cancel' option.
-          break;
-        case chrome.developerPrivate.PackStatus.WARNING:
-          alertTitle = loadTimeData.getString('packExtensionWarningTitle');
-          alertOk = loadTimeData.getString('packExtensionProceedAnyway');
-          alertCancel = loadTimeData.getString('cancel');
-          alertOkCallback = function() {
-            chrome.developerPrivate.packDirectory(
-                response.item_path,
-                response.pem_path,
-                response.override_flags,
-                this.onPackResponse_.bind(this));
-            closeAlert();
-          }.bind(this);
-          alertCancelCallback = closeAlert;
-          break;
-        case chrome.developerPrivate.PackStatus.ERROR:
-          alertTitle = loadTimeData.getString('packExtensionErrorTitle');
-          alertOk = loadTimeData.getString('ok');
-          alertOkCallback = function() {
-            extensions.ExtensionSettings.showOverlay(
-                $('pack-extension-overlay'));
-          };
-          // No 'Cancel' option.
-          break;
-        default:
-          assertNotReached();
-          return;
-      }
-
-      alertOverlay.setValues(alertTitle,
-                             response.message,
-                             alertOk,
-                             alertCancel,
-                             alertOkCallback,
-                             alertCancelCallback);
-      extensions.ExtensionSettings.showOverlay($('alertOverlay'));
-    },
-  };
-
-  // Export
-  return {
-    PackExtensionOverlay: PackExtensionOverlay
-  };
-});
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 0746556..8bbe039 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3620,8 +3620,6 @@
         "app_list/crostini/crostini_app_model_builder.h",
         "app_list/crostini/crostini_installer_view.cc",
         "app_list/crostini/crostini_installer_view.h",
-        "app_list/crostini/crostini_util.cc",
-        "app_list/crostini/crostini_util.h",
         "app_list/internal_app/internal_app_icon_loader.cc",
         "app_list/internal_app/internal_app_icon_loader.h",
         "app_list/internal_app/internal_app_item.cc",
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc
index e504f49..c8b0e3b9 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -14,6 +14,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/file_manager/app_id.h"
 #include "chrome/browser/chromeos/genius_app/app_id.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -27,7 +28,6 @@
 #include "chrome/browser/ui/app_list/chrome_app_list_item.h"
 #include "chrome/browser/ui/app_list/chrome_app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_app_model_builder.h"
-#include "chrome/browser/ui/app_list/crostini/crostini_util.h"
 #include "chrome/browser/ui/app_list/extension_app_item.h"
 #include "chrome/browser/ui/app_list/extension_app_model_builder.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_model_builder.h"
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_item.cc b/chrome/browser/ui/app_list/crostini/crostini_app_item.cc
index 81270cf..a7271b2 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_item.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_item.cc
@@ -8,11 +8,13 @@
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_app_context_menu.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_installer_view.h"
-#include "chrome/browser/ui/app_list/crostini/crostini_util.h"
+#include "ui/app_list/app_list_constants.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_operations.h"
 
 // static
 const char CrostiniAppItem::kItemType[] = "CrostiniAppItem";
@@ -24,7 +26,9 @@
     const std::string& name,
     const gfx::ImageSkia* image_skia)
     : ChromeAppListItem(profile, id) {
-  SetIcon(*image_skia);
+  SetIcon(gfx::ImageSkiaOperations::CreateResizedImage(
+      *image_skia, skia::ImageOperations::RESIZE_BEST,
+      gfx::Size(app_list::kTileIconSize, app_list::kTileIconSize)));
   SetName(name);
   if (sync_item && sync_item->item_ordinal.IsValid()) {
     UpdateFromSync(sync_item);
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc
index 1630e2e8..16cccb5 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc
@@ -4,10 +4,10 @@
 
 #include "chrome/browser/ui/app_list/crostini/crostini_app_model_builder.h"
 
-#include "ash/resources/grit/ash_resources.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_app_item.h"
+#include "chrome/grit/chrome_unscaled_resources.h"
 #include "components/crx_file/id_util.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -54,11 +54,11 @@
   const std::string& localized_name =
       crostini::CrostiniRegistryService::Registration::Localize(
           registration->name);
-  // TODO(timloh): Use a real icon
+  // TODO(timloh): Get an icon from the registry.
   InsertApp(std::make_unique<CrostiniAppItem>(
       profile(), GetSyncItem(app_id), app_id, localized_name,
       ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-          IDR_LOGO_CROSTINI_TERMINAL)));
+          IDR_LOGO_CROSTINI_DEFAULT)));
 }
 
 void CrostiniAppModelBuilder::OnRegistryUpdated(
diff --git a/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc b/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc
index f71a552e..7ff125cd 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc
@@ -11,9 +11,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_app_item.h"
-#include "chrome/browser/ui/app_list/crostini/crostini_util.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/signin/core/account_id/account_id.h"
@@ -29,6 +29,8 @@
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/layout_provider.h"
 
+using crostini::ConciergeClientResult;
+
 namespace {
 CrostiniInstallerView* g_crostini_installer_view = nullptr;
 
@@ -104,10 +106,24 @@
 
   GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
 
-  InstallImageLoader();
+  // Kick off the Crostini Restart sequence. We will be added as an observer.
+  restart_id_ = crostini::CrostiniManager::GetInstance()->RestartCrostini(
+      profile_, kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+      base::BindOnce(&CrostiniInstallerView::StartContainerFinished,
+                     weak_ptr_factory_.GetWeakPtr()),
+      this);
   return false;
 }
 
+bool CrostiniInstallerView::Cancel() {
+  if (restart_id_ != crostini::CrostiniManager::kUninitializedRestartId) {
+    // Abort the long-running flow, and prevent our RestartObserver methods
+    // being called after "this" has been destroyed.
+    crostini::CrostiniManager::GetInstance()->AbortRestartCrostini(restart_id_);
+  }
+  return true;  // Should close the dialog
+}
+
 gfx::Size CrostiniInstallerView::CalculatePreferredSize() const {
   int height =
       GetLayoutManager()->GetPreferredHeightForWidth(this, kDialogWidth);
@@ -123,14 +139,7 @@
                                              Profile* profile)
     : app_name_(base::ASCIIToUTF16(app_item->name())),
       profile_(profile),
-      cryptohome_id_(chromeos::ProfileHelper::Get()
-                         ->GetUserByProfile(profile)
-                         ->username_hash()),
       weak_ptr_factory_(this) {
-  // Get rid of the @domain.name in the container_user_name_ (an email address).
-  container_user_name_ = profile_->GetProfileUserName();
-  container_user_name_ =
-      container_user_name_.substr(0, container_user_name_.find('@'));
 
   views::LayoutProvider* provider = views::LayoutProvider::Get();
   SetLayoutManager(std::make_unique<views::BoxLayout>(
@@ -178,85 +187,38 @@
   GetWidget()->UpdateWindowTitle();
 }
 
-void CrostiniInstallerView::InstallImageLoader() {
-  VLOG(1) << "Installing cros-termina component";
+void CrostiniInstallerView::OnComponentLoaded(ConciergeClientResult result) {
   DCHECK_EQ(state_, State::INSTALL_START);
   state_ = State::INSTALL_IMAGE_LOADER;
-  g_browser_process->platform_part()->cros_component_manager()->Load(
-      "cros-termina",
-      component_updater::CrOSComponentManager::MountPolicy::kMount,
-      base::BindOnce(InstallImageLoaderFinished,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void CrostiniInstallerView::InstallImageLoaderFinished(
-    base::WeakPtr<CrostiniInstallerView> weak_ptr,
-    component_updater::CrOSComponentManager::Error error,
-    const base::FilePath& result) {
-  DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::BindOnce(
-          &CrostiniInstallerView::InstallImageLoaderFinishedOnUIThread,
-          weak_ptr, error, result));
-}
-
-void CrostiniInstallerView::InstallImageLoaderFinishedOnUIThread(
-    component_updater::CrOSComponentManager::Error error,
-    const base::FilePath& result) {
-  if (error != component_updater::CrOSComponentManager::Error::NONE) {
-    LOG(ERROR)
-        << "Failed to install the cros-termina component with error code: "
-        << static_cast<int>(error);
+  if (result != ConciergeClientResult::SUCCESS) {
+    LOG(ERROR) << "Failed to install the cros-termina component";
     HandleError(
         l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_LOAD_TERMINA_ERROR));
     return;
   }
   VLOG(1) << "cros-termina install success";
   StepProgress();
-  StartVmConcierge();
 }
 
-void CrostiniInstallerView::StartVmConcierge() {
+void CrostiniInstallerView::OnConciergeStarted(ConciergeClientResult result) {
   DCHECK_EQ(state_, State::INSTALL_IMAGE_LOADER);
   state_ = State::START_CONCIERGE;
-
-  crostini::CrostiniManager::GetInstance()->StartVmConcierge(
-      base::BindOnce(&CrostiniInstallerView::StartVmConciergeFinished,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void CrostiniInstallerView::StartVmConciergeFinished(bool success) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (!success) {
-    LOG(ERROR) << "Failed to install start Concierge";
+  if (result != ConciergeClientResult::SUCCESS) {
+    LOG(ERROR) << "Failed to install start Concierge with error code: "
+               << static_cast<int>(result);
     HandleError(l10n_util::GetStringUTF16(
         IDS_CROSTINI_INSTALLER_START_CONCIERGE_ERROR));
     return;
   }
   VLOG(1) << "VmConcierge service started";
   StepProgress();
-  CreateDiskImage();
 }
 
-void CrostiniInstallerView::CreateDiskImage() {
-  DCHECK_EQ(state_, State::START_CONCIERGE);
+void CrostiniInstallerView::OnDiskImageCreated(ConciergeClientResult result) {
+  DCHECK_EQ(state_, State::INSTALL_IMAGE_LOADER);
   state_ = State::CREATE_DISK_IMAGE;
-
-  VLOG(1) << "Creating crostini disk image";
-  crostini::CrostiniManager::GetInstance()->CreateDiskImage(
-      cryptohome_id_, base::FilePath(kCrostiniDefaultVmName),
-      vm_tools::concierge::StorageLocation::STORAGE_CRYPTOHOME_ROOT,
-      base::BindOnce(&CrostiniInstallerView::CreateDiskImageFinished,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void CrostiniInstallerView::CreateDiskImageFinished(
-    crostini::ConciergeClientResult result,
-    const base::FilePath& result_path) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (result != crostini::ConciergeClientResult::SUCCESS) {
-    LOG(ERROR) << "Failed to create disk image with error code: "
+  if (result != ConciergeClientResult::SUCCESS) {
+    LOG(ERROR) << "Failed to create disk imagewith error code: "
                << static_cast<int>(result);
     HandleError(l10n_util::GetStringUTF16(
         IDS_CROSTINI_INSTALLER_CREATE_DISK_IMAGE_ERROR));
@@ -264,24 +226,12 @@
   }
   VLOG(1) << "Created crostini disk image";
   StepProgress();
-  StartTerminaVm(result_path);
 }
 
-void CrostiniInstallerView::StartTerminaVm(const base::FilePath& result_path) {
+void CrostiniInstallerView::OnVmStarted(ConciergeClientResult result) {
   DCHECK_EQ(state_, State::CREATE_DISK_IMAGE);
   state_ = State::START_TERMINA_VM;
-
-  VLOG(1) << "Starting Termina VM";
-  crostini::CrostiniManager::GetInstance()->StartTerminaVm(
-      kCrostiniDefaultVmName, result_path,
-      base::BindOnce(&CrostiniInstallerView::StartTerminaVmFinished,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void CrostiniInstallerView::StartTerminaVmFinished(
-    crostini::ConciergeClientResult result) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (result != crostini::ConciergeClientResult::SUCCESS) {
+  if (result != ConciergeClientResult::SUCCESS) {
     LOG(ERROR) << "Failed to start Termina VM with error code: "
                << static_cast<int>(result);
     HandleError(l10n_util::GetStringUTF16(
@@ -290,26 +240,12 @@
   }
   VLOG(1) << "Started Termina VM successfully";
   StepProgress();
-  StartContainer();
-}
-
-void CrostiniInstallerView::StartContainer() {
-  DCHECK_EQ(state_, State::START_TERMINA_VM);
-  state_ = State::START_CONTAINER;
-  VLOG(1) << "In vm " << kCrostiniDefaultVmName << ", starting container "
-          << kCrostiniDefaultContainerName << " as user "
-          << container_user_name_;
-  crostini::CrostiniManager::GetInstance()->StartContainer(
-      kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
-      container_user_name_,
-      base::BindOnce(&CrostiniInstallerView::StartContainerFinished,
-                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void CrostiniInstallerView::StartContainerFinished(
-    crostini::ConciergeClientResult result) {
+    ConciergeClientResult result) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (result != crostini::ConciergeClientResult::SUCCESS) {
+  if (result != ConciergeClientResult::SUCCESS) {
     LOG(ERROR) << "Failed to start container with error code: "
                << static_cast<int>(result);
     HandleError(l10n_util::GetStringUTF16(
diff --git a/chrome/browser/ui/app_list/crostini/crostini_installer_view.h b/chrome/browser/ui/app_list/crostini/crostini_installer_view.h
index 6b822a8..26e2ef5 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_installer_view.h
+++ b/chrome/browser/ui/app_list/crostini/crostini_installer_view.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/component_updater/cros_component_installer.h"
 #include "ui/views/window/dialog_delegate.h"
 
@@ -24,7 +25,9 @@
 
 // The Crostini installer. Provides details about Crostini to the user and
 // installs it if the user chooses to do so.
-class CrostiniInstallerView : public views::DialogDelegateView {
+class CrostiniInstallerView
+    : public views::DialogDelegateView,
+      public crostini::CrostiniManager::RestartObserver {
  public:
   static void Show(const CrostiniAppItem* app_item, Profile* profile);
 
@@ -34,8 +37,15 @@
   base::string16 GetWindowTitle() const override;
   bool ShouldShowCloseButton() const override;
   bool Accept() override;
+  bool Cancel() override;
   gfx::Size CalculatePreferredSize() const override;
 
+  // crostini::CrostiniManager::RestartObserver
+  void OnComponentLoaded(crostini::ConciergeClientResult result) override;
+  void OnConciergeStarted(crostini::ConciergeClientResult result) override;
+  void OnDiskImageCreated(crostini::ConciergeClientResult result) override;
+  void OnVmStarted(crostini::ConciergeClientResult result) override;
+
   static CrostiniInstallerView* GetActiveViewForTesting();
 
  private:
@@ -44,26 +54,6 @@
 
   void HandleError(const base::string16& error_message);
 
-  void InstallImageLoader();
-  static void InstallImageLoaderFinished(
-      base::WeakPtr<CrostiniInstallerView> weak_ptr,
-      component_updater::CrOSComponentManager::Error error,
-      const base::FilePath& result);
-  void InstallImageLoaderFinishedOnUIThread(
-      component_updater::CrOSComponentManager::Error error,
-      const base::FilePath& result);
-
-  void StartVmConcierge();
-  void StartVmConciergeFinished(bool success);
-
-  void CreateDiskImage();
-  void CreateDiskImageFinished(crostini::ConciergeClientResult result,
-                               const base::FilePath& result_path);
-
-  void StartTerminaVm(const base::FilePath& result_path);
-  void StartTerminaVmFinished(crostini::ConciergeClientResult result);
-
-  void StartContainer();
   void StartContainerFinished(crostini::ConciergeClientResult result);
 
   void ShowLoginShell();
@@ -88,8 +78,8 @@
   views::ProgressBar* progress_bar_ = nullptr;
   base::string16 app_name_;
   Profile* profile_;
-  std::string cryptohome_id_;
-  std::string container_user_name_;
+  crostini::CrostiniManager::RestartId restart_id_ =
+      crostini::CrostiniManager::kUninitializedRestartId;
 
   base::WeakPtrFactory<CrostiniInstallerView> weak_ptr_factory_;
 
diff --git a/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc b/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc
index 2d06d74..43bd8c65 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc
@@ -6,10 +6,10 @@
 
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
 #include "chrome/browser/ui/app_list/app_list_service_impl.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_app_model_builder.h"
-#include "chrome/browser/ui/app_list/crostini/crostini_util.h"
 #include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/common/chrome_features.h"
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index 5baf12d..36ef6bf31 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/mus_property_mirror_ash.h"
 #include "ash/public/cpp/shelf_model.h"
@@ -19,9 +18,10 @@
 #include "ash/public/interfaces/window_properties.mojom.h"
 #include "ash/public/interfaces/window_state_type.mojom.h"
 #include "ash/shell.h"
+#include "base/command_line.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/ash_config.h"
-#include "chrome/browser/chromeos/docked_magnifier/docked_magnifier_client.h"
+#include "chrome/browser/chromeos/net/network_portal_notification_controller.h"
 #include "chrome/browser/chromeos/night_light/night_light_client.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
@@ -50,9 +50,11 @@
 #include "chrome/browser/ui/views/select_file_dialog_extension_factory.h"
 #include "chromeos/network/network_connect.h"
 #include "chromeos/network/network_handler.h"
+#include "chromeos/network/portal_detector/network_portal_detector.h"
 #include "components/session_manager/core/session_manager.h"
 #include "components/session_manager/core/session_manager_observer.h"
 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/common/service_manager_connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/ui/public/interfaces/constants.mojom.h"
@@ -257,6 +259,18 @@
   login_screen_client_ = std::make_unique<LoginScreenClient>();
   media_client_ = std::make_unique<MediaClient>();
 
+  // Do not create a NetworkPortalNotificationController for tests since the
+  // NetworkPortalDetector instance may be replaced.
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          ::switches::kTestType)) {
+    chromeos::NetworkPortalDetector* detector =
+        chromeos::network_portal_detector::GetInstance();
+    CHECK(detector);
+    network_portal_notification_controller_ =
+        std::make_unique<chromeos::NetworkPortalNotificationController>(
+            detector);
+  }
+
   // TODO(mash): Port TabScrubber.
   if (chromeos::GetAshConfig() != ash::Config::MASH) {
     // Initialize TabScrubber after the Ash Shell has been initialized.
@@ -281,11 +295,6 @@
         g_browser_process->system_request_context());
     night_light_client_->Start();
   }
-
-  if (ash::features::IsDockedMagnifierEnabled()) {
-    docked_magnifier_client_ = std::make_unique<DockedMagnifierClient>();
-    docked_magnifier_client_->Start();
-  }
 }
 
 void ChromeBrowserMainExtraPartsAsh::PostMainMessageLoopRun() {
@@ -307,6 +316,7 @@
   system_tray_client_.reset();
   session_controller_client_.reset();
   chrome_new_window_client_.reset();
+  network_portal_notification_controller_.reset();
   media_client_.reset();
   login_screen_client_.reset();
   ime_controller_client_.reset();
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
index 9ad744e..19698a2 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
@@ -15,6 +15,10 @@
 class UserActivityForwarder;
 }
 
+namespace chromeos {
+class NetworkPortalNotificationController;
+}
+
 namespace ui {
 class UserActivityDetector;
 }
@@ -27,7 +31,6 @@
 class ChromeNewWindowClient;
 class ChromeShellContentState;
 class DataPromoNotification;
-class DockedMagnifierClient;
 class ImeControllerClient;
 class ImmersiveContextMus;
 class ImmersiveHandlerFactoryMus;
@@ -90,6 +93,10 @@
   std::unique_ptr<VolumeController> volume_controller_;
   std::unique_ptr<VpnListForwarder> vpn_list_forwarder_;
   std::unique_ptr<WallpaperControllerClient> wallpaper_controller_client_;
+  // TODO(stevenjb): Move NetworkPortalNotificationController to c/b/ui/ash and
+  // elim chromeos:: namespace. https://crbug.com/798569.
+  std::unique_ptr<chromeos::NetworkPortalNotificationController>
+      network_portal_notification_controller_;
 
   std::unique_ptr<internal::ChromeLauncherControllerInitializer>
       chrome_launcher_controller_initializer_;
@@ -110,7 +117,6 @@
   // Initialized in PostBrowserStart in all configs:
   std::unique_ptr<DataPromoNotification> data_promo_notification_;
   std::unique_ptr<NightLightClient> night_light_client_;
-  std::unique_ptr<DockedMagnifierClient> docked_magnifier_client_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsAsh);
 };
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 8015912..b1f186d 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -23,6 +23,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/ash_config.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/extensions/chrome_app_icon_loader.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
@@ -33,7 +34,6 @@
 #include "chrome/browser/ui/app_list/app_sync_ui_state.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_icon_loader.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
-#include "chrome/browser/ui/app_list/crostini/crostini_util.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_icon_loader.h"
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
diff --git a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc
index 60478dc..23d6439 100644
--- a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc
+++ b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc
@@ -8,7 +8,10 @@
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/public/cpp/window_properties.h"
 #include "base/bind.h"
-#include "chrome/browser/ui/app_list/crostini/crostini_util.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
+#include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/ui/ash/launcher/app_window_base.h"
 #include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
@@ -20,12 +23,6 @@
 #include "ui/display/manager/display_manager.h"
 #include "ui/views/widget/widget.h"
 
-namespace {
-
-constexpr char kArcAppIdPrefix[] = "org.chromium.arc";
-
-}  // namespace
-
 CrostiniAppWindowShelfController::CrostiniAppWindowShelfController(
     ChromeLauncherController* owner)
     : AppWindowLauncherController(owner) {
@@ -62,30 +59,32 @@
   if (!visible)
     return;
 
-  const std::string* window_app_id =
-      exo::ShellSurface::GetApplicationId(window);
-  if (window_app_id == nullptr)
-    return;
-
-  // Skip handling ARC++ windows.
-  if (strncmp(window_app_id->c_str(), kArcAppIdPrefix,
-              sizeof(kArcAppIdPrefix) - 1) == 0)
-    return;
-
   // Skip when this window has been handled. This can happen when the window
   // becomes visible again.
   auto app_window_it = aura_window_to_app_window_.find(window);
   if (app_window_it != aura_window_to_app_window_.end())
     return;
 
-  RegisterAppWindow(window, window_app_id);
+  const std::string* window_app_id =
+      exo::ShellSurface::GetApplicationId(window);
+  if (window_app_id == nullptr)
+    return;
+  crostini::CrostiniRegistryService* registry_service =
+      crostini::CrostiniRegistryServiceFactory::GetForProfile(
+          owner()->profile());
+  const std::string& shelf_app_id = registry_service->GetCrostiniShelfAppId(
+      *window_app_id, exo::ShellSurface::GetStartupId(window));
+  // Non-crostini apps (i.e. arc++) are filtered out here.
+  if (shelf_app_id.empty())
+    return;
+
+  RegisterAppWindow(window, shelf_app_id);
 }
 
 void CrostiniAppWindowShelfController::RegisterAppWindow(
     aura::Window* window,
-    const std::string* window_app_id) {
-  const std::string crostini_app_id = CreateCrostiniAppId(*window_app_id);
-  const ash::ShelfID shelf_id(crostini_app_id);
+    const std::string& shelf_app_id) {
+  const ash::ShelfID shelf_id(shelf_app_id);
   views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window);
   aura_window_to_app_window_[window] =
       std::make_unique<AppWindowBase>(shelf_id, widget);
diff --git a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.h b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.h
index 2e9123c..6dac2b6 100644
--- a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.h
+++ b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.h
@@ -45,8 +45,7 @@
   using AuraWindowToAppWindow =
       std::map<aura::Window*, std::unique_ptr<AppWindowBase>>;
 
-  void RegisterAppWindow(aura::Window* window,
-                         const std::string* window_app_id);
+  void RegisterAppWindow(aura::Window* window, const std::string& shelf_app_id);
   void UnregisterAppWindow(AppWindowBase* app_window);
 
   // AppWindowLauncherController:
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
index 64dfc15..a763e37 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
@@ -9,9 +9,10 @@
 
 #include "ash/public/cpp/shelf_model.h"
 #include "base/metrics/user_metrics.h"
+#include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
+#include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
-#include "chrome/browser/ui/app_list/crostini/crostini_util.h"
 #include "chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h"
@@ -40,7 +41,9 @@
   }
 
   // Create an CrostiniShelfContextMenu if the item is Crostini app.
-  if (IsCrostiniAppId(item->id.app_id)) {
+  if (crostini::CrostiniRegistryServiceFactory::GetForProfile(
+          controller->profile())
+          ->IsCrostiniShelfAppId(item->id.app_id)) {
     return std::make_unique<CrostiniShelfContextMenu>(controller, item,
                                                       display_id);
   }
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
index c10f54a..1e2fca94 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
@@ -173,7 +173,7 @@
     MDDownloadShelfCloseButton* closeButton = scopedCloseButton;
     closeButton.autoresizingMask =
         [NSView cr_localizedAutoresizingMask:NSViewMinXMargin];
-    closeButton.icon = &vector_icons::kClose16Icon;
+    closeButton.icon = &vector_icons::kCloseRoundedIcon;
     [closeButton
         cr_setAccessibilityLabel:l10n_util::GetNSString(IDS_HIDE_DOWNLOADS)];
     closeButton.target = self;
diff --git a/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm b/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm
index b123fe18..657865bc 100644
--- a/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm
+++ b/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm
@@ -36,18 +36,6 @@
 
 namespace {
 
-// Update the App Controller with a new Profile. Used when a Profile is locked
-// to set the Controller to the Guest profile so the old Profile's bookmarks,
-// etc... cannot be accessed.
-void ChangeAppControllerForProfile(Profile* profile,
-                                   Profile::CreateStatus status) {
-  if (status == Profile::CREATE_STATUS_INITIALIZED) {
-    AppController* controller =
-        base::mac::ObjCCast<AppController>([NSApp delegate]);
-    [controller windowChangedToProfile:profile];
-  }
-}
-
 // An open User Manager window. There can only be one open at a time. This
 // is reset to NULL when the window is closed.
 UserManagerMac* instance_ = nullptr;  // Weak.
@@ -368,14 +356,8 @@
   // will not trigger a -windowChangedToProfile and update the menu bar.
   // This is only important if the active profile is Guest, which may have
   // happened after locking a profile.
-  if (profiles::SetActiveProfileToGuestIfLocked()) {
-    g_browser_process->profile_manager()->CreateProfileAsync(
-        ProfileManager::GetGuestProfilePath(),
-        base::Bind(&ChangeAppControllerForProfile),
-        base::string16(),
-        std::string(),
-        std::string());
-  }
+  if (profiles::SetActiveProfileToGuestIfLocked())
+    app_controller_mac::CreateGuestProfileIfNeeded();
   [[self window] makeKeyAndOrderFront:self];
 }
 
diff --git a/chrome/browser/ui/startup/bad_flags_prompt.cc b/chrome/browser/ui/startup/bad_flags_prompt.cc
index 67037365..e0c6b1c 100644
--- a/chrome/browser/ui/startup/bad_flags_prompt.cc
+++ b/chrome/browser/ui/startup/bad_flags_prompt.cc
@@ -141,25 +141,6 @@
 // On Android, ShowBadFlagsPrompt doesn't show the warning notification
 // for flags which are not available in about:flags.
 #if !defined(OS_ANDROID)
-  // Flags only available in specific builds, for which to display a warning
-  // "the flag is not implemented in this build", if necessary.
-  struct {
-    const char* name;
-    bool is_invalid;
-  } conditional_flags[] = {
-      {switches::kEnableHeapProfiling,
-       base::trace_event::MemoryDumpManager::
-               GetHeapProfilingModeFromCommandLine() ==
-           base::trace_event::kHeapProfilingModeInvalid},
-  };
-  for (auto conditional_flag : conditional_flags) {
-    if (conditional_flag.is_invalid) {
-      ShowBadFlagsInfoBar(web_contents, IDS_UNIMPLEMENTED_FLAGS_WARNING_MESSAGE,
-                          conditional_flag.name);
-      return;
-    }
-  }
-
   for (const char* flag : kBadFlags) {
     if (base::CommandLine::ForCurrentProcess()->HasSwitch(flag)) {
       ShowBadFlagsInfoBar(web_contents, IDS_BAD_FLAGS_WARNING_MESSAGE, flag);
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
index 8dcc110..d1fe741 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -11,6 +11,7 @@
 #include "components/autofill/core/browser/suggestion.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/native_theme/native_theme.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/image_view.h"
@@ -59,8 +60,8 @@
       frontend_id ==
           autofill::POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE;
 
-  SetFocusBehavior(is_separator_ ? FocusBehavior::ALWAYS
-                                 : FocusBehavior::NEVER);
+  SetFocusBehavior(is_separator_ ? FocusBehavior::NEVER
+                                 : FocusBehavior::ALWAYS);
   CreateContent();
 }
 
@@ -73,6 +74,7 @@
     return;
 
   is_selected_ = is_selected;
+  NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true);
   RefreshStyle();
 }
 
@@ -137,8 +139,32 @@
 }
 
 void AutofillPopupRowView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
-  node_data->role = ax::mojom::Role::kMenuItem;
   node_data->SetName(controller_->GetSuggestionAt(line_number_).value);
+
+  if (is_separator_) {
+    // Separators are not selectable.
+    node_data->role = ax::mojom::Role::kSplitter;
+  } else {
+    // Options are selectable.
+    node_data->role = ax::mojom::Role::kMenuItem;
+    node_data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
+                                is_selected_);
+
+    // Compute set size and position in set, which must not include separators.
+    int set_size = 0;
+    int pos_in_set = line_number_ + 1;
+    for (int i = 0; i < controller_->GetLineCount(); ++i) {
+      if (controller_->GetSuggestionAt(i).frontend_id ==
+          autofill::POPUP_ITEM_ID_SEPARATOR) {
+        if (i < line_number_)
+          --pos_in_set;
+      } else {
+        ++set_size;
+      }
+    }
+    node_data->AddIntAttribute(ax::mojom::IntAttribute::kSetSize, set_size);
+    node_data->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, pos_in_set);
+  }
 }
 
 void AutofillPopupRowView::CreateContent() {
@@ -233,11 +259,31 @@
   return size;
 }
 
+void AutofillPopupViewNativeViews::VisibilityChanged(View* starting_from,
+                                                     bool is_visible) {
+  if (is_visible) {
+    GetViewAccessibility().OnAutofillShown();
+  } else {
+    GetViewAccessibility().OnAutofillHidden();
+    NotifyAccessibilityEvent(ax::mojom::Event::kMenuEnd, true);
+  }
+}
+
 void AutofillPopupViewNativeViews::OnSelectedRowChanged(
     base::Optional<int> previous_row_selection,
     base::Optional<int> current_row_selection) {
-  if (previous_row_selection)
+  if (previous_row_selection) {
     rows_[*previous_row_selection]->SetSelected(false);
+  } else {
+    // Fire this the first time a row is selected. By firing this and the
+    // matching kMenuEnd event, we are telling screen readers that the focus
+    // is only changing temporarily, and the screen reader will restore the
+    // focus back to the appropriate textfield when the menu closes.
+    // This is deferred until the first focus so that the screen reader doesn't
+    // treat the textfield as unfocused while the user edits, just because
+    // autofill options are visible.
+    NotifyAccessibilityEvent(ax::mojom::Event::kMenuStart, true);
+  }
 
   if (current_row_selection)
     rows_[*current_row_selection]->SetSelected(true);
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h
index 8823f71..49f4c55 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h
@@ -98,6 +98,9 @@
   void OnMouseMoved(const ui::MouseEvent& event) override {}
 
  private:
+  // views::View:
+  void VisibilityChanged(View* starting_from, bool is_visible) override;
+
   void OnSelectedRowChanged(base::Optional<int> previous_row_selection,
                             base::Optional<int> current_row_selection) override;
   void OnSuggestionsChanged() override;
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
index 326832b..255c746 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
@@ -10,10 +10,12 @@
 #include "build/build_config.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
 #include "chrome/browser/ui/autofill/autofill_popup_layout_model.h"
+#include "chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h"
 #include "components/autofill/core/browser/popup_item_ids.h"
 #include "components/autofill/core/browser/suggestion.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_node_data.h"
 #include "ui/aura/test/aura_test_base.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/test/event_generator.h"
@@ -170,6 +172,45 @@
   view()->Hide();
 }
 
+TEST_F(AutofillPopupViewNativeViewsTest, AccessibilityTest) {
+  CreateAndShowView({autofill::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY,
+                     autofill::POPUP_ITEM_ID_SEPARATOR,
+                     autofill::POPUP_ITEM_ID_AUTOFILL_OPTIONS});
+
+  // Select first item.
+  static_cast<autofill::AutofillPopupRowView*>(view()->child_at(0))
+      ->SetSelected(true);
+
+  EXPECT_EQ(view()->child_count(), 3);
+
+  // Item 0.
+  ui::AXNodeData node_data_0;
+  view()->child_at(0)->GetAccessibleNodeData(&node_data_0);
+  EXPECT_EQ(ax::mojom::Role::kMenuItem, node_data_0.role);
+  EXPECT_EQ(1, node_data_0.GetIntAttribute(ax::mojom::IntAttribute::kPosInSet));
+  EXPECT_EQ(2, node_data_0.GetIntAttribute(ax::mojom::IntAttribute::kSetSize));
+  EXPECT_TRUE(
+      node_data_0.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected));
+
+  // Item 1 (separator).
+  ui::AXNodeData node_data_1;
+  view()->child_at(1)->GetAccessibleNodeData(&node_data_1);
+  EXPECT_FALSE(node_data_1.HasIntAttribute(ax::mojom::IntAttribute::kPosInSet));
+  EXPECT_FALSE(node_data_1.HasIntAttribute(ax::mojom::IntAttribute::kSetSize));
+  EXPECT_EQ(ax::mojom::Role::kSplitter, node_data_1.role);
+  EXPECT_FALSE(
+      node_data_1.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected));
+
+  // Item 2.
+  ui::AXNodeData node_data_2;
+  view()->child_at(2)->GetAccessibleNodeData(&node_data_2);
+  EXPECT_EQ(2, node_data_2.GetIntAttribute(ax::mojom::IntAttribute::kPosInSet));
+  EXPECT_EQ(2, node_data_2.GetIntAttribute(ax::mojom::IntAttribute::kSetSize));
+  EXPECT_EQ(ax::mojom::Role::kMenuItem, node_data_2.role);
+  EXPECT_FALSE(
+      node_data_2.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected));
+}
+
 TEST_P(AutofillPopupViewNativeViewsForEveryTypeTest, ShowClickTest) {
   const TypeClicks& click = GetParam();
   CreateAndShowView({click.id});
diff --git a/chrome/browser/ui/views/download/download_shelf_view.cc b/chrome/browser/ui/views/download/download_shelf_view.cc
index 642148e7..b952f924 100644
--- a/chrome/browser/ui/views/download/download_shelf_view.cc
+++ b/chrome/browser/ui/views/download/download_shelf_view.cc
@@ -342,7 +342,7 @@
       GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR)));
 
   views::SetImageFromVectorIcon(
-      close_button_, vector_icons::kClose16Icon,
+      close_button_, vector_icons::kCloseRoundedIcon,
       DownloadItemView::GetTextColorForThemeProvider(GetThemeProvider()));
 }
 
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc
index 42593d01..b3ace6f 100644
--- a/chrome/browser/ui/views/find_bar_view.cc
+++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -465,6 +465,6 @@
                                 base_icon_color);
   views::SetImageFromVectorIcon(find_next_button_, kCaretDownIcon,
                                 base_icon_color);
-  views::SetImageFromVectorIcon(close_button_, vector_icons::kClose16Icon,
+  views::SetImageFromVectorIcon(close_button_, vector_icons::kCloseRoundedIcon,
                                 base_icon_color);
 }
diff --git a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
index 27078703..9a7b1103 100644
--- a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
+++ b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
@@ -26,8 +26,8 @@
   SetInkDropMode(InkDropMode::ON);
   // Disable focus ring for consistency with sibling buttons and AppMenuButton.
   SetFocusPainter(nullptr);
-  // We have no need for a border, native theme borders can cause our menu icon
-  // to get cropped, see https://crbug.com/831968.
+  // Avoid the native theme border, which would crop the icon (see
+  // https://crbug.com/831968).
   SetBorder(nullptr);
   // This name is guaranteed not to change during the lifetime of this button.
   // Get the app name only, aka "Google Docs" instead of "My Doc - Google Docs",
diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc
index 5bb6b84..1e0fde6 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.cc
+++ b/chrome/browser/ui/views/infobars/infobar_view.cc
@@ -112,7 +112,7 @@
   close_button_ = views::CreateVectorImageButton(this);
   // This is the wrong color, but allows the button's size to be computed
   // correctly.  We'll reset this with the correct color in OnThemeChanged().
-  views::SetImageFromVectorIcon(close_button_, vector_icons::kClose16Icon,
+  views::SetImageFromVectorIcon(close_button_, vector_icons::kCloseRoundedIcon,
                                 gfx::kPlaceholderColor);
   close_button_->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
@@ -216,7 +216,7 @@
   SetBackground(views::CreateSolidBackground(background_color));
 
   const SkColor text_color = GetColor(kTextColor);
-  views::SetImageFromVectorIcon(close_button_, vector_icons::kClose16Icon,
+  views::SetImageFromVectorIcon(close_button_, vector_icons::kCloseRoundedIcon,
                                 text_color);
 
   for (int i = 0; i < child_count(); ++i) {
diff --git a/chrome/browser/ui/views/infobars/infobar_view_unittest.cc b/chrome/browser/ui/views/infobars/infobar_view_unittest.cc
index 444f1fe..57e7937 100644
--- a/chrome/browser/ui/views/infobars/infobar_view_unittest.cc
+++ b/chrome/browser/ui/views/infobars/infobar_view_unittest.cc
@@ -36,6 +36,13 @@
     return InfoBarService::FromWebContents(web_contents_);
   }
 
+  // Detaches |infobar_container_view_| from infobar_service(), so that newly-
+  // created infobars will not be placed in a container.  This can be used to
+  // simulate creating an infobar in a background tab.
+  void DetachContainer() {
+    infobar_container_view_.ChangeInfoBarManager(nullptr);
+  }
+
  private:
   content::TestBrowserThreadBundle thread_bundle_;
   TestingProfile profile_;
@@ -53,3 +60,14 @@
     EXPECT_EQ(i > 0, infobar->ShouldDrawSeparator());
   }
 }
+
+// Regression test for crbug.com/834728 .
+TEST_F(InfoBarViewTest, LayoutOnHiddenInfoBar) {
+  // Calling Layout() on an infobar inside a container should not crash.
+  InfoBarView* infobar = TestInfoBarDelegate::Create(infobar_service());
+  ASSERT_TRUE(infobar);
+  infobar->Layout();
+  // Neither should calling it on an infobar not in a container.
+  DetachContainer();
+  infobar->Layout();
+}
diff --git a/chrome/browser/ui/views/page_info/chosen_object_view.cc b/chrome/browser/ui/views/page_info/chosen_object_view.cc
index 3e291cf..c426974 100644
--- a/chrome/browser/ui/views/page_info/chosen_object_view.cc
+++ b/chrome/browser/ui/views/page_info/chosen_object_view.cc
@@ -76,7 +76,7 @@
   if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
     delete_button_ = views::CreateVectorImageButton(this);
     views::SetImageFromVectorIcon(
-        delete_button_, vector_icons::kClose16Icon,
+        delete_button_, vector_icons::kCloseRoundedIcon,
         views::style::GetColor(*this, CONTEXT_BODY_TEXT_LARGE,
                                views::style::STYLE_PRIMARY));
 
diff --git a/chrome/browser/ui/views/profiles/user_manager_view.cc b/chrome/browser/ui/views/profiles/user_manager_view.cc
index b7fce4d4..07ed21be 100644
--- a/chrome/browser/ui/views/profiles/user_manager_view.cc
+++ b/chrome/browser/ui/views/profiles/user_manager_view.cc
@@ -46,6 +46,10 @@
 #include "ui/views/win/hwnd_util.h"
 #endif
 
+#if defined(OS_MACOSX)
+#include "chrome/browser/app_controller_mac.h"
+#endif
+
 namespace {
 
 // An open User Manager window. There can only be one open at a time. This
@@ -151,6 +155,10 @@
     // active profile to Guest.
     profiles::SetActiveProfileToGuestIfLocked();
 
+#if defined(OS_MACOSX)
+    app_controller_mac::CreateGuestProfileIfNeeded();
+#endif
+
     // Note the time we started opening the User Manager.
     g_user_manager_view->set_user_manager_started_showing(base::Time::Now());
 
@@ -379,6 +387,10 @@
   // active profile to Guest.
   profiles::SetActiveProfileToGuestIfLocked();
 
+#if defined(OS_MACOSX)
+  app_controller_mac::CreateGuestProfileIfNeeded();
+#endif
+
   DCHECK(!g_user_manager_view);
   g_user_manager_view =
       instance.release();  // |g_user_manager_view| takes over ownership.
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 255fb71..53b1fc7cc 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -275,8 +275,7 @@
   if (!network_portal_detector_) {
     NetworkPortalDetectorImpl* detector = new NetworkPortalDetectorImpl(
         g_browser_process->system_network_context_manager()
-            ->GetURLLoaderFactory(),
-        false);
+            ->GetURLLoaderFactory());
     detector->set_portal_test_url(GURL(kRestrictiveProxyURL));
     network_portal_detector_.reset(detector);
     network_portal_detector_->AddObserver(this);
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 40285b1..c58e5f9 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -116,6 +116,7 @@
 const char kEnrollmentJSPath[] = "enrollment.js";
 const char kArcAssistantLogoPath[] = "assistant_logo.png";
 const char kArcPlaystoreCSSPath[] = "playstore.css";
+const char kArcOverlayCSSPath[] = "overlay.css";
 const char kArcPlaystoreJSPath[] = "playstore.js";
 const char kArcPlaystoreLogoPath[] = "playstore.svg";
 const char kProductLogoPath[] = "product-logo.png";
@@ -169,7 +170,8 @@
   // No #else section here as Sync Settings screen is Chrome-specific.
 #endif
 
-  // Required for postprocessing of Goolge PlayStore Terms.
+  // Required for postprocessing of Goolge PlayStore Terms and Overlay help.
+  source->AddResourcePath(kArcOverlayCSSPath, IDR_ARC_SUPPORT_OVERLAY_CSS);
   source->AddResourcePath(kArcPlaystoreCSSPath, IDR_ARC_SUPPORT_PLAYSTORE_CSS);
   source->AddResourcePath(kArcPlaystoreJSPath, IDR_ARC_SUPPORT_PLAYSTORE_JS);
   source->AddResourcePath(kArcPlaystoreLogoPath,
diff --git a/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc b/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc
index bf9bf597..2b653ec 100644
--- a/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc
@@ -31,7 +31,11 @@
     const char* name;
     int id;
   } kLocalizedStrings[] = {
-      {"title", IDS_MULTIDEVICE_SETUP_DIALOG_TITLE}, {"cancel", IDS_CANCEL},
+      {"accept", IDS_MULTIDEVICE_SETUP_ACCEPT_LABEL},
+      {"cancel", IDS_CANCEL},
+      {"done", IDS_DONE},
+      {"title", IDS_MULTIDEVICE_SETUP_DIALOG_TITLE},
+      {"tryAgain", IDS_MULTIDEVICE_SETUP_TRY_AGAIN_LABEL},
   };
 
   for (const auto& entry : kLocalizedStrings)
diff --git a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_browsertest.js b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_browsertest.js
deleted file mode 100644
index 85ec336..0000000
--- a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_browsertest.js
+++ /dev/null
@@ -1,269 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-GEN('#include "base/command_line.h"');
-GEN('#include "chrome/common/chrome_features.h"');
-
-/**
- * TestFixture for kiosk app settings WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function KioskAppSettingsWebUITest() {}
-
-KioskAppSettingsWebUITest.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /**
-   * Browse to the kiosk app settings page.
-   */
-  browsePreload: 'chrome://extensions/',
-
-  /** @override */
-  commandLineSwitches: [{
-    switchName: 'enable-consumer-kiosk',
-  }],
-
-  /** @override */
-  featureList: ['', 'features::kMaterialDesignExtensions'],
-
-  /**
-   * Mock settings data.
-   * @private
-   */
-  settings_: {
-    apps: [
-      {
-        id: 'app_1',
-        name: 'App1 Name',
-        iconURL: '',
-        autoLaunch: false,
-        isLoading: false,
-      },
-      {
-        id: 'app_2',
-        name: '',  // no name
-        iconURL: '',
-        autoLaunch: false,
-        isLoading: true,
-      },
-    ],
-    disableBailout: false,
-    hasAutoLaunchApp: false
-  },
-
-  /**
-   * Register a mock dictionary handler.
-   */
-  preLoad: function() {
-    this.makeAndRegisterMockHandler(
-        ['getKioskAppSettings',
-         'addKioskApp',
-         'removeKioskApp',
-         'enableKioskAutoLaunch',
-         'disableKioskAutoLaunch'
-        ]);
-    this.mockHandler.stubs().getKioskAppSettings(ANYTHING).will(
-        callFunction(function() {
-          extensions.KioskAppsOverlay.setSettings(this.settings_);
-        }.bind(this)));
-    this.mockHandler.stubs().addKioskApp(ANYTHING);
-    this.mockHandler.stubs().removeKioskApp(ANYTHING);
-    this.mockHandler.stubs().enableKioskAutoLaunch(ANYTHING);
-    this.mockHandler.stubs().disableKioskAutoLaunch(ANYTHING);
-  },
-
-  setUp: function() {
-    // Shows the kiosk apps management overlay.
-    cr.dispatchSimpleEvent($('add-kiosk-app'), 'click');
-  }
-};
-
-// Test opening kiosk app settings has correct location and app items have
-// correct label.
-TEST_F('KioskAppSettingsWebUITest', 'testOpenKioskAppSettings', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  var appItems = $('kiosk-app-list').items;
-  assertEquals(this.settings_.apps.length, appItems.length);
-  assertEquals(this.settings_.apps[0].name, appItems[0].name.textContent);
-  assertFalse(appItems[0].icon.classList.contains('spinner'));
-  assertEquals(this.settings_.apps[1].id, appItems[1].name.textContent);
-  assertTrue(appItems[1].icon.classList.contains('spinner'));
-});
-
-// Verify that enter key on 'kiosk-app-id-edit' adds an app.
-TEST_F('KioskAppSettingsWebUITest', 'testAddKioskApp', function() {
-  var testAppId = 'app_3';
-  var appIdInput = $('kiosk-app-id-edit');
-
-  appIdInput.value = testAppId;
-
-  this.mockHandler.expects(once()).addKioskApp([testAppId]);
-  var keypress = new KeyboardEvent('keypress', {cancelable: true, bubbles: true, key: 'Enter'});
-  appIdInput.dispatchEvent(keypress);
-});
-
-// Verify that the 'kiosk-app-add' button adds an app.
-TEST_F('KioskAppSettingsWebUITest', 'testAddKioskAppByAddButton', function() {
-  var testAppId = 'app_3';
-  $('kiosk-app-id-edit').value = testAppId;
-
-  this.mockHandler.expects(once()).addKioskApp([testAppId]);
-  cr.dispatchSimpleEvent($('kiosk-app-add'), 'click');
-});
-
-// Verify that the 'done' button adds an app.
-TEST_F('KioskAppSettingsWebUITest', 'testAddKioskAppByDoneButton', function() {
-  var testAppId = 'app_3';
-  $('kiosk-app-id-edit').value = testAppId;
-
-  this.mockHandler.expects(once()).addKioskApp([testAppId]);
-  cr.dispatchSimpleEvent($('kiosk-options-overlay-confirm'), 'click');
-});
-
-// Test the row delete button.
-TEST_F('KioskAppSettingsWebUITest', 'testRemoveKioskApp', function() {
-  var appItem = $('kiosk-app-list').items[0];
-  var appId = appItem.data.id;
-
-  this.mockHandler.expects(once()).removeKioskApp([appId]);
-  appItem.querySelector('.row-delete-button').click();
-});
-
-// Test enable/disable auto launch buttons.
-TEST_F('KioskAppSettingsWebUITest', 'testEnableDisableAutoLaunch', function() {
-  var appItem = $('kiosk-app-list').items[0];
-  var appId = appItem.data.id;
-
-  var enableAutoLaunchCalled = false;
-  this.mockHandler.expects(once()).enableKioskAutoLaunch([appId]).
-      will(callFunction(function() {
-        enableAutoLaunchCalled = true;
-      }));
-  appItem.querySelector('.enable-auto-launch-button').click();
-  expectTrue(enableAutoLaunchCalled);
-
-  var disableAutoLaunchCalled = false;
-  this.mockHandler.expects(once()).disableKioskAutoLaunch([appId]).
-      will(callFunction(function() {
-        disableAutoLaunchCalled = true;
-      }));
-  appItem.querySelector('.disable-auto-launch-button').click();
-  expectTrue(disableAutoLaunchCalled);
-});
-
-// Verify that updateApp updates app info.
-TEST_F('KioskAppSettingsWebUITest', 'testUpdateApp', function() {
-  var appItems = $('kiosk-app-list').items;
-  assertEquals(appItems[1].data.id, 'app_2');
-  expectEquals(appItems[1].data.name, '');
-  expectTrue(appItems[1].icon.classList.contains('spinner'));
-  expectFalse(appItems[1].autoLaunch);
-
-  // New data changes name, autoLaunch and isLoading.
-  var newName = 'Name for App2';
-  var newApp2 = {
-    id: 'app_2',
-    name: newName,
-    iconURL: '',
-    autoLaunch: true,
-    isLoading: false,
-  };
-  extensions.KioskAppsOverlay.updateApp(newApp2);
-
-  assertEquals('app_2', appItems[1].data.id);
-  expectEquals(newName, appItems[1].data.name, newName);
-  expectEquals(newName, appItems[1].name.textContent);
-  expectFalse(appItems[1].icon.classList.contains('spinner'));
-  expectTrue(appItems[1].autoLaunch);
-});
-
-// Verify that showError makes error banner visible.
-TEST_F('KioskAppSettingsWebUITest', 'testShowError', function() {
-  extensions.KioskAppsOverlay.showError('A bad app');
-  expectTrue($('kiosk-apps-error-banner').classList.contains('visible'));
-});
-
-// Verify that checking disable bailout checkbox brings up confirmation UI and
-// the check only remains when the confirmation UI is acknowledged.
-TEST_F('KioskAppSettingsWebUITest', 'testCheckDisableBailout', function() {
-  var checkbox = $('kiosk-disable-bailout-shortcut');
-  var confirmOverlay = $('kiosk-disable-bailout-confirm-overlay');
-  expectFalse(confirmOverlay.classList.contains('showing'));
-
-  // Un-checking the box does not trigger confirmation.
-  checkbox.checked = false;
-  cr.dispatchSimpleEvent(checkbox, 'change');
-  expectFalse(confirmOverlay.classList.contains('showing'));
-
-  // Checking the box trigger confirmation.
-  checkbox.checked = true;
-  cr.dispatchSimpleEvent(checkbox, 'change');
-  expectTrue(confirmOverlay.classList.contains('showing'));
-
-  // Confirm it and the check remains.
-  cr.dispatchSimpleEvent($('kiosk-disable-bailout-confirm-button'), 'click');
-  expectTrue(checkbox.checked);
-  expectFalse(confirmOverlay.classList.contains('showing'));
-
-  // And canceling resets the check.
-  checkbox.checked = true;
-  cr.dispatchSimpleEvent(checkbox, 'change');
-  expectTrue(confirmOverlay.classList.contains('showing'));
-  cr.dispatchSimpleEvent($('kiosk-disable-bailout-cancel-button'), 'click');
-  expectFalse(checkbox.checked);
-  expectFalse(confirmOverlay.classList.contains('showing'));
-});
-
-// Verify that disable bailout checkbox is hidden without kiosk auto launch.
-TEST_F('KioskAppSettingsWebUITest', 'testHideDisableBailout', function() {
-  var checkbox = $('kiosk-disable-bailout-shortcut');
-  var kioskEnabledSettings = {
-    kioskEnabled: true,
-    autoLaunchEnabled: true
-  };
-  extensions.KioskAppsOverlay.enableKiosk(kioskEnabledSettings);
-  expectFalse(checkbox.parentNode.hidden);
-
-  kioskEnabledSettings.autoLaunchEnabled = false;
-  extensions.KioskAppsOverlay.enableKiosk(kioskEnabledSettings);
-  expectTrue(checkbox.parentNode.hidden);
-});
-
-// Verify that disable bailout checkbox is disabled with no auto launch app.
-TEST_F('KioskAppSettingsWebUITest', 'testAllowDisableBailout', function() {
-  var checkbox = $('kiosk-disable-bailout-shortcut');
-
-  this.settings_.hasAutoLaunchApp = false;
-  extensions.KioskAppsOverlay.setSettings(this.settings_);
-  expectTrue(checkbox.disabled);
-
-  this.settings_.hasAutoLaunchApp = true;
-  extensions.KioskAppsOverlay.setSettings(this.settings_);
-  expectFalse(checkbox.disabled);
-});
-
-/**
- * TestFixture for kiosk app settings when consumer kiosk is disabled.
- * @extends {testing.Test}
- * @constructor
- */
-function NoConsumerKioskWebUITest() {}
-
-NoConsumerKioskWebUITest.prototype = {
-  __proto__: KioskAppSettingsWebUITest.prototype,
-
-  /** @override */
-  commandLineSwitches: [],
-
-  /** @override */
-  setUp: function() {}
-};
-
-// Test kiosk app settings are not visible when consumer kiosk is disabled.
-TEST_F('NoConsumerKioskWebUITest', 'settingsHidden', function() {
-  assertEquals(this.browsePreload, document.location.href);
-  assertTrue($('add-kiosk-app').hidden);
-});
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
deleted file mode 100644
index 7d4bef5..0000000
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
+++ /dev/null
@@ -1,539 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// TODO(dbeam): test for loading unpacked extensions?
-
-GEN('#include "chrome/browser/ui/webui/extensions/' +
-    'extension_settings_browsertest.h"');
-GEN('#include "chrome/common/chrome_features.h"');
-
-// The id of the extension from |InstallGoodExtension|.
-var GOOD_EXTENSION_ID = 'ldnnhddmnhbkjipkidpdiheffobcpfmf';
-
-// The id of the extension from |InstallErrorsExtension|.
-var ERROR_EXTENSION_ID = 'pdlpifnclfacjobnmbpngemkalkjamnf';
-
-/**
- * Test C++ fixture for settings WebUI testing.
- * @constructor
- * @extends {testing.Test}
- */
-function ExtensionSettingsUIBrowserTest() {}
-
-/**
- * TestFixture for extension settings WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function ExtensionSettingsWebUITest() {}
-
-ExtensionSettingsWebUITest.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /** @override */
-  isAsync: true,
-
-  /** @override */
-  runAccessibilityChecks: true,
-
-  /** @override */
-  accessibilityIssuesAreErrors: true,
-
-  /**
-   * A URL to load before starting each test.
-   * @type {string}
-   * @const
-   */
-  browsePreload: 'chrome://extensions/',
-
-  /** @override */
-  typedefCppFixture: 'ExtensionSettingsUIBrowserTest',
-
-  /** @override */
-  featureList: ['', 'features::kMaterialDesignExtensions'],
-
-  /** @override */
-  setUp: function() {
-    testing.Test.prototype.setUp.call(this);
-    testing.Test.disableAnimationsAndTransitions();
-
-    // Enable when failure is resolved.
-    // AX_ARIA_08: http://crbug.com/560903
-    this.accessibilityAuditConfig.ignoreSelectors(
-      'requiredOwnedAriaRoleMissing',
-      '#kiosk-app-list');
-  },
-
-  /**
-   * Holds an array of steps that should happen in order during a test.
-   * The last step should be |testDone|.
-   * @protected {Array<!Function>}
-   * */
-  steps: [],
-
-  /**
-   * Advances to the next step in the test. Every step should call this.
-   * @protected
-   * */
-  nextStep: function() {
-    assertTrue(this.steps.length > 0);
-    this.steps.shift().call(this);
-  },
-
-  /**
-   * Will wait for the page to load before calling the next step. This should be
-   * the first step in every test.
-   * @protected
-   * */
-  waitForPageLoad: function() {
-    assertEquals(this.browsePreload, document.location.href);
-    var extensionList = getRequiredElement('extension-settings-list');
-    extensionList.loadFinished.then(this.nextStep.bind(this));
-  },
-
-  /** @protected */
-  enableDeveloperMode: function() {
-    // Toggling developer mode triggers a page update, so we need to be able to
-    // wait for the update to finish.
-    $('extension-settings-list').resetLoadFinished();
-    var waitForPage = this.waitForPageLoad.bind(this);
-    document.addEventListener('devControlsVisibilityUpdated',
-                              function devCallback() {
-      // Callback should only be handled once.
-      document.removeEventListener('devControlsVisibilityUpdated', devCallback);
-
-      chrome.developerPrivate.getProfileConfiguration(function(profileInfo) {
-        assertTrue(extensionSettings.classList.contains('dev-mode'));
-        assertTrue(profileInfo.inDeveloperMode);
-
-        // This event isn't thrown because transitions are disabled.
-        // Ensure transition here so that any dependent code does not break.
-        ensureTransitionEndEvent($('dev-controls'), 0);
-
-        waitForPage();
-      });
-    });
-
-    var extensionSettings = getRequiredElement('extension-settings');
-    assertFalse(extensionSettings.classList.contains('dev-mode'));
-    $('toggle-dev-on').click();
-  },
-
-  /** @protected */
-  testDeveloperMode: function() {
-    var next = this.nextStep.bind(this);
-    var checkDevModeIsOff = function() {
-      chrome.developerPrivate.getProfileConfiguration(function(profileInfo) {
-        assertFalse(profileInfo.inDeveloperMode);
-        next();
-      });
-    };
-    this.steps = [this.waitForPageLoad,
-                  checkDevModeIsOff,
-                  this.enableDeveloperMode,
-                  testDone];
-    this.nextStep();
-  },
-};
-
-// Flaky: http://crbug.com/505506.
-// Verify that developer mode doesn't change behavior when the number of
-// extensions changes.
-TEST_F('ExtensionSettingsWebUITest', 'DISABLED_testDeveloperModeNoExtensions',
-       function() {
-  this.testDeveloperMode();
-});
-
-TEST_F('ExtensionSettingsWebUITest', 'testEmptyExtensionList', function() {
-  var verifyListIsHiddenAndEmpty = function() {
-    assertTrue($('extension-list-wrapper').hidden);
-    assertFalse($('no-extensions').hidden);
-    assertEquals(0, $('extension-settings-list').childNodes.length);
-    this.nextStep();
-  };
-
-  this.steps = [this.waitForPageLoad, verifyListIsHiddenAndEmpty, testDone];
-  this.nextStep();
-});
-
-TEST_F('ExtensionSettingsWebUITest', 'testChromeSendHandled', function() {
-  var testPackExtenion = function() {
-    // This dialog should be hidden at first.
-    assertFalse($('pack-extension-overlay').classList.contains('showing'));
-
-    // Show the dialog, which triggers a chrome.send() for metrics purposes.
-    cr.dispatchSimpleEvent($('pack-extension'), 'click');
-    assertTrue($('pack-extension-overlay').classList.contains('showing'));
-    this.nextStep();
-  };
-
-  this.steps = [this.waitForPageLoad, testPackExtenion, testDone];
-  this.nextStep();
-});
-
-/**
- * @param {chrome.developerPrivate.EventType} eventType
- * @param {function():void} callback
- * @constructor
- */
-function UpdateListener(eventType, callback) {
-  this.callback_ = callback;
-  this.eventType_ = eventType;
-  this.onItemStateChangedListener_ = this.onItemStateChanged_.bind(this);
-  chrome.developerPrivate.onItemStateChanged.addListener(
-      this.onItemStateChangedListener_);
-}
-
-UpdateListener.prototype = {
-  /** @private */
-  onItemStateChanged_: function(data) {
-    if (this.eventType_ == data.event_type) {
-      window.setTimeout(function() {
-        chrome.developerPrivate.onItemStateChanged.removeListener(
-            this.onItemStateChangedListener_);
-        this.callback_();
-      }.bind(this), 0);
-    }
-  }
-};
-
-function BasicExtensionSettingsWebUITest() {}
-
-BasicExtensionSettingsWebUITest.prototype = {
-  __proto__: ExtensionSettingsWebUITest.prototype,
-
-  /** @override */
-  testGenPreamble: function() {
-    // Install multiple types of extensions to ensure we handle each type.
-    // TODO(devlin): There are more types to add here.
-    GEN('  InstallGoodExtension();');
-    GEN('  InstallErrorsExtension();');
-    GEN('  InstallSharedModule();');
-    GEN('  InstallPackagedApp();');
-
-    GEN('  SetAutoConfirmUninstall();');
-  },
-
-  /** @protected */
-  verifyDisabledWorks: function() {
-    var listener = new UpdateListener(
-        chrome.developerPrivate.EventType.UNLOADED,
-        function() {
-      var node = getRequiredElement(GOOD_EXTENSION_ID);
-      assertTrue(node.classList.contains('inactive-extension'));
-      this.nextStep();
-    }.bind(this));
-    chrome.management.setEnabled(GOOD_EXTENSION_ID, false);
-  },
-
-  /** @protected */
-  verifyEnabledWorks: function() {
-    var listener = new UpdateListener(
-        chrome.developerPrivate.EventType.LOADED,
-        function() {
-      var node = getRequiredElement(GOOD_EXTENSION_ID);
-      assertFalse(node.classList.contains('inactive-extension'));
-      this.nextStep();
-    }.bind(this));
-    chrome.management.setEnabled(GOOD_EXTENSION_ID, true);
-  },
-
-  /** @protected */
-  verifyUninstallWorks: function() {
-    var listener = new UpdateListener(
-        chrome.developerPrivate.EventType.UNINSTALLED,
-        function() {
-      assertEquals(null, $(GOOD_EXTENSION_ID));
-      this.nextStep();
-    }.bind(this));
-    chrome.test.runWithUserGesture(function() {
-      chrome.management.uninstall(GOOD_EXTENSION_ID);
-    });
-  },
-};
-
-// Verify that developer mode doesn't change behavior when the number of
-// extensions changes.
-TEST_F('BasicExtensionSettingsWebUITest', 'testDeveloperModeManyExtensions',
-       function() {
-  this.testDeveloperMode();
-});
-
-TEST_F('BasicExtensionSettingsWebUITest', 'testDisable', function() {
-  this.steps = [this.waitForPageLoad, this.verifyDisabledWorks, testDone];
-  this.nextStep();
-});
-
-TEST_F('BasicExtensionSettingsWebUITest', 'testEnable', function() {
-  this.steps = [this.waitForPageLoad,
-                this.verifyDisabledWorks,
-                this.verifyEnabledWorks,
-                testDone];
-  this.nextStep();
-});
-
-TEST_F('BasicExtensionSettingsWebUITest', 'testUninstall', function() {
-  this.steps = [this.waitForPageLoad, this.verifyUninstallWorks, testDone];
-  this.nextStep();
-});
-
-TEST_F('BasicExtensionSettingsWebUITest', 'testNonEmptyExtensionList',
-       function() {
-  var verifyListIsNotHiddenAndEmpty = function() {
-    assertFalse($('extension-list-wrapper').hidden);
-    assertTrue($('no-extensions').hidden);
-    assertGT($('extension-settings-list').childNodes.length, 0);
-    this.nextStep();
-  };
-
-  this.steps = [this.waitForPageLoad, verifyListIsNotHiddenAndEmpty, testDone];
-  this.nextStep();
-});
-
-function AutoScrollExtensionSettingsWebUITest() {}
-
-/**
- * A variation for testing auto-scroll when an id query param is passed in the
- * url.
- * @constructor
- * @extends {BasicExtensionSettingsWebUITest}
- */
-AutoScrollExtensionSettingsWebUITest.prototype = {
-  __proto__: BasicExtensionSettingsWebUITest.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://extensions/?id=' + GOOD_EXTENSION_ID,
-
-  /** @override */
-  testGenPreamble: function() {
-    BasicExtensionSettingsWebUITest.prototype.testGenPreamble.call(this);
-    // The window needs to be sufficiently small in order to ensure a scroll bar
-    // is available.
-    GEN('  ShrinkWebContentsView();');
-  },
-};
-
-TEST_F('AutoScrollExtensionSettingsWebUITest', 'testAutoScroll', function() {
-  var checkHasScrollbar = function() {
-    assertGT(document.scrollingElement.scrollHeight,
-             document.body.clientHeight);
-    this.nextStep();
-  };
-  var checkIsScrolled = function() {
-    assertGT(document.scrollingElement.scrollTop, 0);
-    this.nextStep();
-  };
-  var checkScrolledToTop = function() {
-    assertEquals(0, document.scrollingElement.scrollTop);
-    this.nextStep();
-  };
-  var scrollToTop = function() {
-    document.scrollingElement.scrollTop = 0;
-    this.nextStep();
-  };
-  // Test that a) autoscroll works on first page load and b) updating the
-  // page doesn't result in autoscroll triggering again.
-  this.steps = [this.waitForPageLoad,
-                checkHasScrollbar,
-                checkIsScrolled,
-                scrollToTop,
-                this.enableDeveloperMode,
-                checkScrolledToTop,
-                testDone];
-  this.nextStep();
-});
-
-function ErrorConsoleExtensionSettingsWebUITest() {}
-
-ErrorConsoleExtensionSettingsWebUITest.prototype = {
-  __proto__: ExtensionSettingsWebUITest.prototype,
-
-  /** @override */
-  testGenPreamble: function() {
-    GEN('  EnableErrorConsole();');
-    GEN('  InstallGoodExtension();');
-    GEN('  InstallErrorsExtension();');
-  },
-};
-
-// Flaky on all platforms: http://crbug.com/499884, http://crbug.com/463245.
-TEST_F('ErrorConsoleExtensionSettingsWebUITest',
-       'DISABLED_testErrorListButtonVisibility', function() {
-  var testButtonVisibility = function() {
-    var extensionList = $('extension-list-wrapper');
-
-    var visibleButtons = extensionList.querySelectorAll(
-        '.errors-link:not([hidden])');
-    expectEquals(1, visibleButtons.length);
-
-    if (visibleButtons.length > 0) {
-      var errorLink = $(ERROR_EXTENSION_ID).querySelector('.errors-link');
-      expectEquals(visibleButtons[0], errorLink);
-
-      var errorIcon = errorLink.querySelector('img');
-      expectTrue(errorIcon.classList.contains('extension-error-warning-icon'));
-    }
-
-    var hiddenButtons = extensionList.querySelectorAll('.errors-link[hidden]');
-    expectEquals(1, hiddenButtons.length);
-
-    this.nextStep();
-  };
-
-  this.steps = [this.waitForPageLoad,
-                this.enableDeveloperMode,
-                testButtonVisibility,
-                testDone];
-  this.nextStep();
-});
-
-/**
- * TestFixture for extension settings WebUI testing (commands config edition).
- * @extends {testing.Test}
- * @constructor
- */
-function SettingsCommandsExtensionSettingsWebUITest() {}
-
-SettingsCommandsExtensionSettingsWebUITest.prototype = {
-  __proto__: ExtensionSettingsWebUITest.prototype,
-
-  /**
-   * A URL to load before starting each test.
-   * @type {string}
-   * @const
-   */
-  browsePreload: 'chrome://extensions/configureCommands',
-};
-
-TEST_F('SettingsCommandsExtensionSettingsWebUITest', 'testChromeSendHandler',
-    function() {
-  // Just navigating to the page should trigger the chrome.send().
-  var assertOverlayVisible = function() {
-    assertTrue($('extension-commands-overlay').classList.contains('showing'));
-    assertEquals($('extension-commands-overlay').getAttribute('aria-hidden'),
-                 'false');
-    this.nextStep();
-  };
-
-  this.steps = [this.waitForPageLoad, assertOverlayVisible, testDone];
-  this.nextStep();
-});
-
-TEST_F('SettingsCommandsExtensionSettingsWebUITest', 'extensionSettingsUri',
-    function() {
-  var closeCommandOverlay = function() {
-    assertTrue($('extension-commands-overlay').classList.contains('showing'));
-    assertEquals($('extension-commands-overlay').getAttribute('aria-hidden'),
-                 'false');
-    assertEquals(window.location.href, 'chrome://extensions/configureCommands');
-
-    // Close command overlay.
-    $('extension-commands-dismiss').click();
-
-    assertFalse($('extension-commands-overlay').classList.contains('showing'));
-    assertEquals($('extension-commands-overlay').getAttribute('aria-hidden'),
-                 'true');
-    this.nextStep();
-  };
-
-  var checkExtensionsUrl = function() {
-    // After closing the overlay, the URL shouldn't include commands overlay
-    // reference.
-    assertEquals(window.location.href, 'chrome://extensions/');
-    this.nextStep();
-  };
-
-  this.steps = [this.waitForPageLoad,
-                closeCommandOverlay,
-                checkExtensionsUrl,
-                testDone];
-  this.nextStep();
-});
-
-/**
- * @constructor
- * @extends {ExtensionSettingsWebUITest}
- */
-function InstallGoodExtensionSettingsWebUITest() {}
-
-InstallGoodExtensionSettingsWebUITest.prototype = {
-  __proto__: ExtensionSettingsWebUITest.prototype,
-
-  /** @override */
-  testGenPreamble: function() {
-    GEN('  InstallGoodExtension();');
-  },
-
-  emptyTestForAccessibility() {
-    this.steps = [this.waitForPageLoad, testDone];
-    this.nextStep();
-  },
-};
-
-TEST_F('InstallGoodExtensionSettingsWebUITest', 'testAccessibility',
-       function() {
-  this.emptyTestForAccessibility();
-});
-
-TEST_F('InstallGoodExtensionSettingsWebUITest', 'showOptions', function() {
-  var showExtensionOptions = function() {
-    var optionsOverlay = extensions.ExtensionOptionsOverlay.getInstance();
-    optionsOverlay.setExtensionAndShow(GOOD_EXTENSION_ID, 'GOOD!', '',
-                                       this.nextStep.bind(this));
-
-    // Preferred size changes don't happen in browser tests. Just fake it.
-    document.querySelector('extensionoptions').onpreferredsizechanged(
-        {width: 500, height: 500});
-  };
-
-  this.steps = [this.waitForPageLoad, showExtensionOptions, testDone];
-  this.nextStep();
-});
-
-/**
- * @constructor
- * @extends {InstallGoodExtensionSettingsWebUITest}
- */
-function ManagedExtensionSettingsWebUITest() {}
-
-ManagedExtensionSettingsWebUITest.prototype = {
-  __proto__: InstallGoodExtensionSettingsWebUITest.prototype,
-
-  /** @override */
-  testGenPreamble: function() {
-    GEN('  AddManagedPolicyProvider();');
-    InstallGoodExtensionSettingsWebUITest.prototype.testGenPreamble.call(this);
-  },
-};
-
-TEST_F('ManagedExtensionSettingsWebUITest', 'testAccessibility', function() {
-  this.emptyTestForAccessibility();
-});
-
-/**
- * @constructor
- * @extends {InstallGoodExtensionSettingsWebUITest}
- */
-function OptionsDialogExtensionSettingsWebUITest() {}
-
-OptionsDialogExtensionSettingsWebUITest.prototype = {
-  __proto__: InstallGoodExtensionSettingsWebUITest.prototype,
-
-  setUp() {
-    InstallGoodExtensionSettingsWebUITest.prototype.setUp.call(this);
-
-    // False positive on iframe hosting the <extensionoptions> guest view.
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'focusableElementNotVisibleAndNotAriaHidden', 'iframe');
-  },
-
-  /** @override */
-  browsePreload: ExtensionSettingsWebUITest.prototype.browsePreload +
-      '?options=' + GOOD_EXTENSION_ID,
-};
-
-TEST_F('OptionsDialogExtensionSettingsWebUITest', 'testAccessibility',
-       function() {
-  this.emptyTestForAccessibility();
-});
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 207eb0e..0e6359f 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
 #include "chrome/browser/ui/webui/extensions/install_extension_handler.h"
 #include "chrome/browser/ui/webui/metrics_handler.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
@@ -54,8 +53,8 @@
 
 class ExtensionWebUiTimer : public content::WebContentsObserver {
  public:
-  explicit ExtensionWebUiTimer(content::WebContents* web_contents, bool is_md)
-      : content::WebContentsObserver(web_contents), is_md_(is_md) {}
+  explicit ExtensionWebUiTimer(content::WebContents* web_contents)
+      : content::WebContentsObserver(web_contents) {}
   ~ExtensionWebUiTimer() override {}
 
   void DidStartNavigation(
@@ -72,13 +71,8 @@
         !timer_) {  // See comment in DocumentOnLoadCompletedInMainFrame()
       return;
     }
-    if (is_md_) {
-      UMA_HISTOGRAM_TIMES("Extensions.WebUi.DocumentLoadedInMainFrameTime.MD",
-                          timer_->Elapsed());
-    } else {
-      UMA_HISTOGRAM_TIMES("Extensions.WebUi.DocumentLoadedInMainFrameTime.Uber",
-                          timer_->Elapsed());
-    }
+    UMA_HISTOGRAM_TIMES("Extensions.WebUi.DocumentLoadedInMainFrameTime.MD",
+                        timer_->Elapsed());
   }
 
   void DocumentOnLoadCompletedInMainFrame() override {
@@ -89,22 +83,14 @@
       // will receive this current callback.
       return;
     }
-    if (is_md_) {
-      UMA_HISTOGRAM_TIMES("Extensions.WebUi.LoadCompletedInMainFrame.MD",
-                          timer_->Elapsed());
-    } else {
-      UMA_HISTOGRAM_TIMES("Extensions.WebUi.LoadCompletedInMainFrame.Uber",
-                          timer_->Elapsed());
-    }
+    UMA_HISTOGRAM_TIMES("Extensions.WebUi.LoadCompletedInMainFrame.MD",
+                        timer_->Elapsed());
     timer_.reset();
   }
 
   void WebContentsDestroyed() override { delete this; }
 
  private:
-  // Whether this is the MD version of the chrome://extensions page.
-  bool is_md_;
-
   std::unique_ptr<base::ElapsedTimer> timer_;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionWebUiTimer);
@@ -390,74 +376,31 @@
   return source;
 }
 
-content::WebUIDataSource* CreateExtensionsHTMLSource() {
-  content::WebUIDataSource* source =
-      content::WebUIDataSource::Create(chrome::kChromeUIExtensionsHost);
-
-  source->SetJsonPath("strings.js");
-  source->AddResourcePath("extensions.js", IDR_EXTENSIONS_JS);
-  source->AddResourcePath("extension_command_list.js",
-                          IDR_EXTENSION_COMMAND_LIST_JS);
-  source->AddResourcePath("extension_list.js", IDR_EXTENSION_LIST_JS);
-  source->SetDefaultResource(IDR_EXTENSIONS_HTML);
-  source->DisableDenyXFrameOptions();
-  return source;
-}
-
 }  // namespace
 
 ExtensionsUI::ExtensionsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
   Profile* profile = Profile::FromWebUI(web_ui);
   content::WebUIDataSource* source = nullptr;
 
-  bool is_md =
-      base::FeatureList::IsEnabled(features::kMaterialDesignExtensions);
+  in_dev_mode_.Init(
+      prefs::kExtensionsUIDeveloperMode, profile->GetPrefs(),
+      base::Bind(&ExtensionsUI::OnDevModeChanged, base::Unretained(this)));
 
-  if (is_md) {
-    in_dev_mode_.Init(
-        prefs::kExtensionsUIDeveloperMode, profile->GetPrefs(),
-        base::Bind(&ExtensionsUI::OnDevModeChanged, base::Unretained(this)));
+  source = CreateMdExtensionsSource(*in_dev_mode_);
 
-    source = CreateMdExtensionsSource(*in_dev_mode_);
-
-    source->AddBoolean(
-        "isGuest",
+  source->AddBoolean(
+      "isGuest",
 #if defined(OS_CHROMEOS)
-        user_manager::UserManager::Get()->IsLoggedInAsGuest() ||
-            user_manager::UserManager::Get()->IsLoggedInAsPublicAccount());
+      user_manager::UserManager::Get()->IsLoggedInAsGuest() ||
+          user_manager::UserManager::Get()->IsLoggedInAsPublicAccount());
 #else
-        profile->IsOffTheRecord());
+      profile->IsOffTheRecord());
 #endif
 
-    auto install_extension_handler =
-        std::make_unique<InstallExtensionHandler>();
-    InstallExtensionHandler* handler = install_extension_handler.get();
-    web_ui->AddMessageHandler(std::move(install_extension_handler));
-    handler->GetLocalizedValues(source);
-  } else {
-    source = CreateExtensionsHTMLSource();
-
-    auto extension_settings_handler =
-        std::make_unique<ExtensionSettingsHandler>();
-    ExtensionSettingsHandler* settings_handler =
-        extension_settings_handler.get();
-    web_ui->AddMessageHandler(std::move(extension_settings_handler));
-    settings_handler->GetLocalizedValues(source);
-
-    auto extension_loader_handler =
-        std::make_unique<ExtensionLoaderHandler>(profile);
-    ExtensionLoaderHandler* loader_handler = extension_loader_handler.get();
-    web_ui->AddMessageHandler(std::move(extension_loader_handler));
-    loader_handler->GetLocalizedValues(source);
-
-    auto install_extension_handler =
-        std::make_unique<InstallExtensionHandler>();
-    InstallExtensionHandler* install_handler = install_extension_handler.get();
-    web_ui->AddMessageHandler(std::move(install_extension_handler));
-    install_handler->GetLocalizedValues(source);
-
-    web_ui->AddMessageHandler(std::make_unique<MetricsHandler>());
-  }
+  auto install_extension_handler = std::make_unique<InstallExtensionHandler>();
+  InstallExtensionHandler* handler = install_extension_handler.get();
+  web_ui->AddMessageHandler(std::move(install_extension_handler));
+  handler->GetLocalizedValues(source);
 
 #if defined(OS_CHROMEOS)
   auto kiosk_app_handler = std::make_unique<chromeos::KioskAppsHandler>(
@@ -475,7 +418,7 @@
   content::WebUIDataSource::Add(profile, source);
 
   // Handles its own lifetime.
-  new ExtensionWebUiTimer(web_ui->GetWebContents(), is_md);
+  new ExtensionWebUiTimer(web_ui->GetWebContents());
 }
 
 ExtensionsUI::~ExtensionsUI() {}
diff --git a/chrome/browser/ui/webui/policy_tool_ui_browsertest.cc b/chrome/browser/ui/webui/policy_tool_ui_browsertest.cc
index 3f812c1f..a740f55 100644
--- a/chrome/browser/ui/webui/policy_tool_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy_tool_ui_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.h"
@@ -261,7 +262,13 @@
   return value->GetString();
 }
 
-IN_PROC_BROWSER_TEST_F(PolicyToolUITest, CreatingSessionFiles) {
+// Flaky on Win buildbots. See crbug.com/832673.
+#if defined(OS_WIN)
+#define MAYBE_CreatingSessionFiles DISABLED_CreatingSessionFiles
+#else
+#define MAYBE_CreatingSessionFiles CreatingSessionFiles
+#endif
+IN_PROC_BROWSER_TEST_F(PolicyToolUITest, MAYBE_CreatingSessionFiles) {
   base::ScopedAllowBlockingForTesting allow_blocking;
   // Check that the directory is not created yet.
   EXPECT_FALSE(PathExists(GetSessionsDir()));
diff --git a/chrome/browser/vr/elements/vector_icon.cc b/chrome/browser/vr/elements/vector_icon.cc
index 3ffdda2d..0570a5d 100644
--- a/chrome/browser/vr/elements/vector_icon.cc
+++ b/chrome/browser/vr/elements/vector_icon.cc
@@ -22,13 +22,11 @@
 
   SkColor GetColor() const { return color_; }
 
-  void SetIcon(const gfx::VectorIcon* icon) {
-    SetAndDirty(&icon_no_1x_.rep, icon ? icon->rep : nullptr);
-  }
+  void SetIcon(const gfx::VectorIcon* icon) { SetAndDirty(&icon_, icon); }
 
  private:
   void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override {
-    if (icon_no_1x_.is_empty())
+    if (icon_ == nullptr || icon_->is_empty())
       return;
     cc::SkiaPaintCanvas paint_canvas(sk_canvas);
     gfx::Canvas gfx_canvas(&paint_canvas, 1.0f);
@@ -39,12 +37,12 @@
     float icon_size = size_.height();
     float icon_corner_offset = (size_.height() - icon_size) / 2;
     VectorIcon::DrawVectorIcon(
-        &gfx_canvas, icon_no_1x_, icon_size,
+        &gfx_canvas, *icon_, icon_size,
         gfx::PointF(icon_corner_offset, icon_corner_offset), color_);
   }
 
   gfx::SizeF size_;
-  gfx::VectorIcon icon_no_1x_{};
+  const gfx::VectorIcon* icon_ = nullptr;
   SkColor color_ = SK_ColorWHITE;
   DISALLOW_COPY_AND_ASSIGN(VectorIconTexture);
 };
@@ -91,12 +89,9 @@
   canvas->Translate(
       {static_cast<int>(corner.x()), static_cast<int>(corner.y())});
 
-  // Explicitly cut out the 1x version of the icon, as PaintVectorIcon draws the
-  // 1x version if device scale factor isn't set. See crbug.com/749146. If all
-  // icons end up being drawn via VectorIcon instances, this will not be
-  // required (the 1x version is automatically elided by this class).
-  gfx::VectorIcon icon_no_1x{icon.rep};
-  PaintVectorIcon(canvas, icon_no_1x, size_px, color);
+  // Don't use CreateVectorIcon() because its icon caching is not thread safe.
+  // Instead, just redraw the VectorIcon.
+  PaintVectorIcon(canvas, icon, size_px, color);
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/elements/vector_icon_unittest.cc b/chrome/browser/vr/elements/vector_icon_unittest.cc
index bf802c0..b1bd0bcf 100644
--- a/chrome/browser/vr/elements/vector_icon_unittest.cc
+++ b/chrome/browser/vr/elements/vector_icon_unittest.cc
@@ -40,7 +40,7 @@
 TEST(VectorIcon, SmokeTest) {
   UiScene scene;
   auto icon = std::make_unique<TestVectorIcon>(kMaximumWidth);
-  icon->SetIcon(vector_icons::kClose16Icon);
+  icon->SetIcon(vector_icons::kCloseRoundedIcon);
   UiTexture* texture = icon->GetTexture();
   scene.AddUiElement(kRoot, std::move(icon));
   base::TimeTicks start_time = MsToTicks(1);
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index be727494..1d0cf4ce5 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -1382,7 +1382,7 @@
       Create<DiscButton>(kWebVrTimeoutMessageButton, kPhaseForeground,
                          base::BindRepeating(&UiBrowserInterface::ExitPresent,
                                              base::Unretained(browser_)),
-                         vector_icons::kClose16Icon, audio_delegate_);
+                         vector_icons::kCloseRoundedIcon, audio_delegate_);
   button->SetVisible(false);
   button->SetTranslate(0, -kTimeoutMessageTextWidthDMM, 0);
   button->SetRotate(1, 0, 0, kTimeoutButtonRotationRad);
@@ -1645,7 +1645,7 @@
       kSpeechRecognitionListeningCloseButton, kPhaseForeground,
       base::BindRepeating(&UiBrowserInterface::SetVoiceSearchActive,
                           base::Unretained(browser_), false),
-      vector_icons::kClose16Icon, audio_delegate_);
+      vector_icons::kCloseRoundedIcon, audio_delegate_);
   close_button->SetSize(kVoiceSearchCloseButtonDiameter,
                         kVoiceSearchCloseButtonDiameter);
   close_button->set_hover_offset(kButtonZOffsetHoverDMM * kContentDistance);
@@ -2585,7 +2585,7 @@
       base::Unretained(model_), base::Unretained(browser_));
   std::unique_ptr<DiscButton> element =
       Create<DiscButton>(kCloseButton, kPhaseForeground, click_handler,
-                         vector_icons::kClose16Icon, audio_delegate_);
+                         vector_icons::kCloseRoundedIcon, audio_delegate_);
   element->set_contributes_to_parent_bounds(false);
   element->SetSize(kCloseButtonDiameter, kCloseButtonDiameter);
   element->set_hover_offset(kButtonZOffsetHoverDMM * kCloseButtonDistance);
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 133b262..419a94a 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -385,7 +385,7 @@
 // Enables media content bitstream remoting, an optimization that can activate
 // during Cast Tab Mirroring.
 const base::Feature kMediaRemoting{"MediaRemoting",
-                                   base::FEATURE_DISABLED_BY_DEFAULT};
+                                   base::FEATURE_ENABLED_BY_DEFAULT};
 #endif  // !defined(OS_ANDROID)
 
 // Enables or disables modal permission prompts.
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 0206f7f..1bcc9f9 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -15,10 +15,18 @@
     "channel": "stable",
     "extension_types": ["extension", "platform_app"]
   },
-  "accessibilityFeatures.read": {
+  "accessibilityFeatures.read": [{
     "channel": "stable",
     "extension_types": ["extension", "platform_app"]
-  },
+  }, {
+    "channel": "stable",
+    "extension_types": ["legacy_packaged_app"],
+    "platforms": ["chromeos"],
+    "whitelist": [
+      "0EA6B717932AD64C469C1CCB6911457733295907",  // http://crbug.com/835115
+      "58B0C2968C335964D5433E89CA4D86628A0E3D4B"   // http://crbug.com/835115
+    ]
+  }],
   "accessibilityPrivate": {
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app", "platform_app"],
diff --git a/chrome/common/extensions/api/automation.idl b/chrome/common/extensions/api/automation.idl
index 8e27ac3..8d98e48 100644
--- a/chrome/common/extensions/api/automation.idl
+++ b/chrome/common/extensions/api/automation.idl
@@ -285,7 +285,11 @@
     /**
      * This node was removed.
      */
-    nodeRemoved
+    nodeRemoved,
+    /**
+     * This subtree has finished an update.
+     */
+    subtreeUpdateEnd
   };
 
   // Where the node's name is from.
diff --git a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
index 4373161..dfe44a7b 100644
--- a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
+++ b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
@@ -202,8 +202,15 @@
     if (!tree_.Unserialize(params.update))
       return false;
 
-    if (is_active_profile)
+    if (is_active_profile) {
       owner_->SendNodesRemovedEvent(&tree_, deleted_node_ids_);
+
+      ui::AXNode* target = tree_.GetFromId(params.id);
+      if (target) {
+        owner_->SendTreeChangeEvent(
+            api::automation::TREE_CHANGE_TYPE_SUBTREEUPDATEEND, &tree_, target);
+      }
+    }
   }
 
   // Exit early if this isn't the active profile.
diff --git a/chrome/renderer/extensions/tabs_hooks_delegate_unittest.cc b/chrome/renderer/extensions/tabs_hooks_delegate_unittest.cc
index 368614f..45170ed9 100644
--- a/chrome/renderer/extensions/tabs_hooks_delegate_unittest.cc
+++ b/chrome/renderer/extensions/tabs_hooks_delegate_unittest.cc
@@ -110,6 +110,9 @@
   tester.TestConnect("4, {name: 'channel'}", "channel",
                      MessageTarget::ForTab(4, messaging_util::kNoFrameId),
                      kExpectIncludeTlsChannelId);
+  tester.TestConnect("9, {frameId: null}", "",
+                     MessageTarget::ForTab(9, messaging_util::kNoFrameId),
+                     kExpectIncludeTlsChannelId);
   tester.TestConnect("9, {frameId: 16}", "", MessageTarget::ForTab(9, 16),
                      kExpectIncludeTlsChannelId);
   tester.TestConnect("25, {}", "",
@@ -141,6 +144,10 @@
   tester.TestSendMessage("1, {data: 'hello'}, function() {}", kStandardMessage,
                          MessageTarget::ForTab(1, messaging_util::kNoFrameId),
                          kExpectIncludeTlsChannelId, SendMessageTester::OPEN);
+  tester.TestSendMessage("1, {data: 'hello'}, {frameId: null}",
+                         kStandardMessage,
+                         MessageTarget::ForTab(1, messaging_util::kNoFrameId),
+                         kExpectIncludeTlsChannelId, SendMessageTester::CLOSED);
   tester.TestSendMessage("1, {data: 'hello'}, {frameId: 10}", kStandardMessage,
                          MessageTarget::ForTab(1, 10),
                          kExpectIncludeTlsChannelId, SendMessageTester::CLOSED);
diff --git a/chrome/services/media_gallery_util/media_metadata_parser.cc b/chrome/services/media_gallery_util/media_metadata_parser.cc
index edeace4..ae99a20 100644
--- a/chrome/services/media_gallery_util/media_metadata_parser.cc
+++ b/chrome/services/media_gallery_util/media_metadata_parser.cc
@@ -62,12 +62,12 @@
        it != extractor.stream_infos().end(); ++it) {
     chrome::mojom::MediaStreamInfoPtr stream_info =
         chrome::mojom::MediaStreamInfo::New(
-            it->type, std::make_unique<base::DictionaryValue>());
+            it->type, base::Value(base::Value::Type::DICTIONARY));
     for (std::map<std::string, std::string>::const_iterator tag_it =
              it->tags.begin();
          tag_it != it->tags.end(); ++tag_it) {
-      stream_info->additional_properties->SetKey(tag_it->first,
-                                                 base::Value(tag_it->second));
+      stream_info->additional_properties.SetKey(tag_it->first,
+                                                base::Value(tag_it->second));
     }
     metadata->raw_tags.push_back(std::move(stream_info));
   }
diff --git a/chrome/services/media_gallery_util/public/mojom/BUILD.gn b/chrome/services/media_gallery_util/public/mojom/BUILD.gn
index 2bc6cbc8..bfe58641 100644
--- a/chrome/services/media_gallery_util/public/mojom/BUILD.gn
+++ b/chrome/services/media_gallery_util/public/mojom/BUILD.gn
@@ -11,7 +11,6 @@
   ]
 
   public_deps = [
-    "//mojo/common:common_custom_types",
     "//mojo/public/mojom/base",
   ]
 }
diff --git a/chrome/services/media_gallery_util/public/mojom/media_parser.mojom b/chrome/services/media_gallery_util/public/mojom/media_parser.mojom
index 3dbbde5..e893c9b 100644
--- a/chrome/services/media_gallery_util/public/mojom/media_parser.mojom
+++ b/chrome/services/media_gallery_util/public/mojom/media_parser.mojom
@@ -4,9 +4,9 @@
 
 module chrome.mojom;
 
-import "mojo/common/values.mojom";
 import "mojo/public/mojom/base/file.mojom";
 import "mojo/public/mojom/base/time.mojom";
+import "mojo/public/mojom/base/values.mojom";
 
 interface MediaParser {
   // Extracts metadata from media data with |mime_type|, |total_size| and
@@ -57,7 +57,7 @@
   string type;
 
   // A string->string dictionary of tags for the media stream.
-  mojo.common.mojom.DictionaryValue additional_properties;
+  mojo_base.mojom.DictionaryValue additional_properties;
 };
 
 // All data are parsed from user-defined media data. The consumer of this API should filter special
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 680fc92..d70ec3b 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -37,8 +37,6 @@
     "../../../browser/ui/webui/chromeos/bluetooth_pairing_dialog_browsertest.js",
     "../../../browser/ui/webui/chromeos/certificate_manager_dialog_browsertest.js",
     "../../../browser/ui/webui/chromeos/set_time_ui_browsertest.js",
-    "../../../browser/ui/webui/extensions/chromeos/kiosk_apps_browsertest.js",
-    "../../../browser/ui/webui/extensions/extension_settings_browsertest.js",
     "../../../browser/ui/webui/identity_internals_ui_browsertest.js",
     "../../../browser/ui/webui/sync_internals_browsertest.js",
     "../chromeos/oobe_webui_browsertest.js",
@@ -119,6 +117,7 @@
 
   if (is_chromeos) {
     sources += [
+      "multidevice_setup/multidevice_setup_browsertest.js",
       "settings/easy_unlock_browsertest_chromeos.js",
       "sys_internals/sys_internals_browsertest.js",
     ]
diff --git a/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js b/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js
new file mode 100644
index 0000000..4ec44bf
--- /dev/null
+++ b/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js
@@ -0,0 +1,38 @@
+// 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.
+
+/** @fileoverview Tests for MultiDevice unified setup WebUI. */
+
+GEN('#if defined(OS_CHROMEOS)');
+
+/** @const {string} Path to source root. */
+var ROOT_PATH = '../../../../../';
+
+// Polymer BrowserTest fixture.
+GEN_INCLUDE(
+    [ROOT_PATH + 'chrome/test/data/webui/polymer_browser_test_base.js']);
+
+/**
+ * Test fixture for MultiDeviceSetup elements.
+ * @constructor
+ * @extends {PolymerTest}
+ */
+function MultiDeviceSetupBrowserTest() {}
+
+MultiDeviceSetupBrowserTest.prototype = {
+  __proto__: PolymerTest.prototype,
+
+  browsePreload: 'chrome://multidevice-setup/',
+
+  extraLibraries: PolymerTest.getLibraries(ROOT_PATH).concat([
+    'navigation_test.js',
+  ]),
+};
+
+TEST_F('MultiDeviceSetupBrowserTest', 'All', function() {
+  multidevice_setup.registerTests();
+  mocha.run();
+});
+
+GEN('#endif');
diff --git a/chrome/test/data/webui/multidevice_setup/navigation_test.js b/chrome/test/data/webui/multidevice_setup/navigation_test.js
new file mode 100644
index 0000000..438bb2b
--- /dev/null
+++ b/chrome/test/data/webui/multidevice_setup/navigation_test.js
@@ -0,0 +1,72 @@
+// 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.
+
+/**
+ * @fileoverview Suite of tests for button navigation functionality in
+ * MultiDevice setup WebUI.
+ */
+cr.define('multidevice_setup', () => {
+  function registerTests() {
+    suite('MultiDeviceSetup', () => {
+      /**
+       * MultiDeviceSetup created before each test.
+       * @type {MultiDeviceSetup}
+       */
+      let multiDeviceSetupElement;
+
+      const FAILURE = 'setup-failed-page';
+      const SUCCESS = 'setup-succeeded-page';
+      const START = 'start-setup-page';
+
+      function tapForwardNavigation() {
+        MockInteractions.tap(
+            multiDeviceSetupElement.$$('button-bar').$.forward);
+      }
+
+      function tapBackwardNavigation() {
+        MockInteractions.tap(
+            multiDeviceSetupElement.$$('button-bar').$.backward);
+      }
+
+      setup(() => {
+        PolymerTest.clearBody();
+        multiDeviceSetupElement = document.createElement('multidevice-setup');
+        document.body.appendChild(multiDeviceSetupElement);
+      });
+
+      test(
+          'Check SetupFailedPage forward button goes to start page',
+          done => {
+            multiDeviceSetupElement.visiblePageName_ = FAILURE;
+            multiDeviceSetupElement.addEventListener(
+                'visible-page_-changed', function() {
+                  if (multiDeviceSetupElement.visiblePage_ &&
+                      multiDeviceSetupElement.visiblePage_.is == START) {
+                    done();
+                  }
+                });
+            tapForwardNavigation();
+          });
+
+      test('Check SetupFailedPage backward button closes UI', done => {
+        multiDeviceSetupElement.visiblePageName_ = FAILURE;
+        multiDeviceSetupElement.addEventListener('ui-closed', () => done());
+        tapBackwardNavigation();
+      });
+
+      test('Check SetupSucceededPage forward button closes UI', done => {
+        multiDeviceSetupElement.visiblePageName_ = SUCCESS;
+        multiDeviceSetupElement.addEventListener('ui-closed', () => done());
+        tapForwardNavigation();
+      });
+
+      test('Check StartSetupPage backward button closes UI', done => {
+        multiDeviceSetupElement.visiblePageName_ = START;
+        multiDeviceSetupElement.addEventListener('ui-closed', () => done());
+        tapBackwardNavigation();
+      });
+    });
+  }
+  return {registerTests: registerTests};
+});
diff --git a/chromecast/README.md b/chromecast/README.md
index 1d2db418..5858c2a 100644
--- a/chromecast/README.md
+++ b/chromecast/README.md
@@ -11,17 +11,14 @@
 
  * If you are adding a new feature, add it to `cast_features.cc` so it lives
  alongside existing features
- * Add registration of your new feature via `RegisterFeature(&feature)`.
- You can add it to `RegisterFeatures()` so it lives with existing features
+ * Add your new feature to the list of `kFeatures` in `cast_features.cc`
 
 ```c++
 const base::Feature kMyFeature{"my_feature", base::FEATURE_DISABLED_BY_DEFAULT};
 
-void RegisterFeatures() {
- // ...other features
- RegisterFeature(&kMyFeature);
+
+const base::Feature* kFeatures[] = {
+  // ..other features
+  &kMyFeature
 }
 ```
-
- * If you are writing a unit test that touches code that reads your feature be
- sure to call `RegisterFeaturesForTesting()` in your unit test constructor
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn
index 11d4149..0e96a5d 100644
--- a/chromecast/base/BUILD.gn
+++ b/chromecast/base/BUILD.gn
@@ -98,6 +98,12 @@
   if (is_android) {
     deps += [ ":jni_headers" ]
   }
+
+  if (chromecast_branding == "public") {
+    sources += [ "cast_features_internal.cc" ]
+  } else {
+    deps += [ "//chromecast/internal/base:cast_internal_features" ]
+  }
 }
 
 # chromecast related switch values
diff --git a/chromecast/base/cast_features.cc b/chromecast/base/cast_features.cc
index fb4eb600..62acd77 100644
--- a/chromecast/base/cast_features.cc
+++ b/chromecast/base/cast_features.cc
@@ -2,28 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chromecast/base/cast_features.h"
+
 #include <algorithm>
 #include <utility>
 
-#include "chromecast/base/cast_features.h"
-
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/lazy_instance.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/field_trial_param_associator.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/no_destructor.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 
 namespace chromecast {
 namespace {
-
-// The mapping of feature names to features that have been registered
-// LazyInstance
-base::LazyInstance<std::vector<const base::Feature*>>::DestructorAtExit
-    g_features;
-
 // A constant used to always activate a FieldTrial.
 const base::FieldTrial::Probability k100PercentProbability = 100;
 
@@ -34,16 +29,10 @@
     LAZY_INSTANCE_INITIALIZER;
 bool g_experiment_ids_initialized = false;
 
-void ClearFeatures() {
-  g_features.Get().clear();
-}
-
-void RegisterFeatures() {
-  RegisterFeature(&kAllowUserMediaAccess);
-  RegisterFeature(&kEnableQuic);
-  RegisterFeature(&kTripleBuffer720);
-  RegisterFeature(&kSingleBuffer);
-  RegisterFeature(&kDisableIdleSocketsCloseOnMemoryPressure);
+// The collection of features that have been registered by unit tests
+std::vector<const base::Feature*>& GetTestFeatures() {
+  static base::NoDestructor<std::vector<const base::Feature*>> g_features_for_test;
+  return *g_features_for_test;
 }
 
 void SetExperimentIds(const base::ListValue& list) {
@@ -125,11 +114,9 @@
 //
 //      --disable-features=enable_foo,enable_bar
 //
-// 5) If you add a new feature to the system you must register the feature.
+// 5) If you add a new feature to the system you must include it in kFeatures
 //    This is because the system relies on knowing all of the features so
-//    it can properly iterate over all features to detect changes. You
-//    should register your feature via RegisterFeature(&feature) and most likely
-//    your feature registration should live in RegisterFeatures() function
+//    it can properly iterate over all features to detect changes.
 //
 
 // Begin Chromecast Feature definitions.
@@ -157,12 +144,30 @@
     base::FEATURE_DISABLED_BY_DEFAULT};
 
 // End Chromecast Feature definitions.
+const base::Feature* kFeatures[] = {
+    &kAllowUserMediaAccess,
+    &kEnableQuic,
+    &kTripleBuffer720,
+    &kSingleBuffer,
+    &kDisableIdleSocketsCloseOnMemoryPressure,
+};
 
 // An iterator for a base::DictionaryValue. Use an alias for brevity in loops.
 using Iterator = base::DictionaryValue::Iterator;
 
-std::vector<const base::Feature*> GetFeatures() {
-  return g_features.Get();
+std::vector<const base::Feature*> GetInternalFeatures();
+
+const std::vector<const base::Feature*>& GetFeatures() {
+  static const base::NoDestructor<std::vector<const base::Feature*>> features([] {
+    auto features = std::vector<const base::Feature*>(
+      kFeatures, kFeatures + sizeof(kFeatures) / sizeof(base::Feature*));
+    auto internal_features = GetInternalFeatures();
+    features.insert(features.end(), internal_features.begin(), internal_features.end());
+    return features;
+  }());
+  if (GetTestFeatures().size() > 0)
+    return GetTestFeatures();
+  return *features;
 }
 
 void InitializeFeatureList(const base::DictionaryValue& dcs_features,
@@ -171,8 +176,6 @@
                            const std::string& cmd_line_disable_features) {
   DCHECK(!base::FeatureList::GetInstance());
 
-  RegisterFeatures();
-
   // Set the experiments.
   SetExperimentIds(dcs_experiment_ids);
 
@@ -257,14 +260,10 @@
   base::FeatureList::SetInstance(std::move(feature_list));
 }
 
-bool IsFeatureRegistered(const base::Feature& feature) {
-  std::vector<const base::Feature*> features = g_features.Get();
-  auto it = std::find(features.begin(), features.end(), &feature);
-  return it != features.end();
-}
-
 bool IsFeatureEnabled(const base::Feature& feature) {
-  DCHECK(IsFeatureRegistered(feature)) << feature.name;
+  DCHECK(std::find(GetFeatures().begin(), GetFeatures().end(), &feature) !=
+         GetFeatures().end())
+      << feature.name;
   return base::FeatureList::IsEnabled(feature);
 }
 
@@ -322,26 +321,14 @@
   return g_experiment_ids.Get();
 }
 
-void ClearFeaturesForTesting() {
-  ClearFeatures();
-}
-
-void RegisterFeature(const base::Feature* feature) {
-  DCHECK(!IsFeatureRegistered(*feature))
-      << feature->name << " is already registered";
-  g_features.Get().push_back(feature);
-}
-
-void RegisterFeaturesForTesting() {
-  // Clear out all existing features. This is to prevent DCHECK failures
-  // for duplicate feature registration during testing
-  ClearFeatures();
-  RegisterFeatures();
-}
-
 void ResetCastFeaturesForTesting() {
   g_experiment_ids_initialized = false;
   base::FeatureList::ClearInstanceForTesting();
+  GetTestFeatures().clear();
+}
+
+void SetFeaturesForTest(std::vector<const base::Feature*> features) {
+  GetTestFeatures() = std::move(features);
 }
 
 }  // namespace chromecast
diff --git a/chromecast/base/cast_features.h b/chromecast/base/cast_features.h
index 8853793..66d4bfd 100644
--- a/chromecast/base/cast_features.h
+++ b/chromecast/base/cast_features.h
@@ -30,7 +30,7 @@
 
 // Get an iterable list of all of the cast features for checking all features as
 // a collection.
-std::vector<const base::Feature*> GetFeatures();
+const std::vector<const base::Feature*>& GetFeatures();
 
 // Below are utilities needed by the Cast receiver to persist feature
 // information. Client code which is simply querying the status of a feature
@@ -50,7 +50,7 @@
                            const std::string& cmd_line_disable_features);
 
 // Determine whether or not a feature is enabled. This replaces
-// base::FeatureList::IsEnabled for Cast builds
+// base::FeatureList::IsEnabled for Cast builds.
 bool IsFeatureEnabled(const base::Feature& feature);
 
 // Given a dictionary of features, create a copy that is ready to be persisted
@@ -64,19 +64,13 @@
 // thread.
 const std::unordered_set<int32_t>& GetDCSExperimentIds();
 
-// Remove all feature registrations. Required for certain test patterns
-void ClearFeaturesForTesting();
-
-// Register a feature. All instances of base::Feature within
-// chromecast should be registered by calling this function.
-void RegisterFeature(const base::Feature* feature);
-
-// Register all known features. For tests only.
-void RegisterFeaturesForTesting();
-
 // Reset static state to ensure clean unittests. For tests only.
 void ResetCastFeaturesForTesting();
 
+// Set the response to GetFeatures(). Calls to this function should
+// be cleaned up by a call to ResetCastFeaturesForTesting() otherwise
+// your test will leak the overridden feature state.
+void SetFeaturesForTest(std::vector<const base::Feature*> features);
 }  // namespace chromecast
 
 #endif  // CHROMECAST_BASE_CAST_FEATURES_H_
diff --git a/chromecast/base/cast_features_internal.cc b/chromecast/base/cast_features_internal.cc
new file mode 100644
index 0000000..4ce667c
--- /dev/null
+++ b/chromecast/base/cast_features_internal.cc
@@ -0,0 +1,14 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+namespace base {
+struct Feature;
+}
+namespace chromecast {
+std::vector<const base::Feature*> GetInternalFeatures() {
+  return std::vector<const base::Feature*>();
+}
+}  // namespace chromecast
diff --git a/chromecast/base/cast_features_unittest.cc b/chromecast/base/cast_features_unittest.cc
index 9ddf3ea..2755e9b 100644
--- a/chromecast/base/cast_features_unittest.cc
+++ b/chromecast/base/cast_features_unittest.cc
@@ -30,6 +30,7 @@
 
   // testing::Test implementation:
   void SetUp() override { ResetCastFeaturesForTesting(); }
+  void TearDown() override { ResetCastFeaturesForTesting(); }
 
  private:
   // A field trial list must be created before attempting to create FieldTrials.
@@ -40,8 +41,6 @@
 };
 
 TEST_F(CastFeaturesTest, EnableDisableMultipleBooleanFeatures) {
-  chromecast::ClearFeaturesForTesting();
-
   // Declare several boolean features.
   base::Feature bool_feature{kTestBooleanFeatureName,
                              base::FEATURE_DISABLED_BY_DEFAULT};
@@ -53,10 +52,8 @@
                                base::FEATURE_ENABLED_BY_DEFAULT};
 
   // Properly register them
-  chromecast::RegisterFeature(&bool_feature);
-  chromecast::RegisterFeature(&bool_feature_2);
-  chromecast::RegisterFeature(&bool_feature_3);
-  chromecast::RegisterFeature(&bool_feature_4);
+  chromecast::SetFeaturesForTest(
+      {&bool_feature, &bool_feature_2, &bool_feature_3, &bool_feature_4});
 
   // Override those features with DCS configs.
   auto experiments = std::make_unique<base::ListValue>();
@@ -77,11 +74,10 @@
 }
 
 TEST_F(CastFeaturesTest, EnableSingleFeatureWithParams) {
-  chromecast::ClearFeaturesForTesting();
   // Define a feature with params.
   base::Feature test_feature{kTestParamsFeatureName,
                              base::FEATURE_DISABLED_BY_DEFAULT};
-  chromecast::RegisterFeature(&test_feature);
+  chromecast::SetFeaturesForTest({&test_feature});
 
   // Pass params via DCS.
   auto experiments = std::make_unique<base::ListValue>();
@@ -114,7 +110,6 @@
 }
 
 TEST_F(CastFeaturesTest, CommandLineOverridesDcsAndDefault) {
-  chromecast::ClearFeaturesForTesting();
   // Declare several boolean features.
   base::Feature bool_feature{kTestBooleanFeatureName,
                              base::FEATURE_DISABLED_BY_DEFAULT};
@@ -125,12 +120,6 @@
   base::Feature bool_feature_4{kTestBooleanFeatureName4,
                                base::FEATURE_ENABLED_BY_DEFAULT};
 
-  // Properly register them
-  chromecast::RegisterFeature(&bool_feature);
-  chromecast::RegisterFeature(&bool_feature_2);
-  chromecast::RegisterFeature(&bool_feature_3);
-  chromecast::RegisterFeature(&bool_feature_4);
-
   // Override those features with DCS configs.
   auto experiments = std::make_unique<base::ListValue>();
   auto features = std::make_unique<base::DictionaryValue>();
@@ -142,7 +131,9 @@
   // Also override a param feature with DCS config.
   base::Feature params_feature{kTestParamsFeatureName,
                                base::FEATURE_ENABLED_BY_DEFAULT};
-  chromecast::RegisterFeature(&params_feature);
+  chromecast::SetFeaturesForTest({&bool_feature, &bool_feature_2,
+                                  &bool_feature_3, &bool_feature_4,
+                                  &params_feature});
 
   auto params = std::make_unique<base::DictionaryValue>();
   params->SetString("foo_key", "foo");
@@ -175,7 +166,6 @@
 }
 
 TEST_F(CastFeaturesTest, SetEmptyExperiments) {
-  chromecast::ClearFeaturesForTesting();
   // Override those features with DCS configs.
   auto experiments = std::make_unique<base::ListValue>();
   auto features = std::make_unique<base::DictionaryValue>();
@@ -201,7 +191,6 @@
 }
 
 TEST_F(CastFeaturesTest, SetSomeGoodExperiments) {
-  chromecast::ClearFeaturesForTesting();
   // Override those features with DCS configs.
   auto experiments = std::make_unique<base::ListValue>();
   auto features = std::make_unique<base::DictionaryValue>();
@@ -220,7 +209,6 @@
 }
 
 TEST_F(CastFeaturesTest, SetAllBadExperiments) {
-  chromecast::ClearFeaturesForTesting();
   // Override those features with DCS configs.
   auto experiments = std::make_unique<base::ListValue>();
   auto features = std::make_unique<base::DictionaryValue>();
diff --git a/chromecast/browser/test/cast_features_browsertest.cc b/chromecast/browser/test/cast_features_browsertest.cc
index 1203f2e..0e2b181 100644
--- a/chromecast/browser/test/cast_features_browsertest.cc
+++ b/chromecast/browser/test/cast_features_browsertest.cc
@@ -90,25 +90,25 @@
                                 base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kTestFeat24{"test_feat_24",
                                 base::FEATURE_ENABLED_BY_DEFAULT};
-void RegisterFeatures() {
-  chromecast::RegisterFeaturesForTesting();
-  chromecast::RegisterFeature(&kTestFeat1);
-  chromecast::RegisterFeature(&kTestFeat2);
-  chromecast::RegisterFeature(&kTestFeat3);
-  chromecast::RegisterFeature(&kTestFeat4);
-  chromecast::RegisterFeature(&kTestFeat11);
-  chromecast::RegisterFeature(&kTestFeat21);
-  chromecast::RegisterFeature(&kTestFeat22);
-  chromecast::RegisterFeature(&kTestFeat23);
-  chromecast::RegisterFeature(&kTestFeat24);
+
+// Extend the default features with test features only used in this browsertest.
+void SetupFeatures() {
+  std::vector<const base::Feature*> features = {
+      &kTestFeat1,  &kTestFeat2,  &kTestFeat3,  &kTestFeat4, &kTestFeat11,
+      &kTestFeat21, &kTestFeat22, &kTestFeat23, &kTestFeat24};
+  std::vector<const base::Feature*> existing_features =
+      chromecast::GetFeatures();
+  features.insert(features.end(), existing_features.begin(),
+                  existing_features.end());
+  chromecast::SetFeaturesForTest(std::move(features));
 }
 
 }  // namespace
 
 class CastFeaturesBrowserTest : public CastBrowserTest {
  public:
-  CastFeaturesBrowserTest() { chromecast::ClearFeaturesForTesting(); }
-  ~CastFeaturesBrowserTest() override {}
+  CastFeaturesBrowserTest() { SetupFeatures(); }
+  ~CastFeaturesBrowserTest() override { chromecast::ResetCastFeaturesForTesting(); }
 
   static PrefService* pref_service() {
     return CastBrowserProcess::GetInstance()->pref_service();
@@ -160,14 +160,12 @@
 // Test that set features activate on the next boot. Part 1 of 3.
 IN_PROC_BROWSER_TEST_F(CastFeaturesBrowserTest,
                        PRE_PRE_TestFeaturesActivateOnBoot) {
-  RegisterFeatures();
   ClearFeaturesFromPrefs({kTestFeat1, kTestFeat2, kTestFeat3, kTestFeat4});
 }
 
 // Test that set features activate on the next boot. Part 2 of 3.
 IN_PROC_BROWSER_TEST_F(CastFeaturesBrowserTest,
                        PRE_TestFeaturesActivateOnBoot) {
-  RegisterFeatures();
   // Default values should be returned.
   ASSERT_FALSE(chromecast::IsFeatureEnabled(kTestFeat1));
   ASSERT_TRUE(chromecast::IsFeatureEnabled(kTestFeat2));
@@ -189,7 +187,6 @@
 
 // Test that features activate on the next boot. Part 3 of 3.
 IN_PROC_BROWSER_TEST_F(CastFeaturesBrowserTest, TestFeaturesActivateOnBoot) {
-  RegisterFeatures();
   // Overriden values set in test case above should be set.
   ASSERT_TRUE(chromecast::IsFeatureEnabled(kTestFeat1));
   ASSERT_TRUE(chromecast::IsFeatureEnabled(kTestFeat2));
@@ -200,13 +197,11 @@
 // Test that features with params activate on boot. Part 1 of 3.
 IN_PROC_BROWSER_TEST_F(CastFeaturesBrowserTest,
                        PRE_PRE_TestParamsActivateOnBoot) {
-  RegisterFeatures();
   ClearFeaturesFromPrefs({kTestFeat11});
 }
 
 // Test that features with params activate on boot. Part 2 of 3.
 IN_PROC_BROWSER_TEST_F(CastFeaturesBrowserTest, PRE_TestParamsActivateOnBoot) {
-  RegisterFeatures();
   // Default value should be returned.
   ASSERT_FALSE(chromecast::IsFeatureEnabled(kTestFeat11));
 
@@ -227,7 +222,6 @@
 
 // Test that features with params activate on boot. Part 3 of 3.
 IN_PROC_BROWSER_TEST_F(CastFeaturesBrowserTest, TestParamsActivateOnBoot) {
-  RegisterFeatures();
   // Check that the feature is now enabled.
   ASSERT_TRUE(chromecast::IsFeatureEnabled(kTestFeat11));
 
@@ -252,14 +246,12 @@
 // Test that only well-formed features are persisted to disk. Part 1 of 3.
 IN_PROC_BROWSER_TEST_F(CastFeaturesBrowserTest,
                        PRE_PRE_TestOnlyWellFormedFeaturesPersisted) {
-  RegisterFeatures();
   ClearFeaturesFromPrefs({kTestFeat21, kTestFeat22, kTestFeat23, kTestFeat24});
 }
 
 // Test that only well-formed features are persisted to disk. Part 2 of 3.
 IN_PROC_BROWSER_TEST_F(CastFeaturesBrowserTest,
                        PRE_TestOnlyWellFormedFeaturesPersisted) {
-  RegisterFeatures();
   // Default values should be returned.
   ASSERT_FALSE(chromecast::IsFeatureEnabled(kTestFeat21));
   ASSERT_TRUE(chromecast::IsFeatureEnabled(kTestFeat22));
@@ -281,7 +273,6 @@
 // Test that only well-formed features are persisted to disk. Part 2 of 2.
 IN_PROC_BROWSER_TEST_F(CastFeaturesBrowserTest,
                        TestOnlyWellFormedFeaturesPersisted) {
-  RegisterFeatures();
   // Only the well-formed parameters should be overriden.
   ASSERT_TRUE(chromecast::IsFeatureEnabled(kTestFeat21));
   ASSERT_FALSE(chromecast::IsFeatureEnabled(kTestFeat24));
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 82998d4a..0d06ae7 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10600.0.0
\ No newline at end of file
+10609.0.0
\ No newline at end of file
diff --git a/chromeos/dbus/fake_concierge_client.cc b/chromeos/dbus/fake_concierge_client.cc
index cf6bc24a..2900977e 100644
--- a/chromeos/dbus/fake_concierge_client.cc
+++ b/chromeos/dbus/fake_concierge_client.cc
@@ -30,8 +30,11 @@
     const vm_tools::concierge::CreateDiskImageRequest& request,
     DBusMethodCallback<vm_tools::concierge::CreateDiskImageResponse> callback) {
   create_disk_image_called_ = true;
+  vm_tools::concierge::CreateDiskImageResponse response;
+  response.set_status(vm_tools::concierge::DISK_STATUS_CREATED);
+  response.set_disk_path("foo");
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(response)));
 }
 
 void FakeConciergeClient::DestroyDiskImage(
@@ -39,38 +42,50 @@
     DBusMethodCallback<vm_tools::concierge::DestroyDiskImageResponse>
         callback) {
   destroy_disk_image_called_ = true;
+  vm_tools::concierge::DestroyDiskImageResponse response;
+  response.set_status(vm_tools::concierge::DISK_STATUS_DESTROYED);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(response)));
 }
 
 void FakeConciergeClient::StartTerminaVm(
     const vm_tools::concierge::StartVmRequest& request,
     DBusMethodCallback<vm_tools::concierge::StartVmResponse> callback) {
   start_termina_vm_called_ = true;
+  vm_tools::concierge::StartVmResponse response;
+  response.set_success(true);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(response)));
 }
 
 void FakeConciergeClient::StopVm(
     const vm_tools::concierge::StopVmRequest& request,
     DBusMethodCallback<vm_tools::concierge::StopVmResponse> callback) {
   stop_vm_called_ = true;
+  vm_tools::concierge::StopVmResponse response;
+  response.set_success(true);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(response)));
 }
 
 void FakeConciergeClient::StartContainer(
     const vm_tools::concierge::StartContainerRequest& request,
     DBusMethodCallback<vm_tools::concierge::StartContainerResponse> callback) {
   start_container_called_ = true;
-  std::move(callback).Run(base::nullopt);
+  vm_tools::concierge::StartContainerResponse response;
+  response.set_status(vm_tools::concierge::CONTAINER_STATUS_RUNNING);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(response)));
 }
 
 void FakeConciergeClient::LaunchContainerApplication(
     const vm_tools::concierge::LaunchContainerApplicationRequest& request,
     DBusMethodCallback<vm_tools::concierge::LaunchContainerApplicationResponse>
         callback) {
-  std::move(callback).Run(base::nullopt);
+  vm_tools::concierge::LaunchContainerApplicationResponse response;
+  response.set_success(true);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(response)));
 }
 
 void FakeConciergeClient::WaitForServiceToBeAvailable(
diff --git a/chromeos/network/portal_detector/mock_network_portal_detector.h b/chromeos/network/portal_detector/mock_network_portal_detector.h
index 7f2ad75..c84a3c2c 100644
--- a/chromeos/network/portal_detector/mock_network_portal_detector.h
+++ b/chromeos/network/portal_detector/mock_network_portal_detector.h
@@ -26,10 +26,9 @@
                    const std::string& service_path));
   MOCK_METHOD0(IsEnabled, bool());
   MOCK_METHOD1(Enable, void(bool start_detection));
-  MOCK_METHOD0(StartDetectionIfIdle, bool());
+  MOCK_METHOD1(StartPortalDetection, bool(bool force));
   MOCK_METHOD1(SetStrategy,
                void(chromeos::PortalDetectorStrategy::StrategyId id));
-  MOCK_METHOD0(OnLockScreenRequest, void());
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockNetworkPortalDetector);
diff --git a/chromeos/network/portal_detector/network_portal_detector.h b/chromeos/network/portal_detector/network_portal_detector.h
index d20017b9..2bd5c488 100644
--- a/chromeos/network/portal_detector/network_portal_detector.h
+++ b/chromeos/network/portal_detector/network_portal_detector.h
@@ -55,6 +55,9 @@
         const NetworkState* network,
         const CaptivePortalState& state) = 0;
 
+    // Called on Shutdown, allows removal of observers. Primarly used in tests.
+    virtual void OnShutdown() {}
+
    protected:
     virtual ~Observer() {}
   };
@@ -93,18 +96,16 @@
   // initiated by this method.
   virtual void Enable(bool start_detection) = 0;
 
-  // Restarts portal detection for the default network if currently in
-  // the idle state. Returns true if new portal detection attempt was
-  // started.
-  virtual bool StartDetectionIfIdle() = 0;
+  // Starts or restarts portal detection for the default network. If not
+  // currently in the idle state, does nothing unless |force| is true in which
+  // case any current detection is stopped and a new attempt is started. Returns
+  // true if a new portal detection attempt was started.
+  virtual bool StartPortalDetection(bool force) = 0;
 
   // Sets current strategy according to |id|. If current detection id
   // doesn't equal to |id|, detection is restarted.
   virtual void SetStrategy(PortalDetectorStrategy::StrategyId id) = 0;
 
-  // Closes portal login window before screen is locked.
-  virtual void OnLockScreenRequest() = 0;
-
   // Returns non-localized string representation of |status|.
   static std::string CaptivePortalStatusString(CaptivePortalStatus status);
 
diff --git a/chromeos/network/portal_detector/network_portal_detector_stub.cc b/chromeos/network/portal_detector/network_portal_detector_stub.cc
index d6aac35..bbeffda 100644
--- a/chromeos/network/portal_detector/network_portal_detector_stub.cc
+++ b/chromeos/network/portal_detector/network_portal_detector_stub.cc
@@ -31,13 +31,11 @@
 
 void NetworkPortalDetectorStub::Enable(bool start_detection) {}
 
-bool NetworkPortalDetectorStub::StartDetectionIfIdle() {
+bool NetworkPortalDetectorStub::StartPortalDetection(bool force) {
   return false;
 }
 
 void NetworkPortalDetectorStub::SetStrategy(
     PortalDetectorStrategy::StrategyId id) {}
 
-void NetworkPortalDetectorStub::OnLockScreenRequest() {}
-
 }  // namespace chromeos
diff --git a/chromeos/network/portal_detector/network_portal_detector_stub.h b/chromeos/network/portal_detector/network_portal_detector_stub.h
index 16e9fd0..3afb362 100644
--- a/chromeos/network/portal_detector/network_portal_detector_stub.h
+++ b/chromeos/network/portal_detector/network_portal_detector_stub.h
@@ -24,9 +24,8 @@
       const std::string& service_path) override;
   bool IsEnabled() override;
   void Enable(bool start_detection) override;
-  bool StartDetectionIfIdle() override;
+  bool StartPortalDetection(bool force) override;
   void SetStrategy(PortalDetectorStrategy::StrategyId id) override;
-  void OnLockScreenRequest() override;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetectorStub);
 };
diff --git a/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container_error_dialog.js b/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container_error_dialog.js
index 28efbb4..5ca0ffd9d1 100644
--- a/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container_error_dialog.js
+++ b/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container_error_dialog.js
@@ -25,7 +25,7 @@
 
 /**
  * One-time initialization of DOM.
- * @private
+ * @protected
  */
 CWSWidgetContainerErrorDialog.prototype.initDom_ = function() {
   cr.ui.dialogs.BaseDialog.prototype.initDom_.call(this);
diff --git a/components/mirroring/service/fake_network_service.h b/components/mirroring/service/fake_network_service.h
index 8237bef..b84b1687 100644
--- a/components/mirroring/service/fake_network_service.h
+++ b/components/mirroring/service/fake_network_service.h
@@ -82,8 +82,12 @@
       base::OnceClosure completion_callback) override {}
   void ClearHttpCache(base::Time start_time,
                       base::Time end_time,
-                      network::mojom::ClearCacheUrlFilterPtr filter,
+                      network::mojom::ClearDataFilterPtr filter,
                       ClearHttpCacheCallback callback) override {}
+  void ClearChannelIds(base::Time start_time,
+                       base::Time end_time,
+                       network::mojom::ClearDataFilterPtr filter,
+                       ClearChannelIdsCallback callback) override {}
   void SetNetworkConditions(
       const std::string& profile_id,
       network::mojom::NetworkConditionsPtr conditions) override {}
diff --git a/components/offline_pages/core/BUILD.gn b/components/offline_pages/core/BUILD.gn
index 4306a717..bd8d10f9 100644
--- a/components/offline_pages/core/BUILD.gn
+++ b/components/offline_pages/core/BUILD.gn
@@ -44,6 +44,8 @@
     "model/offline_page_model_utils.h",
     "model/offline_page_upgrade_types.cc",
     "model/offline_page_upgrade_types.h",
+    "model/persistent_page_consistency_check_task.cc",
+    "model/persistent_page_consistency_check_task.h",
     "model/start_offline_page_upgrade_task.cc",
     "model/start_offline_page_upgrade_task.h",
     "model/startup_maintenance_task.cc",
@@ -167,6 +169,7 @@
     "model/mark_page_accessed_task_unittest.cc",
     "model/offline_page_model_taskified_unittest.cc",
     "model/offline_page_model_utils_unittest.cc",
+    "model/persistent_page_consistency_check_task_unittest.cc",
     "model/start_offline_page_upgrade_task_unittest.cc",
     "model/startup_maintenance_task_unittest.cc",
     "model/store_thumbnail_task_unittest.cc",
diff --git a/components/offline_pages/core/model/offline_page_item_generator.cc b/components/offline_pages/core/model/offline_page_item_generator.cc
index b6a936a..3cf48e6 100644
--- a/components/offline_pages/core/model/offline_page_item_generator.cc
+++ b/components/offline_pages/core/model/offline_page_item_generator.cc
@@ -32,6 +32,10 @@
   item.last_access_time = last_access_time_;
   item.access_count = access_count_;
   item.digest = digest_;
+  item.file_missing_time = file_missing_time_;
+  if (use_offline_id_as_system_download_id_) {
+    item.system_download_id = item.offline_id;
+  }
   return item;
 }
 
@@ -95,4 +99,13 @@
   digest_ = digest;
 }
 
+void OfflinePageItemGenerator::SetFileMissingTime(
+    base::Time file_missing_time) {
+  file_missing_time_ = file_missing_time;
+}
+
+void OfflinePageItemGenerator::SetUseOfflineIdAsSystemDownloadId(bool enable) {
+  use_offline_id_as_system_download_id_ = enable;
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/model/offline_page_item_generator.h b/components/offline_pages/core/model/offline_page_item_generator.h
index c9095b3..e8605bc 100644
--- a/components/offline_pages/core/model/offline_page_item_generator.h
+++ b/components/offline_pages/core/model/offline_page_item_generator.h
@@ -36,6 +36,8 @@
   void SetAccessCount(int access_count);
   void SetArchiveDirectory(const base::FilePath& archive_dir);
   void SetDigest(const std::string& digest);
+  void SetFileMissingTime(base::Time file_missing_time);
+  void SetUseOfflineIdAsSystemDownloadId(bool enable);
 
  private:
   std::string namespace_ = kDefaultNamespace;
@@ -49,6 +51,9 @@
   int access_count_ = 0;
   base::FilePath archive_dir_;
   std::string digest_;
+  base::Time file_missing_time_;
+
+  bool use_offline_id_as_system_download_id_ = false;
 };
 }  // namespace offline_pages
 
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc
index 19b951a..0c7605a 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -28,6 +28,7 @@
 #include "components/offline_pages/core/model/get_thumbnail_task.h"
 #include "components/offline_pages/core/model/mark_page_accessed_task.h"
 #include "components/offline_pages/core/model/offline_page_model_utils.h"
+#include "components/offline_pages/core/model/persistent_page_consistency_check_task.h"
 #include "components/offline_pages/core/model/startup_maintenance_task.h"
 #include "components/offline_pages/core/model/store_thumbnail_task.h"
 #include "components/offline_pages/core/model/update_file_path_task.h"
@@ -715,6 +716,23 @@
       store_.get(), archive_manager_.get(), policy_controller_.get(), now,
       base::BindOnce(&OfflinePageModelTaskified::OnClearCachedPagesDone,
                      weak_ptr_factory_.GetWeakPtr())));
+
+  // TODO(https://crbug.com/834902) This might need a better execution plan.
+  task_queue_.AddTask(std::make_unique<PersistentPageConsistencyCheckTask>(
+      store_.get(), archive_manager_.get(), policy_controller_.get(), now,
+      base::BindOnce(
+          &OfflinePageModelTaskified::OnPersistentPageConsistencyCheckDone,
+          weak_ptr_factory_.GetWeakPtr())));
+}
+
+void OfflinePageModelTaskified::OnPersistentPageConsistencyCheckDone(
+    bool success,
+    const std::vector<int64_t>& pages_deleted) {
+  // If there's no persistent page expired, save some effort by exiting early.
+  // TODO(https://crbug.com/834909), use the temporary hidden bit in
+  // DownloadUIAdapter instead of calling remove directly.
+  if (pages_deleted.size() > 0)
+    download_manager_->Remove(pages_deleted);
 }
 
 void OfflinePageModelTaskified::OnClearCachedPagesDone(
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.h b/components/offline_pages/core/model/offline_page_model_taskified.h
index be193313..52215f2a1 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.h
+++ b/components/offline_pages/core/model/offline_page_model_taskified.h
@@ -205,6 +205,9 @@
   void RunMaintenanceTasks(const base::Time now, bool first_run);
   void OnClearCachedPagesDone(size_t deleted_page_count,
                               ClearStorageTask::ClearStorageResult result);
+  void OnPersistentPageConsistencyCheckDone(
+      bool success,
+      const std::vector<int64_t>& pages_deleted);
 
   // Method for upgrade to public storage.
   void PostSelectItemsMarkedForUpgrade();
diff --git a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
index 453d801d..714f403b 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -23,6 +23,7 @@
 #include "components/offline_pages/core/model/offline_page_item_generator.h"
 #include "components/offline_pages/core/model/offline_page_model_utils.h"
 #include "components/offline_pages/core/model/offline_page_test_utils.h"
+#include "components/offline_pages/core/model/persistent_page_consistency_check_task.h"
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/offline_pages/core/offline_page_item.h"
 #include "components/offline_pages/core/offline_page_metadata_store_sql.h"
@@ -829,7 +830,7 @@
   EXPECT_EQ(2LL, store_test_util()->GetPageCount());
 
   base::MockCallback<DeletePageCallback> callback;
-  EXPECT_CALL(callback, Run(testing::A<DeletePageResult>()));
+  EXPECT_CALL(callback, Run(A<DeletePageResult>()));
   CheckTaskQueueIdle();
 
   model()->DeletePagesByOfflineId({page1.offline_id}, callback.Get());
@@ -1399,11 +1400,12 @@
 // This test is affected by https://crbug.com/725685, which only affects windows
 // platform.
 #if defined(OS_WIN)
-#define MAYBE_ConsistencyCheckExecuted DISABLED_ConsistencyCheckExecuted
+#define MAYBE_StartupMaintenanceTaskExecuted \
+  DISABLED_StartupMaintenanceTaskExecuted
 #else
-#define MAYBE_ConsistencyCheckExecuted ConsistencyCheckExecuted
+#define MAYBE_StartupMaintenanceTaskExecuted StartupMaintenanceTaskExecuted
 #endif
-TEST_F(OfflinePageModelTaskifiedTest, MAYBE_ConsistencyCheckExecuted) {
+TEST_F(OfflinePageModelTaskifiedTest, MAYBE_StartupMaintenanceTaskExecuted) {
   // Insert temporary pages
   page_generator()->SetArchiveDirectory(temporary_dir_path());
   page_generator()->SetNamespace(kDefaultNamespace);
@@ -1420,12 +1422,11 @@
 
   // Insert persistent pages.
   page_generator()->SetNamespace(kDownloadNamespace);
-  // Page missing archive file in pesistent directory.
+  // Page missing archive file in private directory.
   OfflinePageItem persistent_page1 = page_generator()->CreateItem();
   // Page missing metadata entry in database since it's not inserted into store.
   OfflinePageItem persistent_page2 = page_generator()->CreateItemWithTempFile();
-  // Page in persistent namespace saved in persistent directory to simulate
-  // pages saved in legacy directory.
+  // Page in persistent namespace saved in private directory.
   OfflinePageItem persistent_page3 = page_generator()->CreateItemWithTempFile();
   InsertPageIntoStore(persistent_page1);
   InsertPageIntoStore(persistent_page3);
@@ -1438,7 +1439,7 @@
             test_utils::GetFileCountInDirectory(private_archive_dir_path()));
 
   // Execute GetAllPages and move the clock forward to cover the delay, in order
-  // to trigger consistency checks.
+  // to trigger StartupMaintenanceTask execution.
   base::MockCallback<MultipleOfflinePageItemCallback> callback;
   model()->GetAllPages(callback.Get());
   task_runner()->FastForwardBy(
@@ -1446,7 +1447,7 @@
       base::TimeDelta::FromMilliseconds(1));
   PumpLoop();
 
-  EXPECT_EQ(1LL, store_test_util()->GetPageCount());
+  EXPECT_EQ(2LL, store_test_util()->GetPageCount());
   EXPECT_EQ(0UL, test_utils::GetFileCountInDirectory(temporary_dir_path()));
   EXPECT_EQ(1UL,
             test_utils::GetFileCountInDirectory(private_archive_dir_path()));
@@ -1525,6 +1526,115 @@
                                        1);
 }
 
+// This test is affected by https://crbug.com/725685, which only affects windows
+// platform.
+#if defined(OS_WIN)
+#define MAYBE_PersistentPageConsistencyCheckExecuted \
+  DISABLED_PersistentPageConsistencyCheckExecuted
+#else
+#define MAYBE_PersistentPageConsistencyCheckExecuted \
+  PersistentPageConsistencyCheckExecuted
+#endif
+TEST_F(OfflinePageModelTaskifiedTest, PersistentPageConsistencyCheckExecuted) {
+  // The PersistentPageConsistencyCheckTask should not be executed based on time
+  // delays after launch (aka the model being built).
+  task_runner()->FastForwardBy(base::TimeDelta::FromDays(1));
+  PumpLoop();
+  histogram_tester()->ExpectTotalCount(
+      "OfflinePages.ConsistencyCheck.Persistent.Result", 0);
+
+  // GetAllPages should schedule a delayed task that will eventually run
+  // PersistentPageConsistencyCheck.
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  model()->GetAllPages(callback.Get());
+  PumpLoop();
+  histogram_tester()->ExpectTotalCount(
+      "OfflinePages.ConsistencyCheck.Persistent.Result", 0);
+
+  // Add a persistent page with file.
+  page_generator()->SetNamespace(kDownloadNamespace);
+  page_generator()->SetArchiveDirectory(public_archive_dir_path());
+  OfflinePageItem page = page_generator()->CreateItemWithTempFile();
+  page.system_download_id = kDownloadId;
+  InsertPageIntoStore(page);
+  EXPECT_EQ(1UL,
+            test_utils::GetFileCountInDirectory(public_archive_dir_path()));
+  EXPECT_EQ(1LL, store_test_util()->GetPageCount());
+
+  // After the delay (plus 1 millisecond just in case), the consistency check
+  // should be enqueued and executed.
+  const base::TimeDelta run_delay =
+      OfflinePageModelTaskified::kMaintenanceTasksDelay +
+      base::TimeDelta::FromMilliseconds(1);
+  task_runner()->FastForwardBy(run_delay);
+  PumpLoop();
+  // But nothing should change.
+  EXPECT_EQ(1UL,
+            test_utils::GetFileCountInDirectory(public_archive_dir_path()));
+  EXPECT_EQ(1LL, store_test_util()->GetPageCount());
+  histogram_tester()->ExpectTotalCount(
+      "OfflinePages.ConsistencyCheck.Persistent.Result", 1);
+
+  // Delete the file associated with |page|, so the next time when the
+  // consistency check is executed, the page will be marked as hidden.
+  base::DeleteFile(page.file_path, false);
+
+  // Calling GetAllPages after only half of the enforced interval between
+  // consistency check runs should not schedule the task.
+  // Note: The previous elapsed delay is discounted from the clock advance here.
+  task_runner()->FastForwardBy(
+      OfflinePageModelTaskified::kClearStorageInterval / 2 - run_delay);
+  model()->GetAllPages(callback.Get());
+  // And advance the delay too.
+  task_runner()->FastForwardBy(run_delay);
+  PumpLoop();
+  // Confirm no persistent page consistency check is executed.
+  histogram_tester()->ExpectTotalCount(
+      "OfflinePages.ConsistencyCheck.Persistent.Result", 1);
+
+  // Forwarding by the full interval (plus 1 second just in case) should allow
+  // the task to be enqueued again and call GetAllPages again to enqueue the
+  // task.
+  task_runner()->FastForwardBy(
+      OfflinePageModelTaskified::kClearStorageInterval / 2 +
+      base::TimeDelta::FromSeconds(1));
+  model()->GetAllPages(callback.Get());
+  // And advance the delay too.
+  task_runner()->FastForwardBy(run_delay);
+  PumpLoop();
+  // Confirm persistent page consistency check is executed, and the page is
+  // marked as missing file.
+  EXPECT_EQ(0UL,
+            test_utils::GetFileCountInDirectory(public_archive_dir_path()));
+  EXPECT_EQ(1LL, store_test_util()->GetPageCount());
+  auto actual_page = store_test_util()->GetPageByOfflineId(page.offline_id);
+  ASSERT_TRUE(actual_page);
+  EXPECT_NE(base::Time(), actual_page->file_missing_time);
+  histogram_tester()->ExpectTotalCount(
+      "OfflinePages.ConsistencyCheck.Persistent.Result", 2);
+
+  // Forwarding by a long time that is enough for the page with missing file to
+  // get expired.
+  task_runner()->FastForwardBy(base::TimeDelta::FromDays(400));
+  // Saving a page should also immediately enqueue the consistency check task.
+  auto archiver = BuildArchiver(kTestUrl, ArchiverResult::SUCCESSFULLY_CREATED);
+  SavePageWithExpectedResult(kTestUrl, kTestClientId1, kTestUrl2,
+                             kEmptyRequestOrigin, std::move(archiver),
+                             SavePageResult::SUCCESS);
+  // Advance the delay to activate task execution.
+  task_runner()->FastForwardBy(run_delay);
+  PumpLoop();
+  // Confirm persistent page consistency check is executed, and the page is
+  // deleted from database, also notified system download manager.
+  EXPECT_EQ(0UL,
+            test_utils::GetFileCountInDirectory(public_archive_dir_path()));
+  EXPECT_EQ(1LL, store_test_util()->GetPageCount());
+  EXPECT_EQ(page.system_download_id,
+            download_manager_stub()->last_removed_id());
+  histogram_tester()->ExpectTotalCount(
+      "OfflinePages.ConsistencyCheck.Persistent.Result", 3);
+}
+
 TEST_F(OfflinePageModelTaskifiedTest, MaintenanceTasksAreDisabled) {
   // The maintenance tasks should not be executed when disabled by tests.
   model()->DoNotRunMaintenanceTasksForTesting();
diff --git a/components/offline_pages/core/model/persistent_page_consistency_check_task.cc b/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
new file mode 100644
index 0000000..6efa18e
--- /dev/null
+++ b/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
@@ -0,0 +1,254 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/model/persistent_page_consistency_check_task.h"
+
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "components/offline_pages/core/archive_manager.h"
+#include "components/offline_pages/core/client_policy_controller.h"
+#include "components/offline_pages/core/offline_page_client_policy.h"
+#include "components/offline_pages/core/offline_page_metadata_store_sql.h"
+#include "components/offline_pages/core/offline_store_utils.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace base {
+class Time;
+}  // namespace base
+
+namespace offline_pages {
+
+namespace {
+
+#define OFFLINE_PAGES_TABLE_NAME "offlinepages_v1"
+
+const base::TimeDelta kExpireThreshold = base::TimeDelta::FromDays(365);
+
+struct PageInfo {
+  int64_t offline_id;
+  base::FilePath file_path;
+  base::Time file_missing_time;
+  int64_t system_download_id;
+};
+
+std::vector<PageInfo> GetPageInfosByNamespaces(
+    const std::vector<std::string>& temp_namespaces,
+    sql::Connection* db) {
+  std::vector<PageInfo> result;
+
+  static const char kSql[] =
+      "SELECT offline_id, file_path, file_missing_time, system_download_id"
+      " FROM " OFFLINE_PAGES_TABLE_NAME " WHERE client_namespace = ?";
+
+  for (const auto& temp_namespace : temp_namespaces) {
+    sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+    statement.BindString(0, temp_namespace);
+    while (statement.Step()) {
+      result.push_back(
+          {statement.ColumnInt64(0),
+           store_utils::FromDatabaseFilePath(statement.ColumnString(1)),
+           store_utils::FromDatabaseTime(statement.ColumnInt64(2)),
+           statement.ColumnInt64(3)});
+    }
+  }
+
+  return result;
+}
+
+bool DeletePagesByOfflineIds(const std::vector<int64_t>& offline_ids,
+                             sql::Connection* db) {
+  static const char kSql[] =
+      "DELETE FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id = ?";
+
+  for (const auto& offline_id : offline_ids) {
+    sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+    statement.BindInt64(0, offline_id);
+    if (!statement.Run())
+      return false;
+  }
+  return true;
+}
+
+bool MarkPagesAsMissing(const std::vector<int64_t>& ids_of_missing_pages,
+                        base::Time missing_time,
+                        sql::Connection* db) {
+  static const char kSql[] = "UPDATE OR IGNORE " OFFLINE_PAGES_TABLE_NAME
+                             " SET file_missing_time = ?"
+                             " WHERE offline_id = ?";
+
+  for (auto offline_id : ids_of_missing_pages) {
+    sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+    statement.BindInt64(0, store_utils::ToDatabaseTime(missing_time));
+    statement.BindInt64(1, offline_id);
+    if (!statement.Run())
+      return false;
+  }
+  return true;
+}
+
+bool MarkPagesAsReappeared(const std::vector<int64_t>& ids_of_reappeared_pages,
+                           sql::Connection* db) {
+  static const char kSql[] = "UPDATE OR IGNORE " OFFLINE_PAGES_TABLE_NAME
+                             " SET file_missing_time = ?"
+                             " WHERE offline_id = ?";
+
+  base::Time invalid_time;
+  for (auto offline_id : ids_of_reappeared_pages) {
+    sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+    statement.BindInt64(0, store_utils::ToDatabaseTime(invalid_time));
+    statement.BindInt64(1, offline_id);
+    if (!statement.Run())
+      return false;
+  }
+  return true;
+}
+
+PersistentPageConsistencyCheckTask::CheckResult
+PersistentPageConsistencyCheckSync(
+    OfflinePageMetadataStoreSQL* store,
+    const base::FilePath& private_dir,
+    const base::FilePath& public_dir,
+    const std::vector<std::string>& persistent_namespaces,
+    base::Time check_time,
+    sql::Connection* db) {
+  std::vector<int64_t> download_ids_of_deleted_pages;
+  if (!db)
+    return {SyncOperationResult::INVALID_DB_CONNECTION,
+            download_ids_of_deleted_pages};
+
+  sql::Transaction transaction(db);
+  if (!transaction.Begin())
+    return {SyncOperationResult::TRANSACTION_BEGIN_ERROR,
+            download_ids_of_deleted_pages};
+
+  std::vector<PageInfo> persistent_page_infos =
+      GetPageInfosByNamespaces(persistent_namespaces, db);
+
+  std::vector<int64_t> pages_found_missing;
+  std::vector<int64_t> pages_reappeared;
+  std::vector<int64_t> page_ids_to_delete;
+  for (const auto& page_info : persistent_page_infos) {
+    if (base::PathExists(page_info.file_path)) {
+      if (page_info.file_missing_time != base::Time())
+        pages_reappeared.push_back(page_info.offline_id);
+    } else {
+      if (page_info.file_missing_time == base::Time()) {
+        pages_found_missing.push_back(page_info.offline_id);
+      } else {
+        if (check_time - page_info.file_missing_time > kExpireThreshold) {
+          page_ids_to_delete.push_back(page_info.offline_id);
+          download_ids_of_deleted_pages.push_back(page_info.system_download_id);
+        }
+      }
+    }
+  }
+
+  if (!DeletePagesByOfflineIds(page_ids_to_delete, db) ||
+      !MarkPagesAsMissing(pages_found_missing, check_time, db) ||
+      !MarkPagesAsReappeared(pages_reappeared, db)) {
+    return {SyncOperationResult::DB_OPERATION_ERROR,
+            download_ids_of_deleted_pages};
+  }
+
+  if (page_ids_to_delete.size() > 0) {
+    UMA_HISTOGRAM_COUNTS_1M(
+        "OfflinePages.ConsistencyCheck.Persistent.ExpiredEntryCount",
+        base::saturated_cast<int32_t>(page_ids_to_delete.size()));
+  }
+  if (pages_found_missing.size() > 0) {
+    UMA_HISTOGRAM_COUNTS_1M(
+        "OfflinePages.ConsistencyCheck.Persistent.MissingFileCount",
+        base::saturated_cast<int32_t>(pages_found_missing.size()));
+  }
+  if (pages_reappeared.size() > 0) {
+    UMA_HISTOGRAM_COUNTS_1M(
+        "OfflinePages.ConsistencyCheck.Persistent.ReappearedFileCount",
+        base::saturated_cast<int32_t>(pages_reappeared.size()));
+  }
+
+  if (!transaction.Commit())
+    return {SyncOperationResult::TRANSACTION_COMMIT_ERROR,
+            download_ids_of_deleted_pages};
+
+  return {SyncOperationResult::SUCCESS, download_ids_of_deleted_pages};
+}
+
+}  // namespace
+
+PersistentPageConsistencyCheckTask::CheckResult::CheckResult() = default;
+
+PersistentPageConsistencyCheckTask::CheckResult::CheckResult(
+    SyncOperationResult result,
+    const std::vector<int64_t>& system_download_ids)
+    : result(result), download_ids_of_deleted_pages(system_download_ids) {}
+
+PersistentPageConsistencyCheckTask::CheckResult::CheckResult(
+    const CheckResult& other) = default;
+
+PersistentPageConsistencyCheckTask::CheckResult&
+PersistentPageConsistencyCheckTask::CheckResult::operator=(
+    const CheckResult& other) = default;
+
+PersistentPageConsistencyCheckTask::CheckResult::~CheckResult() {}
+
+PersistentPageConsistencyCheckTask::PersistentPageConsistencyCheckTask(
+    OfflinePageMetadataStoreSQL* store,
+    ArchiveManager* archive_manager,
+    ClientPolicyController* policy_controller,
+    base::Time check_time,
+    PersistentPageConsistencyCheckCallback callback)
+    : store_(store),
+      archive_manager_(archive_manager),
+      policy_controller_(policy_controller),
+      check_time_(check_time),
+      callback_(std::move(callback)),
+      weak_ptr_factory_(this) {
+  DCHECK(store_);
+  DCHECK(archive_manager_);
+  DCHECK(policy_controller_);
+}
+
+PersistentPageConsistencyCheckTask::~PersistentPageConsistencyCheckTask() =
+    default;
+
+void PersistentPageConsistencyCheckTask::Run() {
+  std::vector<std::string> namespaces = policy_controller_->GetAllNamespaces();
+  std::vector<std::string> persistent_namespaces;
+  for (const auto& name_space : namespaces) {
+    if (!policy_controller_->IsRemovedOnCacheReset(name_space))
+      persistent_namespaces.push_back(name_space);
+  }
+
+  store_->Execute(base::BindOnce(&PersistentPageConsistencyCheckSync, store_,
+                                 archive_manager_->GetPrivateArchivesDir(),
+                                 archive_manager_->GetPublicArchivesDir(),
+                                 persistent_namespaces, check_time_),
+                  base::BindOnce(&PersistentPageConsistencyCheckTask::
+                                     OnPersistentPageConsistencyCheckDone,
+                                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PersistentPageConsistencyCheckTask::OnPersistentPageConsistencyCheckDone(
+    CheckResult check_result) {
+  UMA_HISTOGRAM_ENUMERATION("OfflinePages.ConsistencyCheck.Persistent.Result",
+                            check_result.result,
+                            SyncOperationResult::RESULT_COUNT);
+  // If sync operation failed, invoke the callback with an empty list of
+  // download ids.
+  if (check_result.result != SyncOperationResult::SUCCESS) {
+    std::move(callback_).Run(false, {});
+  } else {
+    std::move(callback_).Run(true, check_result.download_ids_of_deleted_pages);
+  }
+  TaskComplete();
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/core/model/persistent_page_consistency_check_task.h b/components/offline_pages/core/model/persistent_page_consistency_check_task.h
new file mode 100644
index 0000000..c98d9fa7
--- /dev/null
+++ b/components/offline_pages/core/model/persistent_page_consistency_check_task.h
@@ -0,0 +1,73 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_CORE_MODEL_PERSISTENT_PAGE_CONSISTENCY_CHECK_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_MODEL_PERSISTENT_PAGE_CONSISTENCY_CHECK_TASK_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/offline_store_types.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+
+class ArchiveManager;
+class ClientPolicyController;
+class OfflinePageMetadataStoreSQL;
+
+// This task is responsible for checking consistency of persistent pages, mark
+// the expired ones with the file missing time and recover the previously
+// missing entries back to normal.
+class PersistentPageConsistencyCheckTask : public Task {
+ public:
+  using PersistentPageConsistencyCheckCallback =
+      base::OnceCallback<void(bool success,
+                              const std::vector<int64_t>& pages_deleted)>;
+
+  struct CheckResult {
+    CheckResult();
+    CheckResult(SyncOperationResult result,
+                const std::vector<int64_t>& system_download_ids);
+    CheckResult(const CheckResult& other);
+    CheckResult& operator=(const CheckResult& other);
+    ~CheckResult();
+
+    SyncOperationResult result;
+    std::vector<int64_t> download_ids_of_deleted_pages;
+  };
+
+  PersistentPageConsistencyCheckTask(
+      OfflinePageMetadataStoreSQL* store,
+      ArchiveManager* archive_manager,
+      ClientPolicyController* policy_controller,
+      base::Time check_time,
+      PersistentPageConsistencyCheckCallback callback);
+  ~PersistentPageConsistencyCheckTask() override;
+
+  // Task implementation:
+  void Run() override;
+
+ private:
+  void OnPersistentPageConsistencyCheckDone(CheckResult result);
+
+  // The store containing the offline pages. Not owned.
+  OfflinePageMetadataStoreSQL* store_;
+  // The archive manager storing archive directories. Not owned.
+  ArchiveManager* archive_manager_;
+  // The policy controller which is used to acquire names of namespaces. Not
+  // owned.
+  ClientPolicyController* policy_controller_;
+  base::Time check_time_;
+  // The callback for the task.
+  PersistentPageConsistencyCheckCallback callback_;
+
+  base::WeakPtrFactory<PersistentPageConsistencyCheckTask> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(PersistentPageConsistencyCheckTask);
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_CORE_MODEL_PERSISTENT_PAGE_CONSISTENCY_CHECK_TASK_H_
diff --git a/components/offline_pages/core/model/persistent_page_consistency_check_task_unittest.cc b/components/offline_pages/core/model/persistent_page_consistency_check_task_unittest.cc
new file mode 100644
index 0000000..df1b7df
--- /dev/null
+++ b/components/offline_pages/core/model/persistent_page_consistency_check_task_unittest.cc
@@ -0,0 +1,127 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/model/persistent_page_consistency_check_task.h"
+
+#include "base/bind.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/mock_callback.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/offline_pages/core/client_namespace_constants.h"
+#include "components/offline_pages/core/model/model_task_test_base.h"
+#include "components/offline_pages/core/model/offline_page_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::A;
+using testing::Eq;
+using testing::UnorderedElementsAre;
+
+namespace offline_pages {
+
+using PersistentPageConsistencyCheckCallback =
+    PersistentPageConsistencyCheckTask::PersistentPageConsistencyCheckCallback;
+
+class PersistentPageConsistencyCheckTaskTest : public ModelTaskTestBase {
+ public:
+  PersistentPageConsistencyCheckTaskTest();
+  ~PersistentPageConsistencyCheckTaskTest() override;
+
+  void SetUp() override;
+  bool IsPageMissingFile(const OfflinePageItem& page);
+
+  base::HistogramTester* histogram_tester() { return histogram_tester_.get(); }
+
+ private:
+  std::unique_ptr<base::HistogramTester> histogram_tester_;
+};
+
+PersistentPageConsistencyCheckTaskTest::
+    PersistentPageConsistencyCheckTaskTest() {}
+
+PersistentPageConsistencyCheckTaskTest::
+    ~PersistentPageConsistencyCheckTaskTest() {}
+
+void PersistentPageConsistencyCheckTaskTest::SetUp() {
+  ModelTaskTestBase::SetUp();
+  histogram_tester_ = std::make_unique<base::HistogramTester>();
+}
+
+bool PersistentPageConsistencyCheckTaskTest::IsPageMissingFile(
+    const OfflinePageItem& page) {
+  auto actual_page = store_test_util()->GetPageByOfflineId(page.offline_id);
+  return (actual_page && actual_page->file_missing_time != base::Time());
+}
+
+// This test is affected by https://crbug.com/725685, which only affects windows
+// platform.
+#if defined(OS_WIN)
+#define MAYBE_ClearExpiredPersistentPages DISABLED_ClearExpiredPersistentPages
+#else
+#define MAYBE_ClearExpiredPersistentPages ClearExpiredPersistentPages
+#endif
+TEST_F(PersistentPageConsistencyCheckTaskTest,
+       MAYBE_ClearExpiredPersistentPages) {
+  base::Time expire_time = base::Time::Now() - base::TimeDelta::FromDays(400);
+
+  // |page{1,4}| will be marked as missing file.
+  // |page{2,5}| will be deleted from DB, since they've been expired for longer
+  // than threshold.
+  // |page{3,6}| will remove the file_missing_time from the entry, since
+  // they've been missing files but the files appeared again.
+  generator()->SetUseOfflineIdAsSystemDownloadId(true);
+  generator()->SetNamespace(kDownloadNamespace);
+  generator()->SetArchiveDirectory(PrivateDir());
+  OfflinePageItem page1 = AddPageWithoutFile();
+  generator()->SetFileMissingTime(expire_time);
+  OfflinePageItem page2 = AddPageWithoutFile();
+  OfflinePageItem page3 = AddPage();
+
+  generator()->SetArchiveDirectory(PublicDir());
+  generator()->SetFileMissingTime(base::Time());
+  OfflinePageItem page4 = AddPageWithoutFile();
+  generator()->SetFileMissingTime(expire_time);
+  OfflinePageItem page5 = AddPageWithoutFile();
+  OfflinePageItem page6 = AddPage();
+
+  EXPECT_EQ(6LL, store_test_util()->GetPageCount());
+  EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir()));
+  EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PublicDir()));
+
+  base::MockCallback<PersistentPageConsistencyCheckCallback> callback;
+  EXPECT_CALL(callback,
+              Run(Eq(true), UnorderedElementsAre(page2.system_download_id,
+                                                 page5.system_download_id)));
+
+  auto task = std::make_unique<PersistentPageConsistencyCheckTask>(
+      store(), archive_manager(), policy_controller(), base::Time::Now(),
+      callback.Get());
+  RunTask(std::move(task));
+
+  EXPECT_EQ(4LL, store_test_util()->GetPageCount());
+  EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir()));
+  EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PublicDir()));
+  EXPECT_TRUE(store_test_util()->GetPageByOfflineId(page1.offline_id));
+  EXPECT_TRUE(IsPageMissingFile(page1));
+  EXPECT_FALSE(store_test_util()->GetPageByOfflineId(page2.offline_id));
+  EXPECT_TRUE(store_test_util()->GetPageByOfflineId(page3.offline_id));
+  EXPECT_FALSE(IsPageMissingFile(page3));
+  EXPECT_TRUE(store_test_util()->GetPageByOfflineId(page4.offline_id));
+  EXPECT_TRUE(IsPageMissingFile(page4));
+  EXPECT_FALSE(store_test_util()->GetPageByOfflineId(page5.offline_id));
+  EXPECT_TRUE(store_test_util()->GetPageByOfflineId(page6.offline_id));
+  EXPECT_FALSE(IsPageMissingFile(page6));
+
+  histogram_tester()->ExpectUniqueSample(
+      "OfflinePages.ConsistencyCheck.Persistent.ExpiredEntryCount", 2, 1);
+  histogram_tester()->ExpectUniqueSample(
+      "OfflinePages.ConsistencyCheck.Persistent.MissingFileCount", 2, 1);
+  histogram_tester()->ExpectUniqueSample(
+      "OfflinePages.ConsistencyCheck.Persistent.ReappearedFileCount", 2, 1);
+  histogram_tester()->ExpectUniqueSample(
+      "OfflinePages.ConsistencyCheck.Persistent.Result",
+      static_cast<int>(SyncOperationResult::SUCCESS), 1);
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/core/model/startup_maintenance_task.cc b/components/offline_pages/core/model/startup_maintenance_task.cc
index 405b937..7e33a2a 100644
--- a/components/offline_pages/core/model/startup_maintenance_task.cc
+++ b/components/offline_pages/core/model/startup_maintenance_task.cc
@@ -89,29 +89,51 @@
   return result;
 }
 
-SyncOperationResult ClearLegacyTempPagesSync(
+// This method is clearing the private dir(the legacy dir).
+// - For all files associated with temporary pages:
+//   The strategy is if any temporary page
+//   is still left behind in the legacy dir, delete them.
+// - For all files associated with persistent pages:
+//   Leave them as-is, since they might be still in use.
+// - For all files without any associated DB entry:
+//   Delete the files, since they're 'headless' and has no way to be accessed.
+SyncOperationResult ClearLegacyPagesInPrivateDirSync(
     sql::Connection* db,
-    const std::vector<std::string>& namespaces,
-    const base::FilePath& legacy_archives_dir) {
+    const std::vector<std::string>& temporary_namespaces,
+    const std::vector<std::string>& persistent_namespaces,
+    const base::FilePath& private_dir) {
   // One large database transaction that will:
   // 1. Get temporary page infos from the database.
-  // 2. Decide which pages to delete (still in legacy archive directory).
-  // 3. Delete metadata entries from the database.
+  // 2. Get persistent page infos from the database, in case they're in private
+  //    dir.
+  // 3. Get all file paths in private dir as a set F.
+  // 4. For each temporary page info:
+  //    - If its file path is in F, record its offline id for deletion.
+  // 5. For each persistent page info:
+  //    - If its file path is in F, remove it from F.
+  // 6. Delete page entries by recorded offline ids, and delete the remaining
+  //    files in F.
   sql::Transaction transaction(db);
   if (!transaction.Begin())
     return SyncOperationResult::TRANSACTION_BEGIN_ERROR;
 
-  std::vector<PageInfo> temp_page_infos =
-      GetPageInfosByNamespaces(namespaces, db);
+  std::vector<PageInfo> temporary_page_infos =
+      GetPageInfosByNamespaces(temporary_namespaces, db);
+  std::vector<PageInfo> persistent_page_infos =
+      GetPageInfosByNamespaces(persistent_namespaces, db);
+  std::map<base::FilePath, PageInfo> path_to_page_info;
 
+  std::set<base::FilePath> archive_paths = GetAllArchives(private_dir);
   std::vector<int64_t> offline_ids_to_delete;
-  std::vector<base::FilePath> files_to_delete;
-  for (const auto& page_info : temp_page_infos) {
-    // Get pages whose archive files are still in the legacy archives directory.
-    if (legacy_archives_dir.IsParent(page_info.file_path)) {
+
+  for (const auto& page_info : temporary_page_infos) {
+    if (archive_paths.find(page_info.file_path) != archive_paths.end())
       offline_ids_to_delete.push_back(page_info.offline_id);
-      files_to_delete.push_back(page_info.file_path);
-    }
+  }
+  for (const auto& page_info : persistent_page_infos) {
+    auto iter = archive_paths.find(page_info.file_path);
+    if (iter != archive_paths.end())
+      archive_paths.erase(iter);
   }
 
   // Try to delete the pages by offline ids collected above.
@@ -124,17 +146,26 @@
   if (!transaction.Commit())
     return SyncOperationResult::TRANSACTION_COMMIT_ERROR;
 
+  std::vector<base::FilePath> files_to_delete(archive_paths.begin(),
+                                              archive_paths.end());
   if (!DeleteFiles(files_to_delete))
     return SyncOperationResult::FILE_OPERATION_ERROR;
 
+  size_t headless_file_count =
+      files_to_delete.size() - offline_ids_to_delete.size();
+  if (headless_file_count > 0) {
+    UMA_HISTOGRAM_COUNTS_1M(
+        "OfflinePages.ConsistencyCheck.Legacy.DeletedHeadlessFileCount",
+        headless_file_count);
+  }
+
   return SyncOperationResult::SUCCESS;
 }
 
-SyncOperationResult CheckConsistencySync(
+SyncOperationResult CheckTemporaryPageConsistencySync(
     sql::Connection* db,
     const std::vector<std::string>& namespaces,
-    const base::FilePath& archives_dir,
-    const std::string& prefix_for_uma) {
+    const base::FilePath& archives_dir) {
   // One large database transaction that will:
   // 1. Get page infos by |namespaces| from the database.
   // 2. Decide which pages to delete.
@@ -165,9 +196,8 @@
     // committed.
     if (!DeletePagesByOfflineIds(offline_ids_to_delete, db))
       return SyncOperationResult::DB_OPERATION_ERROR;
-    base::UmaHistogramCounts1M(
-        "OfflinePages.ConsistencyCheck." + prefix_for_uma +
-            ".PagesMissingArchiveFileCount",
+    UMA_HISTOGRAM_COUNTS_1M(
+        "OfflinePages.ConsistencyCheck.Temporary.PagesMissingArchiveFileCount",
         base::saturated_cast<int32_t>(offline_ids_to_delete.size()));
   }
 
@@ -186,9 +216,9 @@
   if (files_to_delete.size() > 0) {
     if (!DeleteFiles(files_to_delete))
       return SyncOperationResult::FILE_OPERATION_ERROR;
-    base::UmaHistogramCounts1M("OfflinePages.ConsistencyCheck." +
-                                   prefix_for_uma + ".PagesMissingDbEntryCount",
-                               static_cast<int32_t>(files_to_delete.size()));
+    UMA_HISTOGRAM_COUNTS_1M(
+        "OfflinePages.ConsistencyCheck.Temporary.PagesMissingDbEntryCount",
+        static_cast<int32_t>(files_to_delete.size()));
   }
 
   return SyncOperationResult::SUCCESS;
@@ -232,25 +262,16 @@
 
   // Clear temporary pages that are in legacy directory, which is also the
   // directory that serves as the 'private' directory.
-  SyncOperationResult result = ClearLegacyTempPagesSync(
-      db, temporary_namespaces, archive_manager->GetPrivateArchivesDir());
+  SyncOperationResult result = ClearLegacyPagesInPrivateDirSync(
+      db, temporary_namespaces, persistent_namespaces,
+      archive_manager->GetPrivateArchivesDir());
 
   // Clear temporary pages in cache directory.
-  result = CheckConsistencySync(db, temporary_namespaces,
-                                archive_manager->GetTemporaryArchivesDir(),
-                                "Temporary" /*prefix_for_uma*/);
+  result = CheckTemporaryPageConsistencySync(
+      db, temporary_namespaces, archive_manager->GetTemporaryArchivesDir());
   UMA_HISTOGRAM_ENUMERATION("OfflinePages.ConsistencyCheck.Temporary.Result",
                             result, SyncOperationResult::RESULT_COUNT);
 
-  // Clear persistent pages in private directory.
-  // TODO(romax): this can be merged with the legacy temporary pages clearing
-  // above.
-  result = CheckConsistencySync(db, persistent_namespaces,
-                                archive_manager->GetPrivateArchivesDir(),
-                                "Persistent" /*prefix_for_uma*/);
-  UMA_HISTOGRAM_ENUMERATION("OfflinePages.ConsistencyCheck.Persistent.Result",
-                            result, SyncOperationResult::RESULT_COUNT);
-
   // Report storage usage UMA.
   ReportStorageUsageSync(db, namespaces, archive_manager);
 
diff --git a/components/offline_pages/core/model/startup_maintenance_task.h b/components/offline_pages/core/model/startup_maintenance_task.h
index dc9b809c..34c3b13 100644
--- a/components/offline_pages/core/model/startup_maintenance_task.h
+++ b/components/offline_pages/core/model/startup_maintenance_task.h
@@ -16,8 +16,8 @@
 class OfflinePageMetadataStoreSQL;
 
 // This task is responsible for executing maintenance sub-tasks during Chrome
-// startup, including: consistency checks, legacy directory cleaning and report
-// storage usage UMA.
+// startup, including: temporary page consistency check, legacy directory
+// cleaning and report storage usage UMA.
 class StartupMaintenanceTask : public Task {
  public:
   StartupMaintenanceTask(OfflinePageMetadataStoreSQL* store,
diff --git a/components/offline_pages/core/model/startup_maintenance_task_unittest.cc b/components/offline_pages/core/model/startup_maintenance_task_unittest.cc
index 9921b6343..bbc1e53f 100644
--- a/components/offline_pages/core/model/startup_maintenance_task_unittest.cc
+++ b/components/offline_pages/core/model/startup_maintenance_task_unittest.cc
@@ -80,18 +80,19 @@
   TestDeletePageInLegacyArchivesDir
 #endif
 TEST_F(StartupMaintenanceTaskTest, MAYBE_TestDeletePageInLegacyArchivesDir) {
+  // |temporary_page| will be removed since it's temporary and its archive file
+  // is in private directory.
+  // |persistent_page| will not be affected by the maintenance task.
   generator()->SetArchiveDirectory(PrivateDir());
   generator()->SetNamespace(kLastNNamespace);
-  OfflinePageItem temporary_page = AddPage();
+  OfflinePageItem temporary_page1 = AddPage();
+  OfflinePageItem temporary_page2 = AddPageWithoutDBEntry();
   generator()->SetNamespace(kDownloadNamespace);
-  OfflinePageItem persistent_page = AddPage();
-  EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM,
-            CheckPagePresence(temporary_page));
-  EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM,
-            CheckPagePresence(persistent_page));
+  OfflinePageItem persistent_page1 = AddPage();
+  OfflinePageItem persistent_page2 = AddPageWithoutDBEntry();
 
   EXPECT_EQ(2LL, store_test_util()->GetPageCount());
-  EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(PrivateDir()));
+  EXPECT_EQ(4UL, test_utils::GetFileCountInDirectory(PrivateDir()));
 
   auto task = std::make_unique<StartupMaintenanceTask>(
       store(), archive_manager(), policy_controller());
@@ -99,8 +100,13 @@
 
   EXPECT_EQ(1LL, store_test_util()->GetPageCount());
   EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir()));
-  EXPECT_FALSE(
-      store_test_util()->GetPageByOfflineId(temporary_page.offline_id));
+  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page1));
+  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page2));
+  EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM,
+            CheckPagePresence(persistent_page1));
+  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(persistent_page2));
+  histogram_tester()->ExpectUniqueSample(
+      "OfflinePages.ConsistencyCheck.Legacy.DeletedHeadlessFileCount", 2, 1);
 }
 
 // This test is affected by https://crbug.com/725685, which only affects windows
@@ -111,7 +117,12 @@
 #define MAYBE_TestDeleteFileWithoutDbEntry TestDeleteFileWithoutDbEntry
 #endif
 TEST_F(StartupMaintenanceTaskTest, MAYBE_TestDeleteFileWithoutDbEntry) {
-  // Only the files without DB entries will be deleted.
+  // |temporary_page1| will not be affected.
+  // |temporary_page2| will have the file deleted since the file doesn't have a
+  // DB entry.
+  // |persistent_page1| will not be affected.
+  // |persistent_page2| will have its file deleted, since the file is in private
+  // directory and has no associated DB entry.
   generator()->SetNamespace(kLastNNamespace);
   generator()->SetArchiveDirectory(TemporaryDir());
   OfflinePageItem temporary_page1 = AddPage();
@@ -141,6 +152,9 @@
   EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM,
             CheckPagePresence(persistent_page1));
   EXPECT_EQ(PagePresence::NONE, CheckPagePresence(persistent_page2));
+
+  histogram_tester()->ExpectUniqueSample(
+      "OfflinePages.ConsistencyCheck.Legacy.DeletedHeadlessFileCount", 1, 1);
   histogram_tester()->ExpectTotalCount(
       "OfflinePages.ConsistencyCheck.Temporary.PagesMissingArchiveFileCount",
       0);
@@ -149,15 +163,6 @@
   histogram_tester()->ExpectUniqueSample(
       "OfflinePages.ConsistencyCheck.Temporary.Result",
       static_cast<int>(SyncOperationResult::SUCCESS), 1);
-  histogram_tester()->ExpectTotalCount(
-      "OfflinePages.ConsistencyCheck.Persistent.PagesMissingArchiveFileCount",
-      0);
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.ConsistencyCheck.Persistent.PagesMissingDbEntryCount", 1,
-      1);
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.ConsistencyCheck.Persistent.Result",
-      static_cast<int>(SyncOperationResult::SUCCESS), 1);
 }
 
 // This test is affected by https://crbug.com/725685, which only affects windows
@@ -168,7 +173,10 @@
 #define MAYBE_TestDeleteDbEntryWithoutFile TestDeleteDbEntryWithoutFile
 #endif
 TEST_F(StartupMaintenanceTaskTest, MAYBE_TestDeleteDbEntryWithoutFile) {
-  // Only the DB entries without associating files will be deleted.
+  // |temporary_page1| will not be affected.
+  // |temporary_page2| will be deleted from DB since it has no file associated.
+  // |persistent_page1| will not be affected.
+  // |persistent_page2| will be marked as file_missing.
   generator()->SetNamespace(kLastNNamespace);
   generator()->SetArchiveDirectory(TemporaryDir());
   OfflinePageItem temporary_page1 = AddPage();
@@ -189,7 +197,7 @@
       store(), archive_manager(), policy_controller());
   RunTask(std::move(task));
 
-  EXPECT_EQ(2LL, store_test_util()->GetPageCount());
+  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
   EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(TemporaryDir()));
   EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir()));
   EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM,
@@ -197,7 +205,8 @@
   EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page2));
   EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM,
             CheckPagePresence(persistent_page1));
-  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(persistent_page2));
+  EXPECT_EQ(PagePresence::DB_ONLY, CheckPagePresence(persistent_page2));
+
   histogram_tester()->ExpectTotalCount(
       "OfflinePages.ConsistencyCheck.Temporary.PagesMissingDbEntryCount", 0);
   histogram_tester()->ExpectUniqueSample(
@@ -206,14 +215,6 @@
   histogram_tester()->ExpectUniqueSample(
       "OfflinePages.ConsistencyCheck.Temporary.Result",
       static_cast<int>(SyncOperationResult::SUCCESS), 1);
-  histogram_tester()->ExpectTotalCount(
-      "OfflinePages.ConsistencyCheck.Persistent.PagesMissingDbEntryCount", 0);
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.ConsistencyCheck.Persistent.PagesMissingArchiveFileCount",
-      1, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.ConsistencyCheck.Persistent.Result",
-      static_cast<int>(SyncOperationResult::SUCCESS), 1);
 }
 
 // This test is affected by https://crbug.com/725685, which only affects windows
@@ -225,27 +226,28 @@
 #endif
 TEST_F(StartupMaintenanceTaskTest, MAYBE_CombinedTest) {
   // Adding a bunch of pages with different setups for temporary pages.
-  // After the consistency check, only page1 will exist.
+  // |temporary_page1| will not be affected.
+  // |temporary_page{2,3,4,5,6}| will be deleted.
   generator()->SetNamespace(kLastNNamespace);
   generator()->SetArchiveDirectory(TemporaryDir());
-  OfflinePageItem page1 = AddPage();
-  OfflinePageItem page2 = AddPageWithoutDBEntry();
-  OfflinePageItem page3 = AddPageWithoutFile();
-  // Adding a bunch of pages with different setups for persistent pages.
-  // After the consistency check, only page4 will exist.
-  generator()->SetNamespace(kDownloadNamespace);
+  OfflinePageItem temporary_page1 = AddPage();
+  OfflinePageItem temporary_page2 = AddPageWithoutDBEntry();
+  OfflinePageItem temporary_page3 = AddPageWithoutFile();
   generator()->SetArchiveDirectory(PrivateDir());
-  OfflinePageItem page4 = AddPage();
-  OfflinePageItem page5 = AddPageWithoutDBEntry();
-  OfflinePageItem page6 = AddPageWithoutFile();
+  OfflinePageItem temporary_page4 = AddPage();
+  OfflinePageItem temporary_page5 = AddPageWithoutDBEntry();
+  OfflinePageItem temporary_page6 = AddPageWithoutFile();
+  // Adding a bunch of pages with different setups for persistent pages.
+  // |persistent_page1| will not be affected.
+  // |persistent_page2| will be deleted from Filesystem, since it's in private
+  // directory.
+  generator()->SetNamespace(kDownloadNamespace);
+  OfflinePageItem persistent_page1 = AddPage();
+  OfflinePageItem persistent_page2 = AddPageWithoutDBEntry();
 
-  EXPECT_EQ(4LL, store_test_util()->GetPageCount());
+  EXPECT_EQ(5LL, store_test_util()->GetPageCount());
   EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(TemporaryDir()));
-  EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(PrivateDir()));
-  EXPECT_EQ(PagePresence::FILESYSTEM_ONLY, CheckPagePresence(page2));
-  EXPECT_EQ(PagePresence::DB_ONLY, CheckPagePresence(page3));
-  EXPECT_EQ(PagePresence::FILESYSTEM_ONLY, CheckPagePresence(page5));
-  EXPECT_EQ(PagePresence::DB_ONLY, CheckPagePresence(page6));
+  EXPECT_EQ(4UL, test_utils::GetFileCountInDirectory(PrivateDir()));
 
   auto task = std::make_unique<StartupMaintenanceTask>(
       store(), archive_manager(), policy_controller());
@@ -254,61 +256,53 @@
   EXPECT_EQ(2LL, store_test_util()->GetPageCount());
   EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(TemporaryDir()));
   EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir()));
-  EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM, CheckPagePresence(page1));
-  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(page2));
-  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(page3));
-  EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM, CheckPagePresence(page4));
-  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(page5));
-  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(page6));
+
+  EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM,
+            CheckPagePresence(temporary_page1));
+  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page2));
+  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page3));
+  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page4));
+  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page5));
+  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page6));
+
+  EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM,
+            CheckPagePresence(persistent_page1));
+  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(persistent_page2));
+
   histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.ConsistencyCheck.Temporary.PagesMissingArchiveFileCount", 1,
+      "OfflinePages.ConsistencyCheck.Legacy.DeletedHeadlessFileCount", 2, 1);
+  histogram_tester()->ExpectUniqueSample(
+      "OfflinePages.ConsistencyCheck.Temporary.PagesMissingArchiveFileCount", 2,
       1);
   histogram_tester()->ExpectUniqueSample(
       "OfflinePages.ConsistencyCheck.Temporary.PagesMissingDbEntryCount", 1, 1);
   histogram_tester()->ExpectUniqueSample(
       "OfflinePages.ConsistencyCheck.Temporary.Result",
       static_cast<int>(SyncOperationResult::SUCCESS), 1);
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.ConsistencyCheck.Persistent.PagesMissingArchiveFileCount",
-      1, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.ConsistencyCheck.Persistent.PagesMissingDbEntryCount", 1,
-      1);
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.ConsistencyCheck.Persistent.Result",
-      static_cast<int>(SyncOperationResult::SUCCESS), 1);
 }
 
 TEST_F(StartupMaintenanceTaskTest, TestKeepingNonMhtmlFile) {
-  // Create an offline page with mhtml extension but has no DB entry.
+  // Create a persistent offline page with mhtml extension but has no DB entry.
+  // It will not be deleted since it's in public directory.
   generator()->SetNamespace(kDownloadNamespace);
-  generator()->SetArchiveDirectory(PrivateDir());
+  generator()->SetArchiveDirectory(PublicDir());
   OfflinePageItem page1 = AddPageWithoutDBEntry();
-  // Create a file with non-mhtml extension.
+  // Create a file with non-mhtml extension. It should not be affected.
   base::FilePath path;
-  base::CreateTemporaryFileInDir(PrivateDir(), &path);
+  base::CreateTemporaryFileInDir(PublicDir(), &path);
   base::FilePath mp3_path = path.AddExtension(FILE_PATH_LITERAL("mp3"));
   EXPECT_TRUE(base::Move(path, mp3_path));
 
   EXPECT_EQ(0LL, store_test_util()->GetPageCount());
-  EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(PrivateDir()));
+  EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(PublicDir()));
 
   auto task = std::make_unique<StartupMaintenanceTask>(
       store(), archive_manager(), policy_controller());
   RunTask(std::move(task));
 
   EXPECT_EQ(0LL, store_test_util()->GetPageCount());
-  EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir()));
-  EXPECT_EQ(PagePresence::NONE, CheckPagePresence(page1));
-  histogram_tester()->ExpectTotalCount(
-      "OfflinePages.ConsistencyCheck.Persistent.PagesMissingArchiveFileCount",
-      0);
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.ConsistencyCheck.Persistent.PagesMissingDbEntryCount", 1,
-      1);
-  histogram_tester()->ExpectUniqueSample(
-      "OfflinePages.ConsistencyCheck.Persistent.Result",
-      static_cast<int>(SyncOperationResult::SUCCESS), 1);
+  EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(PublicDir()));
+  EXPECT_EQ(PagePresence::FILESYSTEM_ONLY, CheckPagePresence(page1));
 }
 
 TEST_F(StartupMaintenanceTaskTest, TestReportStorageUsage) {
diff --git a/components/services/heap_profiling/public/cpp/settings.cc b/components/services/heap_profiling/public/cpp/settings.cc
index 1d4bbc2c..72525f4 100644
--- a/components/services/heap_profiling/public/cpp/settings.cc
+++ b/components/services/heap_profiling/public/cpp/settings.cc
@@ -42,17 +42,15 @@
 Mode GetModeForStartup() {
   const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
 #if BUILDFLAG(USE_ALLOCATOR_SHIM)
+  if (cmdline->HasSwitch("enable-heap-profiling")) {
+    LOG(ERROR) << "--enable-heap-profiling is no longer supported. Use "
+                  "--memlog instead. See documentation at "
+                  "docs/memory/debugging_memory_issues.md";
+    return Mode::kNone;
+  }
+
   if (cmdline->HasSwitch(kMemlog) ||
       base::FeatureList::IsEnabled(kOOPHeapProfilingFeature)) {
-    if (cmdline->HasSwitch(switches::kEnableHeapProfiling)) {
-      // PartitionAlloc doesn't support chained allocation hooks so we can't
-      // run both heap profilers at the same time.
-      LOG(ERROR) << "--" << switches::kEnableHeapProfiling
-                 << " specified with --" << kMemlog
-                 << "which are not compatible. Memlog will be disabled.";
-      return Mode::kNone;
-    }
-
     std::string mode;
     // Respect the commandline switch above the field trial.
     if (cmdline->HasSwitch(kMemlog)) {
diff --git a/components/tracing/common/trace_startup.cc b/components/tracing/common/trace_startup.cc
index 54b6aedd..6ad1aeae 100644
--- a/components/tracing/common/trace_startup.cc
+++ b/components/tracing/common/trace_startup.cc
@@ -22,10 +22,6 @@
   // https://crbug.com/764357
   base::trace_event::TraceLog::GetInstance();
 
-  // Enables heap profiling if "--enable-heap-profiling" flag is passed.
-  base::trace_event::MemoryDumpManager::GetInstance()
-      ->EnableHeapProfilingIfNeeded();
-
   if (command_line.HasSwitch(switches::kTraceStartup)) {
     base::trace_event::TraceConfig trace_config(
         command_line.GetSwitchValueASCII(switches::kTraceStartup),
diff --git a/components/tracing/docs/heap_profiler_internals.md b/components/tracing/docs/heap_profiler_internals.md
deleted file mode 100644
index a54e7f3..0000000
--- a/components/tracing/docs/heap_profiler_internals.md
+++ /dev/null
@@ -1,2 +0,0 @@
-This document has moved to [//docs/memory-infra/heap_profiler_internals.md](/docs/memory-infra/heap_profiler_internals.md).
-
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index 030a9c5..3653ec1 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -14,7 +14,7 @@
     "business.icon",
     "check_circle.icon",
     "close.icon",
-    "close_16.icon",
+    "close_rounded.icon",
     "edit.icon",
     "folder.icon",
     "folder_managed.icon",
diff --git a/components/vector_icons/aggregate_vector_icons.py b/components/vector_icons/aggregate_vector_icons.py
index 112cf7bb..cc7f0c6 100644
--- a/components/vector_icons/aggregate_vector_icons.py
+++ b/components/vector_icons/aggregate_vector_icons.py
@@ -28,21 +28,29 @@
   return "k" + "".join(words) + suffix
 
 
-def GetPathName(name, append_1x=False):
-  return CamelCase(name, "Path1x" if append_1x else "Path")
+def GetPathName(name, size=None):
+  return CamelCase(name, "{}Path".format(size) if size != None else "Path")
 
 
-def GetRepName(name, append_1x=False):
-  return CamelCase(name, "Rep1x" if append_1x else "Rep")
+def GetRepListName(name):
+  return CamelCase(name, "RepList")
 
 
 def GetIconName(name):
   return CamelCase(name, "Icon")
 
 
+def AddIconToDictionary(icon_file, new_icon, icon_size, icon_index):
+  if icon_size in icon_index:
+    Error("Duplicate icon of size {} found in {}.".format(icon_size, icon_file))
+  icon_index[icon_size] = "\n".join(new_icon)
+  return icon_index
+
+
 def ExtractIconReps(icon_file_name):
-  """Reads the contents of the given icon file and returns a list of vector
-     commands for different icon representations stored in that file.
+  """Reads the contents of the given icon file and returns a dictionary of icon
+     sizes to vector commands for different icon representations stored in that
+     file.
 
   Args:
       icon_file_name: The file path of the icon file to read.
@@ -50,9 +58,10 @@
   with open(icon_file_name, "r") as icon_file:
     icon_file_contents = icon_file.readlines()
 
+  current_icon_size = REFERENCE_SIZE_DIP
   icon_sizes = []
   current_icon_representation = []
-  icon_representation_list = []
+  icon_representations = {}
   for line in icon_file_contents:
     # Strip comments and empty lines.
     line = line.partition(CPP_COMMENT_DELIMITER)[0].strip()
@@ -63,28 +72,34 @@
     if line.startswith(CANVAS_DIMENSIONS):
       sizes = re.findall(r"\d+", line)
       if len(sizes) != 1:
-        Error("Malformed {} line found in {} - it should only specify one size."
+        Error("Malformed {} line in {} - it should specify exactly one size."
               .format(CANVAS_DIMENSIONS, icon_file_name))
       icon_sizes.append(int(sizes[0]))
 
       # All icons except the first / default icon must start with
       # "CANVAS_DIMENSIONS", so rely on it here as a icon delimiter.
       if current_icon_representation:
-        icon_representation_list.append("\n".join(current_icon_representation))
+        icon_representations = AddIconToDictionary(
+            icon_file_name, current_icon_representation, current_icon_size,
+            icon_representations)
         current_icon_representation = []
+      current_icon_size = icon_sizes[-1]
+
     current_icon_representation.append(line)
   if current_icon_representation:
-    icon_representation_list.append("\n".join(current_icon_representation))
+    icon_representations = AddIconToDictionary(
+        icon_file_name, current_icon_representation, current_icon_size,
+        icon_representations)
 
-  if not icon_representation_list:
+  if not icon_representations:
     Error("Didn't find any icons in {}.".format(icon_file_name))
 
-  if len(icon_representation_list) != len(icon_sizes):
+  if len(icon_representations) != len(icon_sizes):
     icon_sizes.insert(0, REFERENCE_SIZE_DIP)
   if sorted(icon_sizes, reverse=True) != icon_sizes:
     Error("The icons in {} should be sorted in descending order of size."
           .format(icon_file_name))
-  return icon_representation_list
+  return icon_representations
 
 
 def AggregateVectorIcons(working_directory, file_list, output_cc, output_h):
@@ -157,34 +172,24 @@
       (icon_name, extension) = os.path.splitext(
                                os.path.basename(path_map[icon]))
 
-      # Store the vector-drawing commands for foo_bar.icon in the temporary
-      # variable kFooBarPath.
-      icon_representation_list = ExtractIconReps(path_map[icon])
-      (vector_commands, vector_commands_1x) = None, None
-      if len(icon_representation_list) >= 1:
-        vector_commands = icon_representation_list[0]
-      if len(icon_representation_list) >= 2:
-        vector_commands_1x = icon_representation_list[1]
-      if len(icon_representation_list) >= 3:
-        print "Warning: " + path_map[icon] + " has more than two icon", \
-              "representations. Support for this is still a WIP - see", \
-              "crbug.com/647286. For now, only the first two will be used."
-      output_cc.write("VECTOR_ICON_REP_TEMPLATE({}, {}, {})\n".format(
-          GetPathName(icon_name), GetRepName(icon_name), vector_commands))
+      icon_representations = ExtractIconReps(path_map[icon])
+      icon_representation_strings = []
+      for i, size in enumerate(sorted(icon_representations, reverse=True)):
+        vector_commands = icon_representations[size]
+        icon_path_name = GetPathName(icon_name, size if i != 0 else None)
+        # Store the vector-drawing commands for foo_bar.icon in the temporary
+        # variable kFooBarPath.
+        output_cc.write("VECTOR_ICON_REP_TEMPLATE({}, {})\n".format(
+            icon_path_name, vector_commands))
+        icon_representation_strings.append(
+            "{{{0}, arraysize({0})}}".format(icon_path_name))
 
-      # Store the vector-drawing commands for foo_bar.icon's 1x version in the
-      # temporary variable kFooBarPath1x, if it exists.
-      if vector_commands_1x:
-        output_cc.write("VECTOR_ICON_REP_TEMPLATE({}, {}, {})\n".format(
-            GetPathName(icon_name, True), GetRepName(icon_name, True),
-            vector_commands_1x))
-        output_cc.write("VECTOR_ICON_TEMPLATE2({}, {}, {})\n".format(
-            GetIconName(icon_name), GetRepName(icon_name),
-            GetRepName(icon_name, True)))
-      else:
-        # Define the value of kFooBarIcon.
-        output_cc.write("VECTOR_ICON_TEMPLATE({}, {})\n".format(
-            GetIconName(icon_name), GetRepName(icon_name)))
+      # Another temporary variable kFooBarRepList is used to create all the
+      # VectorIconReps inline, with a pointer to it in the final VectorIcon.
+      output_cc.write("VECTOR_ICON_TEMPLATE_CC({}, {}, {})\n".format(
+          GetRepListName(icon_name), GetIconName(icon_name),
+          ", ".join(icon_representation_strings)))
+
   output_cc.close()
 
 
diff --git a/components/vector_icons/cc_macros.h b/components/vector_icons/cc_macros.h
index eba40a59..e51c4d4 100644
--- a/components/vector_icons/cc_macros.h
+++ b/components/vector_icons/cc_macros.h
@@ -15,19 +15,14 @@
 #define VECTOR_ICON_ID_PREFIX ""
 #endif
 
-#define VECTOR_ICON_REP_TEMPLATE(path_name, rep_name, ...)       \
-  static constexpr gfx::PathElement path_name[] = {__VA_ARGS__}; \
-  constexpr gfx::VectorIconRep rep_name = {path_name, arraysize(path_name)};
+#define VECTOR_ICON_REP_TEMPLATE(path_name, ...) \
+  static constexpr gfx::PathElement path_name[] = {__VA_ARGS__};
 
-// The VectorIcon will be called kMyIcon, and the identifier for the icon might
-// be "my_namespace::kMyIconId".
-#define VECTOR_ICON_TEMPLATE(icon_name, rep_name)                \
-  const char icon_name##Id[] = VECTOR_ICON_ID_PREFIX #icon_name; \
-  const gfx::VectorIcon icon_name = {&rep_name, nullptr, icon_name##Id};
-
-#define VECTOR_ICON_TEMPLATE2(icon_name, rep_name, rep_name_1x)  \
-  const char icon_name##Id[] = VECTOR_ICON_ID_PREFIX #icon_name; \
-  const gfx::VectorIcon icon_name = {&rep_name, &rep_name_1x, icon_name##Id};
+#define VECTOR_ICON_TEMPLATE_CC(rep_list_name, icon_name, ...)                \
+  constexpr char icon_name##Id[] = VECTOR_ICON_ID_PREFIX #icon_name;          \
+  static constexpr gfx::VectorIconRep rep_list_name[] = {__VA_ARGS__};        \
+  const gfx::VectorIcon icon_name = {rep_list_name, arraysize(rep_list_name), \
+                                     icon_name##Id};
 
 #else  // !COMPONENTS_VECTOR_ICONS_CC_MACROS_H_
 #error This file should only be included once.
diff --git a/components/vector_icons/close_16.icon b/components/vector_icons/close_rounded.icon
similarity index 100%
rename from components/vector_icons/close_16.icon
rename to components/vector_icons/close_rounded.icon
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc
index 2de849a..7ca1d13f 100644
--- a/components/viz/service/display/renderer_pixeltest.cc
+++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -818,6 +818,13 @@
 }
 
 template <>
+bool FuzzyForSoftwareOnlyPixelComparator<SkiaRenderer>::Compare(
+    const SkBitmap& actual_bmp,
+    const SkBitmap& expected_bmp) const {
+  return fuzzy_.Compare(actual_bmp, expected_bmp);
+}
+
+template <>
 bool FuzzyForSoftwareOnlyPixelComparator<
     cc::SoftwareRendererWithExpandedViewport>::
     Compare(const SkBitmap& actual_bmp, const SkBitmap& expected_bmp) const {
@@ -1804,7 +1811,7 @@
       cc::FuzzyPixelOffByOneComparator(true)));
 }
 
-TYPED_TEST(NonSkiaRendererPixelTest, FastPassColorFilterAlpha) {
+TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) {
   gfx::Rect viewport_rect(this->device_viewport_size_);
 
   int root_pass_id = 1;
@@ -1882,7 +1889,7 @@
       FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false)));
 }
 
-TYPED_TEST(NonSkiaRendererPixelTest, FastPassSaturateFilter) {
+TYPED_TEST(RendererPixelTest, FastPassSaturateFilter) {
   gfx::Rect viewport_rect(this->device_viewport_size_);
 
   int root_pass_id = 1;
@@ -1942,7 +1949,7 @@
       FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false)));
 }
 
-TYPED_TEST(NonSkiaRendererPixelTest, FastPassFilterChain) {
+TYPED_TEST(RendererPixelTest, FastPassFilterChain) {
   gfx::Rect viewport_rect(this->device_viewport_size_);
 
   int root_pass_id = 1;
@@ -2004,7 +2011,7 @@
       FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false)));
 }
 
-TYPED_TEST(NonSkiaRendererPixelTest, FastPassColorFilterAlphaTranslation) {
+TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) {
   gfx::Rect viewport_rect(this->device_viewport_size_);
 
   int root_pass_id = 1;
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc
index f05f50d..060a293 100644
--- a/components/viz/service/gl/gpu_service_impl.cc
+++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -114,7 +114,9 @@
     std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread,
     scoped_refptr<base::SingleThreadTaskRunner> io_runner,
     const gpu::GpuFeatureInfo& gpu_feature_info,
-    const gpu::GpuPreferences& gpu_preferences)
+    const gpu::GpuPreferences& gpu_preferences,
+    const gpu::GPUInfo& gpu_info_for_hardware_gpu,
+    const gpu::GpuFeatureInfo& gpu_feature_info_for_hardware_gpu)
     : main_runner_(base::ThreadTaskRunnerHandle::Get()),
       io_runner_(std::move(io_runner)),
       watchdog_thread_(std::move(watchdog_thread)),
@@ -123,6 +125,8 @@
       gpu_preferences_(gpu_preferences),
       gpu_info_(gpu_info),
       gpu_feature_info_(gpu_feature_info),
+      gpu_info_for_hardware_gpu_(gpu_info_for_hardware_gpu),
+      gpu_feature_info_for_hardware_gpu_(gpu_feature_info_for_hardware_gpu),
       bindings_(std::make_unique<mojo::BindingSet<mojom::GpuService>>()),
       weak_ptr_factory_(this) {
   DCHECK(!io_runner_->BelongsToCurrentThread());
@@ -190,7 +194,9 @@
     gpu::SyncPointManager* sync_point_manager,
     base::WaitableEvent* shutdown_event) {
   DCHECK(main_runner_->BelongsToCurrentThread());
-  gpu_host->DidInitialize(gpu_info_, gpu_feature_info_);
+  gpu_host->DidInitialize(gpu_info_, gpu_feature_info_,
+                          gpu_info_for_hardware_gpu_,
+                          gpu_feature_info_for_hardware_gpu_);
   gpu_host_ =
       mojom::ThreadSafeGpuHostPtr::Create(gpu_host.PassInterface(), io_runner_);
   if (!in_host_process()) {
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h
index a29e320f..8abf60c 100644
--- a/components/viz/service/gl/gpu_service_impl.h
+++ b/components/viz/service/gl/gpu_service_impl.h
@@ -62,7 +62,9 @@
                  std::unique_ptr<gpu::GpuWatchdogThread> watchdog,
                  scoped_refptr<base::SingleThreadTaskRunner> io_runner,
                  const gpu::GpuFeatureInfo& gpu_feature_info,
-                 const gpu::GpuPreferences& gpu_preferences);
+                 const gpu::GpuPreferences& gpu_preferences,
+                 const gpu::GPUInfo& gpu_info_for_hardware_gpu,
+                 const gpu::GpuFeatureInfo& gpu_feature_info_for_hardware_gpu);
 
   ~GpuServiceImpl() override;
 
@@ -226,6 +228,11 @@
   // Information about general chrome feature support for the GPU.
   gpu::GpuFeatureInfo gpu_feature_info_;
 
+  // What we would have gotten if we haven't fallen back to SwiftShader or
+  // pure software (in the viz case).
+  gpu::GPUInfo gpu_info_for_hardware_gpu_;
+  gpu::GpuFeatureInfo gpu_feature_info_for_hardware_gpu_;
+
   scoped_refptr<mojom::ThreadSafeGpuHostPtr> gpu_host_;
   std::unique_ptr<gpu::GpuChannelManager> gpu_channel_manager_;
   std::unique_ptr<media::MediaGpuChannelManager> media_gpu_channel_manager_;
diff --git a/components/viz/service/gl/gpu_service_impl_unittest.cc b/components/viz/service/gl/gpu_service_impl_unittest.cc
index c36a072f..db04e5f2 100644
--- a/components/viz/service/gl/gpu_service_impl_unittest.cc
+++ b/components/viz/service/gl/gpu_service_impl_unittest.cc
@@ -51,7 +51,8 @@
     ASSERT_TRUE(io_thread_.Start());
     gpu_service_ = std::make_unique<GpuServiceImpl>(
         gpu::GPUInfo(), nullptr /* watchdog_thread */, io_thread_.task_runner(),
-        gpu::GpuFeatureInfo(), gpu::GpuPreferences());
+        gpu::GpuFeatureInfo(), gpu::GpuPreferences(), gpu::GPUInfo(),
+        gpu::GpuFeatureInfo());
   }
 
   void TearDown() override {
diff --git a/components/viz/service/main/viz_main_impl.cc b/components/viz/service/main/viz_main_impl.cc
index 7738314c..df94129 100644
--- a/components/viz/service/main/viz_main_impl.cc
+++ b/components/viz/service/main/viz_main_impl.cc
@@ -143,7 +143,9 @@
 
   gpu_service_ = std::make_unique<GpuServiceImpl>(
       gpu_init_->gpu_info(), gpu_init_->TakeWatchdogThread(), io_task_runner(),
-      gpu_init_->gpu_feature_info(), gpu_init_->gpu_preferences());
+      gpu_init_->gpu_feature_info(), gpu_init_->gpu_preferences(),
+      gpu_init_->gpu_info_for_hardware_gpu(),
+      gpu_init_->gpu_feature_info_for_hardware_gpu());
 }
 
 VizMainImpl::~VizMainImpl() {
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index 07b04a9..672e288 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -279,7 +279,6 @@
   // to the zygote/renderers.
   static const char* const kForwardSwitches[] = {
       switches::kAndroidFontsPath, switches::kClearKeyCdmPathForTesting,
-      switches::kEnableHeapProfiling,
       switches::kEnableLogging,  // Support, e.g., --enable-logging=stderr.
       // Need to tell the zygote that it is headless so that we don't try to use
       // the wrong type of main delegate.
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 7e20243..2bd827526 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -160,7 +160,6 @@
 #endif
 
 #if defined(OS_MACOSX)
-#include "base/allocator/allocator_interception_mac.h"
 #include "base/memory/memory_pressure_monitor_mac.h"
 #include "content/browser/cocoa/system_hotkey_helper_mac.h"
 #include "content/browser/mach_broker_mac.h"
@@ -774,14 +773,6 @@
 
   InitializeMemoryManagementComponent();
 
-#if defined(OS_MACOSX)
-  if (base::CommandLine::InitializedForCurrentProcess() &&
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableHeapProfiling)) {
-    base::allocator::PeriodicallyShimNewMallocZones();
-  }
-#endif
-
 #if BUILDFLAG(ENABLE_PLUGINS)
   // Prior to any processing happening on the IO thread, we create the
   // plugin service as it is predominantly used from the IO thread,
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index dab07a8c..36344ef 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -175,11 +175,14 @@
       browser_plugin_instance_id_));
 }
 
-void BrowserPluginGuest::ResizeDueToAutoResize(const gfx::Size& new_size,
-                                               uint64_t sequence_number) {
+void BrowserPluginGuest::ResizeDueToAutoResize(
+    const gfx::Size& new_size,
+    uint64_t sequence_number,
+    const viz::LocalSurfaceId& child_allocated_surface_id) {
   SendMessageToEmbedder(
       std::make_unique<BrowserPluginMsg_ResizeDueToAutoResize>(
-          browser_plugin_instance_id_, sequence_number));
+          browser_plugin_instance_id_, sequence_number,
+          child_allocated_surface_id));
 }
 
 void BrowserPluginGuest::SizeContents(const gfx::Size& new_size) {
@@ -1038,7 +1041,8 @@
     const FrameResizeParams& resize_params) {
   if (local_surface_id_ > local_surface_id ||
       ((frame_rect_.size() != resize_params.screen_space_rect.size() ||
-        screen_info_ != resize_params.screen_info) &&
+        screen_info_ != resize_params.screen_info ||
+        capture_sequence_number_ != resize_params.capture_sequence_number) &&
        local_surface_id_ == local_surface_id)) {
     SiteInstance* owner_site_instance = delegate_->GetOwnerSiteInstance();
     bad_message::ReceivedBadMessage(
@@ -1051,11 +1055,22 @@
   frame_rect_ = resize_params.screen_space_rect;
   GetWebContents()->SendScreenRects();
   local_surface_id_ = local_surface_id;
+  bool capture_sequence_number_changed =
+      capture_sequence_number_ != resize_params.capture_sequence_number;
+  capture_sequence_number_ = resize_params.capture_sequence_number;
 
   RenderWidgetHostView* view = web_contents()->GetRenderWidgetHostView();
   if (!view)
     return;
 
+  // We could add functionality to set a specific capture sequence number on the
+  // |view|, but knowing that it's changed is sufficient for us simply request
+  // that our RenderWidgetHostView synchronizes its surfaces. Note that this
+  // should only happen during layout tests, since that is the only call that
+  // should trigger the capture sequence number to change.
+  if (capture_sequence_number_changed)
+    view->EnsureSurfaceSynchronizedForLayoutTest();
+
   RenderWidgetHostImpl* render_widget_host =
       RenderWidgetHostImpl::From(view->GetRenderWidgetHost());
   DCHECK(render_widget_host);
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h
index 50b3c014..c6df5805 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -30,6 +30,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
+#include "components/viz/common/surfaces/scoped_surface_id_allocator.h"
 #include "content/common/edit_command.h"
 #include "content/public/browser/browser_plugin_guest_delegate.h"
 #include "content/public/browser/guest_host.h"
@@ -181,8 +182,10 @@
 
   void EnableAutoResize(const gfx::Size& min_size, const gfx::Size& max_size);
   void DisableAutoResize();
-  void ResizeDueToAutoResize(const gfx::Size& new_size,
-                             uint64_t sequence_number);
+  void ResizeDueToAutoResize(
+      const gfx::Size& new_size,
+      uint64_t sequence_number,
+      const viz::LocalSurfaceId& child_allocated_surface_id);
 
   // WebContentsObserver implementation.
   void DidFinishNavigation(NavigationHandle* navigation_handle) override;
@@ -450,6 +453,7 @@
 
   viz::LocalSurfaceId local_surface_id_;
   ScreenInfo screen_info_;
+  uint32_t capture_sequence_number_ = 0u;
 
   // Weak pointer used to ask GeolocationPermissionContext about geolocation
   // permission.
diff --git a/content/browser/browser_plugin/browser_plugin_message_filter.cc b/content/browser/browser_plugin/browser_plugin_message_filter.cc
index fec9859..93bf2a1 100644
--- a/content/browser/browser_plugin/browser_plugin_message_filter.cc
+++ b/content/browser/browser_plugin/browser_plugin_message_filter.cc
@@ -28,6 +28,11 @@
 
 bool BrowserPluginMessageFilter::OnMessageReceived(
     const IPC::Message& message) {
+  if (sub_filter_for_testing_ &&
+      sub_filter_for_testing_->OnMessageReceived(message)) {
+    return true;
+  }
+
   // Any message requested by a BrowserPluginGuest should be routed through
   // a BrowserPluginGuestManager.
   if (BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(message)) {
@@ -82,4 +87,9 @@
       ->OnMessageReceivedFromEmbedder(message);
 }
 
+void BrowserPluginMessageFilter::SetSubFilterForTesting(
+    scoped_refptr<BrowserMessageFilter> sub_filter) {
+  sub_filter_for_testing_ = sub_filter;
+}
+
 } // namespace content
diff --git a/content/browser/browser_plugin/browser_plugin_message_filter.h b/content/browser/browser_plugin/browser_plugin_message_filter.h
index 646f4248..7c03bd3 100644
--- a/content/browser/browser_plugin/browser_plugin_message_filter.h
+++ b/content/browser/browser_plugin/browser_plugin_message_filter.h
@@ -23,6 +23,9 @@
   bool OnMessageReceived(const IPC::Message& message) override;
   void OnDestruct() const override;
 
+  // Test-only functions:
+  void SetSubFilterForTesting(scoped_refptr<BrowserMessageFilter> sub_filter);
+
  private:
   friend class BrowserThread;
   friend class base::DeleteHelper<BrowserPluginMessageFilter>;
@@ -33,6 +36,8 @@
 
   const int render_process_id_;
 
+  scoped_refptr<BrowserMessageFilter> sub_filter_for_testing_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserPluginMessageFilter);
 };
 
diff --git a/content/browser/browsing_data/browsing_data_filter_builder_impl.cc b/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
index 74ba9ff..dd806b36 100644
--- a/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
+++ b/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
@@ -56,17 +56,6 @@
           (mode == BrowsingDataFilterBuilder::WHITELIST));
 }
 
-// True if none of the supplied domains matches this Channel ID's server ID
-// and we're a blacklist, or one of them does and we're a whitelist.
-// The whitelist or blacklist is represented as |domains_and_ips| and |mode|.
-bool MatchesChannelIDForRegisterableDomainsAndIPs(
-    const std::set<std::string>& domains_and_ips,
-    BrowsingDataFilterBuilder::Mode mode,
-    const std::string& channel_id_server_id) {
-  return ((mode == BrowsingDataFilterBuilder::WHITELIST) ==
-      (domains_and_ips.find(channel_id_server_id) != domains_and_ips.end()));
-}
-
 // True if none of the supplied domains matches this plugin's |site| and we're
 // a blacklist, or one of them does and we're a whitelist. The whitelist or
 // blacklist is represented by |domains_and_ips| and |mode|.
@@ -138,13 +127,13 @@
   return base::BindRepeating(&MatchesURL, origins_, domains_, mode_);
 }
 
-network::mojom::ClearCacheUrlFilterPtr
-BrowsingDataFilterBuilderImpl::BuildClearCacheUrlFilter() const {
-  network::mojom::ClearCacheUrlFilterPtr filter =
-      network::mojom::ClearCacheUrlFilter::New();
+network::mojom::ClearDataFilterPtr
+BrowsingDataFilterBuilderImpl::BuildNetworkServiceFilter() const {
+  network::mojom::ClearDataFilterPtr filter =
+      network::mojom::ClearDataFilter::New();
   filter->type = (mode_ == Mode::WHITELIST)
-                     ? network::mojom::ClearCacheUrlFilter::Type::DELETE_MATCHES
-                     : network::mojom::ClearCacheUrlFilter::Type::KEEP_MATCHES;
+                     ? network::mojom::ClearDataFilter::Type::DELETE_MATCHES
+                     : network::mojom::ClearDataFilter::Type::KEEP_MATCHES;
   filter->origins.insert(filter->origins.begin(), origins_.begin(),
                          origins_.end());
   filter->domains.insert(filter->domains.begin(), domains_.begin(),
@@ -172,15 +161,6 @@
   return delete_info;
 }
 
-base::RepeatingCallback<bool(const std::string& channel_id_server_id)>
-BrowsingDataFilterBuilderImpl::BuildChannelIDFilter() const {
-  DCHECK(origins_.empty()) <<
-      "Origin-based deletion is not suitable for channel IDs. Please use "
-      "different scoping, such as RegistrableDomainFilterBuilder.";
-  return base::BindRepeating(&MatchesChannelIDForRegisterableDomainsAndIPs,
-                             domains_, mode_);
-}
-
 base::RepeatingCallback<bool(const std::string& site)>
 BrowsingDataFilterBuilderImpl::BuildPluginFilter() const {
   DCHECK(origins_.empty()) <<
diff --git a/content/browser/browsing_data/browsing_data_filter_builder_impl.h b/content/browser/browsing_data/browsing_data_filter_builder_impl.h
index 0eb04b8a..43aeac9 100644
--- a/content/browser/browsing_data/browsing_data_filter_builder_impl.h
+++ b/content/browser/browsing_data/browsing_data_filter_builder_impl.h
@@ -24,11 +24,8 @@
   bool IsEmptyBlacklist() const override;
   base::RepeatingCallback<bool(const GURL&)>
       BuildGeneralFilter() const override;
-  network::mojom::ClearCacheUrlFilterPtr BuildClearCacheUrlFilter()
-      const override;
+  network::mojom::ClearDataFilterPtr BuildNetworkServiceFilter() const override;
   net::CookieStore::CookieDeletionInfo BuildCookieDeletionInfo() const override;
-  base::RepeatingCallback<bool(const std::string& server_id)>
-      BuildChannelIDFilter() const override;
   base::RepeatingCallback<bool(const std::string& site)>
       BuildPluginFilter() const override;
   Mode GetMode() const override;
diff --git a/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc b/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc
index 7e9cfb0..549b57f 100644
--- a/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc
+++ b/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc
@@ -11,6 +11,7 @@
 
 #include "base/callback.h"
 #include "net/cookies/canonical_cookie.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -301,68 +302,42 @@
     RunTestCase(test_case, builder.BuildCookieDeletionInfo());
 }
 
-TEST(BrowsingDataFilterBuilderImplTest,
-     RegistrableDomainMatchesChannelIDsWhitelist) {
+TEST(BrowsingDataFilterBuilderImplTest, NetworkServiceFilterWhitelist) {
   BrowsingDataFilterBuilderImpl builder(
       BrowsingDataFilterBuilderImpl::WHITELIST);
+  ASSERT_EQ(BrowsingDataFilterBuilderImpl::WHITELIST, builder.GetMode());
   builder.AddRegisterableDomain(std::string(kGoogleDomain));
   builder.AddRegisterableDomain(std::string(kLongETLDDomain));
   builder.AddRegisterableDomain(std::string(kIPAddress));
   builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
   builder.AddRegisterableDomain(std::string(kInternalHostname));
-  base::Callback<bool(const std::string&)> filter =
-      builder.BuildChannelIDFilter();
+  network::mojom::ClearDataFilterPtr filter =
+      builder.BuildNetworkServiceFilter();
 
-  TestCase test_cases[] = {
-      // Channel ID server identifiers can be second level domains, ...
-      {"google.com", true},
-      {"website.sp.nom.br", true},
-      {"second-level-domain.fileserver", true},
-
-      // ... IP addresses, or internal hostnames.
-      {"192.168.1.1", true},
-      {"fileserver", true},
-
-      // Channel IDs not in the whitelist are not matched.
-      {"example.com", false},
-      {"192.168.1.2", false},
-      {"website.fileserver", false},
-  };
-
-  for (TestCase test_case : test_cases)
-    RunTestCase(test_case, filter);
+  EXPECT_EQ(network::mojom::ClearDataFilter_Type::DELETE_MATCHES, filter->type);
+  EXPECT_THAT(filter->domains, testing::UnorderedElementsAre(
+                                   kGoogleDomain, kLongETLDDomain, kIPAddress,
+                                   kUnknownRegistryDomain, kInternalHostname));
+  EXPECT_TRUE(filter->origins.empty());
 }
 
-TEST(BrowsingDataFilterBuilderImplTest,
-     RegistrableDomainMatchesChannelIDsBlacklist) {
+TEST(BrowsingDataFilterBuilderImplTest, NetworkServiceFilterBlacklist) {
   BrowsingDataFilterBuilderImpl builder(
       BrowsingDataFilterBuilderImpl::BLACKLIST);
+  ASSERT_EQ(BrowsingDataFilterBuilderImpl::BLACKLIST, builder.GetMode());
   builder.AddRegisterableDomain(std::string(kGoogleDomain));
   builder.AddRegisterableDomain(std::string(kLongETLDDomain));
   builder.AddRegisterableDomain(std::string(kIPAddress));
   builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
   builder.AddRegisterableDomain(std::string(kInternalHostname));
-  base::Callback<bool(const std::string&)> filter =
-      builder.BuildChannelIDFilter();
+  network::mojom::ClearDataFilterPtr filter =
+      builder.BuildNetworkServiceFilter();
 
-  TestCase test_cases[] = {
-      // Channel ID server identifiers can be second level domains, ...
-      {"google.com", false},
-      {"website.sp.nom.br", false},
-      {"second-level-domain.fileserver", false},
-
-      // ...IP addresses, or internal hostnames.
-      {"192.168.1.1", false},
-      {"fileserver", false},
-
-      // Channel IDs that are not blacklisted are matched.
-      {"example.com", true},
-      {"192.168.1.2", true},
-      {"website.fileserver", true},
-  };
-
-  for (TestCase test_case : test_cases)
-    RunTestCase(test_case, filter);
+  EXPECT_EQ(network::mojom::ClearDataFilter_Type::KEEP_MATCHES, filter->type);
+  EXPECT_THAT(filter->domains, testing::UnorderedElementsAre(
+                                   kGoogleDomain, kLongETLDDomain, kIPAddress,
+                                   kUnknownRegistryDomain, kInternalHostname));
+  EXPECT_TRUE(filter->origins.empty());
 }
 
 TEST(BrowsingDataFilterBuilderImplTest,
diff --git a/content/browser/browsing_data/browsing_data_remover_impl.cc b/content/browser/browsing_data/browsing_data_remover_impl.cc
index 5ded314..02f81bec 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl.cc
@@ -119,34 +119,31 @@
   http_session->CloseAllConnections();
 }
 
-void OnClearedChannelIDsOnIOThread(net::URLRequestContextGetter* rq_context,
-                                   base::OnceClosure callback) {
+void OnClearedChannelIDsOnIOThread(
+    net::URLRequestContextGetter* request_context,
+    base::OnceClosure callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   // Need to close open SSL connections which may be using the channel ids we
   // are deleting.
   // TODO(mattm): http://crbug.com/166069 Make the server bound cert
   // service/store have observers that can notify relevant things directly.
-  rq_context->GetURLRequestContext()
+  // TODO(ericorth): http://crbug.com/824970 Move this over to the network
+  // service and handle within ClearChannelIds().
+  request_context->GetURLRequestContext()
       ->ssl_config_service()
       ->NotifySSLConfigChange();
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, std::move(callback));
 }
 
-void ClearChannelIDsOnIOThread(
-    const base::Callback<bool(const std::string&)>& domain_predicate,
-    base::Time delete_begin,
-    base::Time delete_end,
+void OnClearedChannelIDs(
     scoped_refptr<net::URLRequestContextGetter> request_context,
     base::OnceClosure callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  net::ChannelIDService* channel_id_service =
-      request_context->GetURLRequestContext()->channel_id_service();
-  channel_id_service->GetChannelIDStore()->DeleteForDomainsCreatedBetween(
-      domain_predicate, delete_begin, delete_end,
-      base::Bind(&OnClearedChannelIDsOnIOThread,
-                 base::RetainedRef(std::move(request_context)),
-                 base::Passed(std::move(callback))));
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&OnClearedChannelIDsOnIOThread,
+                     base::RetainedRef(std::move(request_context)),
+                     std::move(callback)));
 }
 
 }  // namespace
@@ -353,16 +350,22 @@
       !(remove_mask & DATA_TYPE_AVOID_CLOSING_CONNECTIONS) &&
       origin_type_mask_ & ORIGIN_TYPE_UNPROTECTED_WEB) {
     base::RecordAction(UserMetricsAction("ClearBrowsingData_ChannelIDs"));
+
+    network::mojom::ClearDataFilterPtr service_filter =
+        filter_builder.BuildNetworkServiceFilter();
+    DCHECK(service_filter->origins.empty())
+        << "Origin-based deletion is not suitable for channel IDs.";
+
     // Since we are running on the UI thread don't call GetURLRequestContext().
     scoped_refptr<net::URLRequestContextGetter> request_context =
         BrowserContext::GetDefaultStoragePartition(browser_context_)
             ->GetURLRequestContext();
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&ClearChannelIDsOnIOThread,
-                       filter_builder.BuildChannelIDFilter(), delete_begin_,
-                       delete_end_, std::move(request_context),
-                       CreatePendingTaskCompletionClosure()));
+    BrowserContext::GetDefaultStoragePartition(browser_context_)
+        ->GetNetworkContext()
+        ->ClearChannelIds(
+            delete_begin, delete_end, std::move(service_filter),
+            base::BindOnce(&OnClearedChannelIDs, std::move(request_context),
+                           CreatePendingTaskCompletionClosureForMojo()));
   }
 
   //////////////////////////////////////////////////////////////////////////////
@@ -469,7 +472,7 @@
       // The clearing of the HTTP cache happens in the network service process
       // when enabled.
       network_context->ClearHttpCache(
-          delete_begin, delete_end, filter_builder.BuildClearCacheUrlFilter(),
+          delete_begin, delete_end, filter_builder.BuildNetworkServiceFilter(),
           CreatePendingTaskCompletionClosureForMojo());
     }
 
diff --git a/content/browser/devtools/protocol/system_info_handler.cc b/content/browser/devtools/protocol/system_info_handler.cc
index 3a90a35d..ca7da4d 100644
--- a/content/browser/devtools/protocol/system_info_handler.cc
+++ b/content/browser/devtools/protocol/system_info_handler.cc
@@ -184,7 +184,8 @@
     // TODO(zmo): CHECK everywhere once https://crbug.com/796386 is fixed.
     gpu::GpuFeatureInfo gpu_feature_info =
         gpu::ComputeGpuFeatureInfoWithHardwareAccelerationDisabled();
-    GpuDataManagerImpl::GetInstance()->UpdateGpuFeatureInfo(gpu_feature_info);
+    GpuDataManagerImpl::GetInstance()->UpdateGpuFeatureInfo(
+        gpu_feature_info, gpu::GpuFeatureInfo());
     UnregisterAndSendResponse();
 #else
     CHECK(false) << "Gathering system GPU info took more than 5 seconds.";
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc
index 5f115f0..33b531e 100644
--- a/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -276,7 +276,8 @@
   // If the |screen_space_rect| or |screen_info| of the frame has changed, then
   // the viz::LocalSurfaceId must also change.
   if ((last_received_local_frame_size_ != resize_params.local_frame_size ||
-       screen_info_ != resize_params.screen_info) &&
+       screen_info_ != resize_params.screen_info ||
+       capture_sequence_number() != resize_params.capture_sequence_number) &&
       local_surface_id_ == surface_id.local_surface_id()) {
     bad_message::ReceivedBadMessage(
         frame_proxy_in_parent_renderer_->GetProcess(),
@@ -404,15 +405,12 @@
 }
 #endif
 
-void CrossProcessFrameConnector::BeginResizeDueToAutoResize() {
-  frame_proxy_in_parent_renderer_->Send(new FrameMsg_BeginResizeDueToAutoResize(
-      frame_proxy_in_parent_renderer_->GetRoutingID()));
-}
-
-void CrossProcessFrameConnector::EndResizeDueToAutoResize(
-    uint64_t sequence_number) {
-  frame_proxy_in_parent_renderer_->Send(new FrameMsg_EndResizeDueToAutoResize(
-      frame_proxy_in_parent_renderer_->GetRoutingID(), sequence_number));
+void CrossProcessFrameConnector::ResizeDueToAutoResize(
+    uint64_t sequence_number,
+    const viz::LocalSurfaceId& child_allocated_surface_id) {
+  frame_proxy_in_parent_renderer_->Send(new FrameMsg_ResizeDueToAutoResize(
+      frame_proxy_in_parent_renderer_->GetRoutingID(), sequence_number,
+      child_allocated_surface_id));
 }
 
 void CrossProcessFrameConnector::SetVisibilityForChildViews(
diff --git a/content/browser/frame_host/cross_process_frame_connector.h b/content/browser/frame_host/cross_process_frame_connector.h
index 422a1ec..0990cbdf 100644
--- a/content/browser/frame_host/cross_process_frame_connector.h
+++ b/content/browser/frame_host/cross_process_frame_connector.h
@@ -111,8 +111,9 @@
   void EmbedRendererWindowTreeClientInParent(
       ui::mojom::WindowTreeClientPtr window_tree_client) override;
 #endif
-  void BeginResizeDueToAutoResize() override;
-  void EndResizeDueToAutoResize(uint64_t sequence_number) override;
+  void ResizeDueToAutoResize(
+      uint64_t sequence_number,
+      const viz::LocalSurfaceId& child_allocated_surface_id) override;
 
   // Set the visibility of immediate child views, i.e. views whose parent view
   // is |view_|.
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc
index 20d0922..f7f5a6ce 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -693,13 +693,9 @@
     const gfx::Size& new_size,
     uint64_t sequence_number,
     const viz::LocalSurfaceId& local_surface_id) {
-  // TODO(cblume): This doesn't currently suppress allocation.
-  // It maintains existing behavior while using the suppression style.
-  // This will be addressed in a follow-up patch.
-  // See https://crbug.com/805073
   base::OnceCallback<void()> allocation_task =
       base::BindOnce(&BrowserPluginGuest::ResizeDueToAutoResize, guest_,
-                     new_size, sequence_number);
+                     new_size, sequence_number, local_surface_id);
   return viz::ScopedSurfaceIdAllocator(std::move(allocation_task));
 }
 
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 741a816..5946d9f5 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -26,6 +26,9 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
+#include "gpu/config/gpu_blacklist.h"
+#include "gpu/config/gpu_driver_bug_list.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
 #include "gpu/config/gpu_feature_type.h"
 #include "gpu/config/gpu_finch_features.h"
 #include "gpu/config/gpu_switches.h"
@@ -42,6 +45,8 @@
 
 const int kMinMSAASampleCount = 0;
 
+enum class GpuFeatureInfoType { kCurrent, kForHardwareGpu };
+
 struct GpuFeatureData {
   std::string name;
   gpu::GpuFeatureStatus status;
@@ -56,80 +61,96 @@
   return command_line->HasSwitch(switches::kForceGpuRasterization);
 }
 
-gpu::GpuFeatureStatus SafeGetFeatureStatus(GpuDataManagerImpl* manager,
-                                           gpu::GpuFeatureType feature) {
-  if (!manager->IsGpuFeatureInfoAvailable()) {
+gpu::GpuFeatureStatus SafeGetFeatureStatus(
+    const gpu::GpuFeatureInfo& gpu_feature_info,
+    gpu::GpuFeatureType feature) {
+  if (!gpu_feature_info.IsInitialized()) {
     // The GPU process probably crashed during startup, but we can't
     // assert this as the test bots are slow, and recording the crash
     // is racy. Be robust and just say that all features are disabled.
     return gpu::kGpuFeatureStatusDisabled;
   }
-  return manager->GetFeatureStatus(feature);
+  DCHECK(feature >= 0 && feature < gpu::NUMBER_OF_GPU_FEATURE_TYPES);
+  return gpu_feature_info.status_values[feature];
 }
 
-gpu::GpuFeatureStatus GetGpuCompositingStatus() {
+gpu::GpuFeatureStatus GetGpuCompositingStatus(
+    const gpu::GpuFeatureInfo& gpu_feature_info,
+    GpuFeatureInfoType type) {
   gpu::GpuFeatureStatus status = SafeGetFeatureStatus(
-      GpuDataManagerImpl::GetInstance(), gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING);
+      gpu_feature_info, gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING);
 #if defined(USE_AURA) || defined(OS_MACOSX)
-  if (status == gpu::kGpuFeatureStatusEnabled &&
+  if (type == GpuFeatureInfoType::kCurrent &&
+      status == gpu::kGpuFeatureStatusEnabled &&
       ImageTransportFactory::GetInstance()->IsGpuCompositingDisabled()) {
+    // We only adjust the status for kCurrent, because compositing status
+    // affects other feature status, and we want to preserve the kHardwareGpu
+    // feature status and don't want them to be modified by the current
+    // compositing status.
     status = gpu::kGpuFeatureStatusDisabled;
   }
 #endif
   return status;
 }
 
-const GpuFeatureData GetGpuFeatureData(size_t index, bool* eof) {
+const GpuFeatureData GetGpuFeatureData(
+    const gpu::GpuFeatureInfo& gpu_feature_info,
+    GpuFeatureInfoType type,
+    size_t index,
+    bool* eof) {
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
 
   const GpuFeatureData kGpuFeatureData[] = {
       {"2d_canvas",
-       SafeGetFeatureStatus(manager,
+       SafeGetFeatureStatus(gpu_feature_info,
                             gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS),
        command_line.HasSwitch(switches::kDisableAccelerated2dCanvas),
-       "Accelerated 2D canvas is unavailable: either disabled via blacklist or "
-       "the command line.",
+       "Accelerated 2D canvas is unavailable: either disabled via blacklist or"
+       " the command line.",
        true, true},
-      {"gpu_compositing", GetGpuCompositingStatus(),
+      {"gpu_compositing", GetGpuCompositingStatus(gpu_feature_info, type),
        command_line.HasSwitch(switches::kDisableGpuCompositing),
        "Gpu compositing has been disabled, either via blacklist, about:flags "
        "or the command line. The browser will fall back to software "
        "compositing and hardware acceleration will be unavailable.",
        true, true},
       {"webgl",
-       SafeGetFeatureStatus(manager, gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL),
+       SafeGetFeatureStatus(gpu_feature_info,
+                            gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL),
        command_line.HasSwitch(switches::kDisableWebGL),
        "WebGL has been disabled via blacklist or the command line.", false,
        true},
-      {"flash_3d", SafeGetFeatureStatus(manager, gpu::GPU_FEATURE_TYPE_FLASH3D),
+      {"flash_3d",
+       SafeGetFeatureStatus(gpu_feature_info, gpu::GPU_FEATURE_TYPE_FLASH3D),
        command_line.HasSwitch(switches::kDisableFlash3d),
        "Using 3d in flash has been disabled, either via blacklist, about:flags "
        "or the command line.",
        true, true},
       {"flash_stage3d",
-       SafeGetFeatureStatus(manager, gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
+       SafeGetFeatureStatus(gpu_feature_info,
+                            gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
        command_line.HasSwitch(switches::kDisableFlashStage3d),
        "Using Stage3d in Flash has been disabled, either via blacklist, "
        "about:flags or the command line.",
        true, true},
       {"flash_stage3d_baseline",
-       SafeGetFeatureStatus(manager,
+       SafeGetFeatureStatus(gpu_feature_info,
                             gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE),
        command_line.HasSwitch(switches::kDisableFlashStage3d),
        "Using Stage3d Baseline profile in Flash has been disabled, either via "
        "blacklist, about:flags or the command line.",
        true, true},
       {"video_decode",
-       SafeGetFeatureStatus(manager,
+       SafeGetFeatureStatus(gpu_feature_info,
                             gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE),
        command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode),
        "Accelerated video decode has been disabled, either via blacklist, "
        "about:flags or the command line.",
        true, true},
       {"rasterization",
-       SafeGetFeatureStatus(manager, gpu::GPU_FEATURE_TYPE_GPU_RASTERIZATION),
+       SafeGetFeatureStatus(gpu_feature_info,
+                            gpu::GPU_FEATURE_TYPE_GPU_RASTERIZATION),
        (command_line.HasSwitch(switches::kDisableGpuRasterization) &&
         !IsForceGpuRasterizationEnabled()),
        "Accelerated rasterization has been disabled, either via blacklist, "
@@ -149,7 +170,8 @@
        "line.",
        false, false},
       {"webgl2",
-       SafeGetFeatureStatus(manager, gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL2),
+       SafeGetFeatureStatus(gpu_feature_info,
+                            gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL2),
        (command_line.HasSwitch(switches::kDisableWebGL) ||
         command_line.HasSwitch(switches::kDisableWebGL2)),
        "WebGL2 has been disabled via blacklist or the command line.", false,
@@ -168,6 +190,142 @@
   return kGpuFeatureData[index];
 }
 
+std::unique_ptr<base::DictionaryValue> GetFeatureStatusImpl(
+    GpuFeatureInfoType type) {
+  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
+  std::string gpu_access_blocked_reason;
+  bool gpu_access_blocked =
+      !manager->GpuAccessAllowed(&gpu_access_blocked_reason);
+  const gpu::GpuFeatureInfo gpu_feature_info =
+      type == GpuFeatureInfoType::kCurrent
+          ? manager->GetGpuFeatureInfo()
+          : manager->GetGpuFeatureInfoForHardwareGpu();
+
+  auto feature_status_dict = std::make_unique<base::DictionaryValue>();
+
+  bool eof = false;
+  for (size_t i = 0; !eof; ++i) {
+    const GpuFeatureData gpu_feature_data =
+        GetGpuFeatureData(gpu_feature_info, type, i, &eof);
+    std::string status;
+    if (gpu_feature_data.disabled || gpu_access_blocked ||
+        gpu_feature_data.status == gpu::kGpuFeatureStatusDisabled) {
+      status = "disabled";
+      if (gpu_feature_data.fallback_to_software)
+        status += "_software";
+      else
+        status += "_off";
+    } else if (gpu_feature_data.status == gpu::kGpuFeatureStatusBlacklisted) {
+      status = "unavailable_off";
+    } else if (gpu_feature_data.status == gpu::kGpuFeatureStatusSoftware) {
+      status = "unavailable_software";
+    } else {
+      status = "enabled";
+      if ((gpu_feature_data.name == "webgl" ||
+           gpu_feature_data.name == "webgl2") &&
+          (GetGpuCompositingStatus(gpu_feature_info, type) !=
+           gpu::kGpuFeatureStatusEnabled))
+        status += "_readback";
+      if (gpu_feature_data.name == "rasterization") {
+        if (IsForceGpuRasterizationEnabled())
+          status += "_force";
+      }
+      if (gpu_feature_data.name == "multiple_raster_threads") {
+        const base::CommandLine& command_line =
+            *base::CommandLine::ForCurrentProcess();
+        if (command_line.HasSwitch(switches::kNumRasterThreads))
+          status += "_force";
+        status += "_on";
+      }
+      if (gpu_feature_data.name == "checker_imaging") {
+        const base::CommandLine& command_line =
+            *base::CommandLine::ForCurrentProcess();
+        if (command_line.HasSwitch(cc::switches::kEnableCheckerImaging))
+          status += "_force";
+        status += "_on";
+      }
+      if (gpu_feature_data.name == "surface_synchronization") {
+        if (features::IsSurfaceSynchronizationEnabled())
+          status += "_on";
+      }
+      if (gpu_feature_data.name == "viz_display_compositor") {
+        if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
+          status += "_on";
+      }
+    }
+    feature_status_dict->SetString(gpu_feature_data.name, status);
+  }
+  return feature_status_dict;
+}
+
+std::unique_ptr<base::ListValue> GetProblemsImpl(GpuFeatureInfoType type) {
+  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
+  std::string gpu_access_blocked_reason;
+  bool gpu_access_blocked =
+      !manager->GpuAccessAllowed(&gpu_access_blocked_reason);
+  const gpu::GpuFeatureInfo gpu_feature_info =
+      type == GpuFeatureInfoType::kCurrent
+          ? manager->GetGpuFeatureInfo()
+          : manager->GetGpuFeatureInfoForHardwareGpu();
+
+  auto problem_list = std::make_unique<base::ListValue>();
+  if (!gpu_feature_info.applied_gpu_blacklist_entries.empty()) {
+    std::unique_ptr<gpu::GpuBlacklist> blacklist(gpu::GpuBlacklist::Create());
+    blacklist->GetReasons(problem_list.get(), "disabledFeatures",
+                          gpu_feature_info.applied_gpu_blacklist_entries);
+  }
+  if (!gpu_feature_info.applied_gpu_driver_bug_list_entries.empty()) {
+    std::unique_ptr<gpu::GpuDriverBugList> bug_list(
+        gpu::GpuDriverBugList::Create());
+    bug_list->GetReasons(problem_list.get(), "workarounds",
+                         gpu_feature_info.applied_gpu_driver_bug_list_entries);
+  }
+
+  if (gpu_access_blocked) {
+    auto problem = std::make_unique<base::DictionaryValue>();
+    problem->SetString("description", "GPU process was unable to boot: " +
+                                          gpu_access_blocked_reason);
+    problem->Set("crBugs", std::make_unique<base::ListValue>());
+    auto disabled_features = std::make_unique<base::ListValue>();
+    disabled_features->AppendString("all");
+    problem->Set("affectedGpuSettings", std::move(disabled_features));
+    problem->SetString("tag", "disabledFeatures");
+    problem_list->Insert(0, std::move(problem));
+  }
+
+  bool eof = false;
+  for (size_t i = 0; !eof; ++i) {
+    const GpuFeatureData gpu_feature_data =
+        GetGpuFeatureData(gpu_feature_info, type, i, &eof);
+    if (gpu_feature_data.disabled) {
+      auto problem = std::make_unique<base::DictionaryValue>();
+      problem->SetString("description", gpu_feature_data.disabled_description);
+      problem->Set("crBugs", std::make_unique<base::ListValue>());
+      auto disabled_features = std::make_unique<base::ListValue>();
+      disabled_features->AppendString(gpu_feature_data.name);
+      problem->Set("affectedGpuSettings", std::move(disabled_features));
+      problem->SetString("tag", "disabledFeatures");
+      problem_list->Append(std::move(problem));
+    }
+  }
+  return problem_list;
+}
+
+std::vector<std::string> GetDriverBugWorkaroundsImpl(GpuFeatureInfoType type) {
+  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
+  const gpu::GpuFeatureInfo gpu_feature_info =
+      type == GpuFeatureInfoType::kCurrent
+          ? manager->GetGpuFeatureInfo()
+          : manager->GetGpuFeatureInfoForHardwareGpu();
+
+  std::vector<std::string> workarounds;
+  for (auto workaround : gpu_feature_info.enabled_gpu_driver_bug_workarounds) {
+    workarounds.push_back(gpu::GpuDriverBugWorkaroundTypeToString(
+        static_cast<gpu::GpuDriverBugWorkaroundType>(workaround)));
+  }
+  return workarounds;
+}
+
 }  // namespace
 
 int NumberOfRendererRasterThreads() {
@@ -296,106 +454,27 @@
 }
 
 std::unique_ptr<base::DictionaryValue> GetFeatureStatus() {
-  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
-  bool gpu_access_blocked = !manager->GpuAccessAllowed(nullptr);
-
-  auto feature_status_dict = std::make_unique<base::DictionaryValue>();
-
-  bool eof = false;
-  for (size_t i = 0; !eof; ++i) {
-    const GpuFeatureData gpu_feature_data = GetGpuFeatureData(i, &eof);
-    std::string status;
-    if (gpu_feature_data.disabled ||
-        (gpu_feature_data.needs_gpu_access && gpu_access_blocked) ||
-        gpu_feature_data.status == gpu::kGpuFeatureStatusDisabled) {
-      status = "disabled";
-      if (gpu_feature_data.fallback_to_software)
-        status += "_software";
-      else
-        status += "_off";
-    } else if (gpu_feature_data.status == gpu::kGpuFeatureStatusBlacklisted) {
-      status = "unavailable_off";
-    } else if (gpu_feature_data.status == gpu::kGpuFeatureStatusSoftware) {
-      status = "unavailable_software";
-    } else {
-      status = "enabled";
-      if ((gpu_feature_data.name == "webgl" ||
-           gpu_feature_data.name == "webgl2") &&
-          (manager->GetFeatureStatus(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING) !=
-           gpu::kGpuFeatureStatusEnabled))
-        status += "_readback";
-      if (gpu_feature_data.name == "rasterization") {
-        if (IsForceGpuRasterizationEnabled())
-          status += "_force";
-      }
-      if (gpu_feature_data.name == "multiple_raster_threads") {
-        const base::CommandLine& command_line =
-            *base::CommandLine::ForCurrentProcess();
-        if (command_line.HasSwitch(switches::kNumRasterThreads))
-          status += "_force";
-        status += "_on";
-      }
-      if (gpu_feature_data.name == "checker_imaging") {
-        const base::CommandLine& command_line =
-            *base::CommandLine::ForCurrentProcess();
-        if (command_line.HasSwitch(cc::switches::kEnableCheckerImaging))
-          status += "_force";
-        status += "_on";
-      }
-      if (gpu_feature_data.name == "surface_synchronization") {
-        if (features::IsSurfaceSynchronizationEnabled())
-          status += "_on";
-      }
-      if (gpu_feature_data.name == "viz_display_compositor") {
-        if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
-          status += "_on";
-      }
-    }
-    feature_status_dict->SetString(gpu_feature_data.name, status);
-  }
-  return feature_status_dict;
+  return GetFeatureStatusImpl(GpuFeatureInfoType::kCurrent);
 }
 
 std::unique_ptr<base::ListValue> GetProblems() {
-  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
-  std::string gpu_access_blocked_reason;
-  bool gpu_access_blocked =
-      !manager->GpuAccessAllowed(&gpu_access_blocked_reason);
-
-  auto problem_list = std::make_unique<base::ListValue>();
-  manager->GetBlacklistReasons(problem_list.get());
-
-  if (gpu_access_blocked) {
-    auto problem = std::make_unique<base::DictionaryValue>();
-    problem->SetString("description", "GPU was unable to initialize: " +
-                                          gpu_access_blocked_reason);
-    problem->Set("crBugs", std::make_unique<base::ListValue>());
-    auto disabled_features = std::make_unique<base::ListValue>();
-    disabled_features->AppendString("all");
-    problem->Set("affectedGpuSettings", std::move(disabled_features));
-    problem->SetString("tag", "disabledFeatures");
-    problem_list->Insert(0, std::move(problem));
-  }
-
-  bool eof = false;
-  for (size_t i = 0; !eof; ++i) {
-    const GpuFeatureData gpu_feature_data = GetGpuFeatureData(i, &eof);
-    if (gpu_feature_data.disabled) {
-      auto problem = std::make_unique<base::DictionaryValue>();
-      problem->SetString("description", gpu_feature_data.disabled_description);
-      problem->Set("crBugs", std::make_unique<base::ListValue>());
-      auto disabled_features = std::make_unique<base::ListValue>();
-      disabled_features->AppendString(gpu_feature_data.name);
-      problem->Set("affectedGpuSettings", std::move(disabled_features));
-      problem->SetString("tag", "disabledFeatures");
-      problem_list->Append(std::move(problem));
-    }
-  }
-  return problem_list;
+  return GetProblemsImpl(GpuFeatureInfoType::kCurrent);
 }
 
 std::vector<std::string> GetDriverBugWorkarounds() {
-  return GpuDataManagerImpl::GetInstance()->GetDriverBugWorkarounds();
+  return GetDriverBugWorkaroundsImpl(GpuFeatureInfoType::kCurrent);
+}
+
+std::unique_ptr<base::DictionaryValue> GetFeatureStatusForHardwareGpu() {
+  return GetFeatureStatusImpl(GpuFeatureInfoType::kForHardwareGpu);
+}
+
+std::unique_ptr<base::ListValue> GetProblemsForHardwareGpu() {
+  return GetProblemsImpl(GpuFeatureInfoType::kForHardwareGpu);
+}
+
+std::vector<std::string> GetDriverBugWorkaroundsForHardwareGpu() {
+  return GetDriverBugWorkaroundsImpl(GpuFeatureInfoType::kForHardwareGpu);
 }
 
 std::vector<gfx::BufferUsageAndFormat>
diff --git a/content/browser/gpu/compositor_util.h b/content/browser/gpu/compositor_util.h
index d31715e..2535f08a 100644
--- a/content/browser/gpu/compositor_util.h
+++ b/content/browser/gpu/compositor_util.h
@@ -47,6 +47,11 @@
 CONTENT_EXPORT std::unique_ptr<base::ListValue> GetProblems();
 CONTENT_EXPORT std::vector<std::string> GetDriverBugWorkarounds();
 
+CONTENT_EXPORT std::unique_ptr<base::DictionaryValue>
+GetFeatureStatusForHardwareGpu();
+CONTENT_EXPORT std::unique_ptr<base::ListValue> GetProblemsForHardwareGpu();
+CONTENT_EXPORT std::vector<std::string> GetDriverBugWorkaroundsForHardwareGpu();
+
 // Populate a list of buffer usage/format for which a per platform specific
 // texture target must be used instead of GL_TEXTURE_2D.
 CONTENT_EXPORT std::vector<gfx::BufferUsageAndFormat>
diff --git a/content/browser/gpu/gpu_data_manager_impl.cc b/content/browser/gpu/gpu_data_manager_impl.cc
index 13f75be6..47dfcfa 100644
--- a/content/browser/gpu/gpu_data_manager_impl.cc
+++ b/content/browser/gpu/gpu_data_manager_impl.cc
@@ -94,12 +94,6 @@
   return private_->HardwareAccelerationEnabled();
 }
 
-void GpuDataManagerImpl::GetDisabledExtensions(
-    std::string* disabled_extensions) const {
-  base::AutoLock auto_lock(lock_);
-  private_->GetDisabledExtensions(disabled_extensions);
-}
-
 void GpuDataManagerImpl::RequestGpuSupportedRuntimeVersion() const {
   base::AutoLock auto_lock(lock_);
   private_->RequestGpuSupportedRuntimeVersion();
@@ -110,21 +104,19 @@
   return private_->GpuProcessStartAllowed();
 }
 
-void GpuDataManagerImpl::GetDisabledWebGLExtensions(
-    std::string* disabled_webgl_extensions) const {
+void GpuDataManagerImpl::UpdateGpuInfo(
+    const gpu::GPUInfo& gpu_info,
+    const gpu::GPUInfo* optional_gpu_info_for_hardware_gpu) {
   base::AutoLock auto_lock(lock_);
-  private_->GetDisabledWebGLExtensions(disabled_webgl_extensions);
-}
-
-void GpuDataManagerImpl::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
-  base::AutoLock auto_lock(lock_);
-  private_->UpdateGpuInfo(gpu_info);
+  private_->UpdateGpuInfo(gpu_info, optional_gpu_info_for_hardware_gpu);
 }
 
 void GpuDataManagerImpl::UpdateGpuFeatureInfo(
-    const gpu::GpuFeatureInfo& gpu_feature_info) {
+    const gpu::GpuFeatureInfo& gpu_feature_info,
+    const gpu::GpuFeatureInfo& gpu_feature_info_for_hardware_gpu) {
   base::AutoLock auto_lock(lock_);
-  private_->UpdateGpuFeatureInfo(gpu_feature_info);
+  private_->UpdateGpuFeatureInfo(gpu_feature_info,
+                                 gpu_feature_info_for_hardware_gpu);
 }
 
 gpu::GpuFeatureInfo GpuDataManagerImpl::GetGpuFeatureInfo() const {
@@ -132,6 +124,17 @@
   return private_->GetGpuFeatureInfo();
 }
 
+gpu::GPUInfo GpuDataManagerImpl::GetGPUInfoForHardwareGpu() const {
+  base::AutoLock auto_lock(lock_);
+  return private_->GetGPUInfoForHardwareGpu();
+}
+
+gpu::GpuFeatureInfo GpuDataManagerImpl::GetGpuFeatureInfoForHardwareGpu()
+    const {
+  base::AutoLock auto_lock(lock_);
+  return private_->GetGpuFeatureInfoForHardwareGpu();
+}
+
 void GpuDataManagerImpl::AppendGpuCommandLine(
     base::CommandLine* command_line) const {
   base::AutoLock auto_lock(lock_);
@@ -144,16 +147,6 @@
   private_->UpdateGpuPreferences(gpu_preferences);
 }
 
-void GpuDataManagerImpl::GetBlacklistReasons(base::ListValue* reasons) const {
-  base::AutoLock auto_lock(lock_);
-  private_->GetBlacklistReasons(reasons);
-}
-
-std::vector<std::string> GpuDataManagerImpl::GetDriverBugWorkarounds() const {
-  base::AutoLock auto_lock(lock_);
-  return private_->GetDriverBugWorkarounds();
-}
-
 void GpuDataManagerImpl::AddLogMessage(int level,
                                        const std::string& header,
                                        const std::string& message) {
@@ -218,6 +211,11 @@
   private_->OnGpuProcessInitFailure();
 }
 
+bool GpuDataManagerImpl::IsGpuProcessUsingHardwareGpu() const {
+  base::AutoLock auto_lock(lock_);
+  return private_->IsGpuProcessUsingHardwareGpu();
+}
+
 GpuDataManagerImpl::GpuDataManagerImpl()
     : private_(GpuDataManagerImplPrivate::Create(this)) {
 }
diff --git a/content/browser/gpu/gpu_data_manager_impl.h b/content/browser/gpu/gpu_data_manager_impl.h
index b775788..6b6714d5 100644
--- a/content/browser/gpu/gpu_data_manager_impl.h
+++ b/content/browser/gpu/gpu_data_manager_impl.h
@@ -81,41 +81,35 @@
   void RemoveObserver(GpuDataManagerObserver* observer) override;
   void DisableHardwareAcceleration() override;
   bool HardwareAccelerationEnabled() const override;
-  void GetDisabledExtensions(std::string* disabled_extensions) const override;
 
   void RequestGpuSupportedRuntimeVersion() const;
   bool GpuProcessStartAllowed() const;
 
-  void GetDisabledWebGLExtensions(std::string* disabled_webgl_extensions) const;
-
   bool IsGpuFeatureInfoAvailable() const;
   gpu::GpuFeatureStatus GetFeatureStatus(gpu::GpuFeatureType feature) const;
 
   // Only update if the current GPUInfo is not finalized.  If blacklist is
   // loaded, run through blacklist and update blacklisted features.
-  void UpdateGpuInfo(const gpu::GPUInfo& gpu_info);
+  void UpdateGpuInfo(const gpu::GPUInfo& gpu_info,
+                     const gpu::GPUInfo* optional_gpu_info_for_hardware_gpu);
 
   // Update the GPU feature info. This updates the blacklist and enabled status
   // of GPU rasterization. In the future this will be used for more features.
-  void UpdateGpuFeatureInfo(const gpu::GpuFeatureInfo& gpu_feature_info);
+  void UpdateGpuFeatureInfo(
+      const gpu::GpuFeatureInfo& gpu_feature_info,
+      const gpu::GpuFeatureInfo& gpu_feature_info_for_hardware_gpu);
 
   gpu::GpuFeatureInfo GetGpuFeatureInfo() const;
 
+  gpu::GPUInfo GetGPUInfoForHardwareGpu() const;
+  gpu::GpuFeatureInfo GetGpuFeatureInfoForHardwareGpu() const;
+
   // Insert switches into gpu process command line: kUseGL, etc.
   void AppendGpuCommandLine(base::CommandLine* command_line) const;
 
   // Update GpuPreferences based on blacklisting decisions.
   void UpdateGpuPreferences(gpu::GpuPreferences* gpu_preferences) const;
 
-  // Returns the reasons for the latest run of blacklisting decisions.
-  // For the structure of returned value, see documentation for
-  // GpuBlacklist::GetBlacklistedReasons().
-  void GetBlacklistReasons(base::ListValue* reasons) const;
-
-  // Returns the workarounds that are applied to the current system as
-  // a vector of strings.
-  std::vector<std::string> GetDriverBugWorkarounds() const;
-
   void AddLogMessage(int level,
                      const std::string& header,
                      const std::string& message);
@@ -160,6 +154,10 @@
   void BlockSwiftShader();
   bool SwiftShaderAllowed() const;
 
+  // Returns false if the latest GPUInfo gl_renderer is from SwiftShader or
+  // Disabled (in the viz case).
+  bool IsGpuProcessUsingHardwareGpu() const;
+
  private:
   friend class GpuDataManagerImplPrivate;
   friend class GpuDataManagerImplPrivateTest;
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index 66b30c3..f1e9a9c 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "base/version.h"
@@ -255,7 +256,7 @@
       base::BindOnce(
           [](const gpu::GPUInfo& gpu_info) {
             TRACE_EVENT0("test_gpu", "OnGraphicsInfoCollected");
-            GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info);
+            GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info, nullptr);
           },
           gpu_info));
 }
@@ -273,7 +274,7 @@
     else
       gpu_feature_info.status_values[ii] = gpu::kGpuFeatureStatusEnabled;
   }
-  UpdateGpuFeatureInfo(gpu_feature_info);
+  UpdateGpuFeatureInfo(gpu_feature_info, gpu::GpuFeatureInfo());
   NotifyGpuInfoUpdate();
 }
 
@@ -281,6 +282,10 @@
   return gpu_info_;
 }
 
+gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfoForHardwareGpu() const {
+  return gpu_info_for_hardware_gpu_;
+}
+
 bool GpuDataManagerImplPrivate::GpuAccessAllowed(
     std::string* reason) const {
   bool swiftshader_available = false;
@@ -421,13 +426,23 @@
   timestamps_of_gpu_resets_.clear();
 }
 
-void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
+void GpuDataManagerImplPrivate::UpdateGpuInfo(
+    const gpu::GPUInfo& gpu_info,
+    const gpu::GPUInfo* optional_gpu_info_for_hardware_gpu) {
   bool sandboxed = gpu_info_.sandboxed;
 #if defined(OS_WIN)
   uint32_t d3d12_feature_level = gpu_info_.d3d12_feature_level;
   uint32_t vulkan_version = gpu_info_.vulkan_version;
 #endif
   gpu_info_ = gpu_info;
+  if (optional_gpu_info_for_hardware_gpu &&
+      !gpu_info_for_hardware_gpu_.IsInitialized()) {
+    if (optional_gpu_info_for_hardware_gpu->IsInitialized()) {
+      gpu_info_for_hardware_gpu_ = *optional_gpu_info_for_hardware_gpu;
+    } else {
+      gpu_info_for_hardware_gpu_ = gpu_info;
+    }
+  }
 #if defined(OS_WIN)
   // On Windows, complete GPUInfo is collected through an unsandboxed
   // GPU process. If the regular GPU process is sandboxed, it should
@@ -457,8 +472,16 @@
 }
 
 void GpuDataManagerImplPrivate::UpdateGpuFeatureInfo(
-    const gpu::GpuFeatureInfo& gpu_feature_info) {
+    const gpu::GpuFeatureInfo& gpu_feature_info,
+    const gpu::GpuFeatureInfo& gpu_feature_info_for_hardware_gpu) {
   gpu_feature_info_ = gpu_feature_info;
+  if (!gpu_feature_info_for_hardware_gpu_.IsInitialized()) {
+    if (gpu_feature_info_for_hardware_gpu.IsInitialized()) {
+      gpu_feature_info_for_hardware_gpu_ = gpu_feature_info_for_hardware_gpu;
+    } else {
+      gpu_feature_info_for_hardware_gpu_ = gpu_feature_info;
+    }
+  }
   if (update_histograms_) {
     UpdateFeatureStats(gpu_feature_info);
     UpdateDriverBugListStats(gpu_feature_info);
@@ -469,6 +492,11 @@
   return gpu_feature_info_;
 }
 
+gpu::GpuFeatureInfo GpuDataManagerImplPrivate::GetGpuFeatureInfoForHardwareGpu()
+    const {
+  return gpu_feature_info_for_hardware_gpu_;
+}
+
 void GpuDataManagerImplPrivate::AppendGpuCommandLine(
     base::CommandLine* command_line) const {
   DCHECK(command_line);
@@ -553,38 +581,14 @@
 }
 
 void GpuDataManagerImplPrivate::OnGpuBlocked() {
+  gpu::GpuFeatureInfo gpu_feature_info_for_hardware_gpu = gpu_feature_info_;
   gpu::GpuFeatureInfo gpu_feature_info = gpu::ComputeGpuFeatureInfoWithNoGpu();
-  UpdateGpuFeatureInfo(gpu_feature_info);
+  UpdateGpuFeatureInfo(gpu_feature_info, gpu_feature_info_for_hardware_gpu);
 
   // Some observers might be waiting.
   NotifyGpuInfoUpdate();
 }
 
-void GpuDataManagerImplPrivate::GetBlacklistReasons(
-    base::ListValue* reasons) const {
-  if (!gpu_feature_info_.applied_gpu_blacklist_entries.empty()) {
-    std::unique_ptr<gpu::GpuBlacklist> blacklist(gpu::GpuBlacklist::Create());
-    blacklist->GetReasons(reasons, "disabledFeatures",
-                          gpu_feature_info_.applied_gpu_blacklist_entries);
-  }
-  if (!gpu_feature_info_.applied_gpu_driver_bug_list_entries.empty()) {
-    std::unique_ptr<gpu::GpuDriverBugList> bug_list(
-        gpu::GpuDriverBugList::Create());
-    bug_list->GetReasons(reasons, "workarounds",
-                         gpu_feature_info_.applied_gpu_driver_bug_list_entries);
-  }
-}
-
-std::vector<std::string>
-GpuDataManagerImplPrivate::GetDriverBugWorkarounds() const {
-  std::vector<std::string> workarounds;
-  for (auto workaround : gpu_feature_info_.enabled_gpu_driver_bug_workarounds) {
-    workarounds.push_back(gpu::GpuDriverBugWorkaroundTypeToString(
-        static_cast<gpu::GpuDriverBugWorkaroundType>(workaround)));
-  }
-  return workarounds;
-}
-
 void GpuDataManagerImplPrivate::AddLogMessage(
     int level, const std::string& header, const std::string& message) {
   // Some clients emit many log messages. This has been observed to consume GBs
@@ -671,18 +675,6 @@
   return true;
 }
 
-void GpuDataManagerImplPrivate::GetDisabledExtensions(
-    std::string* disabled_extensions) const {
-  DCHECK(disabled_extensions);
-  *disabled_extensions = gpu_feature_info_.disabled_extensions;
-}
-
-void GpuDataManagerImplPrivate::GetDisabledWebGLExtensions(
-    std::string* disabled_webgl_extensions) const {
-  DCHECK(disabled_webgl_extensions);
-  *disabled_webgl_extensions = gpu_feature_info_.disabled_webgl_extensions;
-}
-
 void GpuDataManagerImplPrivate::BlockDomainFrom3DAPIs(
     const GURL& url, GpuDataManagerImpl::DomainGuilt guilt) {
   BlockDomainFrom3DAPIsAtTime(url, guilt, base::Time::Now());
@@ -746,6 +738,15 @@
   observer_list_->Notify(FROM_HERE, &GpuDataManagerObserver::OnGpuInfoUpdate);
 }
 
+bool GpuDataManagerImplPrivate::IsGpuProcessUsingHardwareGpu() const {
+  if (base::StartsWith(gpu_info_.gl_renderer, "Google SwiftShader",
+                       base::CompareCase::SENSITIVE))
+    return false;
+  if (gpu_info_.gl_renderer == "Disabled")
+    return false;
+  return true;
+}
+
 std::string GpuDataManagerImplPrivate::GetDomainFromURL(
     const GURL& url) const {
   // For the moment, we just use the host, or its IP address, as the
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.h b/content/browser/gpu/gpu_data_manager_impl_private.h
index 08b4cae..44e3ba9 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.h
+++ b/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -41,6 +41,7 @@
 
   void BlacklistWebGLForTesting();
   gpu::GPUInfo GetGPUInfo() const;
+  gpu::GPUInfo GetGPUInfoForHardwareGpu() const;
   bool GpuAccessAllowed(std::string* reason) const;
   bool GpuProcessStartAllowed() const;
   void RequestCompleteGpuInfoIfNeeded();
@@ -59,18 +60,18 @@
   void BlockSwiftShader();
   bool SwiftShaderAllowed() const;
 
-  void UpdateGpuInfo(const gpu::GPUInfo& gpu_info);
-  void UpdateGpuFeatureInfo(const gpu::GpuFeatureInfo& gpu_feature_info);
+  void UpdateGpuInfo(const gpu::GPUInfo& gpu_info,
+                     const gpu::GPUInfo* optional_gpu_info_for_hardware_gpu);
+  void UpdateGpuFeatureInfo(
+      const gpu::GpuFeatureInfo& gpu_feature_info,
+      const gpu::GpuFeatureInfo& gpu_feature_info_for_hardware_gpu);
   gpu::GpuFeatureInfo GetGpuFeatureInfo() const;
+  gpu::GpuFeatureInfo GetGpuFeatureInfoForHardwareGpu() const;
 
   void AppendGpuCommandLine(base::CommandLine* command_line) const;
 
   void UpdateGpuPreferences(gpu::GpuPreferences* gpu_preferences) const;
 
-  void GetBlacklistReasons(base::ListValue* reasons) const;
-
-  std::vector<std::string> GetDriverBugWorkarounds() const;
-
   void AddLogMessage(int level,
                      const std::string& header,
                      const std::string& message);
@@ -81,9 +82,6 @@
 
   void HandleGpuSwitch();
 
-  void GetDisabledExtensions(std::string* disabled_extensions) const;
-  void GetDisabledWebGLExtensions(std::string* disabled_webgl_extensions) const;
-
   void BlockDomainFrom3DAPIs(
       const GURL& url, GpuDataManagerImpl::DomainGuilt guilt);
   bool Are3DAPIsBlocked(const GURL& top_origin_url,
@@ -105,6 +103,8 @@
   // Notify all observers whenever there is a GPU info update.
   void NotifyGpuInfoUpdate();
 
+  bool IsGpuProcessUsingHardwareGpu() const;
+
   virtual ~GpuDataManagerImplPrivate();
 
  private:
@@ -171,11 +171,14 @@
 
   bool complete_gpu_info_already_requested_;
 
-  // Eventually |blacklisted_features_| should be folded in to this.
   gpu::GpuFeatureInfo gpu_feature_info_;
-
   gpu::GPUInfo gpu_info_;
 
+  // What we would have gotten if we haven't fallen back to SwiftShader or
+  // pure software (in the viz case).
+  gpu::GpuFeatureInfo gpu_feature_info_for_hardware_gpu_;
+  gpu::GPUInfo gpu_info_for_hardware_gpu_;
+
   const scoped_refptr<GpuDataManagerObserverList> observer_list_;
 
   // Contains the 1000 most recent log messages.
diff --git a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
index 252ca41c..d445e5b 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
@@ -140,7 +140,7 @@
   EXPECT_FALSE(observer.gpu_info_updated());
 
   gpu::GPUInfo gpu_info;
-  manager->UpdateGpuInfo(gpu_info);
+  manager->UpdateGpuInfo(gpu_info, nullptr);
   {
     base::RunLoop run_loop;
     run_loop.RunUntilIdle();
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc
index 09ffa77..f476572 100644
--- a/content/browser/gpu/gpu_internals_ui.cc
+++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -144,8 +144,9 @@
       vendor.c_str(), device.c_str(), gpu.active ? " *ACTIVE*" : "");
 }
 
-std::unique_ptr<base::DictionaryValue> GpuInfoAsDictionaryValue() {
-  gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
+std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue(
+    const gpu::GPUInfo& gpu_info,
+    const gpu::GpuFeatureInfo& gpu_feature_info) {
   auto basic_info = std::make_unique<base::ListValue>();
   basic_info->Append(NewDescriptionValuePair(
       "Initialization time",
@@ -206,14 +207,6 @@
                               VulkanVersionToString(gpu_info.vulkan_version)));
 #endif
 
-  std::string disabled_extensions;
-  GpuDataManagerImpl::GetInstance()->GetDisabledExtensions(
-      &disabled_extensions);
-
-  std::string disabled_webgl_extensions;
-  GpuDataManagerImpl::GetInstance()->GetDisabledWebGLExtensions(
-      &disabled_webgl_extensions);
-
   basic_info->Append(
       NewDescriptionValuePair("Driver vendor", gpu_info.driver_vendor));
   basic_info->Append(NewDescriptionValuePair("Driver version",
@@ -238,10 +231,10 @@
                                              gpu_info.gl_version));
   basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS",
                                              gpu_info.gl_extensions));
-  basic_info->Append(NewDescriptionValuePair("Disabled Extensions",
-                                             disabled_extensions));
-  basic_info->Append(NewDescriptionValuePair("Disabled WebGL Extensions",
-                                             disabled_webgl_extensions));
+  basic_info->Append(NewDescriptionValuePair(
+      "Disabled Extensions", gpu_feature_info.disabled_extensions));
+  basic_info->Append(NewDescriptionValuePair(
+      "Disabled WebGL Extensions", gpu_feature_info.disabled_webgl_extensions));
   basic_info->Append(NewDescriptionValuePair("Window system binding vendor",
                                              gpu_info.gl_ws_vendor));
   basic_info->Append(NewDescriptionValuePair("Window system binding version",
@@ -278,8 +271,25 @@
       "GPU process crash count",
       std::make_unique<base::Value>(GpuProcessHost::GetGpuCrashCount())));
 
+#if defined(USE_X11)
+  basic_info->Append(NewDescriptionValuePair(
+      "System visual ID", base::NumberToString(gpu_info.system_visual)));
+  basic_info->Append(NewDescriptionValuePair(
+      "RGBA visual ID", base::NumberToString(gpu_info.rgba_visual)));
+#endif
+
+  return basic_info;
+}
+
+std::unique_ptr<base::DictionaryValue> GpuInfoAsDictionaryValue() {
   auto info = std::make_unique<base::DictionaryValue>();
 
+  const gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
+  const gpu::GpuFeatureInfo gpu_feature_info =
+      GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfo();
+  auto basic_info = BasicGpuInfoAsListValue(gpu_info, gpu_feature_info);
+  info->Set("basicInfo", std::move(basic_info));
+
 #if defined(OS_WIN)
   auto dx_info = std::make_unique<base::Value>();
   if (gpu_info.dx_diagnostics.children.size())
@@ -287,14 +297,6 @@
   info->Set("diagnostics", std::move(dx_info));
 #endif
 
-#if defined(USE_X11)
-  basic_info->Append(NewDescriptionValuePair(
-      "System visual ID", base::NumberToString(gpu_info.system_visual)));
-  basic_info->Append(NewDescriptionValuePair(
-      "RGBA visual ID", base::NumberToString(gpu_info.rgba_visual)));
-#endif
-
-  info->Set("basic_info", std::move(basic_info));
   return info;
 }
 
@@ -625,18 +627,41 @@
 
 void GpuMessageHandler::OnGpuInfoUpdate() {
   // Get GPU Info.
-  std::unique_ptr<base::DictionaryValue> gpu_info_val(
-      GpuInfoAsDictionaryValue());
+  const gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
+  auto gpu_info_val = GpuInfoAsDictionaryValue();
 
   // Add in blacklisting features
   auto feature_status = std::make_unique<base::DictionaryValue>();
   feature_status->Set("featureStatus", GetFeatureStatus());
   feature_status->Set("problems", GetProblems());
   auto workarounds = std::make_unique<base::ListValue>();
-  for (const std::string& workaround : GetDriverBugWorkarounds())
+  for (const auto& workaround : GetDriverBugWorkarounds())
     workarounds->AppendString(workaround);
   feature_status->Set("workarounds", std::move(workarounds));
   gpu_info_val->Set("featureStatus", std::move(feature_status));
+  if (!GpuDataManagerImpl::GetInstance()->IsGpuProcessUsingHardwareGpu()) {
+    auto feature_status_for_hardware_gpu =
+        std::make_unique<base::DictionaryValue>();
+    feature_status_for_hardware_gpu->Set("featureStatus",
+                                         GetFeatureStatusForHardwareGpu());
+    feature_status_for_hardware_gpu->Set("problems",
+                                         GetProblemsForHardwareGpu());
+    auto workarounds_for_hardware_gpu = std::make_unique<base::ListValue>();
+    for (const auto& workaround : GetDriverBugWorkaroundsForHardwareGpu())
+      workarounds_for_hardware_gpu->AppendString(workaround);
+    feature_status_for_hardware_gpu->Set(
+        "workarounds", std::move(workarounds_for_hardware_gpu));
+    gpu_info_val->Set("featureStatusForHardwareGpu",
+                      std::move(feature_status_for_hardware_gpu));
+    const gpu::GPUInfo gpu_info_for_hardware_gpu =
+        GpuDataManagerImpl::GetInstance()->GetGPUInfoForHardwareGpu();
+    const gpu::GpuFeatureInfo gpu_feature_info_for_hardware_gpu =
+        GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfoForHardwareGpu();
+    auto gpu_info_for_hardware_gpu_val = BasicGpuInfoAsListValue(
+        gpu_info_for_hardware_gpu, gpu_feature_info_for_hardware_gpu);
+    gpu_info_val->Set("basicInfoForHardwareGpu",
+                      std::move(gpu_info_for_hardware_gpu_val));
+  }
   gpu_info_val->Set("compositorInfo", CompositorInfo());
   gpu_info_val->Set("gpuMemoryBufferInfo", GpuMemoryBufferInfo());
   gpu_info_val->Set("displayInfo", getDisplayInfo());
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 130bf011..716f9176 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -117,6 +117,57 @@
 
 namespace {
 
+// This matches base::TerminationStatus.
+// These values are persisted to logs. Entries (except MAX_ENUM) should not be
+// renumbered and numeric values should never be reused. Should also avoid
+// OS-defines in this enum to keep the values consistent on all platforms.
+enum class GpuTerminationStatus {
+  NORMAL_TERMINATION = 0,
+  ABNORMAL_TERMINATION = 1,
+  PROCESS_WAS_KILLED = 2,
+  PROCESS_CRASHED = 3,
+  STILL_RUNNING = 4,
+  PROCESS_WAS_KILLED_BY_OOM = 5,
+  OOM_PROTECTED = 6,
+  LAUNCH_FAILED = 7,
+  OOM = 8,
+  MAX_ENUM = 9,
+};
+
+GpuTerminationStatus ConvertToGpuTerminationStatus(
+    base::TerminationStatus status) {
+  switch (status) {
+    case base::TERMINATION_STATUS_NORMAL_TERMINATION:
+      return GpuTerminationStatus::NORMAL_TERMINATION;
+    case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
+      return GpuTerminationStatus::ABNORMAL_TERMINATION;
+    case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
+      return GpuTerminationStatus::PROCESS_WAS_KILLED;
+    case base::TERMINATION_STATUS_PROCESS_CRASHED:
+      return GpuTerminationStatus::PROCESS_CRASHED;
+    case base::TERMINATION_STATUS_STILL_RUNNING:
+      return GpuTerminationStatus::STILL_RUNNING;
+#if defined(OS_CHROMEOS)
+    case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+      return GpuTerminationStatus::PROCESS_WAS_KILLED_BY_OOM;
+#endif
+#if defined(OS_ANDROID)
+    case base::TERMINATION_STATUS_OOM_PROTECTED:
+      return GpuTerminationStatus::OOM_PROTECTED;
+#endif
+    case base::TERMINATION_STATUS_LAUNCH_FAILED:
+      return GpuTerminationStatus::LAUNCH_FAILED;
+    case base::TERMINATION_STATUS_OOM:
+      return GpuTerminationStatus::OOM;
+    case base::TERMINATION_STATUS_MAX_ENUM:
+      NOTREACHED();
+      return GpuTerminationStatus::MAX_ENUM;
+      // Do not add default.
+  }
+  NOTREACHED();
+  return GpuTerminationStatus::ABNORMAL_TERMINATION;
+}
+
 // Command-line switches to propagate to the GPU process.
 static const char* const kSwitchNames[] = {
     service_manager::switches::kDisableSeccompFilterSandbox,
@@ -142,7 +193,6 @@
     switches::kEnableAcceleratedVpxDecode,
 #endif
     switches::kEnableGpuRasterization,
-    switches::kEnableHeapProfiling,
     switches::kEnableLogging,
     switches::kEnableOOPRasterization,
     switches::kEnableVizDevTools,
@@ -633,8 +683,9 @@
   if (!in_process_ && process_launched_) {
     ChildProcessTerminationInfo info =
         process_->GetTerminationInfo(false /* known_dead */);
-    UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationStatus", info.status,
-                              base::TERMINATION_STATUS_MAX_ENUM);
+    UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationStatus2",
+                              ConvertToGpuTerminationStatus(info.status),
+                              GpuTerminationStatus::MAX_ENUM);
 
     if (info.status == base::TERMINATION_STATUS_NORMAL_TERMINATION ||
         info.status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
@@ -1030,7 +1081,9 @@
 
 void GpuProcessHost::DidInitialize(
     const gpu::GPUInfo& gpu_info,
-    const gpu::GpuFeatureInfo& gpu_feature_info) {
+    const gpu::GpuFeatureInfo& gpu_feature_info,
+    const gpu::GPUInfo& gpu_info_for_hardware_gpu,
+    const gpu::GpuFeatureInfo& gpu_feature_info_for_hardware_gpu) {
   UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", true);
   status_ = SUCCESS;
 
@@ -1046,8 +1099,9 @@
   GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance();
   // Update GpuFeatureInfo first, because UpdateGpuInfo() will notify all
   // listeners.
-  gpu_data_manager->UpdateGpuFeatureInfo(gpu_feature_info);
-  gpu_data_manager->UpdateGpuInfo(gpu_info);
+  gpu_data_manager->UpdateGpuFeatureInfo(gpu_feature_info,
+                                         gpu_feature_info_for_hardware_gpu);
+  gpu_data_manager->UpdateGpuInfo(gpu_info, &gpu_info_for_hardware_gpu);
   RunRequestGPUInfoCallbacks(gpu_data_manager->GetGPUInfo());
 }
 
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 51b57b6..b5a0b46 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -203,8 +203,11 @@
   void OnProcessCrashed(int exit_code) override;
 
   // viz::mojom::GpuHost:
-  void DidInitialize(const gpu::GPUInfo& gpu_info,
-                     const gpu::GpuFeatureInfo& gpu_feature_info) override;
+  void DidInitialize(
+      const gpu::GPUInfo& gpu_info,
+      const gpu::GpuFeatureInfo& gpu_feature_info,
+      const gpu::GPUInfo& gpu_info_for_hardware_gpu,
+      const gpu::GpuFeatureInfo& gpu_feature_info_for_hardware_gpu) override;
   void DidFailInitialize() override;
   void DidCreateContextSuccessfully() override;
   void DidCreateOffscreenContext(const GURL& url) override;
diff --git a/content/browser/picture_in_picture/overlay_surface_embedder.cc b/content/browser/picture_in_picture/overlay_surface_embedder.cc
index 0e9780b..1e7d2a0 100644
--- a/content/browser/picture_in_picture/overlay_surface_embedder.cc
+++ b/content/browser/picture_in_picture/overlay_surface_embedder.cc
@@ -19,8 +19,6 @@
   surface_layer_->SetFillsBoundsOpaquely(false);
   // |surface_layer_| bounds are set with the (0, 0) origin point. The
   // positioning of |window_| is dictated by itself.
-  // TODO(apacible): Update |surface_layer_| size when the window is resized.
-  // http://crbug.com/726621
   surface_layer_->SetBounds(
       gfx::Rect(gfx::Point(0, 0), window_->GetBounds().size()));
   window_->GetLayer()->Add(surface_layer_.get());
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.h b/content/browser/renderer_host/browser_compositor_view_mac.h
index 36fd7ef..d33a85a 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.h
+++ b/content/browser/renderer_host/browser_compositor_view_mac.h
@@ -213,6 +213,8 @@
   } repaint_state_ = RepaintState::None;
   bool repaint_auto_resize_enabled_ = false;
 
+  uint32_t capture_sequence_number_ = 0;
+
   base::WeakPtrFactory<BrowserCompositorMac> weak_factory_;
 };
 
diff --git a/content/browser/renderer_host/frame_connector_delegate.cc b/content/browser/renderer_host/frame_connector_delegate.cc
index 9ec6c75..af4f44c 100644
--- a/content/browser/renderer_host/frame_connector_delegate.cc
+++ b/content/browser/renderer_host/frame_connector_delegate.cc
@@ -30,6 +30,7 @@
     const FrameResizeParams& resize_params) {
   screen_info_ = resize_params.screen_info;
   local_surface_id_ = surface_id.local_surface_id();
+  capture_sequence_number_ = resize_params.capture_sequence_number;
 
   SetScreenSpaceRect(resize_params.screen_space_rect);
   SetLocalFrameSize(resize_params.local_frame_size);
diff --git a/content/browser/renderer_host/frame_connector_delegate.h b/content/browser/renderer_host/frame_connector_delegate.h
index 0f8cf97..bc8fbaa 100644
--- a/content/browser/renderer_host/frame_connector_delegate.h
+++ b/content/browser/renderer_host/frame_connector_delegate.h
@@ -77,28 +77,31 @@
                           const FrameResizeParams& resize_params);
 
   // Return the size of the CompositorFrame to use in the child renderer.
-  const gfx::Size& local_frame_size_in_pixels() {
+  const gfx::Size& local_frame_size_in_pixels() const {
     return local_frame_size_in_pixels_;
   }
 
   // Return the size of the CompositorFrame to use in the child renderer in DIP.
   // This is used to set the layout size of the child renderer.
-  const gfx::Size& local_frame_size_in_dip() {
+  const gfx::Size& local_frame_size_in_dip() const {
     return local_frame_size_in_dip_;
   }
 
   // Return the rect in DIP that the RenderWidgetHostViewChildFrame's content
   // will render into.
-  const gfx::Rect& screen_space_rect_in_dip() {
+  const gfx::Rect& screen_space_rect_in_dip() const {
     return screen_space_rect_in_dip_;
   }
 
   // Return the rect in pixels that the RenderWidgetHostViewChildFrame's content
   // will render into.
-  const gfx::Rect& screen_space_rect_in_pixels() {
+  const gfx::Rect& screen_space_rect_in_pixels() const {
     return screen_space_rect_in_pixels_;
   }
 
+  // Return the latest capture sequence number of this delegate.
+  uint32_t capture_sequence_number() const { return capture_sequence_number_; }
+
   // Request that the platform change the mouse cursor when the mouse is
   // positioned over this view's content.
   virtual void UpdateCursor(const WebCursor& cursor) {}
@@ -226,14 +229,12 @@
       ui::mojom::WindowTreeClientPtr window_tree_client) {}
 #endif
 
-  // Called by RenderWidgetHostViewChildFrame when an auto-resize transaction
-  // starts.
-  virtual void BeginResizeDueToAutoResize() {}
-
   // Called by RenderWidgetHostViewChildFrame when the child frame has finished
-  // an auto-resize transaction. Causes allocation of a new LocalSurfaceID
-  // associated with the new size.
-  virtual void EndResizeDueToAutoResize(uint64_t sequence_number) {}
+  // an auto-resize transaction. Provides the viz::LocalSurfaceId and sequence
+  // number to use for the transaction.
+  virtual void ResizeDueToAutoResize(
+      uint64_t sequence_number,
+      const viz::LocalSurfaceId& child_allocated_surface_id) {}
 
   bool has_size() const { return has_size_; }
 
@@ -262,6 +263,8 @@
   bool has_size_ = false;
   const bool use_zoom_for_device_scale_factor_;
 
+  uint32_t capture_sequence_number_ = 0u;
+
   FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewChildFrameZoomForDSFTest,
                            CompositorViewportPixelSize);
 };
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
index 419ea74f..58404d6 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
@@ -37,12 +37,10 @@
 using AudioOutputStream = media::mojom::AudioOutputStream;
 using AudioOutputStreamPtr = mojo::InterfacePtr<AudioOutputStream>;
 using AudioOutputStreamRequest = mojo::InterfaceRequest<AudioOutputStream>;
-using AudioOutputStreamProviderClient =
-    media::mojom::AudioOutputStreamProviderClient;
-using AudioOutputStreamProviderClientPtr =
-    mojo::InterfacePtr<AudioOutputStreamProviderClient>;
-using AudioOutputStreamProviderClientRequest =
-    mojo::InterfaceRequest<AudioOutputStreamProviderClient>;
+using AudioOutputStreamClient = media::mojom::AudioOutputStreamClient;
+using AudioOutputStreamClientPtr = mojo::InterfacePtr<AudioOutputStreamClient>;
+using AudioOutputStreamClientRequest =
+    mojo::InterfaceRequest<AudioOutputStreamClient>;
 using AudioOutputStreamProvider = media::mojom::AudioOutputStreamProvider;
 using AudioOutputStreamProviderPtr =
     mojo::InterfacePtr<AudioOutputStreamProvider>;
@@ -168,21 +166,13 @@
   DISALLOW_COPY_AND_ASSIGN(MockContext);
 };
 
-class MockClient : public AudioOutputStreamProviderClient {
+class MockClient : public AudioOutputStreamClient {
  public:
-  MockClient() : provider_client_binding_(this) {}
+  MockClient() {}
   ~MockClient() override {}
 
-  AudioOutputStreamProviderClientPtr MakeProviderClientPtr() {
-    AudioOutputStreamProviderClientPtr p;
-    provider_client_binding_.Bind(mojo::MakeRequest(&p));
-    return p;
-  }
-
-  void Created(AudioOutputStreamPtr stream,
-               media::mojom::AudioDataPipePtr data_pipe) {
+  void StreamCreated(media::mojom::AudioDataPipePtr data_pipe) {
     was_called_ = true;
-    stream_ = std::move(stream);
   }
 
   bool was_called() { return was_called_; }
@@ -190,8 +180,6 @@
   MOCK_METHOD0(OnError, void());
 
  private:
-  mojo::Binding<AudioOutputStreamProviderClient> provider_client_binding_;
-  AudioOutputStreamPtr stream_;
   bool was_called_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(MockClient);
@@ -211,13 +199,17 @@
 }  // namespace
 
 // This test authorizes and creates a stream, and checks that
-// 1. the ProviderClient callback is called with appropriate parameters.
+// 1. the authorization callback is called with appropriate parameters.
 // 2. the AudioOutputDelegate is created.
 // 3. when the delegate calls OnStreamCreated, this is propagated to the client.
 TEST(RenderFrameAudioOutputStreamFactoryTest, CreateStream) {
   content::TestBrowserThreadBundle thread_bundle;
   AudioOutputStreamProviderPtr provider;
+  AudioOutputStreamPtr output_stream;
   MockClient client;
+  AudioOutputStreamClientPtr client_ptr;
+  mojo::Binding<AudioOutputStreamClient> client_binding(
+      &client, mojo::MakeRequest(&client_ptr));
   media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
   auto factory_context = std::make_unique<MockContext>(true);
   factory_context->PrepareDelegateForCreation(
@@ -237,7 +229,9 @@
             GetTestAudioParameters().AsHumanReadableString());
   EXPECT_TRUE(id.empty());
 
-  provider->Acquire(params, client.MakeProviderClientPtr());
+  provider->Acquire(
+      mojo::MakeRequest(&output_stream), std::move(client_ptr), params,
+      base::BindOnce(&MockClient::StreamCreated, base::Unretained(&client)));
   base::RunLoop().RunUntilIdle();
   ASSERT_NE(event_handler, nullptr);
 
@@ -276,7 +270,11 @@
 TEST(RenderFrameAudioOutputStreamFactoryTest, ConnectionError_DeletesStream) {
   content::TestBrowserThreadBundle thread_bundle;
   AudioOutputStreamProviderPtr provider;
+  AudioOutputStreamPtr output_stream;
   MockClient client;
+  AudioOutputStreamClientPtr client_ptr;
+  mojo::Binding<AudioOutputStreamClient> client_binding(
+      &client, mojo::MakeRequest(&client_ptr));
   bool delegate_is_destructed = false;
   media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
   auto factory_context = std::make_unique<MockContext>(true);
@@ -294,11 +292,14 @@
                         const std::string& id) {}));
   base::RunLoop().RunUntilIdle();
 
-  provider->Acquire(GetTestAudioParameters(), client.MakeProviderClientPtr());
+  provider->Acquire(
+      mojo::MakeRequest(&output_stream), std::move(client_ptr),
+      GetTestAudioParameters(),
+      base::BindOnce(&MockClient::StreamCreated, base::Unretained(&client)));
   base::RunLoop().RunUntilIdle();
   ASSERT_NE(event_handler, nullptr);
   EXPECT_FALSE(delegate_is_destructed);
-  provider.reset();
+  output_stream.reset();
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(delegate_is_destructed);
 }
@@ -306,7 +307,11 @@
 TEST(RenderFrameAudioOutputStreamFactoryTest, DelegateError_DeletesStream) {
   content::TestBrowserThreadBundle thread_bundle;
   AudioOutputStreamProviderPtr provider;
+  AudioOutputStreamPtr output_stream;
   MockClient client;
+  AudioOutputStreamClientPtr client_ptr;
+  mojo::Binding<AudioOutputStreamClient> client_binding(
+      &client, mojo::MakeRequest(&client_ptr));
   bool delegate_is_destructed = false;
   media::AudioOutputDelegate::EventHandler* event_handler = nullptr;
   auto factory_context = std::make_unique<MockContext>(true);
@@ -324,7 +329,10 @@
                         const std::string& id) {}));
   base::RunLoop().RunUntilIdle();
 
-  provider->Acquire(GetTestAudioParameters(), client.MakeProviderClientPtr());
+  provider->Acquire(
+      mojo::MakeRequest(&output_stream), std::move(client_ptr),
+      GetTestAudioParameters(),
+      base::BindOnce(&MockClient::StreamCreated, base::Unretained(&client)));
   base::RunLoop().RunUntilIdle();
   ASSERT_NE(event_handler, nullptr);
   EXPECT_FALSE(delegate_is_destructed);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 8e4198a..825349bd 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1787,9 +1787,8 @@
   MediaInternals* media_internals = MediaInternals::GetInstance();
   // Add BrowserPluginMessageFilter to ensure it gets the first stab at messages
   // from guests.
-  scoped_refptr<BrowserPluginMessageFilter> bp_message_filter(
-      new BrowserPluginMessageFilter(GetID()));
-  AddFilter(bp_message_filter.get());
+  bp_message_filter_ = new BrowserPluginMessageFilter(GetID());
+  AddFilter(bp_message_filter_.get());
 
   scoped_refptr<net::URLRequestContextGetter> request_context(
       storage_partition_impl_->GetURLRequestContext());
@@ -2698,7 +2697,6 @@
     switches::kDomAutomationController,
     switches::kEnableAutomation,
     switches::kEnableExperimentalWebPlatformFeatures,
-    switches::kEnableHeapProfiling,
     switches::kEnableGPUClientLogging,
     switches::kEnableGpuClientTracing,
     switches::kEnableGpuMemoryBufferVideoFrames,
@@ -4398,4 +4396,9 @@
   std::move(callback).Run(histogram_json);
 }
 
+void RenderProcessHostImpl::SetBrowserPluginMessageFilterSubFilterForTesting(
+    scoped_refptr<BrowserMessageFilter> message_filter) const {
+  bp_message_filter_->SetSubFilterForTesting(std::move(message_filter));
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 0ea859f1..c4168e4 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -70,6 +70,7 @@
 }
 
 namespace content {
+class BrowserPluginMessageFilter;
 class ChildConnection;
 class GpuClient;
 class IndexedDBDispatcherHost;
@@ -337,6 +338,9 @@
     return notification_message_filter_.get();
   }
 
+  void SetBrowserPluginMessageFilterSubFilterForTesting(
+      scoped_refptr<BrowserMessageFilter> message_filter) const;
+
   void set_is_for_guests_only_for_testing(bool is_for_guests_only) {
     is_for_guests_only_ = is_for_guests_only;
   }
@@ -683,6 +687,9 @@
   // closure per notification that must be freed when the notification closes.
   scoped_refptr<NotificationMessageFilter> notification_message_filter_;
 
+  // The filter for messages coming from the browser plugin.
+  scoped_refptr<BrowserPluginMessageFilter> bp_message_filter_;
+
   // Used in single-process mode.
   std::unique_ptr<base::Thread> in_process_renderer_;
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 45bae40..f3d461d 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -767,6 +767,7 @@
 
   if (view_) {
     resize_params->new_size = view_->GetRequestedRendererSize();
+    resize_params->capture_sequence_number = view_->GetCaptureSequenceNumber();
     resize_params->compositor_viewport_pixel_size =
         view_->GetCompositorViewportPixelSize();
     resize_params->top_controls_height = view_->GetTopControlsHeight();
@@ -834,7 +835,10 @@
        old_resize_params_->content_source_id !=
            resize_params->content_source_id) ||
       (enable_surface_synchronization_ &&
-       old_resize_params_->local_surface_id != resize_params->local_surface_id);
+       old_resize_params_->local_surface_id !=
+           resize_params->local_surface_id) ||
+      old_resize_params_->capture_sequence_number !=
+          resize_params->capture_sequence_number;
 
   // We don't expect to receive an ACK when the requested size or the physical
   // backing size is empty, or when the main viewport size didn't change.
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index fd8f53fa..9e0a1f91 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -830,6 +830,15 @@
           std::move(callback), start_time));
 }
 
+void RenderWidgetHostViewAndroid::EnsureSurfaceSynchronizedForLayoutTest() {
+  ++latest_capture_sequence_number_;
+  WasResized();
+}
+
+uint32_t RenderWidgetHostViewAndroid::GetCaptureSequenceNumber() const {
+  return latest_capture_sequence_number_;
+}
+
 void RenderWidgetHostViewAndroid::ShowDisambiguationPopup(
     const gfx::Rect& rect_pixels, const SkBitmap& zoomed_bitmap) {
   if (!tap_disambiguator_)
@@ -2007,7 +2016,6 @@
 void RenderWidgetHostViewAndroid::OnDetachedFromWindow() {
   StopObservingRootWindow();
   OnDetachCompositor();
-  view_.set_event_handler(nullptr);
 }
 
 void RenderWidgetHostViewAndroid::OnAttachCompositor() {
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 2486b30ab..82aa4bcc 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -120,6 +120,8 @@
       const gfx::Rect& src_rect,
       const gfx::Size& output_size,
       base::OnceCallback<void(const SkBitmap&)> callback) override;
+  void EnsureSurfaceSynchronizedForLayoutTest() override;
+  uint32_t GetCaptureSequenceNumber() const override;
   bool DoBrowserControlsShrinkBlinkSize() const override;
   float GetTopControlsHeight() const override;
   float GetBottomControlsHeight() const override;
@@ -491,6 +493,7 @@
   base::ObserverList<DestructionObserver> destruction_observers_;
 
   MouseWheelPhaseHandler mouse_wheel_phase_handler_;
+  uint32_t latest_capture_sequence_number_ = 0u;
 
   base::WeakPtrFactory<RenderWidgetHostViewAndroid> weak_ptr_factory_;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index e106d42..8480ce8 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -637,6 +637,11 @@
   return delegated_frame_host_->CanCopyFromCompositingSurface();
 }
 
+void RenderWidgetHostViewAura::EnsureSurfaceSynchronizedForLayoutTest() {
+  ++latest_capture_sequence_number_;
+  WasResized(cc::DeadlinePolicy::UseInfiniteDeadline(), base::nullopt);
+}
+
 bool RenderWidgetHostViewAura::IsShowing() {
   return window_->IsVisible();
 }
@@ -844,6 +849,10 @@
              : RenderWidgetHostViewBase::GetRequestedRendererSize();
 }
 
+uint32_t RenderWidgetHostViewAura::GetCaptureSequenceNumber() const {
+  return latest_capture_sequence_number_;
+}
+
 void RenderWidgetHostViewAura::CopyFromSurface(
     const gfx::Rect& src_subrect,
     const gfx::Size& dst_size,
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index af0b2e6c..957c8ffed 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -140,11 +140,13 @@
   void SetTooltipText(const base::string16& tooltip_text) override;
   void DisplayTooltipText(const base::string16& tooltip_text) override;
   gfx::Size GetRequestedRendererSize() const override;
+  uint32_t GetCaptureSequenceNumber() const override;
   bool IsSurfaceAvailableForCopy() const override;
   void CopyFromSurface(
       const gfx::Rect& src_rect,
       const gfx::Size& output_size,
       base::OnceCallback<void(const SkBitmap&)> callback) override;
+  void EnsureSurfaceSynchronizedForLayoutTest() override;
   gfx::Vector2d GetOffsetFromRootSurface() override;
   gfx::Rect GetBoundsInRootWindow() override;
   void WheelEventAck(const blink::WebMouseWheelEvent& event,
@@ -660,6 +662,11 @@
   std::unique_ptr<CursorManager> cursor_manager_;
   int tab_show_sequence_ = 0;
 
+  // Latest capture sequence number which is incremented when the caller
+  // requests surfaces be synchronized via
+  // EnsureSurfaceSynchronizedForLayoutTest().
+  uint32_t latest_capture_sequence_number_ = 0u;
+
   base::WeakPtrFactory<RenderWidgetHostViewAura> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAura);
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index ca70db5..0ebd7f5 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -154,6 +154,12 @@
   return GetViewBounds().size();
 }
 
+uint32_t RenderWidgetHostViewBase::GetCaptureSequenceNumber() const {
+  // TODO(vmpstr): Implement this for overrides other than aura and child frame.
+  NOTIMPLEMENTED();
+  return 0u;
+}
+
 ui::TextInputClient* RenderWidgetHostViewBase::GetTextInputClient() {
   NOTREACHED();
   return nullptr;
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index 84d4c01..f226d2f 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -197,6 +197,9 @@
   // when the view requires additional throttling.
   virtual gfx::Size GetRequestedRendererSize() const;
 
+  // Returns the current capture sequence number.
+  virtual uint32_t GetCaptureSequenceNumber() const;
+
   // The size of the view's backing surface in non-DPI-adjusted pixels.
   virtual gfx::Size GetCompositorViewportPixelSize() const;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index 7d23113..cde2ec2 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -241,6 +241,17 @@
   return has_frame_;
 }
 
+void RenderWidgetHostViewChildFrame::EnsureSurfaceSynchronizedForLayoutTest() {
+  // The capture sequence number which would normally be updated here is
+  // actually retrieved from the frame connector.
+}
+
+uint32_t RenderWidgetHostViewChildFrame::GetCaptureSequenceNumber() const {
+  if (!frame_connector_)
+    return 0u;
+  return frame_connector_->capture_sequence_number();
+}
+
 void RenderWidgetHostViewChildFrame::Show() {
   if (!host()->is_hidden())
     return;
@@ -1039,12 +1050,9 @@
     const gfx::Size& new_size,
     uint64_t sequence_number,
     const viz::LocalSurfaceId& local_surface_id) {
-  if (frame_connector_)
-    frame_connector_->BeginResizeDueToAutoResize();
-
   base::OnceCallback<void()> allocation_task = base::BindOnce(
       &RenderWidgetHostViewChildFrame::OnResizeDueToAutoResizeComplete,
-      weak_factory_.GetWeakPtr(), sequence_number);
+      weak_factory_.GetWeakPtr(), sequence_number, local_surface_id);
   return viz::ScopedSurfaceIdAllocator(std::move(allocation_task));
 }
 
@@ -1128,9 +1136,10 @@
 }
 
 void RenderWidgetHostViewChildFrame::OnResizeDueToAutoResizeComplete(
-    uint64_t sequence_number) {
+    uint64_t sequence_number,
+    viz::LocalSurfaceId local_surface_id) {
   if (frame_connector_)
-    frame_connector_->EndResizeDueToAutoResize(sequence_number);
+    frame_connector_->ResizeDueToAutoResize(sequence_number, local_surface_id);
 }
 
 void RenderWidgetHostViewChildFrame::DidNavigate() {
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h
index a29772f2..9e6a5dd 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -96,6 +96,8 @@
       const gfx::Rect& src_rect,
       const gfx::Size& output_size,
       base::OnceCallback<void(const SkBitmap&)> callback) override;
+  void EnsureSurfaceSynchronizedForLayoutTest() override;
+  uint32_t GetCaptureSequenceNumber() const override;
   void Show() override;
   void Hide() override;
   bool IsShowing() override;
@@ -296,7 +298,8 @@
   // using CSS.
   bool CanBecomeVisible();
 
-  void OnResizeDueToAutoResizeComplete(uint64_t sequence_number);
+  void OnResizeDueToAutoResizeComplete(uint64_t sequence_number,
+                                       viz::LocalSurfaceId local_surface_id);
 
   std::vector<base::OnceClosure> frame_swapped_callbacks_;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
index 1936d4e4..287d600 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
@@ -191,55 +191,4 @@
                           base::Unretained(this)));
 }
 
-// Test that auto-resize messages only trigger a single allocation/response
-// from the child.
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameTest,
-                       ChildFrameAutoResizeMessages) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), embedded_test_server()->GetURL(
-                   "a.com", "/cross_site_iframe_factory.html?a(b)")));
-
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-
-  // Create our message filter to intercept messages.
-  scoped_refptr<UpdateResizeParamsMessageFilter> message_filter =
-      new UpdateResizeParamsMessageFilter();
-  root->current_frame_host()->GetProcess()->AddFilter(message_filter.get());
-
-  // Load cross-site page into iframe.
-  GURL cross_site_url(
-      embedded_test_server()->GetURL("foo.com", "/title2.html"));
-  // The child frame is created during this blocking call, on the UI thread.
-  // This is racing the IPC we are testing for, which arrives on the IO thread.
-  // Due to this we cannot get the pre-IPC value of the viz::FrameSinkId.
-  NavigateFrameToURL(root->child_at(0), cross_site_url);
-
-  RenderWidgetHostImpl* child_frame_impl =
-      root->child_at(0)->current_frame_host()->GetRenderWidgetHost();
-  child_frame_impl->SetAutoResize(true, gfx::Size(10, 10), gfx::Size(100, 100));
-
-  // Fake an auto-resize update from the parent renderer.
-  int routing_id = root->child_at(0)
-                       ->current_frame_host()
-                       ->GetRenderWidgetHost()
-                       ->GetRoutingID();
-  ViewHostMsg_ResizeOrRepaint_ACK_Params params;
-  params.view_size = gfx::Size(75, 75);
-  params.flags = 0;
-  params.sequence_number = 7;
-  viz::LocalSurfaceId current_id =
-      child_frame_impl->GetView()->GetLocalSurfaceId();
-  params.child_allocated_local_surface_id = viz::LocalSurfaceId(
-      current_id.parent_sequence_number(),
-      current_id.child_sequence_number() + 1, current_id.embed_token());
-  child_frame_impl->OnMessageReceived(
-      ViewHostMsg_ResizeOrRepaint_ACK(routing_id, params));
-
-  // The first UpdateResizeParams message received should have our new sequence
-  // number.
-  EXPECT_EQ(params.sequence_number, message_filter->WaitForSequenceNumber());
-}
-
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
index 7a55f92..d9d839a 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
@@ -355,6 +355,7 @@
   resize_params.screen_space_rect = screen_space_rect;
   resize_params.local_frame_size = compositor_viewport_pixel_size;
   resize_params.auto_resize_sequence_number = 1u;
+  resize_params.capture_sequence_number = 123u;
   test_frame_connector_->UpdateResizeParams(surface_id, resize_params);
 
   ASSERT_EQ(1u, process->sink().message_count());
@@ -368,6 +369,7 @@
             std::get<0>(params).compositor_viewport_pixel_size);
   EXPECT_EQ(screen_space_rect.size(), std::get<0>(params).new_size);
   EXPECT_EQ(local_surface_id, std::get<0>(params).local_surface_id);
+  EXPECT_EQ(123u, std::get<0>(params).capture_sequence_number);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 1385498..65337d2 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -131,6 +131,7 @@
       const gfx::Rect& src_rect,
       const gfx::Size& output_size,
       base::OnceCallback<void(const SkBitmap&)> callback) override;
+  void EnsureSurfaceSynchronizedForLayoutTest() override;
   void FocusedNodeChanged(bool is_editable_node,
                           const gfx::Rect& node_bounds_in_screen) override;
   void DidCreateNewRendererCompositorFrameSink(
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index cd7ae59..4cfeb1e 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -683,6 +683,10 @@
       src_subrect, dst_size, std::move(callback));
 }
 
+void RenderWidgetHostViewMac::EnsureSurfaceSynchronizedForLayoutTest() {
+  // TODO(vmpstr): Figure out what needs to be done here.
+}
+
 void RenderWidgetHostViewMac::SetNeedsBeginFrames(bool needs_begin_frames) {
   needs_begin_frames_ = needs_begin_frames;
   UpdateNeedsBeginFramesInternal();
diff --git a/content/browser/resources/gpu/browser_bridge.js b/content/browser/resources/gpu/browser_bridge.js
index c2ad051..24e4b07 100644
--- a/content/browser/resources/gpu/browser_bridge.js
+++ b/content/browser/resources/gpu/browser_bridge.js
@@ -143,8 +143,8 @@
      * Returns the value of the "Sandboxed" row.
      */
     isSandboxedForTesting : function() {
-      for (i = 0; i < this.gpuInfo_.basic_info.length; ++i) {
-        var info = this.gpuInfo_.basic_info[i];
+      for (i = 0; i < this.gpuInfo_.basicInfo.length; ++i) {
+        var info = this.gpuInfo_.basicInfo[i];
         if (info.description == "Sandboxed")
           return info.value;
       }
diff --git a/content/browser/resources/gpu/info_view.html b/content/browser/resources/gpu/info_view.html
index 288f402d..1d44f6c 100644
--- a/content/browser/resources/gpu/info_view.html
+++ b/content/browser/resources/gpu/info_view.html
@@ -61,6 +61,29 @@
     <div id="diagnostics-table">None</div>
   </div>
 
+  <div class='basic-info-for-hardware-gpu-div'>
+    <h3>Driver Information for Hardware GPU</h3>
+    <div id="basic-info-for-hardware-gpu"></div>
+  </div>
+
+  <div class='feature-status-for-hardware-gpu-div'>
+    <h3>Graphics Feature Status for Hardware GPU</h3>
+    <ul class="feature-status-for-hardware-gpu-list">
+    </ul>
+  </div>
+
+  <div class='workarounds-for-hardware-gpu-div'>
+    <h3>Driver Bug Workarounds for Hardware GPU</h3>
+    <ul class="workarounds-for-hardware-gpu-list">
+    </ul>
+  </div>
+
+  <div class='problems-for-hardware-gpu-div'>
+    <h3>Problems Detected for Hardware GPU</h3>
+    <ul class="problems-for-hardware-gpu-list">
+    </ul>
+  </div>
+
   <div id="log-messages" jsdisplay="values.length">
     <h3>Log Messages</h3>
     <ul>
diff --git a/content/browser/resources/gpu/info_view.js b/content/browser/resources/gpu/info_view.js
index eca2b710..bb8498b7e 100644
--- a/content/browser/resources/gpu/info_view.js
+++ b/content/browser/resources/gpu/info_view.js
@@ -99,6 +99,125 @@
         this.setText_('client-info', '... loading...');
       }
 
+
+      // GPU info, basic
+      var diagnosticsDiv = this.querySelector('.diagnostics');
+      var diagnosticsLoadingDiv = this.querySelector('.diagnostics-loading');
+      var featureStatusList = this.querySelector('.feature-status-list');
+      var problemsDiv = this.querySelector('.problems-div');
+      var problemsList = this.querySelector('.problems-list');
+      var workaroundsDiv = this.querySelector('.workarounds-div');
+      var workaroundsList = this.querySelector('.workarounds-list');
+
+      var basicInfoForHardwareGpuDiv =
+          this.querySelector('.basic-info-for-hardware-gpu-div');
+      var featureStatusForHardwareGpuDiv =
+          this.querySelector('.feature-status-for-hardware-gpu-div');
+      var featureStatusForHardwareGpuList =
+          this.querySelector('.feature-status-for-hardware-gpu-list');
+      var problemsForHardwareGpuDiv =
+          this.querySelector('.problems-for-hardware-gpu-div');
+      var problemsForHardwareGpuList =
+          this.querySelector('.problems-for-hardware-gpu-list');
+      var workaroundsForHardwareGpuDiv =
+          this.querySelector('.workarounds-for-hardware-gpu-div');
+      var workaroundsForHardwareGpuList =
+          this.querySelector('.workarounds-for-hardware-gpu-list');
+
+      var gpuInfo = browserBridge.gpuInfo;
+      var i;
+      if (gpuInfo) {
+        // Not using jstemplate here for blacklist status because we construct
+        // href from data, which jstemplate can't seem to do.
+        if (gpuInfo.featureStatus) {
+          this.appendFeatureInfo_(gpuInfo.featureStatus, featureStatusList,
+                                  problemsDiv, problemsList,
+                                  workaroundsDiv, workaroundsList);
+        } else {
+          featureStatusList.textContent = '';
+          problemsList.hidden = true;
+          workaroundsList.hidden = true;
+        }
+
+        if (gpuInfo.featureStatusForHardwareGpu) {
+          basicInfoForHardwareGpuDiv.hidden = false;
+          featureStatusForHardwareGpuDiv.hidden = false;
+          problemsForHardwareGpuDiv.hidden = false;
+          workaroundsForHardwareGpuDiv.hidden = false;
+          this.appendFeatureInfo_(gpuInfo.featureStatusForHardwareGpu,
+                                  featureStatusForHardwareGpuList,
+                                  problemsForHardwareGpuDiv,
+                                  problemsForHardwareGpuList,
+                                  workaroundsForHardwareGpuDiv,
+                                  workaroundsForHardwareGpuList);
+          if (gpuInfo.basicInfoForHardwareGpu) {
+            this.setTable_('basic-info-for-hardware-gpu',
+                           gpuInfo.basicInfoForHardwareGpu);
+          } else {
+            this.setTable_('basic-info-for-hardware-gpu', []);
+          }
+        } else {
+          basicInfoForHardwareGpuDiv.hidden = true;
+          featureStatusForHardwareGpuDiv.hidden = true;
+          problemsForHardwareGpuDiv.hidden = true;
+          workaroundsForHardwareGpuDiv.hidden = true;
+        }
+
+        if (gpuInfo.basicInfo)
+          this.setTable_('basic-info', gpuInfo.basicInfo);
+        else
+          this.setTable_('basic-info', []);
+
+        if (gpuInfo.compositorInfo)
+          this.setTable_('compositor-info', gpuInfo.compositorInfo);
+        else
+          this.setTable_('compositor-info', []);
+
+        if (gpuInfo.gpuMemoryBufferInfo)
+          this.setTable_('gpu-memory-buffer-info', gpuInfo.gpuMemoryBufferInfo);
+        else
+          this.setTable_('gpu-memory-buffer-info', []);
+
+        if (gpuInfo.displayInfo)
+          this.setTable_('display-info', gpuInfo.displayInfo);
+        else
+          this.setTable_('display-info', []);
+
+        if (gpuInfo.videoAcceleratorsInfo) {
+          this.setTable_(
+              'video-acceleration-info', gpuInfo.videoAcceleratorsInfo);
+        } else {
+          this.setTable_('video-acceleration-info', []);
+        }
+
+        if (gpuInfo.diagnostics) {
+          diagnosticsDiv.hidden = false;
+          diagnosticsLoadingDiv.hidden = true;
+          $('diagnostics-table').hidden = false;
+          this.setTable_('diagnostics-table', gpuInfo.diagnostics);
+        } else if (gpuInfo.diagnostics === null) {
+          // gpu_internals.cc sets diagnostics to null when it is being loaded
+          diagnosticsDiv.hidden = false;
+          diagnosticsLoadingDiv.hidden = false;
+          $('diagnostics-table').hidden = true;
+        } else {
+          diagnosticsDiv.hidden = true;
+        }
+      } else {
+        this.setText_('basic-info', '... loading ...');
+        diagnosticsDiv.hidden = true;
+        featureStatusList.textContent = '';
+        problemsDiv.hidden = true;
+      }
+
+      // Log messages
+      jstProcess(new JsEvalContext({values: browserBridge.logMessages}),
+                 $('log-messages'));
+    },
+
+    appendFeatureInfo_: function(featureInfo, featureStatusList,
+                                 problemsDiv, problemsList,
+                                 workaroundsDiv, workaroundsList) {
       // Feature map
       var featureLabelMap = {
         '2d_canvas': 'Canvas',
@@ -167,130 +286,58 @@
         },
       };
 
-      // GPU info, basic
-      var diagnosticsDiv = this.querySelector('.diagnostics');
-      var diagnosticsLoadingDiv = this.querySelector('.diagnostics-loading');
-      var featureStatusList = this.querySelector('.feature-status-list');
-      var problemsDiv = this.querySelector('.problems-div');
-      var problemsList = this.querySelector('.problems-list');
-      var workaroundsDiv = this.querySelector('.workarounds-div');
-      var workaroundsList = this.querySelector('.workarounds-list');
-      var gpuInfo = browserBridge.gpuInfo;
-      var i;
-      if (gpuInfo) {
-        // Not using jstemplate here for blacklist status because we construct
-        // href from data, which jstemplate can't seem to do.
-        if (gpuInfo.featureStatus) {
-          // feature status list
-          featureStatusList.textContent = '';
-          for (var featureName in gpuInfo.featureStatus.featureStatus) {
-            var featureStatus =
-                gpuInfo.featureStatus.featureStatus[featureName];
-            var featureEl = document.createElement('li');
+      // feature status list
+      featureStatusList.textContent = '';
+      for (var featureName in featureInfo.featureStatus) {
+        var featureStatus = featureInfo.featureStatus[featureName];
+        var featureEl = document.createElement('li');
 
-            var nameEl = document.createElement('span');
-            if (!featureLabelMap[featureName])
-              console.log('Missing featureLabel for', featureName);
-            nameEl.textContent = featureLabelMap[featureName] + ': ';
-            featureEl.appendChild(nameEl);
+        var nameEl = document.createElement('span');
+        if (!featureLabelMap[featureName])
+          console.log('Missing featureLabel for', featureName);
+        nameEl.textContent = featureLabelMap[featureName] + ': ';
+        featureEl.appendChild(nameEl);
 
-            var statusEl = document.createElement('span');
-            var statusInfo = statusMap[featureStatus];
-            if (!statusInfo) {
-              console.log('Missing status for ', featureStatus);
-              statusEl.textContent = 'Unknown';
-              statusEl.className = 'feature-red';
-            } else {
-              statusEl.textContent = statusInfo['label'];
-              statusEl.className = statusInfo['class'];
-            }
-            featureEl.appendChild(statusEl);
-
-            featureStatusList.appendChild(featureEl);
-          }
-
-          // problems list
-          if (gpuInfo.featureStatus.problems.length) {
-            problemsDiv.hidden = false;
-            problemsList.textContent = '';
-            for (i = 0; i < gpuInfo.featureStatus.problems.length; i++) {
-              var problem = gpuInfo.featureStatus.problems[i];
-              var problemEl = this.createProblemEl_(problem);
-              problemsList.appendChild(problemEl);
-            }
-          } else {
-            problemsDiv.hidden = true;
-          }
-
-          // driver bug workarounds list
-          if (gpuInfo.featureStatus.workarounds.length) {
-            workaroundsDiv.hidden = false;
-            workaroundsList.textContent = '';
-            for (i = 0; i < gpuInfo.featureStatus.workarounds.length; i++) {
-              var workaroundEl = document.createElement('li');
-              workaroundEl.textContent = gpuInfo.featureStatus.workarounds[i];
-              workaroundsList.appendChild(workaroundEl);
-            }
-          } else {
-            workaroundsDiv.hidden = true;
-          }
-
+        var statusEl = document.createElement('span');
+        var statusInfo = statusMap[featureStatus];
+        if (!statusInfo) {
+          console.log('Missing status for ', featureStatus);
+          statusEl.textContent = 'Unknown';
+          statusEl.className = 'feature-red';
         } else {
-          featureStatusList.textContent = '';
-          problemsList.hidden = true;
-          workaroundsList.hidden = true;
+          statusEl.textContent = statusInfo['label'];
+          statusEl.className = statusInfo['class'];
         }
+        featureEl.appendChild(statusEl);
 
-        if (gpuInfo.basic_info)
-          this.setTable_('basic-info', gpuInfo.basic_info);
-        else
-          this.setTable_('basic-info', []);
+        featureStatusList.appendChild(featureEl);
+      }
 
-        if (gpuInfo.compositorInfo)
-          this.setTable_('compositor-info', gpuInfo.compositorInfo);
-        else
-          this.setTable_('compositor-info', []);
-
-        if (gpuInfo.gpuMemoryBufferInfo)
-          this.setTable_('gpu-memory-buffer-info', gpuInfo.gpuMemoryBufferInfo);
-        else
-          this.setTable_('gpu-memory-buffer-info', []);
-
-        if (gpuInfo.displayInfo)
-          this.setTable_('display-info', gpuInfo.displayInfo);
-        else
-          this.setTable_('display-info', []);
-
-        if (gpuInfo.videoAcceleratorsInfo) {
-          this.setTable_(
-              'video-acceleration-info', gpuInfo.videoAcceleratorsInfo);
-        } else {
-          this.setTable_('video-acceleration-info', []);
-        }
-
-        if (gpuInfo.diagnostics) {
-          diagnosticsDiv.hidden = false;
-          diagnosticsLoadingDiv.hidden = true;
-          $('diagnostics-table').hidden = false;
-          this.setTable_('diagnostics-table', gpuInfo.diagnostics);
-        } else if (gpuInfo.diagnostics === null) {
-          // gpu_internals.cc sets diagnostics to null when it is being loaded
-          diagnosticsDiv.hidden = false;
-          diagnosticsLoadingDiv.hidden = false;
-          $('diagnostics-table').hidden = true;
-        } else {
-          diagnosticsDiv.hidden = true;
+      // problems list
+      if (featureInfo.problems.length) {
+        problemsDiv.hidden = false;
+        problemsList.textContent = '';
+        for (i = 0; i < featureInfo.problems.length; i++) {
+          var problem = featureInfo.problems[i];
+          var problemEl = this.createProblemEl_(problem);
+          problemsList.appendChild(problemEl);
         }
       } else {
-        this.setText_('basic-info', '... loading ...');
-        diagnosticsDiv.hidden = true;
-        featureStatusList.textContent = '';
         problemsDiv.hidden = true;
       }
 
-      // Log messages
-      jstProcess(new JsEvalContext({values: browserBridge.logMessages}),
-                 $('log-messages'));
+      // driver bug workarounds list
+      if (featureInfo.workarounds.length) {
+        workaroundsDiv.hidden = false;
+        workaroundsList.textContent = '';
+        for (i = 0; i < featureInfo.workarounds.length; i++) {
+          var workaroundEl = document.createElement('li');
+          workaroundEl.textContent = featureInfo.workarounds[i];
+          workaroundsList.appendChild(workaroundEl);
+        }
+      } else {
+        workaroundsDiv.hidden = true;
+      }
     },
 
     createProblemEl_: function(problem) {
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index 2663268b..752f5e7 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -74,10 +74,6 @@
 #include "content/public/common/content_descriptors.h"
 #endif
 
-#if defined(OS_MACOSX)
-#include "base/allocator/allocator_interception_mac.h"
-#endif
-
 namespace content {
 namespace {
 
@@ -562,14 +558,6 @@
       connection_timeout = temp;
   }
 
-#if defined(OS_MACOSX)
-  if (base::CommandLine::InitializedForCurrentProcess() &&
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableHeapProfiling)) {
-    base::allocator::PeriodicallyShimNewMallocZones();
-  }
-#endif
-
   message_loop_->task_runner()->PostDelayedTask(
       FROM_HERE,
       base::BindOnce(&ChildThreadImpl::EnsureConnected,
diff --git a/content/common/browser_plugin/browser_plugin_messages.h b/content/common/browser_plugin/browser_plugin_messages.h
index 8799191..1d6c41d 100644
--- a/content/common/browser_plugin/browser_plugin_messages.h
+++ b/content/common/browser_plugin/browser_plugin_messages.h
@@ -187,11 +187,12 @@
                      int /* browser_plugin_instance_id */,
                      bool /* reverse */)
 
-// When a guest resizes due to auto-resize, this message informs the
-// BrowserPlugin to request a new viz::LocalSurfaceId.
-IPC_MESSAGE_CONTROL2(BrowserPluginMsg_ResizeDueToAutoResize,
+// Informs the BrowserPlugin that the guest's auto-resize transaction is
+// complete and it should update with the provided viz::LocalSurfaceId.
+IPC_MESSAGE_CONTROL3(BrowserPluginMsg_ResizeDueToAutoResize,
                      int /* browser_plugin_instance_id */,
-                     uint64_t /* sequence_number */)
+                     uint64_t /* sequence_number */,
+                     viz::LocalSurfaceId /* child_allocated_surface_id */)
 
 // Requests a viz::LocalSurfaceId to enable auto-resize mode from the parent
 // renderer.
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index d8ac388..da691e7 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -243,6 +243,7 @@
   IPC_STRUCT_TRAITS_MEMBER(auto_resize_sequence_number)
   IPC_STRUCT_TRAITS_MEMBER(screen_space_rect)
   IPC_STRUCT_TRAITS_MEMBER(local_frame_size)
+  IPC_STRUCT_TRAITS_MEMBER(capture_sequence_number)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(blink::FramePolicy)
@@ -995,15 +996,11 @@
 // Tells the RenderFrame to clear the focused element (if any).
 IPC_MESSAGE_ROUTED0(FrameMsg_ClearFocusedElement)
 
-// Informs the parent renderer that the child is beginning an autoresize
-// transaction.
-IPC_MESSAGE_ROUTED(FrameMsg_BeginResizeDueToAutoResize)
-
 // Informs the parent renderer that the child has completed an autoresize
-// transaction and that the child can now allocate a new viz::LocalSurfaceId
-// for its new size.
-IPC_MESSAGE_ROUTED1(FrameMsg_EndResizeDueToAutoResize,
-                    uint64_t /* sequence_number */)
+// transaction and should update with the provided viz::LocalSurfaceId.
+IPC_MESSAGE_ROUTED2(FrameMsg_ResizeDueToAutoResize,
+                    uint64_t /* sequence_number */,
+                    viz::LocalSurfaceId /* child_allocated_surface_id */)
 
 // Requests a viz::LocalSurfaceId to enable auto-resize mode from the parent
 // renderer.
diff --git a/content/common/frame_resize_params.cc b/content/common/frame_resize_params.cc
index fc5059d..39a7791 100644
--- a/content/common/frame_resize_params.cc
+++ b/content/common/frame_resize_params.cc
@@ -6,12 +6,9 @@
 
 namespace content {
 
-FrameResizeParams::FrameResizeParams()
-    : auto_resize_enabled(false), auto_resize_sequence_number(0u) {}
-
+FrameResizeParams::FrameResizeParams() = default;
 FrameResizeParams::FrameResizeParams(const FrameResizeParams& other) = default;
-
-FrameResizeParams::~FrameResizeParams() {}
+FrameResizeParams::~FrameResizeParams() = default;
 
 FrameResizeParams& FrameResizeParams::operator=(
     const FrameResizeParams& other) = default;
diff --git a/content/common/frame_resize_params.h b/content/common/frame_resize_params.h
index 4255907..50c09d9 100644
--- a/content/common/frame_resize_params.h
+++ b/content/common/frame_resize_params.h
@@ -24,7 +24,7 @@
   ScreenInfo screen_info;
 
   // Whether or not blink should be in auto-resize mode.
-  bool auto_resize_enabled;
+  bool auto_resize_enabled = false;
 
   // The minimum size for Blink if auto-resize is enabled.
   gfx::Size min_size_for_auto_resize;
@@ -35,11 +35,13 @@
   // This variable is increased after each auto-resize. If the
   // renderer receives a ResizeParams with stale auto_resize_seqence_number,
   // then the resize request is dropped.
-  uint64_t auto_resize_sequence_number;
+  uint64_t auto_resize_sequence_number = 0u;
 
   gfx::Rect screen_space_rect;
 
   gfx::Size local_frame_size;
+
+  uint32_t capture_sequence_number = 0u;
 };
 
 }  // namespace content
diff --git a/content/common/resize_params.cc b/content/common/resize_params.cc
index 5e1fd102..eeb4d67 100644
--- a/content/common/resize_params.cc
+++ b/content/common/resize_params.cc
@@ -6,20 +6,10 @@
 
 namespace content {
 
-ResizeParams::ResizeParams()
-    : auto_resize_enabled(false),
-      auto_resize_sequence_number(0u),
-      browser_controls_shrink_blink_size(false),
-      scroll_focused_node_into_view(false),
-      top_controls_height(0.f),
-      bottom_controls_height(0.f),
-      is_fullscreen_granted(false),
-      display_mode(blink::kWebDisplayModeUndefined),
-      needs_resize_ack(false),
-      content_source_id(0u) {}
-
+ResizeParams::ResizeParams() = default;
 ResizeParams::ResizeParams(const ResizeParams& other) = default;
+ResizeParams::~ResizeParams() = default;
 
-ResizeParams::~ResizeParams() {}
+ResizeParams& ResizeParams::operator=(const ResizeParams& other) = default;
 
 }  // namespace content
diff --git a/content/common/resize_params.h b/content/common/resize_params.h
index 51c472d..5abe35ec 100644
--- a/content/common/resize_params.h
+++ b/content/common/resize_params.h
@@ -19,11 +19,13 @@
   ResizeParams(const ResizeParams& other);
   ~ResizeParams();
 
+  ResizeParams& operator=(const ResizeParams& other);
+
   // Information about the screen (dpi, depth, etc..).
   ScreenInfo screen_info;
 
   // Whether or not blink should be in auto-resize mode.
-  bool auto_resize_enabled;
+  bool auto_resize_enabled = false;
 
   // The minimum size for Blink if auto-resize is enabled.
   gfx::Size min_size_for_auto_resize;
@@ -34,7 +36,7 @@
   // This variable is increased after each auto-resize. If the
   // renderer receives a ResizeParams with stale auto_resize_seqence_number,
   // then the resize request is dropped.
-  uint64_t auto_resize_sequence_number;
+  uint64_t auto_resize_sequence_number = 0u;
 
   // The size for the widget in DIPs.
   gfx::Size new_size;
@@ -46,18 +48,18 @@
 
   // Whether or not Blink's viewport size should be shrunk by the height of the
   // URL-bar (always false on platforms where URL-bar hiding isn't supported).
-  bool browser_controls_shrink_blink_size;
+  bool browser_controls_shrink_blink_size = false;
 
   // Whether or not the focused node should be scrolled into view after the
   // resize.
-  bool scroll_focused_node_into_view;
+  bool scroll_focused_node_into_view = false;
 
   // The height of the top controls (always 0 on platforms where URL-bar hiding
   // isn't supported).
-  float top_controls_height;
+  float top_controls_height = 0.f;
 
   // The height of the bottom controls.
-  float bottom_controls_height;
+  float bottom_controls_height = 0.f;
 
   // The local surface ID to use (if valid).
   base::Optional<viz::LocalSurfaceId> local_surface_id;
@@ -68,20 +70,25 @@
   gfx::Size visible_viewport_size;
 
   // Indicates whether tab-initiated fullscreen was granted.
-  bool is_fullscreen_granted;
+  bool is_fullscreen_granted = false;
 
   // The display mode.
-  blink::WebDisplayMode display_mode;
+  blink::WebDisplayMode display_mode = blink::kWebDisplayModeUndefined;
 
   // If set, requests the renderer to reply with a
   // ViewHostMsg_ResizeOrRepaint_ACK with the
   // ViewHostMsg_ResizeOrRepaint_ACK_Flags::IS_RESIZE_ACK bit set in flags.
-  bool needs_resize_ack;
+  bool needs_resize_ack = false;
 
   // This variable is increased after each cross-document navigation. If the
   // renderer receives a ResizeParams with stale content_source_id, it still
   // performs the resize but doesn't use the given LocalSurfaceId.
-  uint32_t content_source_id;
+  uint32_t content_source_id = 0u;
+
+  // This represents the latest capture sequence number requested. When this is
+  // incremented, that means the caller wants to synchronize surfaces which
+  // should cause a new LocalSurfaceId to be generated.
+  uint32_t capture_sequence_number = 0u;
 };
 
 }  // namespace content
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index d2881f98..1d5f2b9e 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -179,6 +179,7 @@
   IPC_STRUCT_TRAITS_MEMBER(display_mode)
   IPC_STRUCT_TRAITS_MEMBER(needs_resize_ack)
   IPC_STRUCT_TRAITS_MEMBER(content_source_id)
+  IPC_STRUCT_TRAITS_MEMBER(capture_sequence_number)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(content::MenuItem)
diff --git a/content/public/browser/browsing_data_filter_builder.h b/content/public/browser/browsing_data_filter_builder.h
index b4ffa39..84035ad 100644
--- a/content/public/browser/browsing_data_filter_builder.h
+++ b/content/public/browser/browsing_data_filter_builder.h
@@ -67,9 +67,11 @@
   virtual base::RepeatingCallback<bool(const GURL&)>
       BuildGeneralFilter() const = 0;
 
-  // Builds a filter that can be used with the network service, more precisely
-  // with NetworkContext.ClearHttpCache().
-  virtual network::mojom::ClearCacheUrlFilterPtr BuildClearCacheUrlFilter()
+  // Builds a filter that can be used with the network service. This uses a Mojo
+  // struct rather than a predicate function (as used by the rest of the filters
+  // built by this class) because we need to be able to pass the filter to the
+  // network service via IPC.
+  virtual network::mojom::ClearDataFilterPtr BuildNetworkServiceFilter()
       const = 0;
 
   // Builds a CookieDeletionInfo object that matches cookies whose sources are
@@ -77,11 +79,6 @@
   virtual net::CookieStore::CookieDeletionInfo BuildCookieDeletionInfo()
       const = 0;
 
-  // Builds a filter that matches channel IDs whose server identifiers are in
-  // the whitelist, or aren't in the blacklist.
-  virtual base::RepeatingCallback<bool(const std::string& server_id)>
-      BuildChannelIDFilter() const = 0;
-
   // Builds a filter that matches the |site| of a plugin.
   virtual base::RepeatingCallback<bool(const std::string& site)>
       BuildPluginFilter() const = 0;
diff --git a/content/public/browser/gpu_data_manager.h b/content/public/browser/gpu_data_manager.h
index ebe6ba5..481bf03 100644
--- a/content/public/browser/gpu_data_manager.h
+++ b/content/public/browser/gpu_data_manager.h
@@ -61,10 +61,6 @@
   // Whether a GPU is in use (as opposed to a software renderer).
   virtual bool HardwareAccelerationEnabled() const = 0;
 
-  // Extensions that are currently disabled.
-  virtual void GetDisabledExtensions(
-      std::string* disabled_extensions) const = 0;
-
  protected:
   virtual ~GpuDataManager() {}
 };
diff --git a/content/public/browser/render_widget_host_view.h b/content/public/browser/render_widget_host_view.h
index 1ced1c48..3b9d912 100644
--- a/content/public/browser/render_widget_host_view.h
+++ b/content/public/browser/render_widget_host_view.h
@@ -184,8 +184,7 @@
   // visible viewport.
   virtual void SetInsets(const gfx::Insets& insets) = 0;
 
-  // Returns true if the current display surface is available, a prerequisite
-  // for CopyFromSurface() to succeed.
+  // Returns true if the current display surface is available.
   virtual bool IsSurfaceAvailableForCopy() const = 0;
 
   // Copies the given subset of the view's surface, optionally scales it, and
@@ -214,6 +213,10 @@
       const gfx::Size& output_size,
       base::OnceCallback<void(const SkBitmap&)> callback) = 0;
 
+  // Ensures that all surfaces are synchronized for the next call to
+  // CopyFromSurface. This is used by LayoutTests.
+  virtual void EnsureSurfaceSynchronizedForLayoutTest() = 0;
+
   // Creates a video capturer, which will allow the caller to receive a stream
   // of media::VideoFrames captured from this view. The capturer is configured
   // to target this view, so there is no need to call ChangeTarget() before
diff --git a/content/public/browser/site_isolation_policy.cc b/content/public/browser/site_isolation_policy.cc
index aa1599d..0a75907 100644
--- a/content/public/browser/site_isolation_policy.cc
+++ b/content/public/browser/site_isolation_policy.cc
@@ -72,11 +72,6 @@
   if (UseDedicatedProcessesForAllSites())
     return false;
 
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableSiteIsolationTrials)) {
-    return false;
-  }
-
   // The feature needs to be checked last, because checking the feature
   // activates the field trial and assigns the client either to a control or an
   // experiment group - such assignment should be final.
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index d377a68..decf99d 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -37,20 +37,24 @@
 #include "content/browser/accessibility/browser_accessibility.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/browser_plugin/browser_plugin_guest.h"
+#include "content/browser/browser_plugin/browser_plugin_message_filter.h"
 #include "content/browser/compositor/surface_utils.h"
 #include "content/browser/frame_host/cross_process_frame_connector.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
 #include "content/browser/service_manager/service_manager_context.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_contents/web_contents_view.h"
+#include "content/common/browser_plugin/browser_plugin_messages.h"
 #include "content/common/fileapi/file_system_messages.h"
 #include "content/common/fileapi/webblob_messages.h"
 #include "content/common/frame_messages.h"
+#include "content/common/frame_resize_params.h"
 #include "content/common/input/synthetic_web_input_event_builders.h"
 #include "content/common/input_messages.h"
 #include "content/common/view_messages.h"
@@ -73,6 +77,7 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/service_names.mojom.h"
+#include "content/public/common/use_zoom_for_dsf_policy.h"
 #include "content/public/test/simple_url_loader_test_helper.h"
 #include "content/public/test/test_fileapi_operation_waiter.h"
 #include "content/public/test/test_navigation_observer.h"
@@ -2539,4 +2544,181 @@
       process_group_name);
 }
 
+bool TestChildOrGuestAutoresize(bool is_guest,
+                                RenderProcessHost* embedder_rph,
+                                RenderWidgetHost* guest_rwh) {
+  RenderProcessHostImpl* embedder_rph_impl =
+      static_cast<RenderProcessHostImpl*>(embedder_rph);
+  RenderWidgetHostImpl* guest_rwh_impl =
+      static_cast<RenderWidgetHostImpl*>(guest_rwh);
+
+  scoped_refptr<UpdateResizeParamsMessageFilter> filter(
+      new UpdateResizeParamsMessageFilter());
+
+  // Register the message filter for the guest or child. For guest, we must use
+  // a special hook, as there are already message filters installed which will
+  // supercede us.
+  if (is_guest) {
+    embedder_rph_impl->SetBrowserPluginMessageFilterSubFilterForTesting(
+        filter.get());
+  } else {
+    embedder_rph_impl->AddFilter(filter.get());
+  }
+
+  viz::LocalSurfaceId current_id =
+      guest_rwh_impl->GetView()->GetLocalSurfaceId();
+  // The guest may not yet be fully attached / initted. If not, |current_id|
+  // will be invalid, and we should wait for an ID before proceeding.
+  if (!current_id.is_valid())
+    current_id = filter->WaitForSurfaceId();
+
+  // Enable auto-resize.
+  guest_rwh_impl->SetAutoResize(true, gfx::Size(10, 10), gfx::Size(100, 100));
+
+  // Fake an auto-resize update.
+  int routing_id = guest_rwh_impl->GetRoutingID();
+  ViewHostMsg_ResizeOrRepaint_ACK_Params params;
+  params.view_size = gfx::Size(75, 75);
+  params.flags = 0;
+  params.sequence_number = 7;
+  params.child_allocated_local_surface_id = viz::LocalSurfaceId(
+      current_id.parent_sequence_number(),
+      current_id.child_sequence_number() + 1, current_id.embed_token());
+  guest_rwh_impl->OnMessageReceived(
+      ViewHostMsg_ResizeOrRepaint_ACK(routing_id, params));
+
+  // Get the first delivered surface id and ensure it has the surface id which
+  // we expect.
+  return filter->WaitForSurfaceId() == params.child_allocated_local_surface_id;
+}
+
+const uint32_t UpdateResizeParamsMessageFilter::kMessageClassesToFilter[2] = {
+    FrameMsgStart, BrowserPluginMsgStart};
+
+UpdateResizeParamsMessageFilter::UpdateResizeParamsMessageFilter()
+    : content::BrowserMessageFilter(kMessageClassesToFilter,
+                                    arraysize(kMessageClassesToFilter)),
+      screen_space_rect_run_loop_(std::make_unique<base::RunLoop>()),
+      screen_space_rect_received_(false) {}
+
+void UpdateResizeParamsMessageFilter::WaitForRect() {
+  screen_space_rect_run_loop_->Run();
+}
+
+void UpdateResizeParamsMessageFilter::ResetRectRunLoop() {
+  last_rect_ = gfx::Rect();
+  screen_space_rect_run_loop_.reset(new base::RunLoop);
+  screen_space_rect_received_ = false;
+}
+
+viz::FrameSinkId UpdateResizeParamsMessageFilter::GetOrWaitForId() {
+  // No-op if already quit.
+  frame_sink_id_run_loop_.Run();
+  return frame_sink_id_;
+}
+
+viz::LocalSurfaceId UpdateResizeParamsMessageFilter::WaitForSurfaceId() {
+  surface_id_run_loop_.reset(new base::RunLoop);
+  surface_id_run_loop_->Run();
+  return last_surface_id_;
+}
+
+UpdateResizeParamsMessageFilter::~UpdateResizeParamsMessageFilter() {}
+
+void UpdateResizeParamsMessageFilter::OnUpdateFrameHostResizeParams(
+    const viz::SurfaceId& surface_id,
+    const FrameResizeParams& resize_params) {
+  OnUpdateResizeParams(surface_id.local_surface_id(),
+                       surface_id.frame_sink_id(), resize_params);
+}
+
+void UpdateResizeParamsMessageFilter::OnUpdateBrowserPluginResizeParams(
+    int browser_plugin_guest_instance_id,
+    viz::LocalSurfaceId surface_id,
+    FrameResizeParams resize_params) {
+  OnUpdateResizeParams(surface_id, viz::FrameSinkId(), resize_params);
+}
+
+void UpdateResizeParamsMessageFilter::OnUpdateResizeParams(
+    const viz::LocalSurfaceId& local_surface_id,
+    const viz::FrameSinkId& frame_sink_id,
+    const FrameResizeParams& resize_params) {
+  gfx::Rect screen_space_rect_in_dip = resize_params.screen_space_rect;
+  if (IsUseZoomForDSFEnabled()) {
+    screen_space_rect_in_dip =
+        gfx::Rect(gfx::ScaleToFlooredPoint(
+                      resize_params.screen_space_rect.origin(),
+                      1.f / resize_params.screen_info.device_scale_factor),
+                  gfx::ScaleToCeiledSize(
+                      resize_params.screen_space_rect.size(),
+                      1.f / resize_params.screen_info.device_scale_factor));
+  }
+  // Track each rect updates.
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&UpdateResizeParamsMessageFilter::OnUpdatedFrameRectOnUI,
+                     this, screen_space_rect_in_dip));
+
+  // Track each surface id update.
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&UpdateResizeParamsMessageFilter::OnUpdatedSurfaceIdOnUI,
+                     this, local_surface_id));
+
+  // Record the received value. We cannot check the current state of the child
+  // frame, as it can only be processed on the UI thread, and we cannot block
+  // here.
+  frame_sink_id_ = frame_sink_id;
+
+  // There can be several updates before a valid viz::FrameSinkId is ready. Do
+  // not quit |run_loop_| until after we receive a valid one.
+  if (!frame_sink_id_.is_valid())
+    return;
+
+  // We can't nest on the IO thread. So tests will wait on the UI thread, so
+  // post there to exit the nesting.
+  content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
+      ->PostTask(FROM_HERE,
+                 base::BindOnce(
+                     &UpdateResizeParamsMessageFilter::OnUpdatedFrameSinkIdOnUI,
+                     this));
+}
+
+void UpdateResizeParamsMessageFilter::OnUpdatedFrameRectOnUI(
+    const gfx::Rect& rect) {
+  last_rect_ = rect;
+  if (!screen_space_rect_received_) {
+    screen_space_rect_received_ = true;
+    // Tests looking at the rect currently expect all received input to finish
+    // processing before the test continutes.
+    screen_space_rect_run_loop_->QuitWhenIdle();
+  }
+}
+
+void UpdateResizeParamsMessageFilter::OnUpdatedFrameSinkIdOnUI() {
+  frame_sink_id_run_loop_.Quit();
+}
+
+void UpdateResizeParamsMessageFilter::OnUpdatedSurfaceIdOnUI(
+    viz::LocalSurfaceId surface_id) {
+  last_surface_id_ = surface_id;
+  if (surface_id_run_loop_) {
+    surface_id_run_loop_->QuitWhenIdle();
+  }
+}
+
+bool UpdateResizeParamsMessageFilter::OnMessageReceived(
+    const IPC::Message& message) {
+  IPC_BEGIN_MESSAGE_MAP(UpdateResizeParamsMessageFilter, message)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateResizeParams,
+                        OnUpdateFrameHostResizeParams)
+    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateResizeParams,
+                        OnUpdateBrowserPluginResizeParams)
+  IPC_END_MESSAGE_MAP()
+
+  // We do not consume the message, so that we can verify the effects of it
+  // being processed.
+  return false;
+}
+
 }  // namespace content
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 7bdc7185..a8eb280 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -71,6 +71,7 @@
 namespace content {
 
 class BrowserContext;
+struct FrameResizeParams;
 class InterstitialPage;
 class MessageLoopRunner;
 class NavigationHandle;
@@ -1143,6 +1144,65 @@
 // called on the IO thread.
 bool HasValidProcessForProcessGroup(const std::string& process_group_name);
 
+// Performs a simple auto-resize flow and ensures that the embedder gets a
+// single response messages back from the guest, with the expected values.
+bool TestChildOrGuestAutoresize(bool is_guest,
+                                RenderProcessHost* embedder_rph,
+                                RenderWidgetHost* guest_rwh);
+
+// Class to sniff incoming IPCs for either FrameHostMsg_UpdateResizeParams or
+// BrowserPluginHostMsg_UpdateResizeParams messages. This allows the message to
+// continue to the target child so that processing can be verified by tests.
+class UpdateResizeParamsMessageFilter : public content::BrowserMessageFilter {
+ public:
+  UpdateResizeParamsMessageFilter();
+
+  gfx::Rect last_rect() const { return last_rect_; }
+
+  void WaitForRect();
+  void ResetRectRunLoop();
+
+  // Returns the new viz::FrameSinkId immediately if the IPC has been received.
+  // Otherwise this will block the UI thread until it has been received, then it
+  // will return the new viz::FrameSinkId.
+  viz::FrameSinkId GetOrWaitForId();
+
+  // Waits for the next viz::LocalSurfaceId be received and returns it.
+  viz::LocalSurfaceId WaitForSurfaceId();
+
+ protected:
+  ~UpdateResizeParamsMessageFilter() override;
+
+ private:
+  void OnUpdateFrameHostResizeParams(const viz::SurfaceId& surface_id,
+                                     const FrameResizeParams& resize_params);
+  void OnUpdateBrowserPluginResizeParams(int browser_plugin_guest_instance_id,
+                                         viz::LocalSurfaceId surface_id,
+                                         FrameResizeParams resize_params);
+  void OnUpdateResizeParams(const viz::LocalSurfaceId& surface_id,
+                            const viz::FrameSinkId& frame_sink_id,
+                            const FrameResizeParams& resize_params);
+  // |rect| is in DIPs.
+  void OnUpdatedFrameRectOnUI(const gfx::Rect& rect);
+  void OnUpdatedFrameSinkIdOnUI();
+  void OnUpdatedSurfaceIdOnUI(viz::LocalSurfaceId surface_id);
+
+  bool OnMessageReceived(const IPC::Message& message) override;
+
+  static const uint32_t kMessageClassesToFilter[2];
+  viz::FrameSinkId frame_sink_id_;
+  base::RunLoop frame_sink_id_run_loop_;
+
+  std::unique_ptr<base::RunLoop> screen_space_rect_run_loop_;
+  bool screen_space_rect_received_;
+  gfx::Rect last_rect_;
+
+  viz::LocalSurfaceId last_surface_id_;
+  std::unique_ptr<base::RunLoop> surface_id_run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(UpdateResizeParamsMessageFilter);
+};
+
 }  // namespace content
 
 #endif  // CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index c5fe59a..6e405a6b 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -250,7 +250,30 @@
 }
 #endif
 
-void BrowserPlugin::WasResized() {
+void BrowserPlugin::WasResized(
+    const viz::LocalSurfaceId& child_allocated_surface_id) {
+  // TODO(ericrk): Once we short-circuit responses to child allocated surface
+  // IDs, we can remove |surface_id_changed| here and simply update.
+  // https://crbug.com/811944
+  bool surface_id_changed = false;
+  if (child_allocated_surface_id.is_valid()) {
+    viz::LocalSurfaceId previous_id = GetLocalSurfaceId();
+    parent_local_surface_id_allocator_.UpdateFromChild(
+        child_allocated_surface_id);
+    surface_id_changed = previous_id != GetLocalSurfaceId();
+  }
+
+  // We no longer use auto resize sequence numbers to trigger ID generation,
+  // instead getting auto resize IDs from the child. If our auto-resize
+  // sequence number changed our surface ID must change as well.
+  // TODO(ericrk): Once we short-circuit, we can remove references to sequence
+  // numbers and clean this up. https://crbug.com/811944.
+  if (sent_resize_params_ &&
+      sent_resize_params_->auto_resize_sequence_number !=
+          pending_resize_params_.auto_resize_sequence_number) {
+    DCHECK(surface_id_changed);
+  }
+
   bool size_changed = !sent_resize_params_ ||
                       sent_resize_params_->auto_resize_enabled !=
                           pending_resize_params_.auto_resize_enabled ||
@@ -261,29 +284,40 @@
                       sent_resize_params_->local_frame_size !=
                           pending_resize_params_.local_frame_size ||
                       sent_resize_params_->screen_space_rect.size() !=
-                          pending_resize_params_.screen_space_rect.size() ||
-                      sent_resize_params_->auto_resize_sequence_number !=
-                          pending_resize_params_.auto_resize_sequence_number;
+                          pending_resize_params_.screen_space_rect.size();
+
+  // Note that the following flag is true if the capture sequence number
+  // actually changed. That is, it is false if we did not have
+  // |sent_resize_params_|, which is different from the other local flags here.
+  bool capture_sequence_number_changed =
+      sent_resize_params_ && sent_resize_params_->capture_sequence_number !=
+                                 pending_resize_params_.capture_sequence_number;
 
   bool synchronized_params_changed =
       !sent_resize_params_ || size_changed ||
-      sent_resize_params_->screen_info != pending_resize_params_.screen_info;
+      sent_resize_params_->screen_info != pending_resize_params_.screen_info ||
+      capture_sequence_number_changed;
 
   if (synchronized_params_changed)
     parent_local_surface_id_allocator_.GenerateId();
 
   if (enable_surface_synchronization_ && frame_sink_id_.is_valid()) {
-    // TODO(vmpstr): When capture_sequence_number is available, the deadline
-    // should be infinite if the sequence number has changed.
+    // If we're synchronizing surfaces, then use an infinite deadline to ensure
+    // everything is synchronized.
+    cc::DeadlinePolicy deadline =
+        capture_sequence_number_changed
+            ? cc::DeadlinePolicy::UseInfiniteDeadline()
+            : cc::DeadlinePolicy::UseDefaultDeadline();
     compositing_helper_->SetPrimarySurfaceId(
         viz::SurfaceId(frame_sink_id_, GetLocalSurfaceId()),
-        screen_space_rect().size(), cc::DeadlinePolicy::UseDefaultDeadline());
+        screen_space_rect().size(), deadline);
   }
 
   bool position_changed = !sent_resize_params_ ||
                           sent_resize_params_->screen_space_rect.origin() !=
                               pending_resize_params_.screen_space_rect.origin();
-  bool resize_params_changed = synchronized_params_changed || position_changed;
+  bool resize_params_changed =
+      synchronized_params_changed || position_changed || surface_id_changed;
 
   if (resize_params_changed && attached()) {
     // Let the browser know about the updated view rect.
@@ -323,7 +357,7 @@
   attached_ = true;
   if (child_local_surface_id)
     parent_local_surface_id_allocator_.Reset(*child_local_surface_id);
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
 }
 
 void BrowserPlugin::OnGuestGone(int browser_plugin_instance_id) {
@@ -337,13 +371,15 @@
   guest_crashed_ = false;
   frame_sink_id_ = frame_sink_id;
   sent_resize_params_ = base::nullopt;
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
 }
 
-void BrowserPlugin::OnResizeDueToAutoResize(int browser_plugin_instance_id,
-                                            uint64_t sequence_number) {
+void BrowserPlugin::OnResizeDueToAutoResize(
+    int browser_plugin_instance_id,
+    uint64_t sequence_number,
+    viz::LocalSurfaceId child_allocated_local_surface_id) {
   pending_resize_params_.auto_resize_sequence_number = sequence_number;
-  WasResized();
+  WasResized(child_allocated_local_surface_id);
 }
 
 void BrowserPlugin::OnEnableAutoResize(int browser_plugin_instance_id,
@@ -352,12 +388,12 @@
   pending_resize_params_.auto_resize_enabled = true;
   pending_resize_params_.min_size_for_auto_resize = min_size;
   pending_resize_params_.max_size_for_auto_resize = max_size;
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
 }
 
 void BrowserPlugin::OnDisableAutoResize(int browser_plugin_instance_id) {
   pending_resize_params_.auto_resize_enabled = false;
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
 }
 
 void BrowserPlugin::OnSetCursor(int browser_plugin_instance_id,
@@ -449,7 +485,13 @@
                                         screen_info.device_scale_factor);
     return;
   }
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
+}
+
+void BrowserPlugin::UpdateCaptureSequenceNumber(
+    uint32_t capture_sequence_number) {
+  pending_resize_params_.capture_sequence_number = capture_sequence_number;
+  WasResized(viz::LocalSurfaceId());
 }
 
 bool BrowserPlugin::ShouldGuestBeFocused() const {
@@ -581,7 +623,7 @@
                                         screen_info().device_scale_factor);
     return;
   }
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
 }
 
 void BrowserPlugin::UpdateFocus(bool focused, blink::WebFocusType focus_type) {
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
index a123a1b..0d46f46 100644
--- a/content/renderer/browser_plugin/browser_plugin.h
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -76,6 +76,8 @@
 
   void ScreenInfoChanged(const ScreenInfo& screen_info);
 
+  void UpdateCaptureSequenceNumber(uint32_t capture_sequence_number);
+
   // Indicates whether the guest should be focused.
   bool ShouldGuestBeFocused() const;
 
@@ -90,7 +92,7 @@
   // Returns the last allocated LocalSurfaceId.
   const viz::LocalSurfaceId& GetLocalSurfaceId() const;
 
-  void WasResized();
+  void WasResized(const viz::LocalSurfaceId& child_allocated_local_surface_id);
 
   // Returns whether a message should be forwarded to BrowserPlugin.
   static bool ShouldForwardToBrowserPlugin(const IPC::Message& message);
@@ -193,7 +195,8 @@
   void OnGuestGone(int instance_id);
   void OnGuestReady(int instance_id, const viz::FrameSinkId& frame_sink_id);
   void OnResizeDueToAutoResize(int browser_plugin_instance_id,
-                               uint64_t sequence_number);
+                               uint64_t sequence_number,
+                               viz::LocalSurfaceId child_allocated_surface_id);
   void OnEnableAutoResize(int browser_plugin_instance_id,
                           const gfx::Size& min_size,
                           const gfx::Size& max_size);
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index a5fc045..03e4eaf8 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -29,6 +29,7 @@
 #include "media/base/media_switches.h"
 #include "media/base/renderer_factory_selector.h"
 #include "media/base/surface_manager.h"
+#include "media/blink/remote_playback_client_wrapper_impl.h"
 #include "media/blink/resource_fetch_context.h"
 #include "media/blink/webencryptedmediaclient_impl.h"
 #include "media/blink/webmediaplayer_impl.h"
@@ -53,6 +54,7 @@
 #include "content/renderer/media/android/stream_texture_wrapper_impl.h"
 #include "media/base/android/media_codec_util.h"
 #include "media/base/media.h"
+#include "media/renderers/flinging_renderer_client_factory.h"
 #include "url/gurl.h"
 #endif
 
@@ -242,9 +244,10 @@
 
   base::WeakPtr<media::MediaObserver> media_observer;
 
-  auto factory_selector =
-      CreateRendererFactorySelector(media_log.get(), use_media_player_renderer,
-                                    GetDecoderFactory(), &media_observer);
+  auto factory_selector = CreateRendererFactorySelector(
+      media_log.get(), use_media_player_renderer, GetDecoderFactory(),
+      std::make_unique<media::RemotePlaybackClientWrapperImpl>(client),
+      &media_observer);
 
 #if BUILDFLAG(ENABLE_MEDIA_REMOTING)
   DCHECK(media_observer);
@@ -343,6 +346,7 @@
     media::MediaLog* media_log,
     bool use_media_player,
     media::DecoderFactory* decoder_factory,
+    std::unique_ptr<media::RemotePlaybackClientWrapper> client_wrapper,
     base::WeakPtr<media::MediaObserver>* out_media_observer) {
   RenderThreadImpl* render_thread = RenderThreadImpl::current();
   // Render thread may not exist in tests, returning nullptr if it does not.
@@ -354,6 +358,7 @@
 #if defined(OS_ANDROID)
   DCHECK(remote_interfaces_);
 
+  // MediaPlayerRendererClientFactory setup.
   auto mojo_media_player_renderer_factory =
       std::make_unique<media::MojoRendererFactory>(
           media::mojom::HostedRendererType::kMediaPlayer,
@@ -373,6 +378,38 @@
                      base::ThreadTaskRunnerHandle::Get())));
 
   factory_selector->SetUseMediaPlayer(use_media_player);
+
+  // FlingingRendererClientFactory (FRCF) setup.
+  auto mojo_flinging_factory = std::make_unique<media::MojoRendererFactory>(
+      media::mojom::HostedRendererType::kFlinging,
+      media::MojoRendererFactory::GetGpuFactoriesCB(),
+      GetMediaInterfaceFactory());
+
+  // Save a temp copy of the pointer, before moving it into the FRCF.
+  // The FRCF cannot be aware of the MojoRendererFactory directly, due to
+  // layering issues.
+  media::MojoRendererFactory* temp_mojo_flinging_factory =
+      mojo_flinging_factory.get();
+
+  auto flinging_factory =
+      std::make_unique<media::FlingingRendererClientFactory>(
+          std::move(mojo_flinging_factory), std::move(client_wrapper));
+
+  // base::Unretained is safe here because the FRCF owns the MojoRendererFactory
+  // and is guaranteed to outlive it.
+  temp_mojo_flinging_factory->SetGetTypeSpecificIdCB(base::BindRepeating(
+      &media::FlingingRendererClientFactory::GetActivePresentationId,
+      base::Unretained(flinging_factory.get())));
+
+  // base::Unretained is safe here because |factory_selector| owns
+  // |flinging_factory|.
+  factory_selector->SetQueryIsFlingingActiveCB(
+      base::Bind(&media::FlingingRendererClientFactory::IsFlingingActive,
+                 base::Unretained(flinging_factory.get())));
+
+  factory_selector->AddFactory(
+      media::RendererFactorySelector::FactoryType::FLINGING,
+      std::move(flinging_factory));
 #endif  // defined(OS_ANDROID)
 
   bool use_mojo_renderer_factory = false;
diff --git a/content/renderer/media/media_factory.h b/content/renderer/media/media_factory.h
index 406b172..1d5aeece 100644
--- a/content/renderer/media/media_factory.h
+++ b/content/renderer/media/media_factory.h
@@ -43,6 +43,7 @@
 class DecoderFactory;
 class MediaLog;
 class MediaObserver;
+class RemotePlaybackClientWrapper;
 class RendererWebMediaPlayerDelegate;
 class SurfaceManager;
 class WebEncryptedMediaClientImpl;
@@ -112,6 +113,7 @@
       media::MediaLog* media_log,
       bool use_media_player,
       media::DecoderFactory* decoder_factory,
+      std::unique_ptr<media::RemotePlaybackClientWrapper> client_wrapper,
       base::WeakPtr<media::MediaObserver>* out_media_observer);
 
   blink::WebMediaPlayer* CreateWebMediaPlayerForMediaStream(
diff --git a/content/renderer/media/mojo_audio_output_ipc.cc b/content/renderer/media/mojo_audio_output_ipc.cc
index 883c1e4..287c8a8 100644
--- a/content/renderer/media/mojo_audio_output_ipc.cc
+++ b/content/renderer/media/mojo_audio_output_ipc.cc
@@ -32,9 +32,9 @@
 MojoAudioOutputIPC::~MojoAudioOutputIPC() {
   DCHECK(!AuthorizationRequested() && !StreamCreationRequested())
       << "CloseStream must be called before destructing the AudioOutputIPC";
-  // No sequence check.
-  // Destructing |weak_factory_| on any sequence is safe since it's not used
-  // after the final call to CloseStream, where its pointers are invalidated.
+  // No thread check.
+  // Destructing |weak_factory_| on any thread is safe since it's not used after
+  // the final call to CloseStream, where its pointers are invalidated.
 }
 
 void MojoAudioOutputIPC::RequestDeviceAuthorization(
@@ -81,13 +81,17 @@
   // Since the creation callback won't fire if the provider binding is gone
   // and |this| owns |stream_provider_|, unretained is safe.
   stream_creation_start_time_ = base::TimeTicks::Now();
-  media::mojom::AudioOutputStreamProviderClientPtr client_ptr;
+  media::mojom::AudioOutputStreamClientPtr client_ptr;
   binding_.Bind(mojo::MakeRequest(&client_ptr));
-  // Unretained is safe because |this| owns |binding_|.
-  binding_.set_connection_error_with_reason_handler(
-      base::BindOnce(&MojoAudioOutputIPC::ProviderClientBindingDisconnected,
-                     base::Unretained(this)));
-  stream_provider_->Acquire(params, std::move(client_ptr));
+  stream_provider_->Acquire(mojo::MakeRequest(&stream_), std::move(client_ptr),
+                            params,
+                            base::BindOnce(&MojoAudioOutputIPC::StreamCreated,
+                                           base::Unretained(this)));
+
+  // Don't set a connection error handler. Either an error has already been
+  // signaled through the AudioOutputStreamClient interface, or the connection
+  // is broken because the frame owning |this| was destroyed, in which
+  // case |this| will soon be cleaned up anyways.
 }
 
 void MojoAudioOutputIPC::PlayStream() {
@@ -119,25 +123,18 @@
   stream_->SetVolume(volume);
 }
 
-void MojoAudioOutputIPC::ProviderClientBindingDisconnected(
-    uint32_t disconnect_reason,
-    const std::string& description) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+void MojoAudioOutputIPC::OnError() {
+  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(delegate_);
-  if (disconnect_reason == kPlatformErrorDisconnectReason) {
-    delegate_->OnError();
-  }
-  // Otherwise, disconnection was due to the frame owning |this| being
-  // destructed or having a navigation. In this case, |this| will soon be
-  // cleaned up.
+  delegate_->OnError();
 }
 
-bool MojoAudioOutputIPC::AuthorizationRequested() const {
+bool MojoAudioOutputIPC::AuthorizationRequested() {
   return stream_provider_.is_bound();
 }
 
-bool MojoAudioOutputIPC::StreamCreationRequested() const {
-  return binding_.is_bound();
+bool MojoAudioOutputIPC::StreamCreationRequested() {
+  return stream_.is_bound();
 }
 
 media::mojom::AudioOutputStreamProviderRequest
@@ -206,14 +203,13 @@
   delegate_->OnDeviceAuthorized(status, params, device_id);
 }
 
-void MojoAudioOutputIPC::Created(media::mojom::AudioOutputStreamPtr stream,
-                                 media::mojom::AudioDataPipePtr data_pipe) {
+void MojoAudioOutputIPC::StreamCreated(
+    media::mojom::AudioDataPipePtr data_pipe) {
   DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(delegate_);
 
   UMA_HISTOGRAM_TIMES("Media.Audio.Render.OutputDeviceStreamCreationTime",
                       base::TimeTicks::Now() - stream_creation_start_time_);
-  stream_ = std::move(stream);
 
   base::PlatformFile socket_handle;
   auto result =
diff --git a/content/renderer/media/mojo_audio_output_ipc.h b/content/renderer/media/mojo_audio_output_ipc.h
index b91da3e..e2bd52f 100644
--- a/content/renderer/media/mojo_audio_output_ipc.h
+++ b/content/renderer/media/mojo_audio_output_ipc.h
@@ -24,7 +24,7 @@
 // thread.
 class CONTENT_EXPORT MojoAudioOutputIPC
     : public media::AudioOutputIPC,
-      public media::mojom::AudioOutputStreamProviderClient {
+      public media::mojom::AudioOutputStreamClient {
  public:
   using FactoryAccessorCB =
       base::RepeatingCallback<mojom::RendererAudioOutputStreamFactory*()>;
@@ -48,20 +48,15 @@
   void CloseStream() override;
   void SetVolume(double volume) override;
 
-  // media::mojom::AudioOutputStreamProviderClient implementation.
-  void Created(media::mojom::AudioOutputStreamPtr stream,
-               media::mojom::AudioDataPipePtr data_pipe) override;
+  // media::mojom::AudioOutputStreamClient implementation.
+  void OnError() override;
 
  private:
   using AuthorizationCB = mojom::RendererAudioOutputStreamFactory::
       RequestDeviceAuthorizationCallback;
 
-  bool AuthorizationRequested() const;
-  bool StreamCreationRequested() const;
-
-  void ProviderClientBindingDisconnected(uint32_t disconnect_reason,
-                                         const std::string& description);
-
+  bool AuthorizationRequested();
+  bool StreamCreationRequested();
   media::mojom::AudioOutputStreamProviderRequest MakeProviderRequest();
 
   // Tries to acquire a RendererAudioOutputStreamFactory and requests device
@@ -76,11 +71,11 @@
                                    const media::AudioParameters& params,
                                    const std::string& device_id) const;
 
-  SEQUENCE_CHECKER(sequence_checker_);
+  void StreamCreated(media::mojom::AudioDataPipePtr data_pipe);
 
   const FactoryAccessorCB factory_accessor_;
 
-  mojo::Binding<media::mojom::AudioOutputStreamProviderClient> binding_;
+  mojo::Binding<media::mojom::AudioOutputStreamClient> binding_;
   media::mojom::AudioOutputStreamProviderPtr stream_provider_;
   media::mojom::AudioOutputStreamPtr stream_;
   media::AudioOutputIPCDelegate* delegate_ = nullptr;
diff --git a/content/renderer/media/mojo_audio_output_ipc_unittest.cc b/content/renderer/media/mojo_audio_output_ipc_unittest.cc
index 8d8a03e..ca3697a 100644
--- a/content/renderer/media/mojo_audio_output_ipc_unittest.cc
+++ b/content/renderer/media/mojo_audio_output_ipc_unittest.cc
@@ -57,33 +57,30 @@
       EXPECT_TRUE(binding_);
   }
 
-  void Acquire(const media::AudioParameters& params,
-               media::mojom::AudioOutputStreamProviderClientPtr provider_client)
-      override {
+  void Acquire(media::mojom::AudioOutputStreamRequest stream_request,
+               media::mojom::AudioOutputStreamClientPtr client_ptr,
+               const media::AudioParameters& params,
+               AcquireCallback callback) override {
     EXPECT_EQ(binding_, base::nullopt);
     EXPECT_NE(stream_, nullptr);
-    std::swap(provider_client, provider_client_);
-    media::mojom::AudioOutputStreamPtr stream_ptr;
-    binding_.emplace(stream_, mojo::MakeRequest(&stream_ptr));
+    std::swap(client_, client_ptr);
+    binding_.emplace(stream_, std::move(stream_request));
     base::CancelableSyncSocket foreign_socket;
     EXPECT_TRUE(
         base::CancelableSyncSocket::CreatePair(&socket_, &foreign_socket));
-    provider_client_->Created(
-        std::move(stream_ptr),
-        {base::in_place, mojo::SharedBufferHandle::Create(kMemoryLength),
-         mojo::WrapPlatformFile(foreign_socket.Release())});
+    std::move(callback).Run({base::in_place,
+                             mojo::SharedBufferHandle::Create(kMemoryLength),
+                             mojo::WrapPlatformFile(foreign_socket.Release())});
   }
 
-  void SignalErrorToProviderClient() {
-    provider_client_.ResetWithReason(
-        media::mojom::AudioOutputStreamProviderClient::
-            kPlatformErrorDisconnectReason,
-        std::string());
+  media::mojom::AudioOutputStreamClient* client() {
+    DCHECK(client_.get());
+    return client_.get();
   }
 
  private:
   media::mojom::AudioOutputStream* stream_;
-  media::mojom::AudioOutputStreamProviderClientPtr provider_client_;
+  media::mojom::AudioOutputStreamClientPtr client_;
   base::Optional<mojo::Binding<media::mojom::AudioOutputStream>> binding_;
   base::CancelableSyncSocket socket_;
 };
@@ -137,10 +134,6 @@
     expected_device_id_ = device_id;
   }
 
-  void SignalErrorToProviderClient() {
-    provider_->SignalErrorToProviderClient();
-  }
-
   void Disconnect() {
     binding_.Close();
     this_proxy_.reset();
@@ -150,6 +143,10 @@
     expect_request_ = false;
   }
 
+  media::mojom::AudioOutputStreamClient* client() {
+    return provider_->client();
+  }
+
   MojoAudioOutputIPC::FactoryAccessorCB GetAccessor() {
     return base::BindRepeating(&TestRemoteFactory::get, base::Unretained(this));
   }
@@ -389,7 +386,7 @@
     Mock::VerifyAndClearExpectations(&delegate);
 
     EXPECT_CALL(delegate, OnError());
-    stream_factory.SignalErrorToProviderClient();
+    stream_factory.client()->OnError();
     base::RunLoop().RunUntilIdle();
     Mock::VerifyAndClearExpectations(&delegate);
 
@@ -533,12 +530,6 @@
   StrictMock<MockStream> stream;
   StrictMock<MockDelegate> delegate;
 
-  EXPECT_CALL(delegate, OnDeviceAuthorized(
-                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
-                            _, std::string(kReturnedDeviceId)));
-  EXPECT_CALL(delegate, GotOnStreamCreated());
-  EXPECT_CALL(stream, Play());
-
   const std::unique_ptr<media::AudioOutputIPC> ipc =
       std::make_unique<MojoAudioOutputIPC>(
           stream_factory.GetAccessor(),
@@ -548,9 +539,15 @@
 
   ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId);
   ipc->CreateStream(&delegate, Params());
-  base::RunLoop().RunUntilIdle();
   ipc->PlayStream();
+
+  EXPECT_CALL(delegate, OnDeviceAuthorized(
+                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                            _, std::string(kReturnedDeviceId)));
+  EXPECT_CALL(delegate, GotOnStreamCreated());
+  EXPECT_CALL(stream, Play());
   base::RunLoop().RunUntilIdle();
+
   ipc->CloseStream();
   base::RunLoop().RunUntilIdle();
 }
@@ -561,12 +558,6 @@
   StrictMock<MockStream> stream;
   StrictMock<MockDelegate> delegate;
 
-  EXPECT_CALL(delegate, OnDeviceAuthorized(
-                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
-                            _, std::string(kReturnedDeviceId)));
-  EXPECT_CALL(delegate, GotOnStreamCreated());
-  EXPECT_CALL(stream, Pause());
-
   const std::unique_ptr<media::AudioOutputIPC> ipc =
       std::make_unique<MojoAudioOutputIPC>(
           stream_factory.GetAccessor(),
@@ -576,9 +567,15 @@
 
   ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId);
   ipc->CreateStream(&delegate, Params());
-  base::RunLoop().RunUntilIdle();
   ipc->PauseStream();
+
+  EXPECT_CALL(delegate, OnDeviceAuthorized(
+                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                            _, std::string(kReturnedDeviceId)));
+  EXPECT_CALL(delegate, GotOnStreamCreated());
+  EXPECT_CALL(stream, Pause());
   base::RunLoop().RunUntilIdle();
+
   ipc->CloseStream();
   base::RunLoop().RunUntilIdle();
 }
@@ -589,12 +586,6 @@
   StrictMock<MockStream> stream;
   StrictMock<MockDelegate> delegate;
 
-  EXPECT_CALL(delegate, OnDeviceAuthorized(
-                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
-                            _, std::string(kReturnedDeviceId)));
-  EXPECT_CALL(delegate, GotOnStreamCreated());
-  EXPECT_CALL(stream, SetVolume(kNewVolume));
-
   const std::unique_ptr<media::AudioOutputIPC> ipc =
       std::make_unique<MojoAudioOutputIPC>(
           stream_factory.GetAccessor(),
@@ -604,9 +595,15 @@
 
   ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId);
   ipc->CreateStream(&delegate, Params());
-  base::RunLoop().RunUntilIdle();
   ipc->SetVolume(kNewVolume);
+
+  EXPECT_CALL(delegate, OnDeviceAuthorized(
+                            media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK,
+                            _, std::string(kReturnedDeviceId)));
+  EXPECT_CALL(delegate, GotOnStreamCreated());
+  EXPECT_CALL(stream, SetVolume(kNewVolume));
   base::RunLoop().RunUntilIdle();
+
   ipc->CloseStream();
   base::RunLoop().RunUntilIdle();
 }
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index 3c02df5f..493c7c4 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -1125,31 +1125,4 @@
       {{GURL(kTestFirstURL), kFrameEventDidCommitSameDocumentLoad}});
 }
 
-// Verify that a RenderFrameProxy correctly handles autoresize.
-TEST_F(RenderFrameImplTest, ProxyAutoresize) {
-  auto* proxy = RenderFrameProxy::FromRoutingID(kFrameProxyRouteId);
-
-  // Send a ViewChanged message to initialize our proxy with a frame sink.
-  FrameMsg_ViewChanged_Params view_changed_params;
-  view_changed_params.frame_sink_id = viz::FrameSinkId(20, 21);
-  FrameMsg_ViewChanged view_changed(kFrameProxyRouteId, view_changed_params);
-  proxy->OnMessageReceived(view_changed);
-  render_thread_->sink().ClearMessages();
-
-  // Send a simulated sequence of messages representing an auto-resize
-  // transaction.
-  FrameMsg_BeginResizeDueToAutoResize begin_msg(kFrameProxyRouteId);
-  proxy->OnMessageReceived(begin_msg);
-  proxy->FrameRectsChanged(blink::WebRect(0, 0, 300, 300),
-                           blink::WebRect(0, 0, 300, 300));
-  FrameMsg_EndResizeDueToAutoResize end_msg(kFrameProxyRouteId, 7);
-  proxy->OnMessageReceived(end_msg);
-
-  // We should have exactly one UpdateResizeParams message.
-  const IPC::Message* msg1 = render_thread_->sink().GetUniqueMessageMatching(
-      FrameHostMsg_UpdateResizeParams::ID);
-  EXPECT_TRUE(msg1);
-  render_thread_->sink().ClearMessages();
-}
-
 }  // namespace content
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 5d56039..6fbdc4fd 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -258,7 +258,7 @@
 void RenderFrameProxy::ResendResizeParams() {
   // Reset |sent_resize_params_| in order to allocate a new viz::LocalSurfaceId.
   sent_resize_params_ = base::nullopt;
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
 }
 
 void RenderFrameProxy::WillBeginCompositorFrame() {
@@ -280,7 +280,13 @@
                                         screen_info.device_scale_factor);
     return;
   }
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
+}
+
+void RenderFrameProxy::UpdateCaptureSequenceNumber(
+    uint32_t capture_sequence_number) {
+  pending_resize_params_.capture_sequence_number = capture_sequence_number;
+  WasResized(viz::LocalSurfaceId());
 }
 
 void RenderFrameProxy::SetReplicatedState(const FrameReplicationState& state) {
@@ -417,10 +423,7 @@
                         OnSetFrameOwnerProperties)
     IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateOrigin, OnDidUpdateOrigin)
     IPC_MESSAGE_HANDLER(InputMsg_SetFocus, OnSetPageFocus)
-    IPC_MESSAGE_HANDLER(FrameMsg_BeginResizeDueToAutoResize,
-                        OnBeginResizeDueToAutoResize)
-    IPC_MESSAGE_HANDLER(FrameMsg_EndResizeDueToAutoResize,
-                        OnEndResizeDueToAutoResize)
+    IPC_MESSAGE_HANDLER(FrameMsg_ResizeDueToAutoResize, OnResizeDueToAutoResize)
     IPC_MESSAGE_HANDLER(FrameMsg_EnableAutoResize, OnEnableAutoResize)
     IPC_MESSAGE_HANDLER(FrameMsg_DisableAutoResize, OnDisableAutoResize)
     IPC_MESSAGE_HANDLER(FrameMsg_SetFocusedFrame, OnSetFocusedFrame)
@@ -567,16 +570,11 @@
   web_frame_->ScrollRectToVisible(rect_to_scroll, params);
 }
 
-void RenderFrameProxy::OnBeginResizeDueToAutoResize() {
-  DCHECK(!transaction_pending_);
-  transaction_pending_ = true;
-}
-
-void RenderFrameProxy::OnEndResizeDueToAutoResize(uint64_t sequence_number) {
-  DCHECK(transaction_pending_);
-  transaction_pending_ = false;
+void RenderFrameProxy::OnResizeDueToAutoResize(
+    uint64_t sequence_number,
+    viz::LocalSurfaceId child_allocated_surface_id) {
   pending_resize_params_.auto_resize_sequence_number = sequence_number;
-  WasResized();
+  WasResized(child_allocated_surface_id);
 }
 
 void RenderFrameProxy::OnEnableAutoResize(const gfx::Size& min_size,
@@ -584,12 +582,12 @@
   pending_resize_params_.auto_resize_enabled = true;
   pending_resize_params_.min_size_for_auto_resize = min_size;
   pending_resize_params_.max_size_for_auto_resize = max_size;
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
 }
 
 void RenderFrameProxy::OnDisableAutoResize() {
   pending_resize_params_.auto_resize_enabled = false;
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
 }
 
 #if defined(USE_AURA)
@@ -599,10 +597,41 @@
 }
 #endif
 
-void RenderFrameProxy::WasResized() {
-  if (!frame_sink_id_.is_valid() || crashed_ || transaction_pending_)
+void RenderFrameProxy::WasResized(
+    const viz::LocalSurfaceId& child_allocated_surface_id) {
+  if (!frame_sink_id_.is_valid() || crashed_)
     return;
 
+  // Note that the following flag is true if the capture sequence number
+  // actually changed. That is, it is false if we did not have
+  // |sent_resize_params_|, which is different from
+  // |synchronized_params_changed| below.
+  bool capture_sequence_number_changed =
+      sent_resize_params_ && sent_resize_params_->capture_sequence_number !=
+                                 pending_resize_params_.capture_sequence_number;
+
+  // TODO(ericrk): Once we short-circuit responses to child allocated surface
+  // IDs, we can remove |surface_id_changed| here and simply update.
+  // https://crbug.com/811944
+  bool surface_id_changed = false;
+  if (child_allocated_surface_id.is_valid()) {
+    viz::LocalSurfaceId previous_id = local_surface_id_;
+    local_surface_id_ = parent_local_surface_id_allocator_.UpdateFromChild(
+        child_allocated_surface_id);
+    surface_id_changed = previous_id != local_surface_id_;
+  }
+
+  // We no longer use auto resize sequence numbers to trigger ID generation,
+  // instead getting auto resize IDs from the child. If our auto-resize
+  // sequence number changed our surface ID must change as well.
+  // TODO(ericrk): Once we short-circuit, we can remove references to sequence
+  // numbers and clean this up. https://crbug.com/811944.
+  if (sent_resize_params_ &&
+      sent_resize_params_->auto_resize_sequence_number !=
+          pending_resize_params_.auto_resize_sequence_number) {
+    DCHECK(surface_id_changed);
+  }
+
   bool synchronized_params_changed =
       !sent_resize_params_ ||
       sent_resize_params_->auto_resize_enabled !=
@@ -616,25 +645,28 @@
       sent_resize_params_->screen_space_rect.size() !=
           pending_resize_params_.screen_space_rect.size() ||
       sent_resize_params_->screen_info != pending_resize_params_.screen_info ||
-      sent_resize_params_->auto_resize_sequence_number !=
-          pending_resize_params_.auto_resize_sequence_number;
+      capture_sequence_number_changed;
 
   if (synchronized_params_changed)
     local_surface_id_ = parent_local_surface_id_allocator_.GenerateId();
 
   viz::SurfaceId surface_id(frame_sink_id_, local_surface_id_);
   if (enable_surface_synchronization_) {
-    // TODO(vmpstr): When capture_sequence_number is available, the deadline
-    // should be infinite if the sequence number has changed.
-    compositing_helper_->SetPrimarySurfaceId(
-        surface_id, local_frame_size(),
-        cc::DeadlinePolicy::UseDefaultDeadline());
+    // If we're synchronizing surfaces, then use an infinite deadline to ensure
+    // everything is synchronized.
+    cc::DeadlinePolicy deadline =
+        capture_sequence_number_changed
+            ? cc::DeadlinePolicy::UseInfiniteDeadline()
+            : cc::DeadlinePolicy::UseDefaultDeadline();
+    compositing_helper_->SetPrimarySurfaceId(surface_id, local_frame_size(),
+                                             deadline);
   }
 
   bool rect_changed =
       !sent_resize_params_ || sent_resize_params_->screen_space_rect !=
                                   pending_resize_params_.screen_space_rect;
-  bool resize_params_changed = synchronized_params_changed || rect_changed;
+  bool resize_params_changed =
+      synchronized_params_changed || rect_changed || surface_id_changed;
 
 #if defined(USE_AURA)
   if (rect_changed && mus_embedded_frame_) {
@@ -773,7 +805,7 @@
                                         screen_info().device_scale_factor);
     return;
   }
-  WasResized();
+  WasResized(viz::LocalSurfaceId());
 }
 
 void RenderFrameProxy::UpdateRemoteViewportIntersection(
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 99795ac..47a4faf1 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -134,6 +134,10 @@
   // ScreenInfo has changed.
   void OnScreenInfoChanged(const ScreenInfo& screen_info);
 
+  // Invoked by RenderWidget when a new capture sequence number was set,
+  // indicating that surfaces should be synchronized.
+  void UpdateCaptureSequenceNumber(uint32_t capture_sequence_number);
+
   // Pass replicated information, such as security origin, to this
   // RenderFrameProxy's WebRemoteFrame.
   void SetReplicatedState(const FrameReplicationState& state);
@@ -157,7 +161,7 @@
       std::unique_ptr<MusEmbeddedFrame> mus_embedded_frame);
 #endif
 
-  void WasResized();
+  void WasResized(const viz::LocalSurfaceId& child_allocated_surface_id);
 
   const gfx::Rect& screen_space_rect() const {
     return pending_resize_params_.screen_space_rect;
@@ -250,8 +254,8 @@
   void OnSetHasReceivedUserGesture();
   void OnScrollRectToVisible(const gfx::Rect& rect_to_scroll,
                              const blink::WebScrollIntoViewParams& params);
-  void OnBeginResizeDueToAutoResize();
-  void OnEndResizeDueToAutoResize(uint64_t sequence_number);
+  void OnResizeDueToAutoResize(uint64_t sequence_number,
+                               viz::LocalSurfaceId child_allocated_surface_id);
   void OnEnableAutoResize(const gfx::Size& min_size, const gfx::Size& max_size);
   void OnDisableAutoResize();
   void OnSetHasReceivedUserGestureBeforeNavigation(bool value);
@@ -301,11 +305,6 @@
   // |sent_resize_params_|.
   FrameResizeParams pending_resize_params_;
 
-  // Whether we are in the middle of a transaction which modifies
-  // |pending_resize_params_|. If so, we delay allocating a new LocalSurfaceId
-  // until the transaction completes.
-  bool transaction_pending_ = false;
-
   bool crashed_ = false;
 
   viz::FrameSinkId frame_sink_id_;
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 724673f..647b3375 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -447,6 +447,7 @@
     params.visible_viewport_size = params.new_size;
     params.auto_resize_enabled = view()->auto_resize_mode();
     params.auto_resize_sequence_number = view()->auto_resize_sequence_number();
+    params.capture_sequence_number = view()->capture_sequence_number();
     params.min_size_for_auto_resize = view()->min_size_for_auto_resize();
     params.max_size_for_auto_resize = view()->max_size_for_auto_resize();
     params.needs_resize_ack = false;
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 6b72983..23d78a6 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -1296,6 +1296,7 @@
   UpdateSurfaceAndScreenInfo(new_local_surface_id,
                              new_compositor_viewport_pixel_size,
                              params.screen_info);
+  UpdateCaptureSequenceNumber(params.capture_sequence_number);
   if (compositor_) {
     // If surface synchronization is enabled, then this will use the provided
     // |local_surface_id_| to submit the next generated CompositorFrame.
@@ -1854,6 +1855,19 @@
     UpdateWebViewWithDeviceScaleFactor();
 }
 
+void RenderWidget::UpdateCaptureSequenceNumber(
+    uint32_t capture_sequence_number) {
+  if (capture_sequence_number == last_capture_sequence_number_)
+    return;
+  last_capture_sequence_number_ = capture_sequence_number;
+
+  // Notify observers of the new capture sequence number.
+  for (auto& observer : render_frame_proxies_)
+    observer.UpdateCaptureSequenceNumber(capture_sequence_number);
+  for (auto& observer : browser_plugins_)
+    observer.UpdateCaptureSequenceNumber(capture_sequence_number);
+}
+
 void RenderWidget::OnRepaint(gfx::Size size_to_paint) {
   // During shutdown we can just ignore this message.
   if (!GetWebWidget())
@@ -2269,7 +2283,7 @@
     gfx::Size new_compositor_viewport_pixel_size =
         gfx::ScaleToCeiledSize(size_, GetWebScreenInfo().device_scale_factor);
     viz::LocalSurfaceId local_surface_id;
-    if (!compositor_viewport_pixel_size_.IsEmpty())
+    if (!new_compositor_viewport_pixel_size.IsEmpty())
       local_surface_id = child_local_surface_id_allocator_.GenerateId();
     UpdateSurfaceAndScreenInfo(
         local_surface_id, new_compositor_viewport_pixel_size, screen_info_);
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index ab70a7b7..25beb801 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -429,6 +429,11 @@
   const gfx::Size& max_size_for_auto_resize() const {
     return max_size_for_auto_resize_;
   }
+
+  uint32_t capture_sequence_number() const {
+    return last_capture_sequence_number_;
+  }
+
   // MainThreadEventQueueClient overrides.
 
   // Requests a BeginMainFrame callback from the compositor.
@@ -900,6 +905,8 @@
       const gfx::Size& new_compositor_viewport_pixel_size,
       const ScreenInfo& new_screen_info);
 
+  void UpdateCaptureSequenceNumber(uint32_t capture_sequence_number);
+
   // A variant of Send but is fatal if it fails. The browser may
   // be waiting for this IPC Message and if the send fails the browser will
   // be left in a state waiting for something that never comes. And if it
@@ -992,11 +999,12 @@
   gfx::Rect viewport_intersection_;
   gfx::Rect compositor_visible_rect_;
 
-  // Cache whether or not we have touch handlers, to reduce IPCs sent.
   // Different consumers in the browser process makes different assumptions, so
   // must always send the first IPC regardless of value.
   base::Optional<bool> has_touch_handlers_;
 
+  uint32_t last_capture_sequence_number_ = 0u;
+
   base::WeakPtrFactory<RenderWidget> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderWidget);
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index 04eb7e6..b86b30b 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -517,6 +517,18 @@
     EXPECT_TRUE(local_surface_id2.has_value());
   }
 
+  // Our first child allocated LSI should match |fake_parent_local_surface_id|
+  // with an incremented child sequence number.
+  EXPECT_NE(fake_parent_local_surface_id, local_surface_id1);
+  EXPECT_EQ(fake_parent_local_surface_id.parent_sequence_number(),
+            local_surface_id1->parent_sequence_number());
+  EXPECT_EQ(fake_parent_local_surface_id.child_sequence_number() + 1,
+            local_surface_id1->child_sequence_number());
+  EXPECT_EQ(fake_parent_local_surface_id.embed_token(),
+            local_surface_id2->embed_token());
+
+  // Our second child allocated LSI should match the first with an incremented
+  // child sequence number.
   EXPECT_NE(local_surface_id1, local_surface_id2);
   EXPECT_EQ(local_surface_id1->parent_sequence_number(),
             local_surface_id2->parent_sequence_number());
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
index e6aefb32..aec857e 100644
--- a/content/test/content_browser_test_utils_internal.cc
+++ b/content/test/content_browser_test_utils_internal.cc
@@ -365,114 +365,6 @@
   }
 }
 
-UpdateResizeParamsMessageFilter::UpdateResizeParamsMessageFilter()
-    : content::BrowserMessageFilter(FrameMsgStart),
-      screen_space_rect_run_loop_(std::make_unique<base::RunLoop>()),
-      screen_space_rect_received_(false) {}
-
-void UpdateResizeParamsMessageFilter::WaitForRect() {
-  screen_space_rect_run_loop_->Run();
-}
-
-void UpdateResizeParamsMessageFilter::ResetRectRunLoop() {
-  last_rect_ = gfx::Rect();
-  screen_space_rect_run_loop_.reset(new base::RunLoop);
-  screen_space_rect_received_ = false;
-}
-
-viz::FrameSinkId UpdateResizeParamsMessageFilter::GetOrWaitForId() {
-  // No-op if already quit.
-  frame_sink_id_run_loop_.Run();
-  return frame_sink_id_;
-}
-
-uint64_t UpdateResizeParamsMessageFilter::WaitForSequenceNumber() {
-  sequence_number_run_loop_.reset(new base::RunLoop);
-  sequence_number_run_loop_->Run();
-  return last_sequence_number_;
-}
-
-UpdateResizeParamsMessageFilter::~UpdateResizeParamsMessageFilter() {}
-
-void UpdateResizeParamsMessageFilter::OnUpdateResizeParams(
-    const viz::SurfaceId& surface_id,
-    const FrameResizeParams& resize_params) {
-  gfx::Rect screen_space_rect_in_dip = resize_params.screen_space_rect;
-  if (IsUseZoomForDSFEnabled()) {
-    screen_space_rect_in_dip =
-        gfx::Rect(gfx::ScaleToFlooredPoint(
-                      resize_params.screen_space_rect.origin(),
-                      1.f / resize_params.screen_info.device_scale_factor),
-                  gfx::ScaleToCeiledSize(
-                      resize_params.screen_space_rect.size(),
-                      1.f / resize_params.screen_info.device_scale_factor));
-  }
-  // Track each rect updates.
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&UpdateResizeParamsMessageFilter::OnUpdatedFrameRectOnUI,
-                     this, screen_space_rect_in_dip));
-
-  // Track each sequence number update.
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::BindOnce(
-          &UpdateResizeParamsMessageFilter::OnUpdatedSequenceNumberOnUI, this,
-          resize_params.auto_resize_sequence_number));
-
-  // Record the received value. We cannot check the current state of the child
-  // frame, as it can only be processed on the UI thread, and we cannot block
-  // here.
-  frame_sink_id_ = surface_id.frame_sink_id();
-
-  // There can be several updates before a valid viz::FrameSinkId is ready. Do
-  // not quit |run_loop_| until after we receive a valid one.
-  if (!frame_sink_id_.is_valid())
-    return;
-
-  // We can't nest on the IO thread. So tests will wait on the UI thread, so
-  // post there to exit the nesting.
-  content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
-      ->PostTask(FROM_HERE,
-                 base::BindOnce(
-                     &UpdateResizeParamsMessageFilter::OnUpdatedFrameSinkIdOnUI,
-                     this));
-}
-
-void UpdateResizeParamsMessageFilter::OnUpdatedFrameRectOnUI(
-    const gfx::Rect& rect) {
-  last_rect_ = rect;
-  if (!screen_space_rect_received_) {
-    screen_space_rect_received_ = true;
-    // Tests looking at the rect currently expect all received input to finish
-    // processing before the test continutes.
-    screen_space_rect_run_loop_->QuitWhenIdle();
-  }
-}
-
-void UpdateResizeParamsMessageFilter::OnUpdatedFrameSinkIdOnUI() {
-  frame_sink_id_run_loop_.Quit();
-}
-
-void UpdateResizeParamsMessageFilter::OnUpdatedSequenceNumberOnUI(
-    uint64_t sequence_number) {
-  last_sequence_number_ = sequence_number;
-  if (sequence_number_run_loop_) {
-    sequence_number_run_loop_->QuitWhenIdle();
-  }
-}
-
-bool UpdateResizeParamsMessageFilter::OnMessageReceived(
-    const IPC::Message& message) {
-  IPC_BEGIN_MESSAGE_MAP(UpdateResizeParamsMessageFilter, message)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateResizeParams, OnUpdateResizeParams)
-  IPC_END_MESSAGE_MAP()
-
-  // We do not consume the message, so that we can verify the effects of it
-  // being processed.
-  return false;
-}
-
 RenderProcessHostKillWaiter::RenderProcessHostKillWaiter(
     RenderProcessHost* render_process_host)
     : exit_watcher_(render_process_host,
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
index 70f1dc3..b1505ecd 100644
--- a/content/test/content_browser_test_utils_internal.h
+++ b/content/test/content_browser_test_utils_internal.h
@@ -35,7 +35,6 @@
 class Shell;
 class SiteInstance;
 class ToRenderFrameHost;
-struct FrameResizeParams;
 
 // Navigates the frame represented by |node| to |url|, blocking until the
 // navigation finishes.
@@ -191,52 +190,6 @@
   DISALLOW_COPY_AND_ASSIGN(UrlCommitObserver);
 };
 
-// Class to sniff incoming IPCs for FrameHostMsg_UpdateResizeParams messages.
-// This allows the message to continue to the target child so that processing
-// can be verified by tests.
-class UpdateResizeParamsMessageFilter : public content::BrowserMessageFilter {
- public:
-  UpdateResizeParamsMessageFilter();
-
-  gfx::Rect last_rect() const { return last_rect_; }
-
-  void WaitForRect();
-  void ResetRectRunLoop();
-
-  // Returns the new viz::FrameSinkId immediately if the IPC has been received.
-  // Otherwise this will block the UI thread until it has been received, then it
-  // will return the new viz::FrameSinkId.
-  viz::FrameSinkId GetOrWaitForId();
-
-  // Waits for the next sequence number to be received and returns it.
-  uint64_t WaitForSequenceNumber();
-
- protected:
-  ~UpdateResizeParamsMessageFilter() override;
-
- private:
-  void OnUpdateResizeParams(const viz::SurfaceId& surface_id,
-                            const FrameResizeParams& resize_params);
-  // |rect| is in DIPs.
-  void OnUpdatedFrameRectOnUI(const gfx::Rect& rect);
-  void OnUpdatedFrameSinkIdOnUI();
-  void OnUpdatedSequenceNumberOnUI(uint64_t sequence_number);
-
-  bool OnMessageReceived(const IPC::Message& message) override;
-
-  viz::FrameSinkId frame_sink_id_;
-  base::RunLoop frame_sink_id_run_loop_;
-
-  std::unique_ptr<base::RunLoop> screen_space_rect_run_loop_;
-  bool screen_space_rect_received_;
-  gfx::Rect last_rect_;
-
-  uint64_t last_sequence_number_ = 0;
-  std::unique_ptr<base::RunLoop> sequence_number_run_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(UpdateResizeParamsMessageFilter);
-};
-
 // Waits for a kill of the given RenderProcessHost and returns the
 // BadMessageReason that caused a //content-triggerred kill.
 //
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index b0a00a0..e114e3a 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -1257,47 +1257,45 @@
     ],
   },
 
-  # Temporarily disabled while we roll Vulkan.
-  # TODO(jmadill): Re-enable after roll. http://anglebug.com/2393
-  # 'angle_deqp_gles2_vulkan_tests': {
-  #   'tester_configs': [
-  #     {
-  #       'predicate': Predicates.DEQP,
-  #       'swarming_dimension_sets': [
-  #         # NVIDIA Win 10
-  #         {
-  #           'gpu': NVIDIA_QUADRO_P400_ALL_DRIVERS,
-  #           'os': WIN10_NVIDIA_QUADRO_P400_STABLE_OS,
-  #         },
-  #         # AMD Win 7
-  #         {
-  #           'gpu': '1002:6613',
-  #           'os': 'Windows-2008ServerR2-SP1'
-  #         },
-  #         # NVIDIA Linux Quadro P400
-  #         {
-  #           'gpu': LINUX_QUADRO_P400_STABLE_DRIVER,
-  #           'os': 'Ubuntu'
-  #         },
-  #       ],
-  #     },
-  #   ],
-  #   'disabled_tester_configs': [
-  #     {
-  #       'names': [
-  #         'Linux FYI Ozone (Intel)',
-  #       ],
-  #     },
-  #   ],
-  #   'desktop_swarming': {
-  #     'shards': 4,
-  #   },
-  #   'test': 'angle_deqp_gles2_tests',
-  #   'args': [
-  #     '--test-launcher-batch-limit=400',
-  #     '--deqp-egl-display-type=angle-vulkan'
-  #   ]
-  # },
+  'angle_deqp_gles2_vulkan_tests': {
+    'tester_configs': [
+      {
+        'predicate': Predicates.DEQP,
+        'swarming_dimension_sets': [
+          # NVIDIA Win 10
+          {
+            'gpu': NVIDIA_QUADRO_P400_ALL_DRIVERS,
+            'os': WIN10_NVIDIA_QUADRO_P400_STABLE_OS,
+          },
+          # AMD Win 7
+          {
+            'gpu': '1002:6613',
+            'os': 'Windows-2008ServerR2-SP1'
+          },
+          # NVIDIA Linux Quadro P400
+          {
+            'gpu': LINUX_QUADRO_P400_STABLE_DRIVER,
+            'os': 'Ubuntu'
+          },
+        ],
+      },
+    ],
+    'disabled_tester_configs': [
+      {
+        'names': [
+          'Linux FYI Ozone (Intel)',
+        ],
+      },
+    ],
+    'desktop_swarming': {
+      'shards': 4,
+    },
+    'test': 'angle_deqp_gles2_tests',
+    'args': [
+      '--test-launcher-batch-limit=400',
+      '--deqp-egl-display-type=angle-vulkan'
+    ]
+  },
 
   'angle_deqp_gles3_gles_tests': {
     'tester_configs': [
diff --git a/content/test/gpu/gpu_tests/context_lost_expectations.py b/content/test/gpu/gpu_tests/context_lost_expectations.py
index 25b7599a..1b201a5a 100644
--- a/content/test/gpu/gpu_tests/context_lost_expectations.py
+++ b/content/test/gpu/gpu_tests/context_lost_expectations.py
@@ -53,10 +53,3 @@
               ['android', ('qualcomm', 'Adreno (TM) 420')], bug=611906)
     self.Fail('ContextLost_WebGLContextLostFromQuantity',
               ['android', ('qualcomm', 'Adreno (TM) 420')], bug=611906)
-
-    # Nexus 9 and Nvidia Shield TV
-    self.Fail('ContextLost_WebGLBlockedAfterJSNavigation',
-              ['android', 'nvidia'], bug=832886)
-    self.Fail('ContextLost_WebGLUnblockedAfterUserInitiatedReload',
-              ['android', 'nvidia'], bug=832886)
-
diff --git a/content/test/gpu/gpu_tests/context_lost_integration_test.py b/content/test/gpu/gpu_tests/context_lost_integration_test.py
index ff083ce..2804c58 100644
--- a/content/test/gpu/gpu_tests/context_lost_integration_test.py
+++ b/content/test/gpu/gpu_tests/context_lost_integration_test.py
@@ -298,7 +298,11 @@
         self.fail(
           'Page should have been blocked from getting a new WebGL context')
     finally:
-      gpucrash_tab.Close()
+      # This try/except is still needed. crbug.com/832886
+      try:
+        gpucrash_tab.Close()
+      except Exception:
+        print 'Tab crashed while closing chrome://gpucrash'
 
   def _ContextLost_WebGLUnblockedAfterUserInitiatedReload(self, test_path):
     self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([]))
@@ -334,7 +338,11 @@
         self.fail(
           'WebGL should have been unblocked after a user-initiated navigation')
     finally:
-      gpucrash_tab.Close()
+      # This try/except is still needed. crbug.com/832886
+      try:
+        gpucrash_tab.Close()
+      except Exception:
+        print 'Tab crashed while closing chrome://gpucrash'
 
 def load_tests(loader, tests, pattern):
   del loader, tests, pattern  # Unused.
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
index 3360d4fd..d1550ca 100644
--- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -79,6 +79,7 @@
              ('GpuProcess_gpu_info_complete', 'gpu/functional_3d_css.html'),
              ('GpuProcess_driver_bug_workarounds_in_gpu_process', 'chrome:gpu'),
              ('GpuProcess_readback_webgl_gpu_process', 'chrome:gpu'),
+             ('GpuProcess_feature_status_under_swiftshader', 'chrome:gpu'),
              ('GpuProcess_only_one_workaround', 'chrome:gpu'),
              ('GpuProcess_disable_gpu', 'gpu/functional_webgl.html'),
              ('GpuProcess_disable_gpu_and_swiftshader',
@@ -186,7 +187,7 @@
                 'workarounds are not equal: %s != %s, diff: %s' %
                 (browser_list, gpu_list, list(diff)))
 
-    basic_infos = tab.EvaluateJavaScript('browserBridge.gpuInfo.basic_info')
+    basic_infos = tab.EvaluateJavaScript('browserBridge.gpuInfo.basicInfo')
     disabled_gl_extensions = None
     for info in basic_infos:
       if info['description'].startswith('Disabled Extensions'):
@@ -262,6 +263,40 @@
     if not result:
       self.fail('WebGL readback setup failed: %s' % feature_status_list)
 
+  def _GpuProcess_feature_status_under_swiftshader(self, test_path):
+    if not self._SupportsSwiftShader():
+      return
+    # Hit test group 2 with entry 153 from kSoftwareRenderingListEntries.
+    self.RestartBrowserIfNecessaryWithArgs([
+      '--gpu-blacklist-test-group=2'])
+    self._Navigate(test_path)
+    feature_status_list = self.tab.EvaluateJavaScript(
+        'browserBridge.gpuInfo.featureStatus.featureStatus')
+    for name, status in feature_status_list.items():
+      if name == 'webgl':
+        if status != 'unavailable_software':
+          self.fail('WebGL status for SwiftShader failed: %s' % status)
+          return
+      elif name == '2d_canvas':
+        if status != 'unavailable_software':
+          self.fail('2D Canvas status for SwiftShader failed: %s' % status)
+          return
+      else:
+        pass
+    feature_status_for_hardware_gpu_list = self.tab.EvaluateJavaScript(
+        'browserBridge.gpuInfo.featureStatusForHardwareGpu.featureStatus')
+    for name, status in feature_status_for_hardware_gpu_list.items():
+      if name == 'webgl':
+        if status != 'unavailable_off':
+          self.fail('WebGL status for hardware GPU failed: %s' % status)
+          return
+      elif name == '2d_canvas':
+        if status != 'enabled':
+          self.fail('2D Canvas status for hardware GPU failed: %s' % status)
+          return
+      else:
+        pass
+
   def _GpuProcess_only_one_workaround(self, test_path):
     # Start this test by launching the browser with no command line
     # arguments.
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index 5d9711c9..14f6872d 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -93,15 +93,9 @@
     self.Fail('Pixel_WebGL_PremultipliedAlpha_False',
               ['android', 'nvidia'], bug=791733)
 
-    self.Flaky('Pixel_WebGLTransparentGreenTriangle_NoAlpha_ImplicitClear',
-        ['mac', 'intel'], bug=832900)
-
     # TODO(zmo): temporarily suppress these two tests until new
     # reference images with new names are generated.
     self.Fail('Pixel_Canvas2DRedBox_NoGpuProcess',
               ['linux', 'mac', 'win'], bug=744658)
     self.Fail('Pixel_CSS3DBlueBox_NoGpuProcess',
               ['linux', 'mac', 'win'], bug=744658)
-
-    # TODO(kbr): temporary suppression for new test.
-    self.Fail('Pixel_WebGLSadCanvas', bug=575305)
diff --git a/content/test/gpu/gpu_tests/pixel_integration_test.py b/content/test/gpu/gpu_tests/pixel_integration_test.py
index 11f06e5..cffd126 100644
--- a/content/test/gpu/gpu_tests/pixel_integration_test.py
+++ b/content/test/gpu/gpu_tests/pixel_integration_test.py
@@ -130,67 +130,75 @@
     tab.Navigate(url, script_to_evaluate_on_commit=test_harness_script)
     tab.action_runner.WaitForJavaScriptCondition(
       'domAutomationController._proceed', timeout=300)
-    if tab.EvaluateJavaScript('domAutomationController._readyForActions'):
+    do_page_action = tab.EvaluateJavaScript(
+      'domAutomationController._readyForActions')
+    if do_page_action:
       self._DoPageAction(tab, page)
-    if not tab.EvaluateJavaScript('domAutomationController._succeeded'):
-      self.fail('page indicated test failure')
-    if not tab.screenshot_supported:
-      self.fail('Browser does not support screenshot capture')
-    screenshot = tab.Screenshot(5)
-    if screenshot is None:
-      self.fail('Could not capture screenshot')
-    dpr = tab.EvaluateJavaScript('window.devicePixelRatio')
-    if page.test_rect:
-      screenshot = image_util.Crop(
-          screenshot, int(page.test_rect[0] * dpr),
-          int(page.test_rect[1] * dpr), int(page.test_rect[2] * dpr),
-          int(page.test_rect[3] * dpr))
-    if page.expected_colors:
-      # Use expected colors instead of ref images for validation.
-      self._ValidateScreenshotSamples(
-          tab, page.name, screenshot, page.expected_colors, dpr)
-      return
-    image_name = self._UrlToImageName(page.name)
-    if self.GetParsedCommandLineOptions().upload_refimg_to_cloud_storage:
-      if self._ConditionallyUploadToCloudStorage(image_name, page, tab,
-                                                 screenshot):
-        # This is the new reference image; there's nothing to compare against.
-        ref_png = screenshot
+    try:
+      if not tab.EvaluateJavaScript('domAutomationController._succeeded'):
+        self.fail('page indicated test failure')
+      if not tab.screenshot_supported:
+        self.fail('Browser does not support screenshot capture')
+      screenshot = tab.Screenshot(5)
+      if screenshot is None:
+        self.fail('Could not capture screenshot')
+      dpr = tab.EvaluateJavaScript('window.devicePixelRatio')
+      if page.test_rect:
+        screenshot = image_util.Crop(
+            screenshot, int(page.test_rect[0] * dpr),
+            int(page.test_rect[1] * dpr), int(page.test_rect[2] * dpr),
+            int(page.test_rect[3] * dpr))
+      if page.expected_colors:
+        # Use expected colors instead of ref images for validation.
+        self._ValidateScreenshotSamples(
+            tab, page.name, screenshot, page.expected_colors, dpr)
+        return
+      image_name = self._UrlToImageName(page.name)
+      if self.GetParsedCommandLineOptions().upload_refimg_to_cloud_storage:
+        if self._ConditionallyUploadToCloudStorage(image_name, page, tab,
+                                                   screenshot):
+          # This is the new reference image; there's nothing to compare against.
+          ref_png = screenshot
+        else:
+          # There was a preexisting reference image, so we might as well
+          # compare against it.
+          ref_png = self._DownloadFromCloudStorage(image_name, page, tab)
+      elif self.GetParsedCommandLineOptions().\
+          download_refimg_from_cloud_storage:
+        # This bot doesn't have the ability to properly generate a
+        # reference image, so download it from cloud storage.
+        try:
+          ref_png = self._DownloadFromCloudStorage(image_name, page, tab)
+        except cloud_storage.NotFoundError:
+          # There is no reference image yet in cloud storage. This
+          # happens when the revision of the test is incremented or when
+          # a new test is added, because the trybots are not allowed to
+          # produce reference images, only the bots on the main
+          # waterfalls. Report this as a failure so the developer has to
+          # take action by explicitly suppressing the failure and
+          # removing the suppression once the reference images have been
+          # generated. Otherwise silent failures could happen for long
+          # periods of time.
+          self.fail('Could not find image %s in cloud storage' % image_name)
       else:
-        # There was a preexisting reference image, so we might as well
-        # compare against it.
-        ref_png = self._DownloadFromCloudStorage(image_name, page, tab)
-    elif self.GetParsedCommandLineOptions().download_refimg_from_cloud_storage:
-      # This bot doesn't have the ability to properly generate a
-      # reference image, so download it from cloud storage.
-      try:
-        ref_png = self._DownloadFromCloudStorage(image_name, page, tab)
-      except cloud_storage.NotFoundError:
-        # There is no reference image yet in cloud storage. This
-        # happens when the revision of the test is incremented or when
-        # a new test is added, because the trybots are not allowed to
-        # produce reference images, only the bots on the main
-        # waterfalls. Report this as a failure so the developer has to
-        # take action by explicitly suppressing the failure and
-        # removing the suppression once the reference images have been
-        # generated. Otherwise silent failures could happen for long
-        # periods of time.
-        self.fail('Could not find image %s in cloud storage' % image_name)
-    else:
-      # Legacy path using on-disk results.
-      ref_png = self._GetReferenceImage(
-        self.GetParsedCommandLineOptions().reference_dir,
-        image_name, page.revision, screenshot)
+        # Legacy path using on-disk results.
+        ref_png = self._GetReferenceImage(
+          self.GetParsedCommandLineOptions().reference_dir,
+          image_name, page.revision, screenshot)
 
-    # Test new snapshot against existing reference image
-    if not image_util.AreEqual(ref_png, screenshot, tolerance=page.tolerance):
-      if self.GetParsedCommandLineOptions().test_machine_name:
-        self._UploadErrorImagesToCloudStorage(image_name, screenshot, ref_png)
-      else:
-        self._WriteErrorImages(
-          self.GetParsedCommandLineOptions().generated_dir, image_name,
-          screenshot, ref_png)
-      self.fail('Reference image did not match captured screen')
+      # Test new snapshot against existing reference image
+      if not image_util.AreEqual(ref_png, screenshot, tolerance=page.tolerance):
+        if self.GetParsedCommandLineOptions().test_machine_name:
+          self._UploadErrorImagesToCloudStorage(image_name, screenshot, ref_png)
+        else:
+          self._WriteErrorImages(
+            self.GetParsedCommandLineOptions().generated_dir, image_name,
+            screenshot, ref_png)
+        self.fail('Reference image did not match captured screen')
+    finally:
+      if do_page_action:
+        # Assume that page actions might have killed the GPU process.
+        self._RestartBrowser('Must restart after page actions')
 
   def _DoPageAction(self, tab, page):
     getattr(self, '_' + page.optional_action)(tab, page)
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h
index 038d8883..15a0f0c 100644
--- a/content/test/test_render_view_host.h
+++ b/content/test/test_render_view_host.h
@@ -99,6 +99,7 @@
   void SetNeedsBeginFrames(bool needs_begin_frames) override {}
   void SetWantsAnimateOnlyBeginFrames() override {}
   void TakeFallbackContentFrom(RenderWidgetHostView* view) override;
+  void EnsureSurfaceSynchronizedForLayoutTest() override {}
 
   // RenderWidgetHostViewBase:
   void InitAsPopup(RenderWidgetHostView* parent_host_view,
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 6982c5b..7990f5a 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -137,7 +137,10 @@
 
     # Serial is supported in below platforms. See //device/servial/BUILD.gn
     if (is_win || is_linux || is_mac) {
-      sources += [ "serial/serial_io_handler_posix_unittest.cc" ]
+      sources += [
+        "serial/serial_device_enumerator_unittest.cc",
+        "serial/serial_io_handler_posix_unittest.cc",
+      ]
       deps += [ "//device/serial" ]
     }
   }
diff --git a/device/serial/serial_device_enumerator_unittest.cc b/device/serial/serial_device_enumerator_unittest.cc
new file mode 100644
index 0000000..4f0f55a
--- /dev/null
+++ b/device/serial/serial_device_enumerator_unittest.cc
@@ -0,0 +1,23 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/serial/serial_device_enumerator.h"
+
+#include <memory>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+TEST(SerialDeviceEnumeratorTest, GetDevices) {
+  // There is no guarantee that a test machine will have a serial device
+  // available. The purpose of this test is to ensure that the process of
+  // attempting to enumerate devices does not cause a crash.
+  auto enumerator = SerialDeviceEnumerator::Create();
+  ASSERT_TRUE(enumerator);
+  std::vector<mojom::SerialDeviceInfoPtr> devices = enumerator->GetDevices();
+}
+
+}  // namespace device
diff --git a/docs/README.md b/docs/README.md
index 7aee7c0..3997dff0 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -291,6 +291,9 @@
 *   [VoiceOver](ios/voiceover.md) - Using Apple's VoiceOver feature with
     Chromium on iOS.
 
+### Memory
+*   [Memory Overview](memory/README.md)
+
 ### Memory Infrastructure Timeline Profiling (MemoryInfra)
 *   [Overview](memory-infra/README.md)
 *   [GPU Profiling](memory-infra/probe-gpu.md)
@@ -299,7 +302,6 @@
 *   [Memory Usage in CC](memory-infra/probe-cc.md)
 *   [Memory Benchmarks](memory-infra/memory_benchmarks.md)
 *   [Heap Profiling](memory-infra/heap_profiler.md)
-*   [Heap Profiling Internals](memory-infra/heap_profiler_internals.md)
 
 ### Misc
 *   [Useful URLs](useful_urls.md) - A collection of links to various tools and
diff --git a/docs/memory-infra/README.md b/docs/memory-infra/README.md
index 84593a8..37404df 100644
--- a/docs/memory-infra/README.md
+++ b/docs/memory-infra/README.md
@@ -114,7 +114,6 @@
 
  * [Adding MemoryInfra Tracing to a Component](adding_memory_infra_tracing.md)
  * [GPU Memory Tracing](probe-gpu.md)
- * [Heap Profiler Internals](heap_profiler_internals.md)
  * [Heap Profiling with MemoryInfra](heap_profiler.md)
  * [Startup Tracing with MemoryInfra](memory_infra_startup_tracing.md)
 
diff --git a/docs/memory-infra/heap_profiler_internals.md b/docs/memory-infra/heap_profiler_internals.md
deleted file mode 100644
index d1019c8..0000000
--- a/docs/memory-infra/heap_profiler_internals.md
+++ /dev/null
@@ -1,184 +0,0 @@
-# Heap Profiler Internals
-
-This document describes how the heap profiler works and how to add heap
-profiling support to your allocator. If you just want to know how to use it,
-see [Heap Profiling with MemoryInfra](heap_profiler.md)
-
-[TOC]
-
-## Overview
-
-The heap profiler consists of tree main components:
-
- * **The Context Tracker**: Responsible for providing context (pseudo stack
-   backtrace) when an allocation occurs.
- * **The Allocation Register**: A specialized hash table that stores allocation
-   details by address.
- * **The Heap Dump Writer**: Extracts the most important information from a set
-   of recorded allocations and converts it into a format that can be dumped into
-   the trace log.
-
-These components are designed to work well together, but to be usable
-independently as well.
-
-When there is a way to get notified of all allocations and frees, this is the
-normal flow:
-
- 1. When an allocation occurs, call
-    [`AllocationContextTracker::GetInstanceForCurrentThread()->GetContextSnapshot()`][context-tracker]
-    to get an [`AllocationContext`][alloc-context].
- 2. Insert that context together with the address and size into an
-    [`AllocationRegister`][alloc-register] by calling `Insert()`.
- 3. When memory is freed, remove it from the register with `Remove()`.
- 4. On memory dump, collect the allocations from the register, call
-    [`ExportHeapDump()`][export-heap-dump], and add the generated heap dump to
-    the memory dump.
-
-[context-tracker]:  https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/heap_profiler_allocation_context_tracker.h
-[alloc-context]:    https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/heap_profiler_allocation_context.h
-[alloc-register]:   https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/heap_profiler_allocation_register.h
-[export-heap-dump]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/heap_profiler_heap_dump_writer.h
-
-*** aside
-An allocator can skip step 2 and 3 if it is able to store the context itself,
-and if it is able to enumerate all allocations for step 4.
-***
-
-When heap profiling is enabled (the `--enable-heap-profiling` flag is passed),
-the memory dump manager calls `OnHeapProfilingEnabled()` on every
-`MemoryDumpProvider` as early as possible, so allocators can start recording
-allocations. This should be done even when tracing has not been started,
-because these allocations might still be around when a heap dump happens during
-tracing.
-
-## Context Tracker
-
-The [`AllocationContextTracker`][context-tracker] is a thread-local object. Its
-main purpose is to keep track of a pseudo stack of trace events. Chrome has
-been instrumented with lots of `TRACE_EVENT` macros. These trace events push
-their name to a thread-local stack when they go into scope, and pop when they
-go out of scope, if all of the following conditions have been met:
-
- * A trace is being recorded.
- * The category of the event is enabled in the trace config.
- * Heap profiling is enabled (with the `--enable-heap-profiling` flag).
-
-This means that allocations that occur before tracing is started will not have
-backtrace information in their context.
-
-A thread-local instance of the context tracker is initialized lazily when it is
-first accessed. This might be because a trace event pushed or popped, or because
-`GetContextSnapshot()` was called when an allocation occurred.
-
-[`AllocationContext`][alloc-context] is what is used to group and break down
-allocations. Currently `AllocationContext` has the following fields:
-
- * Backtrace: filled by the context tracker, obtained from the thread-local
-   pseudo stack.
- * Type name: to be filled in at a point where the type of a pointer is known,
-   set to _[unknown]_ by default.
-
-It is possible to modify this context after insertion into the register, for
-instance to set the type name if it was not known at the time of allocation.
-
-## Allocation Register
-
-The [`AllocationRegister`][alloc-register] is a hash table specialized for
-storing `(size, AllocationContext)` pairs by address. It has been optimized for
-Chrome's typical number of unfreed allocations, and it is backed by `mmap`
-memory directly so there are no reentrancy issues when using it to record
-`malloc` allocations.
-
-The allocation register is threading-agnostic. Access must be synchronised
-properly.
-
-## Heap Dump Writer
-
-Dumping every single allocation in the allocation register straight into the
-trace log is not an option due to the sheer volume (~300k unfreed allocations).
-The role of the [`ExportHeapDump()`][export-heap-dump] function is to group
-allocations, striking a balance between trace log size and detail.
-
-See the [Heap Dump Format][heap-dump-format] document for more details about the
-structure of the heap dump in the trace log.
-
-[heap-dump-format]: https://docs.google.com/document/d/1NqBg1MzVnuMsnvV1AKLdKaPSPGpd81NaMPVk5stYanQ
-
-## Instrumenting an Allocator
-
-Below is an example of adding heap profiling support to an allocator that has
-an existing memory dump provider.
-
-```cpp
-class FooDumpProvider : public MemoryDumpProvider {
-
-  // Kept as pointer because |AllocationRegister| allocates a lot of virtual
-  // address space when constructed, so only construct it when heap profiling is
-  // enabled.
-  scoped_ptr<AllocationRegister> allocation_register_;
-  Lock allocation_register_lock_;
-
-  static FooDumpProvider* GetInstance();
-
-  void InsertAllocation(void* address, size_t size) {
-    AllocationContext context = AllocationContextTracker::GetInstanceForCurrentThread()->GetContextSnapshot();
-    AutoLock lock(allocation_register_lock_);
-    allocation_register_->Insert(address, size, context);
-  }
-
-  void RemoveAllocation(void* address) {
-    AutoLock lock(allocation_register_lock_);
-    allocation_register_->Remove(address);
-  }
-
-  // Will be called as early as possible by the memory dump manager.
-  void OnHeapProfilingEnabled(bool enabled) override {
-    AutoLock lock(allocation_register_lock_);
-    allocation_register_.reset(new AllocationRegister());
-
-    // At this point, make sure that from now on, for every allocation and
-    // free, |FooDumpProvider::GetInstance()->InsertAllocation()| and
-    // |RemoveAllocation| are called.
-  }
-
-  bool OnMemoryDump(const MemoryDumpArgs& args,
-                    ProcessMemoryDump& pmd) override {
-    // Do regular dumping here.
-
-    // Dump the heap only for detailed dumps.
-    if (args.level_of_detail == MemoryDumpLevelOfDetail::DETAILED) {
-      TraceEventMemoryOverhead overhead;
-      hash_map<AllocationContext, size_t> bytes_by_context;
-
-      {
-        AutoLock lock(allocation_register_lock_);
-        if (allocation_register_) {
-          // Group allocations in the register into |bytes_by_context|, but do
-          // no additional processing inside the lock.
-          for (const auto& alloc_size : *allocation_register_)
-            bytes_by_context[alloc_size.context] += alloc_size.size;
-
-          allocation_register_->EstimateTraceMemoryOverhead(&overhead);
-        }
-      }
-
-      if (!bytes_by_context.empty()) {
-        scoped_refptr<TracedValue> heap_dump = ExportHeapDump(
-            bytes_by_context,
-            pmd->session_state()->stack_frame_deduplicator(),
-            pmb->session_state()->type_name_deduplicator());
-        pmd->AddHeapDump("foo_allocator", heap_dump);
-        overhead.DumpInto("tracing/heap_profiler", pmd);
-      }
-    }
-
-    return true;
-  }
-};
-
-```
-
-*** aside
-The implementation for `malloc` is more complicated because it needs to deal
-with reentrancy.
-***
diff --git a/extensions/renderer/messaging_util.cc b/extensions/renderer/messaging_util.cc
index cc292b0..3ab9ded 100644
--- a/extensions/renderer/messaging_util.cc
+++ b/extensions/renderer/messaging_util.cc
@@ -183,7 +183,10 @@
 
     if (!v8_frame_id->IsUndefined()) {
       DCHECK(v8_frame_id->IsInt32());
-      options.frame_id = v8_frame_id->Int32Value();
+      int frame_id = v8_frame_id.As<v8::Int32>()->Value();
+      // NOTE(devlin): JS bindings coerce any negative value to -1. For
+      // backwards compatibility, we do the same here.
+      options.frame_id = frame_id < 0 ? -1 : frame_id;
     }
   }
 
diff --git a/extensions/renderer/messaging_util_unittest.cc b/extensions/renderer/messaging_util_unittest.cc
index 89e248bd..80a7ab0 100644
--- a/extensions/renderer/messaging_util_unittest.cc
+++ b/extensions/renderer/messaging_util_unittest.cc
@@ -49,6 +49,37 @@
   }
 }
 
+TEST_F(MessagingUtilTest, TestParseMessageOptionsFrameId) {
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = MainContext();
+
+  struct {
+    int expected_frame_id;
+    const char* string_options;
+  } test_cases[] = {
+      {messaging_util::kNoFrameId, "({})"},
+      {messaging_util::kNoFrameId, "({frameId: undefined})"},
+      // Note: we don't test null here, because the argument parsing code
+      // ensures we would never pass undefined to ParseMessageOptions (and
+      // there's a DCHECK to validate it). The null case is tested in the tabs'
+      // API hooks delegate test.
+      {0, "({frameId: 0})"},
+      {2, "({frameId: 2})"},
+  };
+
+  for (const auto& test_case : test_cases) {
+    SCOPED_TRACE(test_case.string_options);
+    v8::Local<v8::Value> value =
+        V8ValueFromScriptSource(context, test_case.string_options);
+    ASSERT_FALSE(value.IsEmpty());
+    ASSERT_TRUE(value->IsObject());
+    messaging_util::MessageOptions options =
+        messaging_util::ParseMessageOptions(context, value.As<v8::Object>(),
+                                            messaging_util::PARSE_FRAME_ID);
+    EXPECT_EQ(test_case.expected_frame_id, options.frame_id);
+  }
+}
+
 using MessagingUtilWithSystemTest = NativeExtensionBindingsSystemUnittest;
 
 TEST_F(MessagingUtilWithSystemTest, TestGetTargetIdFromExtensionContext) {
diff --git a/gpu/config/gpu_info.cc b/gpu/config/gpu_info.cc
index 29b70f43..0c092cb 100644
--- a/gpu/config/gpu_info.cc
+++ b/gpu/config/gpu_info.cc
@@ -99,6 +99,10 @@
   return gpu;
 }
 
+bool GPUInfo::IsInitialized() const {
+  return gpu.vendor_id != 0 || !gl_vendor.empty();
+}
+
 void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
   struct GPUInfoKnownFields {
     base::TimeDelta initialization_time;
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h
index 3562a7c..8b27e08 100644
--- a/gpu/config/gpu_info.h
+++ b/gpu/config/gpu_info.h
@@ -119,6 +119,8 @@
   // The currently active gpu.
   const GPUDevice& active_gpu() const;
 
+  bool IsInitialized() const;
+
   // The amount of time taken to get from the process starting to the message
   // loop being pumped.
   base::TimeDelta initialization_time;
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index 0d3ce07..16072ae 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -409,14 +409,17 @@
 }
 
 void GpuInit::AdjustInfoToSwiftShader() {
+  gpu_info_for_hardware_gpu_ = gpu_info_;
+  gpu_feature_info_for_hardware_gpu_ = gpu_feature_info_;
   gpu_feature_info_ = ComputeGpuFeatureInfoForSwiftShader();
-  gpu_info_.gl_vendor = "Google Inc. (" + gpu_info_.gl_vendor + ")";
-  gpu_info_.gl_renderer = "Google SwiftShader (" + gpu_info_.gl_renderer + ")";
-  gpu_info_.gl_version =
-      "OpenGL ES 2.0 SwiftShader (" + gpu_info_.gl_version + ")";
+  gpu_info_.gl_vendor = "Google Inc.";
+  gpu_info_.gl_renderer = "Google SwiftShader";
+  gpu_info_.gl_version = "OpenGL ES 2.0 SwiftShader";
 }
 
 void GpuInit::AdjustInfoToNoGpu() {
+  gpu_info_for_hardware_gpu_ = gpu_info_;
+  gpu_feature_info_for_hardware_gpu_ = gpu_feature_info_;
   gpu_feature_info_ = ComputeGpuFeatureInfoWithNoGpu();
   gpu_info_.gl_vendor = "Disabled";
   gpu_info_.gl_renderer = "Disabled";
diff --git a/gpu/ipc/service/gpu_init.h b/gpu/ipc/service/gpu_init.h
index f104b6c..813c0e6 100644
--- a/gpu/ipc/service/gpu_init.h
+++ b/gpu/ipc/service/gpu_init.h
@@ -48,6 +48,12 @@
 
   const GPUInfo& gpu_info() const { return gpu_info_; }
   const GpuFeatureInfo& gpu_feature_info() const { return gpu_feature_info_; }
+  const GPUInfo& gpu_info_for_hardware_gpu() const {
+    return gpu_info_for_hardware_gpu_;
+  }
+  const GpuFeatureInfo& gpu_feature_info_for_hardware_gpu() const {
+    return gpu_feature_info_for_hardware_gpu_;
+  }
   const GpuPreferences& gpu_preferences() const { return gpu_preferences_; }
   std::unique_ptr<GpuWatchdogThread> TakeWatchdogThread() {
     return std::move(watchdog_thread_);
@@ -62,6 +68,11 @@
   GpuPreferences gpu_preferences_;
   bool init_successful_ = false;
 
+  // The following data are collected from hardware GPU and saved before
+  // switching to SwiftShader.
+  GPUInfo gpu_info_for_hardware_gpu_;
+  GpuFeatureInfo gpu_feature_info_for_hardware_gpu_;
+
   bool ShouldEnableSwiftShader(base::CommandLine* command_line,
                                bool blacklist_needs_more_info);
   void AdjustInfoToSwiftShader();
diff --git a/infra/config/branch/cq.cfg b/infra/config/branch/cq.cfg
index 5942440..054abe404 100644
--- a/infra/config/branch/cq.cfg
+++ b/infra/config/branch/cq.cfg
@@ -106,7 +106,7 @@
       }
       builders {
         name: "linux_chromium_tsan_rel_ng"
-        equivalent_to { bucket: "luci.chromium.try" percentage: 10 }
+        equivalent_to { bucket: "luci.chromium.try" percentage: 100 }
       }
       builders {
         # Temporary addition to gather data for LUCI migration.
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index b7485a9..ba76b6e 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -415,11 +415,18 @@
     builders {
       name: "Android arm64 Builder (dbg)"
       mixins: "android-ci"
+      mixins: "goma-many-jobs-for-ci"
       dimensions: "os:Ubuntu-14.04"
       execution_timeout_secs: 14400  # 4h
     }
 
     builders {
+      name: "Android Cronet Builder"
+      mixins: "android-ci"
+      dimensions: "os:Ubuntu-14.04"
+    }
+
+    builders {
       name: "Android FYI 32 Vk Release (Nexus 5X)"
       mixins: "android-gpu-fyi-ci"
     }
@@ -1116,6 +1123,11 @@
     }
     builders {
       mixins: "android-try"
+      name: "android_cronet"
+      dimensions: "os:Ubuntu-14.04"
+    }
+    builders {
+      mixins: "android-try"
       name: "android_n5x_swarming_dbg"
       dimensions: "os:Ubuntu-14.04"
     }
diff --git a/infra/config/global/luci-milo-dev.cfg b/infra/config/global/luci-milo-dev.cfg
index 99c5857..3380ee35 100644
--- a/infra/config/global/luci-milo-dev.cfg
+++ b/infra/config/global/luci-milo-dev.cfg
@@ -3436,6 +3436,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.android/android_archive_rel_ng"
@@ -3527,6 +3528,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.angle/android_angle_deqp_rel_ng"
@@ -3594,6 +3596,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.chromiumos/chromeos-amd64-generic-rel"
@@ -3619,6 +3622,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.linux/cast_shell_audio_linux"
@@ -3764,6 +3768,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.mac/ios-device"
@@ -3873,6 +3878,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.perf/Android Compile Perf"
@@ -3916,6 +3922,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.win/win10_chromium_x64_rel_ng"
@@ -4000,6 +4007,7 @@
   repo_url: "https://chromium.googlesource.com/chromium/src"
   ref: "refs/heads/master"
   manifest_name: "REVISION"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.blink/linux_trusty_blink_compile_dbg"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index f44e4f86..ecf9fb7 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -1653,6 +1653,17 @@
     category: "chromium.linux|debug"
     short_name: "ci"
   }
+
+  builders: {
+    name: "buildbot/chromium.android/Android Cronet Builder"
+    category: "chromium.android|cronet"
+    short_name: "bb"
+  }
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Android Cronet Builder"
+    category: "chromium.android|cronet"
+    short_name: "ci"
+  }
   builders: {
     name: "buildbot/chromium.fyi/Android deterministic"
     category: "chromium.android|release"
@@ -1738,17 +1749,8 @@
   header_id: "chromium"
 
   builders: {
-    name: "buildbot/chromium.android/Android Cronet ARM64 Builder"
-    category: "cronet"
-    short_name: "rel"
-  }
-  builders: {
-    name: "buildbot/chromium.android/Android Cronet ARM64 Builder (dbg)"
-    category: "cronet"
-    short_name: "dbg"
-  }
-  builders: {
     name: "buildbot/chromium.android/Android Cronet Builder"
+    name: "buildbucket/luci.chromium.ci/Android Cronet Builder"
     category: "cronet"
     short_name: "rel"
   }
@@ -1778,21 +1780,31 @@
     short_name: "mar"
   }
   builders: {
-    name: "buildbot/chromium.android/Android Cronet x86 Builder"
+    name: "buildbot/chromium.android/Android Cronet Marshmallow 64bit Perf"
     category: "cronet"
+    short_name: "prf"
+  }
+  builders: {
+    name: "buildbot/chromium.android/Android Cronet ARM64 Builder"
+    category: "cronet|arm64"
+    short_name: "rel"
+  }
+  builders: {
+    name: "buildbot/chromium.android/Android Cronet ARM64 Builder (dbg)"
+    category: "cronet|arm64"
+    short_name: "dbg"
+  }
+  builders: {
+    name: "buildbot/chromium.android/Android Cronet x86 Builder"
+    category: "cronet|x86"
     short_name: "rel"
   }
   builders: {
     name: "buildbot/chromium.android/Android Cronet x86 Builder (dbg)"
-    category: "cronet"
+    category: "cronet|x86"
     short_name: "dbg"
   }
   builders: {
-    name: "buildbot/chromium.android/Android Cronet Marshmallow 64bit Perf"
-    category: "cronet"
-    short_name: "prf"
-  }
-  builders: {
     name: "buildbot/chromium.android/Android arm Builder (dbg)"
     category: "builder|arm"
     short_name: "32"
@@ -3762,6 +3774,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.android/android_archive_rel_ng"
@@ -3813,6 +3826,7 @@
   }
   builders: {
     name: "buildbot/tryserver.chromium.android/android_cronet"
+    name: "buildbucket/luci.chromium.try/android_cronet"
   }
   builders: {
     name: "buildbot/tryserver.chromium.android/android_cronet_tester"
@@ -3850,6 +3864,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.chromiumos/chromeos-amd64-generic-rel"
@@ -3875,6 +3890,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.linux/cast_shell_audio_linux"
@@ -4005,6 +4021,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.mac/ios-device"
@@ -4114,6 +4131,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.chromium.perf/Android Compile Perf"
@@ -4157,6 +4175,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbucket/luci.chromium.try/win10_chromium_x64_dbg_ng"
@@ -4244,6 +4263,7 @@
   repo_url: "https://chromium.googlesource.com/chromium/src"
   ref: "refs/heads/master"
   manifest_name: "REVISION"
+  builder_view_only: true
 
   builders: {
     name: "buildbot/tryserver.blink/linux_trusty_blink_compile_dbg"
@@ -4296,6 +4316,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbucket/luci.chromium.try/android_angle_deqp_rel_ng"
@@ -4363,6 +4384,7 @@
   ref: "refs/heads/master"
   manifest_name: "REVISION"
   header_id: "chromium"
+  builder_view_only: true
 
   builders: {
     name: "buildbucket/luci.chromium.try/android_arm64_dbg_recipe"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index 77bb9d1c..157080a 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -53,6 +53,7 @@
 
   # Android. Sorted alphabetically.
   triggers: "Android arm64 Builder (dbg)"
+  triggers: "Android Cronet Builder"
   triggers: "Android FYI 32 Vk Release (Nexus 5X)"
   triggers: "Android FYI 64 Vk Release (Nexus 5X)"
   triggers: "Android FYI dEQP Release (Nexus 5X)"
@@ -142,6 +143,16 @@
 }
 
 job {
+  id: "Android Cronet Builder"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Android Cronet Builder"
+  }
+}
+
+job {
   id: "Android FYI 32 Vk Release (Nexus 5X)"
   acl_sets: "default"
   buildbucket: {
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 2db398d..0e9689e 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -4075,7 +4075,13 @@
   if (self.currentWebState) {
     UIEdgeInsets contentPadding =
         self.currentWebState->GetWebViewProxy().contentInset;
-    contentPadding.top = AlignValueToPixel(progress * [self toolbarHeight]);
+    CGFloat toolbarHeightFullscreen = 0;
+    if (IsUIRefreshPhase1Enabled()) {
+      toolbarHeightFullscreen = kToolbarHeightFullscreen;
+    }
+    CGFloat toolbarHeightDelta = [self toolbarHeight] - toolbarHeightFullscreen;
+    contentPadding.top = AlignValueToPixel(toolbarHeightFullscreen +
+                                           progress * toolbarHeightDelta);
     contentPadding.bottom =
         AlignValueToPixel(progress * [self secondaryToolbarHeightWithInset]);
     self.currentWebState->GetWebViewProxy().contentInset = contentPadding;
diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc
index ae7b77d..266284b 100644
--- a/media/audio/audio_output_device.cc
+++ b/media/audio/audio_output_device.cc
@@ -249,7 +249,6 @@
   if (state_ == PAUSED) {
     TRACE_EVENT_ASYNC_BEGIN0(
         "audio", "StartingPlayback", audio_callback_.get());
-    ipc_->SetVolume(volume_);
     ipc_->PlayStream();
     state_ = PLAYING;
     play_on_start_ = false;
@@ -302,12 +301,8 @@
 
 void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
   DCHECK(task_runner()->BelongsToCurrentThread());
-  if (state_ >= CREATING_STREAM) {
-    // Defer playing until start unless we've already started.
-    volume_ = volume;
-    if (state_ == PLAYING)
-      ipc_->SetVolume(volume_);
-  }
+  if (state_ >= CREATING_STREAM)
+    ipc_->SetVolume(volume);
 }
 
 void AudioOutputDevice::OnError() {
diff --git a/media/audio/audio_output_device.h b/media/audio/audio_output_device.h
index bed3fbe..dae0c14 100644
--- a/media/audio/audio_output_device.h
+++ b/media/audio/audio_output_device.h
@@ -187,9 +187,6 @@
   // State of Play() / Pause() calls before OnStreamCreated() is called.
   bool play_on_start_;
 
-  // Last set volume.
-  double volume_ = 1.0;
-
   // The media session ID used to identify which input device to be started.
   // Only used by Unified IO.
   int session_id_;
diff --git a/media/base/renderer_factory_selector.cc b/media/base/renderer_factory_selector.cc
index 4e50612..ef2b579 100644
--- a/media/base/renderer_factory_selector.cc
+++ b/media/base/renderer_factory_selector.cc
@@ -35,6 +35,9 @@
   if (query_is_remoting_active_cb_ && query_is_remoting_active_cb_.Run())
     next_factory_type = FactoryType::COURIER;
 
+  if (query_is_flinging_active_cb_ && query_is_flinging_active_cb_.Run())
+    next_factory_type = FactoryType::FLINGING;
+
   DVLOG(1) << __func__ << " Selecting factory type: " << next_factory_type;
 
   RendererFactory* current_factory = factories_[next_factory_type].get();
@@ -56,4 +59,10 @@
   query_is_remoting_active_cb_ = query_is_remoting_active_cb;
 }
 
+void RendererFactorySelector::SetQueryIsFlingingActiveCB(
+    QueryIsFlingingActiveCB query_is_flinging_active_cb) {
+  DCHECK(!query_is_flinging_active_cb_);
+  query_is_flinging_active_cb_ = query_is_flinging_active_cb;
+}
+
 }  // namespace media
diff --git a/media/base/renderer_factory_selector.h b/media/base/renderer_factory_selector.h
index c579434..6d929b1d4c 100644
--- a/media/base/renderer_factory_selector.h
+++ b/media/base/renderer_factory_selector.h
@@ -17,13 +17,15 @@
 class MEDIA_EXPORT RendererFactorySelector {
  public:
   using QueryIsRemotingActiveCB = base::Callback<bool()>;
+  using QueryIsFlingingActiveCB = base::Callback<bool()>;
 
   enum FactoryType {
     DEFAULT,       // DefaultRendererFactory.
     MOJO,          // MojoRendererFactory.
     MEDIA_PLAYER,  // MediaPlayerRendererClientFactory.
     COURIER,       // CourierRendererFactory.
-    FACTORY_TYPE_MAX = COURIER,
+    FLINGING,      // FlingingRendererClientFactory
+    FACTORY_TYPE_MAX = FLINGING,
   };
 
   RendererFactorySelector();
@@ -54,10 +56,16 @@
   void SetQueryIsRemotingActiveCB(
       QueryIsRemotingActiveCB query_is_remoting_active_cb);
 
+  // Sets the callback to query whether we are currently flinging media, and if
+  // we should temporarily use the FLINGING factory.
+  void SetQueryIsFlingingActiveCB(
+      QueryIsFlingingActiveCB query_is_flinging_active_cb);
+
  private:
   bool use_media_player_ = false;
 
   QueryIsRemotingActiveCB query_is_remoting_active_cb_;
+  QueryIsFlingingActiveCB query_is_flinging_active_cb_;
 
   base::Optional<FactoryType> base_factory_type_;
   std::unique_ptr<RendererFactory> factories_[FACTORY_TYPE_MAX + 1];
diff --git a/media/base/test_helpers.cc b/media/base/test_helpers.cc
index 01599dde..c4a349b 100644
--- a/media/base/test_helpers.cc
+++ b/media/base/test_helpers.cc
@@ -126,6 +126,7 @@
 }
 
 static VideoDecoderConfig GetTestConfig(VideoCodec codec,
+                                        VideoCodecProfile config,
                                         VideoRotation rotation,
                                         gfx::Size coded_size,
                                         bool is_encrypted) {
@@ -133,8 +134,8 @@
   gfx::Size natural_size = coded_size;
 
   return VideoDecoderConfig(
-      codec, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_I420, COLOR_SPACE_JPEG,
-      rotation, coded_size, visible_rect, natural_size, EmptyExtraData(),
+      codec, config, PIXEL_FORMAT_I420, COLOR_SPACE_JPEG, rotation, coded_size,
+      visible_rect, natural_size, EmptyExtraData(),
       is_encrypted ? AesCtrEncryptionScheme() : Unencrypted());
 }
 
@@ -143,38 +144,44 @@
 
 // static
 VideoDecoderConfig TestVideoConfig::Invalid() {
-  return GetTestConfig(kUnknownVideoCodec, VIDEO_ROTATION_0, kNormalSize,
-                       false);
+  return GetTestConfig(kUnknownVideoCodec, VIDEO_CODEC_PROFILE_UNKNOWN,
+                       VIDEO_ROTATION_0, kNormalSize, false);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::Normal(VideoCodec codec) {
-  return GetTestConfig(codec, VIDEO_ROTATION_0, kNormalSize, false);
+  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, VIDEO_ROTATION_0,
+                       kNormalSize, false);
 }
 
 // static
-VideoDecoderConfig TestVideoConfig::NormalH264() {
-  return GetTestConfig(kCodecH264, VIDEO_ROTATION_0, kNormalSize, false);
+VideoDecoderConfig TestVideoConfig::NormalH264(VideoCodecProfile config) {
+  return GetTestConfig(kCodecH264, config, VIDEO_ROTATION_0, kNormalSize,
+                       false);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::NormalEncrypted(VideoCodec codec) {
-  return GetTestConfig(codec, VIDEO_ROTATION_0, kNormalSize, true);
+  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, VIDEO_ROTATION_0,
+                       kNormalSize, true);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::NormalRotated(VideoRotation rotation) {
-  return GetTestConfig(kCodecVP8, rotation, kNormalSize, false);
+  return GetTestConfig(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, rotation,
+                       kNormalSize, false);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::Large(VideoCodec codec) {
-  return GetTestConfig(codec, VIDEO_ROTATION_0, kLargeSize, false);
+  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, VIDEO_ROTATION_0,
+                       kLargeSize, false);
 }
 
 // static
 VideoDecoderConfig TestVideoConfig::LargeEncrypted(VideoCodec codec) {
-  return GetTestConfig(codec, VIDEO_ROTATION_0, kLargeSize, true);
+  return GetTestConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, VIDEO_ROTATION_0,
+                       kLargeSize, true);
 }
 
 // static
diff --git a/media/base/test_helpers.h b/media/base/test_helpers.h
index 1003154..21ea5cc 100644
--- a/media/base/test_helpers.h
+++ b/media/base/test_helpers.h
@@ -88,7 +88,8 @@
   static VideoDecoderConfig Invalid();
 
   static VideoDecoderConfig Normal(VideoCodec codec = kCodecVP8);
-  static VideoDecoderConfig NormalH264();
+  static VideoDecoderConfig NormalH264(
+      VideoCodecProfile = VIDEO_CODEC_PROFILE_UNKNOWN);
   static VideoDecoderConfig NormalEncrypted(VideoCodec codec = kCodecVP8);
   static VideoDecoderConfig NormalRotated(VideoRotation rotation);
 
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 391c797..b82376a7 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -576,6 +576,7 @@
   testonly = true
   deps = [
     "//base",
+    "//base/test:test_support",
     "//media:test_support",
     "//media/gpu",
     "//media/gpu/ipc/service:unit_tests",
@@ -594,6 +595,7 @@
       "windows/d3d11_cdm_proxy_unittest.cc",
       "windows/d3d11_mocks.cc",
       "windows/d3d11_mocks.h",
+      "windows/d3d11_video_decoder_unittest.cc",
     ]
     libs = [ "dxguid.lib" ]
   }
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc
index 6c52a1fc..354aea0 100644
--- a/media/gpu/windows/d3d11_video_decoder.cc
+++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -45,18 +45,32 @@
 
 namespace media {
 
-D3D11VideoDecoder::D3D11VideoDecoder(
+std::unique_ptr<VideoDecoder> D3D11VideoDecoder::Create(
     scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
     const gpu::GpuPreferences& gpu_preferences,
-    base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb)
-    : impl_task_runner_(std::move(gpu_task_runner)),
-      gpu_preferences_(gpu_preferences),
-      weak_factory_(this) {
+    const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
+    base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb) {
   // We create |impl_| on the wrong thread, but we never use it here.
   // Note that the output callback will hop to our thread, post the video
   // frame, and along with a callback that will hop back to the impl thread
   // when it's released.
-  impl_ = std::make_unique<D3D11VideoDecoderImpl>(get_stub_cb);
+  // Note that we WrapUnique<VideoDecoder> rather than D3D11VideoDecoder to make
+  // this castable; the deleters have to match.
+  return base::WrapUnique<VideoDecoder>(new D3D11VideoDecoder(
+      std::move(gpu_task_runner), gpu_preferences, gpu_workarounds,
+      std::make_unique<D3D11VideoDecoderImpl>(get_stub_cb)));
+}
+
+D3D11VideoDecoder::D3D11VideoDecoder(
+    scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
+    const gpu::GpuPreferences& gpu_preferences,
+    const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
+    std::unique_ptr<D3D11VideoDecoderImpl> impl)
+    : impl_(std::move(impl)),
+      impl_task_runner_(std::move(gpu_task_runner)),
+      gpu_preferences_(gpu_preferences),
+      gpu_workarounds_(gpu_workarounds),
+      weak_factory_(this) {
   impl_weak_ = impl_->GetWeakPtr();
 }
 
@@ -78,13 +92,15 @@
     const InitCB& init_cb,
     const OutputCB& output_cb,
     const WaitingForDecryptionKeyCB& waiting_for_decryption_key_cb) {
-  if (IsUnsupported(config)) {
+  if (!IsPotentiallySupported(config)) {
     init_cb.Run(false);
     return;
   }
 
   // Bind our own init / output cb that hop to this thread, so we don't call the
   // originals on some other thread.
+  // Important but subtle note: base::Bind will copy |config_| since it's a
+  // const ref.
   // TODO(liberato): what's the lifetime of |cdm_context|?
   impl_task_runner_->PostTask(
       FROM_HERE,
@@ -127,19 +143,21 @@
   return impl_->GetMaxDecodeRequests();
 }
 
-bool D3D11VideoDecoder::IsUnsupported(const VideoDecoderConfig& config) {
+bool D3D11VideoDecoder::IsPotentiallySupported(
+    const VideoDecoderConfig& config) {
   // TODO(liberato): All of this could be moved into MojoVideoDecoder, so that
   // it could run on the client side and save the IPC hop.
 
   // Must be H264.
   const bool is_h264 = config.profile() >= H264PROFILE_MIN &&
                        config.profile() <= H264PROFILE_MAX;
+
   if (!is_h264)
-    return true;
+    return false;
 
   // Must use NV12, which excludes HDR.
   if (config.profile() == H264PROFILE_HIGH10PROFILE)
-    return true;
+    return false;
 
   // TODO(liberato): dxva checks IsHDR() in the target colorspace, but we don't
   // have the target colorspace.  It's commented as being for vpx, though, so
@@ -147,15 +165,16 @@
 
   // Must use the validating decoder.
   if (gpu_preferences_.use_passthrough_cmd_decoder)
-    return true;
+    return false;
 
   // Must allow zero-copy of nv12 textures.
-  // TODO(liberato): check gpu workarounds too, once it's plumbed through.  It
-  // will be added as part of VDAVideoDecoder.
   if (!gpu_preferences_.enable_zero_copy_dxgi_video)
-    return true;
+    return false;
 
-  return false;
+  if (gpu_workarounds_.disable_dxgi_zero_copy_video)
+    return false;
+
+  return true;
 }
 
 }  // namespace media
diff --git a/media/gpu/windows/d3d11_video_decoder.h b/media/gpu/windows/d3d11_video_decoder.h
index f9551e8..dcf3f9d 100644
--- a/media/gpu/windows/d3d11_video_decoder.h
+++ b/media/gpu/windows/d3d11_video_decoder.h
@@ -11,6 +11,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
+#include "gpu/command_buffer/service/gpu_preferences.h"
+#include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "gpu/ipc/service/command_buffer_stub.h"
 #include "media/base/video_decoder.h"
 #include "media/gpu/media_gpu_export.h"
@@ -18,6 +20,7 @@
 namespace media {
 
 class D3D11VideoDecoderImpl;
+class D3D11VideoDecoderTest;
 
 // Thread-hopping implementation of D3D11VideoDecoder.  It's meant to run on
 // a random thread, and hop to the gpu main thread.  It does this so that it
@@ -27,11 +30,11 @@
 // now, it's easier to hop threads.
 class MEDIA_GPU_EXPORT D3D11VideoDecoder : public VideoDecoder {
  public:
-  D3D11VideoDecoder(
+  static std::unique_ptr<VideoDecoder> Create(
       scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
       const gpu::GpuPreferences& gpu_preferences,
+      const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
       base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb);
-  ~D3D11VideoDecoder() override;
 
   // VideoDecoder implementation:
   std::string GetDisplayName() const override;
@@ -49,11 +52,24 @@
   bool CanReadWithoutStalling() const override;
   int GetMaxDecodeRequests() const override;
 
-  // Return true if |config| definitely isn't going to work, so that we can fail
+  // Return false |config| definitely isn't going to work, so that we can fail
   // init without bothering with a thread hop.
-  bool IsUnsupported(const VideoDecoderConfig& config);
+  bool IsPotentiallySupported(const VideoDecoderConfig& config);
+
+ protected:
+  // Owners should call Destroy(). This is automatic via
+  // std::default_delete<media::VideoDecoder> when held by a
+  // std::unique_ptr<media::VideoDecoder>.
+  ~D3D11VideoDecoder() override;
 
  private:
+  friend class D3D11VideoDecoderTest;
+
+  D3D11VideoDecoder(scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
+                    const gpu::GpuPreferences& gpu_preferences,
+                    const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
+                    std::unique_ptr<D3D11VideoDecoderImpl> impl);
+
   // The implementation, which we trampoline to the impl thread.
   // This must be freed on the impl thread.
   std::unique_ptr<D3D11VideoDecoderImpl> impl_;
@@ -65,6 +81,7 @@
   scoped_refptr<base::SequencedTaskRunner> impl_task_runner_;
 
   gpu::GpuPreferences gpu_preferences_;
+  gpu::GpuDriverBugWorkarounds gpu_workarounds_;
 
   base::WeakPtrFactory<D3D11VideoDecoder> weak_factory_;
 
diff --git a/media/gpu/windows/d3d11_video_decoder_unittest.cc b/media/gpu/windows/d3d11_video_decoder_unittest.cc
new file mode 100644
index 0000000..d29b30a
--- /dev/null
+++ b/media/gpu/windows/d3d11_video_decoder_unittest.cc
@@ -0,0 +1,146 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/gpu/windows/d3d11_video_decoder.h"
+
+#include <d3d11.h>
+#include <d3d11_1.h>
+#include <initguid.h>
+
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/test_helpers.h"
+#include "media/gpu/windows/d3d11_mocks.h"
+#include "media/gpu/windows/d3d11_video_decoder_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+
+namespace media {
+
+class MockD3D11VideoDecoderImpl : public D3D11VideoDecoderImpl {
+ public:
+  MockD3D11VideoDecoderImpl()
+      : D3D11VideoDecoderImpl(
+            base::RepeatingCallback<gpu::CommandBufferStub*()>()) {}
+
+  MOCK_METHOD6(
+      Initialize,
+      void(const VideoDecoderConfig& config,
+           bool low_delay,
+           CdmContext* cdm_context,
+           const InitCB& init_cb,
+           const OutputCB& output_cb,
+           const WaitingForDecryptionKeyCB& waiting_for_decryption_key_cb));
+
+  MOCK_METHOD2(Decode,
+               void(scoped_refptr<DecoderBuffer> buffer,
+                    const DecodeCB& decode_cb));
+  MOCK_METHOD1(Reset, void(const base::RepeatingClosure& closure));
+};
+
+class D3D11VideoDecoderTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    // Set up some sane defaults.
+    gpu_preferences_.enable_zero_copy_dxgi_video = true;
+    gpu_preferences_.use_passthrough_cmd_decoder = false;
+    gpu_workarounds_.disable_dxgi_zero_copy_video = false;
+    supported_config_ = TestVideoConfig::NormalH264(H264PROFILE_MAIN);
+  }
+
+  void TearDown() override {
+    decoder_.reset();
+    // Run the gpu thread runner to tear down |impl_|.
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void CreateDecoder() {
+    std::unique_ptr<MockD3D11VideoDecoderImpl> impl =
+        std::make_unique<MockD3D11VideoDecoderImpl>();
+    impl_ = impl.get();
+
+    gpu_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+
+    decoder_ = base::WrapUnique<VideoDecoder>(new D3D11VideoDecoder(
+        gpu_task_runner_, gpu_preferences_, gpu_workarounds_, std::move(impl)));
+  }
+
+  enum InitExpectation {
+    kExpectFailure = false,
+    kExpectSuccess = true,
+  };
+
+  void InitializeDecoder(const VideoDecoderConfig& config,
+                         InitExpectation expectation) {
+    const bool low_delay = false;
+    CdmContext* cdm_context = nullptr;
+
+    if (expectation == kExpectSuccess) {
+      EXPECT_CALL(*this, MockInitCB(_)).Times(0);
+      EXPECT_CALL(*impl_, Initialize(_, low_delay, cdm_context, _, _, _));
+    } else {
+      EXPECT_CALL(*this, MockInitCB(false));
+    }
+
+    decoder_->Initialize(config, low_delay, cdm_context,
+                         base::BindRepeating(&D3D11VideoDecoderTest::MockInitCB,
+                                             base::Unretained(this)),
+                         VideoDecoder::OutputCB(),
+                         VideoDecoder::WaitingForDecryptionKeyCB());
+    base::RunLoop().RunUntilIdle();
+  }
+
+  base::test::ScopedTaskEnvironment env_;
+
+  scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
+
+  std::unique_ptr<VideoDecoder> decoder_;
+  gpu::GpuPreferences gpu_preferences_;
+  gpu::GpuDriverBugWorkarounds gpu_workarounds_;
+  MockD3D11VideoDecoderImpl* impl_ = nullptr;
+  VideoDecoderConfig supported_config_;
+
+  MOCK_METHOD1(MockInitCB, void(bool));
+};
+
+TEST_F(D3D11VideoDecoderTest, SupportsH264) {
+  CreateDecoder();
+  // Make sure that we're testing H264.
+  ASSERT_EQ(supported_config_.profile(), H264PROFILE_MAIN);
+  InitializeDecoder(supported_config_, kExpectSuccess);
+}
+
+TEST_F(D3D11VideoDecoderTest, DoesNotSupportVP8) {
+  CreateDecoder();
+  InitializeDecoder(TestVideoConfig::Normal(kCodecVP8), kExpectFailure);
+}
+
+TEST_F(D3D11VideoDecoderTest, DoesNotSupportVP9) {
+  CreateDecoder();
+  InitializeDecoder(TestVideoConfig::Normal(kCodecVP9), kExpectFailure);
+}
+
+TEST_F(D3D11VideoDecoderTest, RequiresZeroCopyPreference) {
+  gpu_preferences_.enable_zero_copy_dxgi_video = false;
+  CreateDecoder();
+  InitializeDecoder(supported_config_, kExpectFailure);
+}
+
+TEST_F(D3D11VideoDecoderTest, FailsIfUsingPassthroughDecoder) {
+  gpu_preferences_.use_passthrough_cmd_decoder = true;
+  CreateDecoder();
+  InitializeDecoder(supported_config_, kExpectFailure);
+}
+
+TEST_F(D3D11VideoDecoderTest, FailsIfZeroCopyWorkaround) {
+  gpu_workarounds_.disable_dxgi_zero_copy_video = true;
+  CreateDecoder();
+  InitializeDecoder(supported_config_, kExpectFailure);
+}
+
+}  // namespace media
diff --git a/media/mojo/clients/mojo_renderer_factory.cc b/media/mojo/clients/mojo_renderer_factory.cc
index 2601efde..4a2096a 100644
--- a/media/mojo/clients/mojo_renderer_factory.cc
+++ b/media/mojo/clients/mojo_renderer_factory.cc
@@ -27,6 +27,11 @@
 
 MojoRendererFactory::~MojoRendererFactory() = default;
 
+void MojoRendererFactory::SetGetTypeSpecificIdCB(
+    const GetTypeSpecificIdCB& get_type_specific_id) {
+  get_type_specific_id_ = get_type_specific_id;
+}
+
 std::unique_ptr<Renderer> MojoRendererFactory::CreateRenderer(
     const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
     const scoped_refptr<base::TaskRunner>& /* worker_task_runner */,
@@ -52,7 +57,10 @@
   mojom::RendererPtr renderer_ptr;
 
   if (interface_factory_) {
-    interface_factory_->CreateRenderer(hosted_renderer_type_, std::string(),
+    interface_factory_->CreateRenderer(hosted_renderer_type_,
+                                       get_type_specific_id_.is_null()
+                                           ? std::string()
+                                           : get_type_specific_id_.Run(),
                                        mojo::MakeRequest(&renderer_ptr));
   } else {
     NOTREACHED();
diff --git a/media/mojo/clients/mojo_renderer_factory.h b/media/mojo/clients/mojo_renderer_factory.h
index f0fa1f33..5096df53 100644
--- a/media/mojo/clients/mojo_renderer_factory.h
+++ b/media/mojo/clients/mojo_renderer_factory.h
@@ -24,6 +24,7 @@
 class MojoRendererFactory : public RendererFactory {
  public:
   using GetGpuFactoriesCB = base::Callback<GpuVideoAcceleratorFactories*()>;
+  using GetTypeSpecificIdCB = base::Callback<std::string()>;
 
   MojoRendererFactory(mojom::HostedRendererType type,
                       const GetGpuFactoriesCB& get_gpu_factories_cb,
@@ -39,10 +40,19 @@
       const RequestOverlayInfoCB& request_overlay_info_cb,
       const gfx::ColorSpace& target_color_space) final;
 
+  // Sets the callback that will fetch the TypeSpecificId when
+  // InterfaceFactory::CreateRenderer() is called. What the string represents
+  // depends on the value of |hosted_renderer_type_|. Currently, we only use it
+  // with mojom::HostedRendererType::kFlinging, in which case
+  // |get_type_specific_id| should return the presentation ID to be given to the
+  // FlingingRenderer in the browser process.
+  void SetGetTypeSpecificIdCB(const GetTypeSpecificIdCB& get_type_specific_id);
+
  private:
   mojom::RendererPtr GetRendererPtr();
 
   GetGpuFactoriesCB get_gpu_factories_cb_;
+  GetTypeSpecificIdCB get_type_specific_id_;
 
   // InterfaceFactory or InterfaceProvider used to create or connect to remote
   // renderer.
diff --git a/media/mojo/interfaces/audio_output_stream.mojom b/media/mojo/interfaces/audio_output_stream.mojom
index fbc1fbf..2ccf4b75 100644
--- a/media/mojo/interfaces/audio_output_stream.mojom
+++ b/media/mojo/interfaces/audio_output_stream.mojom
@@ -25,6 +25,21 @@
   SetVolume(double volume);
 };
 
+interface AudioOutputStreamClient {
+  // Called if the stream has an error such as failing to open/losing access to
+  // a device. This renders the stream unusable.
+  OnError();
+};
+
+interface AudioOutputStreamProvider {
+  // Creates a new AudioOutputStream using |params|. |data_pipe| is used to
+  // transfer audio data.
+  // Can only be called once.
+  Acquire(AudioOutputStream& output_stream, AudioOutputStreamClient client,
+    AudioParameters params)
+    => (AudioDataPipe data_pipe);
+};
+
 // An AudioOutputStreamObserver gets notifications about events related to an
 // AudioOutputStream. DidStartPlaying() is invoked when the stream starts
 // playing and it is eventually followed by a DidStopPlaying() call. A stream
@@ -33,13 +48,6 @@
 // Note: It is possible that DidStopPlaying() is not called in shutdown
 // situations.
 interface AudioOutputStreamObserver {
-  // This code is used as disconnect reason when stream ended or failed to
-  // start due to an unrecoverable platform error, e.g. the hardware device is
-  // busy or disconnected.
-  // If the error code isn't used, the stream ended due to being terminated by
-  // the client.
-  const uint32 kPlatformErrorDisconnectReason = 1;
-
   // This notification indicates that the stream started playing. The stream
   // should be considered non-audible until a DidChangeAudibleState() call says
   // otherwise.
@@ -55,27 +63,3 @@
   // DidStartPlaying() and before DidStopPlaying().
   DidChangeAudibleState(bool is_audible);
 };
-
-interface AudioOutputStreamProvider {
-  // Creates a new AudioOutputStream using |params|. |client| is notified when
-  // the stream is ready. The stream lifetime is bound by the lifetime of
-  // |client|. On error, the |client| will have a disconnect reason among the
-  // specified ones in AudioOutputStreamProviderClient.
-  // Can only be called once.
-  Acquire(AudioParameters params, AudioOutputStreamProviderClient client);
-};
-
-interface AudioOutputStreamProviderClient {
-  // This code is used as disconnect reason when stream ended or failed to
-  // start due to an unrecoverable platform error, e.g. the hardware device is
-  // busy or disconnected.
-  // If the error code isn't used, the stream ended/wasn't started due to the
-  // stream becoming unnecessary or unwanted, or the request was dropped.
-  const uint32 kPlatformErrorDisconnectReason = 1;
-
-  // |stream| is used to pass commands to the stream, and |data_pipe| is used
-  // to transfer the audio data.
-  // TODO(https://crbug.com/787806): Currently, this will be called at most
-  // once. In the future, it may be called several times.
-  Created(AudioOutputStream stream, AudioDataPipe data_pipe);
-};
diff --git a/media/mojo/services/OWNERS b/media/mojo/services/OWNERS
index da9d4b5c..fce6c7a 100644
--- a/media/mojo/services/OWNERS
+++ b/media/mojo/services/OWNERS
@@ -15,6 +15,3 @@
 
 per-file pipeline_apptest_manifest.json=set noparent
 per-file pipeline_apptest_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file mojo_audio_output*=file://media/audio/OWNERS
-per-file mojo_audio_input*=file://media/audio/OWNERS
diff --git a/media/mojo/services/gpu_mojo_media_client.cc b/media/mojo/services/gpu_mojo_media_client.cc
index f4ecc9f..fa8a58d 100644
--- a/media/mojo/services/gpu_mojo_media_client.cc
+++ b/media/mojo/services/gpu_mojo_media_client.cc
@@ -136,8 +136,8 @@
                           command_buffer_id->channel_token,
                           command_buffer_id->route_id));
 #elif defined(OS_WIN)
-  return std::make_unique<D3D11VideoDecoder>(
-      gpu_task_runner_, gpu_preferences_,
+  return D3D11VideoDecoder::Create(
+      gpu_task_runner_, gpu_preferences_, gpu_workarounds_,
       base::BindRepeating(&GetCommandBufferStub, media_gpu_channel_manager_,
                           command_buffer_id->channel_token,
                           command_buffer_id->route_id));
diff --git a/media/mojo/services/mojo_audio_output_stream.cc b/media/mojo/services/mojo_audio_output_stream.cc
index 57af5108..79e5241 100644
--- a/media/mojo/services/mojo_audio_output_stream.cc
+++ b/media/mojo/services/mojo_audio_output_stream.cc
@@ -15,20 +15,29 @@
 namespace media {
 
 MojoAudioOutputStream::MojoAudioOutputStream(
+    mojom::AudioOutputStreamRequest request,
+    mojom::AudioOutputStreamClientPtr client,
     CreateDelegateCallback create_delegate_callback,
     StreamCreatedCallback stream_created_callback,
-    DeleterCallback deleter_callback)
+    base::OnceClosure deleter_callback)
     : stream_created_callback_(std::move(stream_created_callback)),
       deleter_callback_(std::move(deleter_callback)),
-      binding_(this),
+      binding_(this, std::move(request)),
+      client_(std::move(client)),
       weak_factory_(this) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(stream_created_callback_);
   DCHECK(deleter_callback_);
+  // |this| owns |binding_|, so unretained is safe.
+  binding_.set_connection_error_handler(
+      base::BindOnce(&MojoAudioOutputStream::OnError, base::Unretained(this)));
+  client_.set_connection_error_handler(
+      base::BindOnce(&MojoAudioOutputStream::OnError, base::Unretained(this)));
   delegate_ = std::move(create_delegate_callback).Run(this);
   if (!delegate_) {
     // Failed to initialize the stream. We cannot call |deleter_callback_| yet,
     // since construction isn't done.
+    binding_.Close();
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(&MojoAudioOutputStream::OnStreamError,
@@ -86,27 +95,21 @@
   DCHECK(buffer_handle.is_valid());
   DCHECK(socket_handle.is_valid());
 
-  mojom::AudioOutputStreamPtr stream;
-  binding_.Bind(mojo::MakeRequest(&stream));
-  // |this| owns |binding_| so unretained is safe.
-  binding_.set_connection_error_handler(base::BindOnce(
-      &MojoAudioOutputStream::StreamConnectionLost, base::Unretained(this)));
-
-  std::move(stream_created_callback_)
-      .Run(std::move(stream), {base::in_place, std::move(buffer_handle),
-                               std::move(socket_handle)});
+  base::ResetAndReturn(&stream_created_callback_)
+      .Run(
+          {base::in_place, std::move(buffer_handle), std::move(socket_handle)});
 }
 
 void MojoAudioOutputStream::OnStreamError(int stream_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(deleter_callback_);
-  std::move(deleter_callback_).Run(/*had_error*/ true);  // Deletes |this|.
+  client_->OnError();
+  OnError();
 }
 
-void MojoAudioOutputStream::StreamConnectionLost() {
+void MojoAudioOutputStream::OnError() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(deleter_callback_);
-  std::move(deleter_callback_).Run(/*had_error*/ false);  // Deletes |this|.
+  std::move(deleter_callback_).Run();  // Deletes |this|.
 }
 
 }  // namespace media
diff --git a/media/mojo/services/mojo_audio_output_stream.h b/media/mojo/services/mojo_audio_output_stream.h
index d4958dda..2170526 100644
--- a/media/mojo/services/mojo_audio_output_stream.h
+++ b/media/mojo/services/mojo_audio_output_stream.h
@@ -23,22 +23,21 @@
       public AudioOutputDelegate::EventHandler {
  public:
   using StreamCreatedCallback =
-      base::OnceCallback<void(mojom::AudioOutputStreamPtr,
-                              media::mojom::AudioDataPipePtr)>;
+      mojom::AudioOutputStreamProvider::AcquireCallback;
   using CreateDelegateCallback =
       base::OnceCallback<std::unique_ptr<AudioOutputDelegate>(
           AudioOutputDelegate::EventHandler*)>;
-  using DeleterCallback = base::OnceCallback<void(bool)>;
 
   // |create_delegate_callback| is used to obtain an AudioOutputDelegate for the
   // stream in the constructor. |stream_created_callback| is called when the
   // stream has been initialized. |deleter_callback| is called when this class
-  // should be removed (stream ended/error). Its argument indicates if an error
-  // was encountered (false indicates that the remote end closed the stream).
-  // |deleter_callback| is required to destroy |this| synchronously.
-  MojoAudioOutputStream(CreateDelegateCallback create_delegate_callback,
+  // should be removed (stream ended/error). |deleter_callback| is required to
+  // destroy |this| synchronously.
+  MojoAudioOutputStream(mojom::AudioOutputStreamRequest request,
+                        mojom::AudioOutputStreamClientPtr client,
+                        CreateDelegateCallback create_delegate_callback,
                         StreamCreatedCallback stream_created_callback,
-                        DeleterCallback deleter_callback);
+                        base::OnceClosure deleter_callback);
 
   ~MojoAudioOutputStream() override;
 
@@ -55,13 +54,15 @@
       std::unique_ptr<base::CancelableSyncSocket> foreign_socket) override;
   void OnStreamError(int stream_id) override;
 
-  void StreamConnectionLost();
+  // Closes connection to client and notifies owner.
+  void OnError();
 
   SEQUENCE_CHECKER(sequence_checker_);
 
   StreamCreatedCallback stream_created_callback_;
-  DeleterCallback deleter_callback_;
+  base::OnceClosure deleter_callback_;
   mojo::Binding<AudioOutputStream> binding_;
+  mojom::AudioOutputStreamClientPtr client_;
   std::unique_ptr<AudioOutputDelegate> delegate_;
   base::WeakPtrFactory<MojoAudioOutputStream> weak_factory_;
 
diff --git a/media/mojo/services/mojo_audio_output_stream_provider.cc b/media/mojo/services/mojo_audio_output_stream_provider.cc
index 74ccb4a..32e7b7f 100644
--- a/media/mojo/services/mojo_audio_output_stream_provider.cc
+++ b/media/mojo/services/mojo_audio_output_stream_provider.cc
@@ -23,9 +23,8 @@
       observer_binding_(observer_.get()) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Unretained is safe since |this| owns |binding_|.
-  binding_.set_connection_error_handler(
-      base::BindOnce(&MojoAudioOutputStreamProvider::CleanUp,
-                     base::Unretained(this), /*had_error*/ false));
+  binding_.set_connection_error_handler(base::Bind(
+      &MojoAudioOutputStreamProvider::OnError, base::Unretained(this)));
   DCHECK(create_delegate_callback_);
   DCHECK(deleter_callback_);
 }
@@ -35,8 +34,10 @@
 }
 
 void MojoAudioOutputStreamProvider::Acquire(
+    mojom::AudioOutputStreamRequest stream_request,
+    mojom::AudioOutputStreamClientPtr client,
     const AudioParameters& params,
-    mojom::AudioOutputStreamProviderClientPtr provider_client) {
+    AcquireCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 #if !defined(OS_ANDROID)
   if (params.IsBitstreamFormat()) {
@@ -52,31 +53,29 @@
     return;
   }
 
-  provider_client_ = std::move(provider_client);
-
   mojom::AudioOutputStreamObserverPtr observer_ptr;
   observer_binding_.Bind(mojo::MakeRequest(&observer_ptr));
   // Unretained is safe since |this| owns |audio_output_|.
-  audio_output_.emplace(
-      base::BindOnce(std::move(create_delegate_callback_), params,
-                     std::move(observer_ptr)),
-      base::BindOnce(&mojom::AudioOutputStreamProviderClient::Created,
-                     base::Unretained(provider_client_.get())),
-      base::BindOnce(&MojoAudioOutputStreamProvider::CleanUp,
-                     base::Unretained(this)));
+  audio_output_.emplace(std::move(stream_request), std::move(client),
+                        base::BindOnce(std::move(create_delegate_callback_),
+                                       params, std::move(observer_ptr)),
+                        std::move(callback),
+                        base::BindOnce(&MojoAudioOutputStreamProvider::OnError,
+                                       base::Unretained(this)));
 }
 
-void MojoAudioOutputStreamProvider::CleanUp(bool had_error) {
-  if (had_error) {
-    provider_client_.ResetWithReason(
-        mojom::AudioOutputStreamProviderClient::kPlatformErrorDisconnectReason,
-        std::string());
-  }
+void MojoAudioOutputStreamProvider::OnError() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Deletes |this|:
   std::move(deleter_callback_).Run(this);
 }
 
 void MojoAudioOutputStreamProvider::BadMessage(const std::string& error) {
   mojo::ReportBadMessage(error);
+  if (binding_.is_bound())
+    binding_.Unbind();
+  if (observer_binding_.is_bound())
+    observer_binding_.Unbind();
   std::move(deleter_callback_).Run(this);  // deletes |this|.
 }
 
diff --git a/media/mojo/services/mojo_audio_output_stream_provider.h b/media/mojo/services/mojo_audio_output_stream_provider.h
index 0d580f3..f642571b 100644
--- a/media/mojo/services/mojo_audio_output_stream_provider.h
+++ b/media/mojo/services/mojo_audio_output_stream_provider.h
@@ -42,25 +42,25 @@
 
  private:
   // mojom::AudioOutputStreamProvider implementation.
-  void Acquire(
-      const AudioParameters& params,
-      mojom::AudioOutputStreamProviderClientPtr provider_client) override;
+  void Acquire(mojom::AudioOutputStreamRequest stream_request,
+               mojom::AudioOutputStreamClientPtr client,
+               const AudioParameters& params,
+               AcquireCallback acquire_callback) override;
 
   // Called when |audio_output_| had an error.
-  void CleanUp(bool had_error);
+  void OnError();
 
   // Closes mojo connections, reports a bad message, and self-destructs.
   void BadMessage(const std::string& error);
 
   SEQUENCE_CHECKER(sequence_checker_);
 
+  base::Optional<MojoAudioOutputStream> audio_output_;
   mojo::Binding<AudioOutputStreamProvider> binding_;
   CreateDelegateCallback create_delegate_callback_;
   DeleterCallback deleter_callback_;
   std::unique_ptr<mojom::AudioOutputStreamObserver> observer_;
   mojo::Binding<mojom::AudioOutputStreamObserver> observer_binding_;
-  base::Optional<MojoAudioOutputStream> audio_output_;
-  mojom::AudioOutputStreamProviderClientPtr provider_client_;
 
   DISALLOW_COPY_AND_ASSIGN(MojoAudioOutputStreamProvider);
 };
diff --git a/media/mojo/services/mojo_audio_output_stream_provider_unittest.cc b/media/mojo/services/mojo_audio_output_stream_provider_unittest.cc
index e559976..49edfa9 100644
--- a/media/mojo/services/mojo_audio_output_stream_provider_unittest.cc
+++ b/media/mojo/services/mojo_audio_output_stream_provider_unittest.cc
@@ -31,6 +31,8 @@
 using MockDeleter = base::MockCallback<
     base::OnceCallback<void(mojom::AudioOutputStreamProvider*)>>;
 
+void FakeAcquireCallback(mojom::AudioDataPipePtr data_pipe) {}
+
 class FakeObserver : public mojom::AudioOutputStreamObserver {
  public:
   FakeObserver() = default;
@@ -81,22 +83,26 @@
       mojo::MakeRequest(&provider_ptr), base::BindOnce(&CreateFakeDelegate),
       deleter.Get(), std::make_unique<FakeObserver>());
 
-  mojom::AudioOutputStreamProviderClientPtr client_1;
-  mojo::MakeRequest(&client_1);
-  provider_ptr->Acquire(media::AudioParameters::UnavailableDeviceParams(),
-                        std::move(client_1));
+  mojom::AudioOutputStreamPtr stream_1;
+  mojom::AudioOutputStreamClientPtr client_1;
+  mojom::AudioOutputStreamClientRequest client_request_1 =
+      mojo::MakeRequest(&client_1);
 
-  mojom::AudioOutputStreamProviderClientPtr client_2;
-  mojo::MakeRequest(&client_2);
-  provider_ptr->Acquire(media::AudioParameters::UnavailableDeviceParams(),
-                        std::move(client_2));
+  mojom::AudioOutputStreamPtr stream_2;
+  mojom::AudioOutputStreamClientPtr client_2;
+  mojom::AudioOutputStreamClientRequest client_request_2 =
+      mojo::MakeRequest(&client_2);
+  provider_ptr->Acquire(mojo::MakeRequest(&stream_1), std::move(client_1),
+                        media::AudioParameters::UnavailableDeviceParams(),
+                        base::BindOnce(&FakeAcquireCallback));
+  provider_ptr->Acquire(mojo::MakeRequest(&stream_2), std::move(client_2),
+                        media::AudioParameters::UnavailableDeviceParams(),
+                        base::BindOnce(&FakeAcquireCallback));
 
   EXPECT_CALL(deleter, Run(provider)).WillOnce(DeleteArg<0>());
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(got_bad_message);
   Mock::VerifyAndClear(&deleter);
-
-  mojo::edk::SetDefaultProcessErrorCallback(mojo::edk::ProcessErrorCallback());
 }
 
 TEST(MojoAudioOutputStreamProviderTest,
@@ -118,9 +124,12 @@
       mojo::MakeRequest(&provider_ptr), base::BindOnce(&CreateFakeDelegate),
       deleter.Get(), std::make_unique<FakeObserver>());
 
-  mojom::AudioOutputStreamProviderClientPtr client;
-  mojo::MakeRequest(&client);
-  provider_ptr->Acquire(params, std::move(client));
+  mojom::AudioOutputStreamPtr stream;
+  mojom::AudioOutputStreamClientPtr client;
+  mojom::AudioOutputStreamClientRequest client_request =
+      mojo::MakeRequest(&client);
+  provider_ptr->Acquire(mojo::MakeRequest(&stream), std::move(client), params,
+                        base::BindOnce(&FakeAcquireCallback));
 
 #if defined(OS_ANDROID)
   base::RunLoop().RunUntilIdle();
@@ -135,7 +144,6 @@
   EXPECT_TRUE(got_bad_message);
   Mock::VerifyAndClear(&deleter);
 #endif
-  mojo::edk::SetDefaultProcessErrorCallback(mojo::edk::ProcessErrorCallback());
 }
 
 }  // namespace media
diff --git a/media/mojo/services/mojo_audio_output_stream_unittest.cc b/media/mojo/services/mojo_audio_output_stream_unittest.cc
index 9df6d45..efd1619 100644
--- a/media/mojo/services/mojo_audio_output_stream_unittest.cc
+++ b/media/mojo/services/mojo_audio_output_stream_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/run_loop.h"
 #include "base/sync_socket.h"
 #include "media/audio/audio_output_controller.h"
-#include "mojo/public/cpp/system/message_pipe.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -89,14 +88,14 @@
 
 class MockDeleter {
  public:
-  MOCK_METHOD1(Finished, void(bool));
+  MOCK_METHOD0(Finished, void());
 };
 
-class MockClient {
+class MockClient : public mojom::AudioOutputStreamClient {
  public:
   MockClient() = default;
 
-  void Initialize(mojom::AudioDataPipePtr data_pipe) {
+  void Initialized(mojom::AudioDataPipePtr data_pipe) {
     ASSERT_TRUE(data_pipe->shared_memory.is_valid());
     ASSERT_TRUE(data_pipe->socket.is_valid());
 
@@ -122,6 +121,8 @@
 
   MOCK_METHOD0(GotNotification, void());
 
+  MOCK_METHOD0(OnError, void());
+
  private:
   std::unique_ptr<base::SharedMemory> buffer_;
   std::unique_ptr<base::CancelableSyncSocket> socket_;
@@ -132,9 +133,9 @@
   return nullptr;
 }
 
-void NotCalled(mojom::AudioOutputStreamPtr, mojom::AudioDataPipePtr) {
-  ADD_FAILURE() << "The StreamCreated callback was called despite the test "
-                   "expecting it not to.";
+void NotCalled(mojom::AudioDataPipePtr data_pipe) {
+  EXPECT_TRUE(false) << "The StreamCreated callback was called despite the "
+                        "test expecting it not to.";
 }
 
 }  // namespace
@@ -142,30 +143,23 @@
 class MojoAudioOutputStreamTest : public Test {
  public:
   MojoAudioOutputStreamTest()
-      : foreign_socket_(std::make_unique<TestCancelableSyncSocket>()) {}
+      : foreign_socket_(std::make_unique<TestCancelableSyncSocket>()),
+        client_binding_(&client_, mojo::MakeRequest(&client_ptr_)) {}
 
   AudioOutputStreamPtr CreateAudioOutput() {
-    mojom::AudioOutputStreamPtr p;
-    pending_stream_request_ = mojo::MakeRequest(&p);
+    AudioOutputStreamPtr p;
     ExpectDelegateCreation();
     impl_ = std::make_unique<MojoAudioOutputStream>(
+        mojo::MakeRequest(&p), std::move(client_ptr_),
         base::BindOnce(&MockDelegateFactory::CreateDelegate,
                        base::Unretained(&mock_delegate_factory_)),
-        base::BindOnce(&MojoAudioOutputStreamTest::CreatedStream,
-                       base::Unretained(this)),
+        base::BindOnce(&MockClient::Initialized, base::Unretained(&client_)),
         base::BindOnce(&MockDeleter::Finished, base::Unretained(&deleter_)));
+    EXPECT_TRUE(p.is_bound());
     return p;
   }
 
  protected:
-  void CreatedStream(mojom::AudioOutputStreamPtr stream,
-                     mojom::AudioDataPipePtr data_pipe) {
-    EXPECT_EQ(mojo::FuseMessagePipes(pending_stream_request_.PassMessagePipe(),
-                                     stream.PassInterface().PassHandle()),
-              MOJO_RESULT_OK);
-    client_.Initialize(std::move(data_pipe));
-  }
-
   void ExpectDelegateCreation() {
     delegate_ = new StrictMock<MockDelegate>();
     mock_delegate_factory_.PrepareDelegateForCreation(
@@ -186,51 +180,45 @@
   StrictMock<MockDelegateFactory> mock_delegate_factory_;
   StrictMock<MockDeleter> deleter_;
   StrictMock<MockClient> client_;
-  mojom::AudioOutputStreamRequest pending_stream_request_;
+  media::mojom::AudioOutputStreamClientPtr client_ptr_;
+  mojo::Binding<media::mojom::AudioOutputStreamClient> client_binding_;
   std::unique_ptr<MojoAudioOutputStream> impl_;
 };
 
 TEST_F(MojoAudioOutputStreamTest, NoDelegate_SignalsError) {
+  bool deleter_called = false;
+  EXPECT_CALL(client_, OnError()).Times(1);
   mojom::AudioOutputStreamPtr stream_ptr;
   MojoAudioOutputStream stream(
+      mojo::MakeRequest(&stream_ptr), std::move(client_ptr_),
       base::BindOnce(&CreateNoDelegate), base::BindOnce(&NotCalled),
-      base::BindOnce(&MockDeleter::Finished, base::Unretained(&deleter_)));
-  EXPECT_CALL(deleter_, Finished(true));
+      base::BindOnce([](bool* p) { *p = true; }, &deleter_called));
+  EXPECT_FALSE(deleter_called)
+      << "Stream shouldn't call the deleter from its constructor.";
   base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(deleter_called);
 }
 
 TEST_F(MojoAudioOutputStreamTest, Play_Plays) {
   AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
-
-  EXPECT_CALL(client_, GotNotification());
   EXPECT_CALL(*delegate_, OnPlayStream());
 
-  delegate_event_handler_->OnStreamCreated(kStreamId, &mem_,
-                                           std::move(foreign_socket_));
   audio_output_ptr->Play();
   base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(MojoAudioOutputStreamTest, Pause_Pauses) {
   AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
-
-  EXPECT_CALL(client_, GotNotification());
   EXPECT_CALL(*delegate_, OnPauseStream());
 
-  delegate_event_handler_->OnStreamCreated(kStreamId, &mem_,
-                                           std::move(foreign_socket_));
   audio_output_ptr->Pause();
   base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(MojoAudioOutputStreamTest, SetVolume_SetsVolume) {
   AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
-
-  EXPECT_CALL(client_, GotNotification());
   EXPECT_CALL(*delegate_, OnSetVolume(kNewVolume));
 
-  delegate_event_handler_->OnStreamCreated(kStreamId, &mem_,
-                                           std::move(foreign_socket_));
   audio_output_ptr->SetVolume(kNewVolume);
   base::RunLoop().RunUntilIdle();
 }
@@ -265,11 +253,9 @@
 
 TEST_F(MojoAudioOutputStreamTest, SetVolumeTooLarge_Error) {
   AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
-  EXPECT_CALL(deleter_, Finished(true));
-  EXPECT_CALL(client_, GotNotification());
+  EXPECT_CALL(deleter_, Finished());
+  EXPECT_CALL(client_, OnError()).Times(1);
 
-  delegate_event_handler_->OnStreamCreated(kStreamId, &mem_,
-                                           std::move(foreign_socket_));
   audio_output_ptr->SetVolume(15);
   base::RunLoop().RunUntilIdle();
   Mock::VerifyAndClear(&deleter_);
@@ -277,11 +263,9 @@
 
 TEST_F(MojoAudioOutputStreamTest, SetVolumeNegative_Error) {
   AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
-  EXPECT_CALL(deleter_, Finished(true));
-  EXPECT_CALL(client_, GotNotification());
+  EXPECT_CALL(deleter_, Finished());
+  EXPECT_CALL(client_, OnError()).Times(1);
 
-  delegate_event_handler_->OnStreamCreated(kStreamId, &mem_,
-                                           std::move(foreign_socket_));
   audio_output_ptr->SetVolume(-0.5);
   base::RunLoop().RunUntilIdle();
   Mock::VerifyAndClear(&deleter_);
@@ -289,7 +273,8 @@
 
 TEST_F(MojoAudioOutputStreamTest, DelegateErrorBeforeCreated_PropagatesError) {
   AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
-  EXPECT_CALL(deleter_, Finished(true));
+  EXPECT_CALL(deleter_, Finished());
+  EXPECT_CALL(client_, OnError()).Times(1);
 
   ASSERT_NE(nullptr, delegate_event_handler_);
   delegate_event_handler_->OnStreamError(kStreamId);
@@ -301,7 +286,8 @@
 TEST_F(MojoAudioOutputStreamTest, DelegateErrorAfterCreated_PropagatesError) {
   AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
   EXPECT_CALL(client_, GotNotification());
-  EXPECT_CALL(deleter_, Finished(true));
+  EXPECT_CALL(deleter_, Finished());
+  EXPECT_CALL(client_, OnError()).Times(1);
   base::RunLoop().RunUntilIdle();
 
   ASSERT_NE(nullptr, delegate_event_handler_);
@@ -314,14 +300,9 @@
   Mock::VerifyAndClear(&deleter_);
 }
 
-TEST_F(MojoAudioOutputStreamTest, RemoteEndGone_CallsDeleter) {
+TEST_F(MojoAudioOutputStreamTest, RemoteEndGone_Error) {
   AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
-
-  EXPECT_CALL(client_, GotNotification());
-  EXPECT_CALL(deleter_, Finished(false));
-
-  delegate_event_handler_->OnStreamCreated(kStreamId, &mem_,
-                                           std::move(foreign_socket_));
+  EXPECT_CALL(deleter_, Finished());
   audio_output_ptr.reset();
   base::RunLoop().RunUntilIdle();
   Mock::VerifyAndClear(&deleter_);
diff --git a/media/renderers/BUILD.gn b/media/renderers/BUILD.gn
index 10b5d8f..5002ccf 100644
--- a/media/renderers/BUILD.gn
+++ b/media/renderers/BUILD.gn
@@ -15,6 +15,8 @@
     "audio_renderer_impl.h",
     "default_renderer_factory.cc",
     "default_renderer_factory.h",
+    "flinging_renderer_client_factory.cc",
+    "flinging_renderer_client_factory.h",
     "paint_canvas_video_renderer.cc",
     "paint_canvas_video_renderer.h",
     "remote_playback_client_wrapper.h",
diff --git a/media/renderers/flinging_renderer_client_factory.cc b/media/renderers/flinging_renderer_client_factory.cc
new file mode 100644
index 0000000..0343b95
--- /dev/null
+++ b/media/renderers/flinging_renderer_client_factory.cc
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/renderers/flinging_renderer_client_factory.h"
+
+#include "base/logging.h"
+#include "media/base/overlay_info.h"
+
+namespace media {
+
+FlingingRendererClientFactory::FlingingRendererClientFactory(
+    std::unique_ptr<RendererFactory> mojo_flinging_factory,
+    std::unique_ptr<RemotePlaybackClientWrapper> remote_playback_client)
+    : mojo_flinging_factory_(std::move(mojo_flinging_factory)),
+      remote_playback_client_(std::move(remote_playback_client)) {}
+
+FlingingRendererClientFactory::~FlingingRendererClientFactory() = default;
+
+std::unique_ptr<Renderer> FlingingRendererClientFactory::CreateRenderer(
+    const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
+    const scoped_refptr<base::TaskRunner>& worker_task_runner,
+    AudioRendererSink* audio_renderer_sink,
+    VideoRendererSink* video_renderer_sink,
+    const RequestOverlayInfoCB& request_overlay_info_cb,
+    const gfx::ColorSpace& target_color_space) {
+  DCHECK(IsFlingingActive());
+  return mojo_flinging_factory_->CreateRenderer(
+      media_task_runner, worker_task_runner, audio_renderer_sink,
+      video_renderer_sink, request_overlay_info_cb, target_color_space);
+}
+
+std::string FlingingRendererClientFactory::GetActivePresentationId() {
+  return remote_playback_client_->GetActivePresentationId();
+}
+
+bool FlingingRendererClientFactory::IsFlingingActive() {
+  return !GetActivePresentationId().empty();
+}
+
+}  // namespace media
diff --git a/media/renderers/flinging_renderer_client_factory.h b/media/renderers/flinging_renderer_client_factory.h
new file mode 100644
index 0000000..73a28a5
--- /dev/null
+++ b/media/renderers/flinging_renderer_client_factory.h
@@ -0,0 +1,55 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_RENDERERS_FLINGING_RENDERER_CLIENT_FACTORY_H_
+#define MEDIA_RENDERERS_FLINGING_RENDERER_CLIENT_FACTORY_H_
+
+#include "media/base/media_export.h"
+#include "media/base/renderer_factory.h"
+#include "media/renderers/remote_playback_client_wrapper.h"
+
+namespace media {
+
+// Creates a renderer for media flinging.
+// The FRCF uses a MojoRendererFactory to create a FlingingRenderer in the
+// browser process. The actual renderer returned by the FRCF is a MojoRenderer
+// directly (as opposed to a dedicated FlingingRendererClient), because all the
+// renderer needs to do is forward calls to the FlingingRenderer in the browser.
+class MEDIA_EXPORT FlingingRendererClientFactory : public RendererFactory {
+ public:
+  // |mojo_flinging_factory| should be created using
+  // HostedRendererType::kFlinging, and GetActivePresentationId()
+  // should be given to it through SetGetTypeSpecificIdCB().
+  FlingingRendererClientFactory(
+      std::unique_ptr<RendererFactory> mojo_flinging_factory,
+      std::unique_ptr<RemotePlaybackClientWrapper> remote_playback_client);
+  ~FlingingRendererClientFactory() override;
+
+  std::unique_ptr<Renderer> CreateRenderer(
+      const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
+      const scoped_refptr<base::TaskRunner>& worker_task_runner,
+      AudioRendererSink* audio_renderer_sink,
+      VideoRendererSink* video_renderer_sink,
+      const RequestOverlayInfoCB& request_overlay_info_cb,
+      const gfx::ColorSpace& target_color_space) override;
+
+  // Returns whether media flinging has started, based off of whether the
+  // |remote_playback_client_| has a presentation ID or not. Called by
+  // RendererFactorySelector to determine when to create a FlingingRenderer.
+  bool IsFlingingActive();
+
+  // Used by the |mojo_flinging_factory_| to retrieve the latest presentation ID
+  // when CreateRenderer() is called.
+  std::string GetActivePresentationId();
+
+ private:
+  std::unique_ptr<RendererFactory> mojo_flinging_factory_;
+  std::unique_ptr<RemotePlaybackClientWrapper> remote_playback_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(FlingingRendererClientFactory);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_RENDERERS_FLINGING_RENDERER_CLIENT_FACTORY_H_
diff --git a/media/test/data/multiple_cdm_types.html b/media/test/data/multiple_cdm_types.html
index ad313ea6..84a11fb 100644
--- a/media/test/data/multiple_cdm_types.html
+++ b/media/test/data/multiple_cdm_types.html
@@ -79,7 +79,9 @@
     session3 = session;
     log('Crash session2');
     return session.update(crashJwkSet);
-  }).then(function() {
+  }).finally(function() {
+    // Due to the crash, the update() above could resolve or reject.
+    // So use "finally" so that we continue the test regardless.
     log('Session2 crashed');
     return session2.closed;
   }).then(function() {
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index a6f4b27..21546bb 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -692,13 +692,13 @@
   }
   void SetChannelID(std::unique_ptr<ChannelID> channel_id) override {}
   void DeleteChannelID(const std::string& server_identifier,
-                       const base::Closure& completion_callback) override {}
+                       base::OnceClosure completion_callback) override {}
   void DeleteForDomainsCreatedBetween(
       const base::Callback<bool(const std::string&)>& domain_predicate,
       base::Time delete_begin,
       base::Time delete_end,
-      const base::Closure& completion_callback) override {}
-  void DeleteAll(const base::Closure& completion_callback) override {}
+      base::OnceClosure completion_callback) override {}
+  void DeleteAll(base::OnceClosure completion_callback) override {}
   void GetAllChannelIDs(const GetChannelIDListCallback& callback) override {}
   int GetChannelIDCount() override { return 0; }
   void SetForceKeepSessionState() override {}
@@ -719,13 +719,13 @@
   }
   void SetChannelID(std::unique_ptr<ChannelID> channel_id) override {}
   void DeleteChannelID(const std::string& server_identifier,
-                       const base::Closure& completion_callback) override {}
+                       base::OnceClosure completion_callback) override {}
   void DeleteForDomainsCreatedBetween(
       const base::Callback<bool(const std::string&)>& domain_predicate,
       base::Time delete_begin,
       base::Time delete_end,
-      const base::Closure& completion_callback) override {}
-  void DeleteAll(const base::Closure& completion_callback) override {}
+      base::OnceClosure completion_callback) override {}
+  void DeleteAll(base::OnceClosure completion_callback) override {}
   void GetAllChannelIDs(const GetChannelIDListCallback& callback) override {}
   int GetChannelIDCount() override { return 0; }
   void SetForceKeepSessionState() override {}
diff --git a/net/ssl/channel_id_store.h b/net/ssl/channel_id_store.h
index da4d195c..8e8e5c27 100644
--- a/net/ssl/channel_id_store.h
+++ b/net/ssl/channel_id_store.h
@@ -53,10 +53,11 @@
 
   typedef std::list<ChannelID> ChannelIDList;
 
-  typedef base::Callback<
+  typedef base::RepeatingCallback<
       void(int, const std::string&, std::unique_ptr<crypto::ECPrivateKey>)>
       GetChannelIDCallback;
-  typedef base::Callback<void(const ChannelIDList&)> GetChannelIDListCallback;
+  typedef base::RepeatingCallback<void(const ChannelIDList&)>
+      GetChannelIDListCallback;
 
   virtual ~ChannelIDStore();
 
@@ -74,9 +75,8 @@
   virtual void SetChannelID(std::unique_ptr<ChannelID> channel_id) = 0;
 
   // Removes a keypair from the store.
-  virtual void DeleteChannelID(
-      const std::string& server_identifier,
-      const base::Closure& completion_callback) = 0;
+  virtual void DeleteChannelID(const std::string& server_identifier,
+                               base::OnceClosure completion_callback) = 0;
 
   // Deletes the channel ID keypairs that have a creation_date greater than
   // or equal to |delete_begin| and less than |delete_end| and whose server
@@ -86,10 +86,10 @@
       const base::Callback<bool(const std::string&)>& domain_predicate,
       base::Time delete_begin,
       base::Time delete_end,
-      const base::Closure& completion_callback) = 0;
+      base::OnceClosure completion_callback) = 0;
 
   // Removes all channel ID keypairs from the store.
-  virtual void DeleteAll(const base::Closure& completion_callback) = 0;
+  virtual void DeleteAll(base::OnceClosure completion_callback) = 0;
 
   // Returns all channel ID keypairs.
   virtual void GetAllChannelIDs(const GetChannelIDListCallback& callback) = 0;
diff --git a/net/ssl/default_channel_id_store.cc b/net/ssl/default_channel_id_store.cc
index 34f656a..218d13f 100644
--- a/net/ssl/default_channel_id_store.cc
+++ b/net/ssl/default_channel_id_store.cc
@@ -33,15 +33,15 @@
   virtual void Run(DefaultChannelIDStore* store) = 0;
 
  protected:
-  void InvokeCallback(base::Closure callback) const;
+  void InvokeCallback(base::OnceClosure callback) const;
 };
 
 DefaultChannelIDStore::Task::~Task() = default;
 
 void DefaultChannelIDStore::Task::InvokeCallback(
-    base::Closure callback) const {
+    base::OnceClosure callback) const {
   if (!callback.is_null())
-    callback.Run();
+    std::move(callback).Run();
 }
 
 // --------------------------------------------------------------------------
@@ -75,8 +75,8 @@
                                 GetChannelIDCallback());
   DCHECK(err != ERR_IO_PENDING);
 
-  InvokeCallback(base::Bind(callback_, err, server_identifier_,
-                            base::Passed(std::move(key_result))));
+  InvokeCallback(base::BindOnce(callback_, err, server_identifier_,
+                                std::move(key_result)));
 }
 
 // --------------------------------------------------------------------------
@@ -109,22 +109,19 @@
     : public DefaultChannelIDStore::Task {
  public:
   DeleteChannelIDTask(const std::string& server_identifier,
-                      const base::Closure& callback);
+                      base::OnceClosure callback);
   ~DeleteChannelIDTask() override;
   void Run(DefaultChannelIDStore* store) override;
 
  private:
   std::string server_identifier_;
-  base::Closure callback_;
+  base::OnceClosure callback_;
 };
 
-DefaultChannelIDStore::DeleteChannelIDTask::
-    DeleteChannelIDTask(
-        const std::string& server_identifier,
-        const base::Closure& callback)
-        : server_identifier_(server_identifier),
-          callback_(callback) {
-}
+DefaultChannelIDStore::DeleteChannelIDTask::DeleteChannelIDTask(
+    const std::string& server_identifier,
+    base::OnceClosure callback)
+    : server_identifier_(server_identifier), callback_(std::move(callback)) {}
 
 DefaultChannelIDStore::DeleteChannelIDTask::~DeleteChannelIDTask() = default;
 
@@ -132,7 +129,7 @@
     DefaultChannelIDStore* store) {
   store->SyncDeleteChannelID(server_identifier_);
 
-  InvokeCallback(callback_);
+  InvokeCallback(std::move(callback_));
 }
 
 // --------------------------------------------------------------------------
@@ -144,7 +141,7 @@
       const base::Callback<bool(const std::string&)>& domain_predicate,
       base::Time delete_begin,
       base::Time delete_end,
-      const base::Closure& callback);
+      base::OnceClosure callback);
   ~DeleteForDomainsCreatedBetweenTask() override;
   void Run(DefaultChannelIDStore* store) override;
 
@@ -152,7 +149,7 @@
   const base::Callback<bool(const std::string&)> domain_predicate_;
   base::Time delete_begin_;
   base::Time delete_end_;
-  base::Closure callback_;
+  base::OnceClosure callback_;
 };
 
 DefaultChannelIDStore::DeleteForDomainsCreatedBetweenTask::
@@ -160,11 +157,11 @@
         const base::Callback<bool(const std::string&)>& domain_predicate,
         base::Time delete_begin,
         base::Time delete_end,
-        const base::Closure& callback)
+        base::OnceClosure callback)
     : domain_predicate_(domain_predicate),
       delete_begin_(delete_begin),
       delete_end_(delete_end),
-      callback_(callback) {}
+      callback_(std::move(callback)) {}
 
 DefaultChannelIDStore::DeleteForDomainsCreatedBetweenTask::
     ~DeleteForDomainsCreatedBetweenTask() = default;
@@ -174,7 +171,7 @@
   store->SyncDeleteForDomainsCreatedBetween(domain_predicate_, delete_begin_,
                                             delete_end_);
 
-  InvokeCallback(callback_);
+  InvokeCallback(std::move(callback_));
 }
 
 // --------------------------------------------------------------------------
@@ -203,7 +200,7 @@
   ChannelIDList key_list;
   store->SyncGetAllChannelIDs(&key_list);
 
-  InvokeCallback(base::Bind(callback_, key_list));
+  InvokeCallback(base::BindOnce(std::move(callback_), key_list));
 }
 
 // --------------------------------------------------------------------------
@@ -248,24 +245,23 @@
 
 void DefaultChannelIDStore::DeleteChannelID(
     const std::string& server_identifier,
-    const base::Closure& callback) {
+    base::OnceClosure callback) {
   RunOrEnqueueTask(std::unique_ptr<Task>(
-      new DeleteChannelIDTask(server_identifier, callback)));
+      new DeleteChannelIDTask(server_identifier, std::move(callback))));
 }
 
 void DefaultChannelIDStore::DeleteForDomainsCreatedBetween(
     const base::Callback<bool(const std::string&)>& domain_predicate,
     base::Time delete_begin,
     base::Time delete_end,
-    const base::Closure& callback) {
+    base::OnceClosure callback) {
   RunOrEnqueueTask(std::unique_ptr<Task>(new DeleteForDomainsCreatedBetweenTask(
-      domain_predicate, delete_begin, delete_end, callback)));
+      domain_predicate, delete_begin, delete_end, std::move(callback))));
 }
 
-void DefaultChannelIDStore::DeleteAll(
-    const base::Closure& callback) {
+void DefaultChannelIDStore::DeleteAll(base::OnceClosure callback) {
   DeleteForDomainsCreatedBetween(base::Bind(&AllDomainsPredicate), base::Time(),
-                                 base::Time(), callback);
+                                 base::Time(), std::move(callback));
 }
 
 void DefaultChannelIDStore::GetAllChannelIDs(
diff --git a/net/ssl/default_channel_id_store.h b/net/ssl/default_channel_id_store.h
index bc5ab07..da94d78 100644
--- a/net/ssl/default_channel_id_store.h
+++ b/net/ssl/default_channel_id_store.h
@@ -52,13 +52,13 @@
                    const GetChannelIDCallback& callback) override;
   void SetChannelID(std::unique_ptr<ChannelID> channel_id) override;
   void DeleteChannelID(const std::string& server_identifier,
-                       const base::Closure& callback) override;
+                       base::OnceClosure callback) override;
   void DeleteForDomainsCreatedBetween(
       const base::Callback<bool(const std::string&)>& domain_predicate,
       base::Time delete_begin,
       base::Time delete_end,
-      const base::Closure& callback) override;
-  void DeleteAll(const base::Closure& callback) override;
+      base::OnceClosure callback) override;
+  void DeleteAll(base::OnceClosure callback) override;
   void GetAllChannelIDs(const GetChannelIDListCallback& callback) override;
   void Flush() override;
   int GetChannelIDCount() override;
diff --git a/services/audio/output_stream.cc b/services/audio/output_stream.cc
index f1bbfbb..02f7f24 100644
--- a/services/audio/output_stream.cc
+++ b/services/audio/output_stream.cc
@@ -22,6 +22,7 @@
     CreatedCallback created_callback,
     DeleteCallback delete_callback,
     media::mojom::AudioOutputStreamRequest stream_request,
+    media::mojom::AudioOutputStreamClientPtr client,
     media::mojom::AudioOutputStreamObserverAssociatedPtr observer,
     media::mojom::AudioLogPtr log,
     media::AudioManager* audio_manager,
@@ -32,6 +33,7 @@
     : foreign_socket_(),
       delete_callback_(std::move(delete_callback)),
       binding_(this, std::move(stream_request)),
+      client_(std::move(client)),
       observer_(std::move(observer)),
       log_(media::mojom::ThreadSafeAudioLogPtr::Create(std::move(log))),
       coordinator_(coordinator),
@@ -48,6 +50,7 @@
                   &reader_),
       weak_factory_(this) {
   DCHECK(binding_.is_bound());
+  DCHECK(client_.is_bound());
   DCHECK(observer_.is_bound());
   DCHECK(created_callback);
   DCHECK(delete_callback_);
@@ -57,6 +60,7 @@
   base::RepeatingClosure error_handler =
       base::BindRepeating(&OutputStream::OnError, base::Unretained(this));
   binding_.set_connection_error_handler(error_handler);
+  client_.set_connection_error_handler(error_handler);
 
   // We allow the observer to terminate the stream by closing the message pipe.
   observer_.set_connection_error_handler(std::move(error_handler));
@@ -178,10 +182,8 @@
 void OutputStream::OnControllerError() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
 
-  // Only propagate platform errors to the observer.
-  observer_.ResetWithReason(
-      media::mojom::AudioOutputStreamObserver::kPlatformErrorDisconnectReason,
-      std::string());
+  // Only propagate platform errors to the renderer.
+  client_->OnError();
   log_->get()->OnError();
   OnError();
 }
diff --git a/services/audio/output_stream.h b/services/audio/output_stream.h
index aa04feb..939854e 100644
--- a/services/audio/output_stream.h
+++ b/services/audio/output_stream.h
@@ -48,6 +48,7 @@
   OutputStream(CreatedCallback created_callback,
                DeleteCallback delete_callback,
                media::mojom::AudioOutputStreamRequest stream_request,
+               media::mojom::AudioOutputStreamClientPtr client,
                media::mojom::AudioOutputStreamObserverAssociatedPtr observer,
                media::mojom::AudioLogPtr log,
                media::AudioManager* audio_manager,
@@ -81,6 +82,7 @@
   base::CancelableSyncSocket foreign_socket_;
   DeleteCallback delete_callback_;
   mojo::Binding<AudioOutputStream> binding_;
+  media::mojom::AudioOutputStreamClientPtr client_;
   media::mojom::AudioOutputStreamObserverAssociatedPtr observer_;
   const scoped_refptr<media::mojom::ThreadSafeAudioLogPtr> log_;
   GroupCoordinator* const coordinator_;
diff --git a/services/audio/output_stream_unittest.cc b/services/audio/output_stream_unittest.cc
index 9b8e82ec..5c40fd8 100644
--- a/services/audio/output_stream_unittest.cc
+++ b/services/audio/output_stream_unittest.cc
@@ -52,7 +52,30 @@
   DISALLOW_COPY_AND_ASSIGN(MockStream);
 };
 
-const uint32_t kNoDisconnectReason = 0;
+class MockClient : public media::mojom::AudioOutputStreamClient {
+ public:
+  MockClient() : binding_(this) {}
+
+  media::mojom::AudioOutputStreamClientPtr MakePtr() {
+    DCHECK(!binding_.is_bound());
+    media::mojom::AudioOutputStreamClientPtr ptr;
+    binding_.Bind(mojo::MakeRequest(&ptr));
+    binding_.set_connection_error_handler(base::BindOnce(
+        &MockClient::BindingConnectionError, base::Unretained(this)));
+    return ptr;
+  }
+
+  void CloseBinding() { binding_.Close(); }
+
+  MOCK_METHOD0(OnError, void());
+
+  MOCK_METHOD0(BindingConnectionError, void());
+
+ private:
+  mojo::Binding<media::mojom::AudioOutputStreamClient> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockClient);
+};
 
 class MockObserver : public media::mojom::AudioOutputStreamObserver {
  public:
@@ -62,7 +85,7 @@
     DCHECK(!binding_.is_bound());
     media::mojom::AudioOutputStreamObserverAssociatedPtrInfo ptr_info;
     binding_.Bind(mojo::MakeRequest(&ptr_info));
-    binding_.set_connection_error_with_reason_handler(base::BindOnce(
+    binding_.set_connection_error_handler(base::BindOnce(
         &MockObserver::BindingConnectionError, base::Unretained(this)));
     return ptr_info;
   }
@@ -73,8 +96,7 @@
   MOCK_METHOD0(DidStopPlaying, void());
   MOCK_METHOD1(DidChangeAudibleState, void(bool));
 
-  MOCK_METHOD2(BindingConnectionError,
-               void(uint32_t /*disconnect_reason*/, const std::string&));
+  MOCK_METHOD0(BindingConnectionError, void());
 
  private:
   mojo::AssociatedBinding<media::mojom::AudioOutputStreamObserver> binding_;
@@ -125,14 +147,17 @@
   media::mojom::AudioOutputStreamPtr CreateStream() {
     media::mojom::AudioOutputStreamPtr stream_ptr;
     stream_factory_ptr_->CreateOutputStream(
-        mojo::MakeRequest(&stream_ptr), observer_.MakePtrInfo(), log_.MakePtr(),
-        "", media::AudioParameters::UnavailableDeviceParams(),
+        mojo::MakeRequest(&stream_ptr), client_.MakePtr(),
+        observer_.MakePtrInfo(), log_.MakePtr(), "",
+        media::AudioParameters::UnavailableDeviceParams(),
         base::UnguessableToken::Create(), created_callback_.Get());
     return stream_ptr;
   }
 
   media::MockAudioManager& audio_manager() { return audio_manager_; }
 
+  MockClient& client() { return client_; }
+
   MockObserver& observer() { return observer_; }
 
   MockLog& log() { return log_; }
@@ -149,6 +174,7 @@
   StreamFactory stream_factory_;
   mojom::StreamFactoryPtr stream_factory_ptr_;
   mojo::Binding<mojom::StreamFactory> stream_factory_binding_;
+  StrictMock<MockClient> client_;
   StrictMock<MockObserver> observer_;
   NiceMock<MockLog> log_;
   StrictMock<MockCreatedCallback> created_callback_;
@@ -177,7 +203,8 @@
 
   EXPECT_CALL(env.log(), OnClosed());
   EXPECT_CALL(mock_stream, Close());
-  EXPECT_CALL(env.observer(), BindingConnectionError(kNoDisconnectReason, _));
+  EXPECT_CALL(env.observer(), BindingConnectionError());
+  EXPECT_CALL(env.client(), BindingConnectionError());
   stream_ptr.reset();
   base::RunLoop().RunUntilIdle();
 }
@@ -201,11 +228,41 @@
   Mock::VerifyAndClear(&env.created_callback());
 
   EXPECT_CALL(mock_stream, Close());
+  EXPECT_CALL(env.client(), BindingConnectionError());
 
   env.observer().CloseBinding();
   base::RunLoop().RunUntilIdle();
 
   Mock::VerifyAndClear(&mock_stream);
+  Mock::VerifyAndClear(&env.client());
+}
+
+TEST(AudioServiceOutputStreamTest,
+     ConstructStreamAndDestructClient_DestructsStream) {
+  TestEnvironment env;
+  MockStream mock_stream;
+  env.audio_manager().SetMakeOutputStreamCB(base::BindRepeating(
+      [](media::AudioOutputStream* stream, const media::AudioParameters& params,
+         const std::string& device_id) { return stream; },
+      &mock_stream));
+
+  EXPECT_CALL(env.created_callback(), Created(successfully_));
+  EXPECT_CALL(mock_stream, Open()).WillOnce(Return(true));
+  EXPECT_CALL(mock_stream, SetVolume(1));
+
+  media::mojom::AudioOutputStreamPtr stream_ptr = env.CreateStream();
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClear(&mock_stream);
+  Mock::VerifyAndClear(&env.created_callback());
+
+  EXPECT_CALL(mock_stream, Close());
+  EXPECT_CALL(env.observer(), BindingConnectionError());
+
+  env.client().CloseBinding();
+  base::RunLoop().RunUntilIdle();
+
+  Mock::VerifyAndClear(&mock_stream);
+  Mock::VerifyAndClear(&env.observer());
 }
 
 TEST(AudioServiceOutputStreamTest,
@@ -227,12 +284,14 @@
   Mock::VerifyAndClear(&env.created_callback());
 
   EXPECT_CALL(mock_stream, Close());
-  EXPECT_CALL(env.observer(), BindingConnectionError(kNoDisconnectReason, _));
+  EXPECT_CALL(env.observer(), BindingConnectionError());
+  EXPECT_CALL(env.client(), BindingConnectionError());
 
   stream_ptr.reset();
   base::RunLoop().RunUntilIdle();
 
   Mock::VerifyAndClear(&mock_stream);
+  Mock::VerifyAndClear(&env.client());
   Mock::VerifyAndClear(&env.observer());
 }
 
@@ -268,7 +327,8 @@
   EXPECT_CALL(mock_stream, Close());
   EXPECT_CALL(env.observer(), DidChangeAudibleState(false)).Times(AtMost(1));
   EXPECT_CALL(env.observer(), DidStopPlaying()).Times(AtMost(1));
-  EXPECT_CALL(env.observer(), BindingConnectionError(kNoDisconnectReason, _));
+  EXPECT_CALL(env.observer(), BindingConnectionError());
+  EXPECT_CALL(env.client(), BindingConnectionError());
   stream_ptr.reset();
   base::RunLoop().RunUntilIdle();
 }
@@ -310,7 +370,8 @@
   Mock::VerifyAndClear(&env.observer());
 
   EXPECT_CALL(mock_stream, Close());
-  EXPECT_CALL(env.observer(), BindingConnectionError(kNoDisconnectReason, _));
+  EXPECT_CALL(env.observer(), BindingConnectionError());
+  EXPECT_CALL(env.client(), BindingConnectionError());
   stream_ptr.reset();
   base::RunLoop().RunUntilIdle();
 }
@@ -340,7 +401,8 @@
   Mock::VerifyAndClear(&mock_stream);
 
   EXPECT_CALL(mock_stream, Close());
-  EXPECT_CALL(env.observer(), BindingConnectionError(kNoDisconnectReason, _));
+  EXPECT_CALL(env.observer(), BindingConnectionError());
+  EXPECT_CALL(env.client(), BindingConnectionError());
   stream_ptr.reset();
   base::RunLoop().RunUntilIdle();
 }
@@ -363,7 +425,8 @@
   Mock::VerifyAndClear(&env.created_callback());
 
   EXPECT_CALL(mock_stream, Close());
-  EXPECT_CALL(env.observer(), BindingConnectionError(kNoDisconnectReason, _));
+  EXPECT_CALL(env.observer(), BindingConnectionError());
+  EXPECT_CALL(env.client(), BindingConnectionError());
   EXPECT_CALL(env.bad_message_callback(), Run(_));
   stream_ptr->SetVolume(-0.1);
   base::RunLoop().RunUntilIdle();
@@ -387,7 +450,8 @@
   Mock::VerifyAndClear(&env.created_callback());
 
   EXPECT_CALL(mock_stream, Close());
-  EXPECT_CALL(env.observer(), BindingConnectionError(kNoDisconnectReason, _));
+  EXPECT_CALL(env.observer(), BindingConnectionError());
+  EXPECT_CALL(env.client(), BindingConnectionError());
   EXPECT_CALL(env.bad_message_callback(), Run(_));
   stream_ptr->SetVolume(1.1);
   base::RunLoop().RunUntilIdle();
@@ -402,12 +466,12 @@
   media::mojom::AudioOutputStreamPtr stream_ptr = env.CreateStream();
 
   EXPECT_CALL(env.created_callback(), Created(unsuccessfully_));
-  EXPECT_CALL(env.observer(),
-              BindingConnectionError(media::mojom::AudioOutputStreamObserver::
-                                         kPlatformErrorDisconnectReason,
-                                     _));
+  EXPECT_CALL(env.observer(), BindingConnectionError());
   EXPECT_CALL(env.log(), OnError());
+  EXPECT_CALL(env.client(), OnError());
+  EXPECT_CALL(env.client(), BindingConnectionError());
   base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClear(&env.client());
   Mock::VerifyAndClear(&env.observer());
 }
 
@@ -422,12 +486,12 @@
   media::mojom::AudioOutputStreamPtr stream_ptr = env.CreateStream();
   EXPECT_CALL(env.created_callback(), Created(unsuccessfully_));
 
-  EXPECT_CALL(env.observer(),
-              BindingConnectionError(media::mojom::AudioOutputStreamObserver::
-                                         kPlatformErrorDisconnectReason,
-                                     _));
+  EXPECT_CALL(env.observer(), BindingConnectionError());
+  EXPECT_CALL(env.client(), OnError());
+  EXPECT_CALL(env.client(), BindingConnectionError());
 
   base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClear(&env.client());
   Mock::VerifyAndClear(&env.observer());
 }
 
diff --git a/services/audio/public/mojom/stream_factory.mojom b/services/audio/public/mojom/stream_factory.mojom
index 91bc545c8..9e9a6dcc 100644
--- a/services/audio/public/mojom/stream_factory.mojom
+++ b/services/audio/public/mojom/stream_factory.mojom
@@ -50,6 +50,7 @@
   // will later be used for muting streams or capturing them for loopback.
   CreateOutputStream(
     media.mojom.AudioOutputStream& stream,
+    media.mojom.AudioOutputStreamClient client,
     associated media.mojom.AudioOutputStreamObserver observer,
     media.mojom.AudioLog log,
     string device_id, media.mojom.AudioParameters params,
diff --git a/services/audio/stream_factory.cc b/services/audio/stream_factory.cc
index cf1866a9..9c442ee6 100644
--- a/services/audio/stream_factory.cc
+++ b/services/audio/stream_factory.cc
@@ -54,6 +54,7 @@
 
 void StreamFactory::CreateOutputStream(
     media::mojom::AudioOutputStreamRequest stream_request,
+    media::mojom::AudioOutputStreamClientPtr client,
     media::mojom::AudioOutputStreamObserverAssociatedPtrInfo observer_info,
     media::mojom::AudioLogPtr log,
     const std::string& output_device_id,
@@ -71,8 +72,9 @@
 
   output_streams_.insert(std::make_unique<OutputStream>(
       std::move(created_callback), std::move(deleter_callback),
-      std::move(stream_request), std::move(observer), std::move(log),
-      audio_manager_, output_device_id, params, &coordinator_, group_id));
+      std::move(stream_request), std::move(client), std::move(observer),
+      std::move(log), audio_manager_, output_device_id, params, &coordinator_,
+      group_id));
 }
 
 void StreamFactory::BindMuter(mojom::LocalMuterAssociatedRequest request,
diff --git a/services/audio/stream_factory.h b/services/audio/stream_factory.h
index 185b0177..3ef6673 100644
--- a/services/audio/stream_factory.h
+++ b/services/audio/stream_factory.h
@@ -65,6 +65,7 @@
 
   void CreateOutputStream(
       media::mojom::AudioOutputStreamRequest stream_request,
+      media::mojom::AudioOutputStreamClientPtr client,
       media::mojom::AudioOutputStreamObserverAssociatedPtrInfo observer_info,
       media::mojom::AudioLogPtr log,
       const std::string& output_device_id,
diff --git a/services/device/media_transfer_protocol/mtp_device_manager.cc b/services/device/media_transfer_protocol/mtp_device_manager.cc
index 4c28628..c7b49e3 100644
--- a/services/device/media_transfer_protocol/mtp_device_manager.cc
+++ b/services/device/media_transfer_protocol/mtp_device_manager.cc
@@ -41,6 +41,36 @@
   std::move(callback).Run(std::move(storage_info_ptr_list));
 }
 
+void GetStorageInfoCallbackWrapper(
+    mojom::MtpManager::GetStorageInfoCallback callback,
+    const mojom::MtpStorageInfo* storage_info) {
+  std::move(callback).Run(storage_info->Clone());
+}
+
+void GetStorageInfoFromDeviceCallbackWrapper(
+    mojom::MtpManager::GetStorageInfoFromDeviceCallback callback,
+    const mojom::MtpStorageInfo& storage_info,
+    bool error) {
+  std::move(callback).Run(storage_info.Clone(), error);
+}
+
+void ReadDirectoryCallbackWrapper(
+    mojom::MtpManager::ReadDirectoryCallback callback,
+    const std::vector<mojom::MtpFileEntry>& file_entries,
+    bool has_more,
+    bool error) {
+  std::vector<mojom::MtpFileEntryPtr> files(file_entries.size());
+  for (size_t i = 0; i < file_entries.size(); ++i)
+    files[i] = file_entries[i].Clone();
+  std::move(callback).Run(std::move(files), has_more, error);
+}
+
+void GetFileInfoCallbackWrapper(mojom::MtpManager::GetFileInfoCallback callback,
+                                const mojom::MtpFileEntry& file_entry,
+                                bool error) {
+  std::move(callback).Run(file_entry.Clone(), error);
+}
+
 }  // namespace
 
 MtpDeviceManager::MtpDeviceManager() {}
@@ -51,7 +81,6 @@
   bindings_.AddBinding(this, std::move(request));
 }
 
-// mojom::MtpManager override.
 void MtpDeviceManager::EnumerateStoragesAndSetClient(
     mojom::MtpManagerClientAssociatedPtrInfo client,
     EnumerateStoragesAndSetClientCallback callback) {
@@ -68,4 +97,98 @@
       base::BindOnce(EnumerateStorageCallbackWrapper, std::move(callback)));
 }
 
+void MtpDeviceManager::GetStorageInfo(const std::string& storage_name,
+                                      GetStorageInfoCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->GetStorageInfo(
+      storage_name,
+      base::BindOnce(GetStorageInfoCallbackWrapper, std::move(callback)));
+}
+
+void MtpDeviceManager::GetStorageInfoFromDevice(
+    const std::string& storage_name,
+    GetStorageInfoFromDeviceCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->GetStorageInfoFromDevice(
+      storage_name,
+      base::Bind(GetStorageInfoFromDeviceCallbackWrapper,
+                 base::AdaptCallbackForRepeating(std::move(callback))));
+}
+
+void MtpDeviceManager::OpenStorage(const std::string& storage_name,
+                                   const std::string& mode,
+                                   OpenStorageCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->OpenStorage(
+      storage_name, mode, base::AdaptCallbackForRepeating(std::move(callback)));
+}
+
+void MtpDeviceManager::CloseStorage(const std::string& storage_handle,
+                                    CloseStorageCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->CloseStorage(
+      storage_handle, base::AdaptCallbackForRepeating(std::move(callback)));
+}
+
+void MtpDeviceManager::CreateDirectory(const std::string& storage_handle,
+                                       uint32_t parent_id,
+                                       const std::string& directory_name,
+                                       CreateDirectoryCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->CreateDirectory(
+      storage_handle, parent_id, directory_name,
+      base::AdaptCallbackForRepeating(std::move(callback)));
+}
+
+void MtpDeviceManager::ReadDirectory(const std::string& storage_handle,
+                                     uint32_t file_id,
+                                     uint64_t max_size,
+                                     ReadDirectoryCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->ReadDirectory(
+      storage_handle, file_id, max_size,
+      base::Bind(ReadDirectoryCallbackWrapper,
+                 base::AdaptCallbackForRepeating(std::move(callback))));
+}
+
+void MtpDeviceManager::ReadFileChunk(const std::string& storage_handle,
+                                     uint32_t file_id,
+                                     uint32_t offset,
+                                     uint32_t count,
+                                     ReadFileChunkCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->ReadFileChunk(
+      storage_handle, file_id, offset, count,
+      base::AdaptCallbackForRepeating(std::move(callback)));
+}
+
+void MtpDeviceManager::GetFileInfo(const std::string& storage_handle,
+                                   uint32_t file_id,
+                                   GetFileInfoCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->GetFileInfo(
+      storage_handle, file_id,
+      base::Bind(GetFileInfoCallbackWrapper,
+                 base::AdaptCallbackForRepeating(std::move(callback))));
+}
+
+void MtpDeviceManager::RenameObject(const std::string& storage_handle,
+                                    uint32_t object_id,
+                                    const std::string& new_name,
+                                    RenameObjectCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->RenameObject(
+      storage_handle, object_id, new_name,
+      base::AdaptCallbackForRepeating(std::move(callback)));
+}
+
+void MtpDeviceManager::CopyFileFromLocal(const std::string& storage_handle,
+                                         int64_t source_file_descriptor,
+                                         uint32_t parent_id,
+                                         const std::string& file_name,
+                                         CopyFileFromLocalCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->CopyFileFromLocal(
+      storage_handle, source_file_descriptor, parent_id, file_name,
+      base::AdaptCallbackForRepeating(std::move(callback)));
+}
+
+void MtpDeviceManager::DeleteObject(const std::string& storage_handle,
+                                    uint32_t object_id,
+                                    DeleteObjectCallback callback) {
+  MediaTransferProtocolManager::GetInstance()->DeleteObject(
+      storage_handle, object_id,
+      base::AdaptCallbackForRepeating(std::move(callback)));
+}
+
 }  // namespace device
diff --git a/services/device/media_transfer_protocol/mtp_device_manager.h b/services/device/media_transfer_protocol/mtp_device_manager.h
index 6632621..11d9667 100644
--- a/services/device/media_transfer_protocol/mtp_device_manager.h
+++ b/services/device/media_transfer_protocol/mtp_device_manager.h
@@ -32,6 +32,44 @@
   void EnumerateStoragesAndSetClient(
       mojom::MtpManagerClientAssociatedPtrInfo client,
       EnumerateStoragesAndSetClientCallback callback) override;
+  void GetStorageInfo(const std::string& storage_name,
+                      GetStorageInfoCallback callback) override;
+  void GetStorageInfoFromDevice(
+      const std::string& storage_name,
+      GetStorageInfoFromDeviceCallback callback) override;
+  void OpenStorage(const std::string& storage_name,
+                   const std::string& mode,
+                   OpenStorageCallback callback) override;
+  void CloseStorage(const std::string& storage_handle,
+                    CloseStorageCallback callback) override;
+  void CreateDirectory(const std::string& storage_handle,
+                       uint32_t parent_id,
+                       const std::string& directory_name,
+                       CreateDirectoryCallback callback) override;
+  void ReadDirectory(const std::string& storage_handle,
+                     uint32_t file_id,
+                     uint64_t max_size,
+                     ReadDirectoryCallback callback) override;
+  void ReadFileChunk(const std::string& storage_handle,
+                     uint32_t file_id,
+                     uint32_t offset,
+                     uint32_t count,
+                     ReadFileChunkCallback callback) override;
+  void GetFileInfo(const std::string& storage_handle,
+                   uint32_t file_id,
+                   GetFileInfoCallback callback) override;
+  void RenameObject(const std::string& storage_handle,
+                    uint32_t object_id,
+                    const std::string& new_name,
+                    RenameObjectCallback callback) override;
+  void CopyFileFromLocal(const std::string& storage_handle,
+                         int64_t source_file_descriptor,
+                         uint32_t parent_id,
+                         const std::string& file_name,
+                         CopyFileFromLocalCallback callback) override;
+  void DeleteObject(const std::string& storage_handle,
+                    uint32_t object_id,
+                    DeleteObjectCallback callback) override;
 
  private:
   std::unique_ptr<MediaTransferProtocolManager::Observer> observer_;
diff --git a/services/device/public/mojom/mtp_manager.mojom b/services/device/public/mojom/mtp_manager.mojom
index dc98a5e..09527f52 100644
--- a/services/device/public/mojom/mtp_manager.mojom
+++ b/services/device/public/mojom/mtp_manager.mojom
@@ -4,6 +4,7 @@
 
 module device.mojom;
 
+import "device/media_transfer_protocol/public/mojom/mtp_file_entry.mojom";
 import "device/media_transfer_protocol/public/mojom/mtp_storage_info.mojom";
 
 interface MtpManagerClient {
@@ -21,4 +22,57 @@
   // the client being set and storage updates being made.
   EnumerateStoragesAndSetClient(associated MtpManagerClient client) =>
     (array<MtpStorageInfo> storages);
+
+  // Gets storage metadata for |storage_name|.
+  GetStorageInfo(string storage_name) =>
+    (MtpStorageInfo storage_info);
+
+  // Reads the metadata of |storage_name| from device.
+  GetStorageInfoFromDevice(string storage_name) =>
+    (MtpStorageInfo storage_info, bool error);
+
+  // Opens |storage_name| in |mode|.
+  OpenStorage(string storage_name, string mode) =>
+    (string storage_handle, bool error);
+
+  // Closes |storage_handle|.
+  CloseStorage(string storage_handle) => (bool error);
+
+  // Creates |directory_name| in |parent_id|.
+  CreateDirectory(string storage_handle, uint32 parent_id,
+      string directory_name) => (bool error);
+
+  // Reads directory entries from |file_id| on |storage_handle|.
+  // |max_size| is a maximum number of files to be read.
+  ReadDirectory(string storage_handle,
+      uint32 file_id, uint64 max_size) =>
+    (array<MtpFileEntry> file_entries, bool has_more, bool error);
+
+
+  // Reads file data from |file_id| on |storage_handle|.
+  // Reads |count| bytes of data starting at |offset|.
+  ReadFileChunk(string storage_handle,
+      uint32 file_id,
+      uint32 offset,
+      uint32 count) => (string data, bool error);
+
+  // Gets the file metadata for |file_id| on |storage_handle|.
+  GetFileInfo(string storage_handle,
+      uint32 file_id) =>
+    (MtpFileEntry file_entry, bool error);
+
+  // Renames |object_id| to |new_name|.
+  RenameObject(string storage_handle,
+      uint32 object_id,
+      string new_name) => (bool error);
+
+  // Copies the file from |source_file_descriptor| to |file_name| on
+  // |parent_id|.
+  CopyFileFromLocal(string storage_handle,
+      int64 source_file_descriptor,
+      uint32 parent_id,
+      string file_name) => (bool error);
+
+  // Deletes |object_id|.
+  DeleteObject(string storage_handle, uint32 object_id) => (bool error);
 };
diff --git a/services/network/http_cache_data_remover.cc b/services/network/http_cache_data_remover.cc
index 95c695bd..d3c8406 100644
--- a/services/network/http_cache_data_remover.cc
+++ b/services/network/http_cache_data_remover.cc
@@ -20,7 +20,7 @@
 
 namespace {
 
-bool DoesUrlMatchFilter(mojom::ClearCacheUrlFilter_Type filter_type,
+bool DoesUrlMatchFilter(mojom::ClearDataFilter_Type filter_type,
                         const std::set<url::Origin>& origins,
                         const std::set<std::string>& domains,
                         const GURL& url) {
@@ -34,13 +34,13 @@
   bool found_origin = (origins.find(url::Origin::Create(url)) != origins.end());
 
   return ((found_domain || found_origin) ==
-          (filter_type == mojom::ClearCacheUrlFilter_Type::DELETE_MATCHES));
+          (filter_type == mojom::ClearDataFilter_Type::DELETE_MATCHES));
 }
 
 }  // namespace
 
 HttpCacheDataRemover::HttpCacheDataRemover(
-    mojom::ClearCacheUrlFilterPtr url_filter,
+    mojom::ClearDataFilterPtr url_filter,
     base::Time delete_begin,
     base::Time delete_end,
     HttpCacheDataRemoverCallback done_callback)
@@ -69,7 +69,7 @@
 // static.
 std::unique_ptr<HttpCacheDataRemover> HttpCacheDataRemover::CreateAndStart(
     net::URLRequestContext* url_request_context,
-    mojom::ClearCacheUrlFilterPtr url_filter,
+    mojom::ClearDataFilterPtr url_filter,
     base::Time delete_begin,
     base::Time delete_end,
     HttpCacheDataRemoverCallback done_callback) {
diff --git a/services/network/http_cache_data_remover.h b/services/network/http_cache_data_remover.h
index 4108a5d..a8a32a6 100644
--- a/services/network/http_cache_data_remover.h
+++ b/services/network/http_cache_data_remover.h
@@ -41,7 +41,7 @@
   // interface and might be slow.
   static std::unique_ptr<HttpCacheDataRemover> CreateAndStart(
       net::URLRequestContext* url_request_context,
-      mojom::ClearCacheUrlFilterPtr url_filter,
+      mojom::ClearDataFilterPtr url_filter,
       base::Time delete_begin,
       base::Time delete_end,
       HttpCacheDataRemoverCallback done_callback);
@@ -49,7 +49,7 @@
   ~HttpCacheDataRemover();
 
  private:
-  HttpCacheDataRemover(mojom::ClearCacheUrlFilterPtr url_filter,
+  HttpCacheDataRemover(mojom::ClearDataFilterPtr url_filter,
                        base::Time delete_begin,
                        base::Time delete_end,
                        HttpCacheDataRemoverCallback done_callback);
diff --git a/services/network/http_cache_data_remover_unittest.cc b/services/network/http_cache_data_remover_unittest.cc
index 4aba258..23dc86b 100644
--- a/services/network/http_cache_data_remover_unittest.cc
+++ b/services/network/http_cache_data_remover_unittest.cc
@@ -104,7 +104,7 @@
               static_cast<size_t>(backend_->GetEntryCount()));
   }
 
-  void RemoveData(mojom::ClearCacheUrlFilterPtr filter,
+  void RemoveData(mojom::ClearDataFilterPtr filter,
                   base::Time start_time,
                   base::Time end_time) {
     base::RunLoop run_loop;
@@ -158,8 +158,8 @@
 }
 
 TEST_F(HttpCacheDataRemoverTest, FilterDeleteByDomain) {
-  mojom::ClearCacheUrlFilterPtr filter = mojom::ClearCacheUrlFilter::New();
-  filter->type = mojom::ClearCacheUrlFilter_Type::DELETE_MATCHES;
+  mojom::ClearDataFilterPtr filter = mojom::ClearDataFilter::New();
+  filter->type = mojom::ClearDataFilter_Type::DELETE_MATCHES;
   filter->domains.push_back("wikipedia.com");
   filter->domains.push_back("google.com");
   RemoveData(std::move(filter), base::Time(), base::Time());
@@ -171,8 +171,8 @@
 }
 
 TEST_F(HttpCacheDataRemoverTest, FilterKeepByDomain) {
-  mojom::ClearCacheUrlFilterPtr filter = mojom::ClearCacheUrlFilter::New();
-  filter->type = mojom::ClearCacheUrlFilter_Type::KEEP_MATCHES;
+  mojom::ClearDataFilterPtr filter = mojom::ClearDataFilter::New();
+  filter->type = mojom::ClearDataFilter_Type::KEEP_MATCHES;
   filter->domains.push_back("wikipedia.com");
   filter->domains.push_back("google.com");
   RemoveData(std::move(filter), base::Time(), base::Time());
@@ -184,8 +184,8 @@
 }
 
 TEST_F(HttpCacheDataRemoverTest, FilterDeleteByOrigin) {
-  mojom::ClearCacheUrlFilterPtr filter = mojom::ClearCacheUrlFilter::New();
-  filter->type = mojom::ClearCacheUrlFilter_Type::DELETE_MATCHES;
+  mojom::ClearDataFilterPtr filter = mojom::ClearDataFilter::New();
+  filter->type = mojom::ClearDataFilter_Type::DELETE_MATCHES;
   filter->origins.push_back(url::Origin::Create(GURL("http://www.google.com")));
   filter->origins.push_back(url::Origin::Create(GURL("http://localhost:1234")));
   RemoveData(std::move(filter), base::Time(), base::Time());
@@ -195,8 +195,8 @@
 }
 
 TEST_F(HttpCacheDataRemoverTest, FilterKeepByOrigin) {
-  mojom::ClearCacheUrlFilterPtr filter = mojom::ClearCacheUrlFilter::New();
-  filter->type = mojom::ClearCacheUrlFilter_Type::KEEP_MATCHES;
+  mojom::ClearDataFilterPtr filter = mojom::ClearDataFilter::New();
+  filter->type = mojom::ClearDataFilter_Type::KEEP_MATCHES;
   filter->origins.push_back(url::Origin::Create(GURL("http://www.google.com")));
   filter->origins.push_back(url::Origin::Create(GURL("http://localhost:1234")));
   RemoveData(std::move(filter), base::Time(), base::Time());
@@ -206,8 +206,8 @@
 }
 
 TEST_F(HttpCacheDataRemoverTest, FilterDeleteByDomainAndOrigin) {
-  mojom::ClearCacheUrlFilterPtr filter = mojom::ClearCacheUrlFilter::New();
-  filter->type = mojom::ClearCacheUrlFilter_Type::DELETE_MATCHES;
+  mojom::ClearDataFilterPtr filter = mojom::ClearDataFilter::New();
+  filter->type = mojom::ClearDataFilter_Type::DELETE_MATCHES;
   filter->domains.push_back("wikipedia.com");
   filter->origins.push_back(url::Origin::Create(GURL("http://localhost:1234")));
   RemoveData(std::move(filter), base::Time(), base::Time());
@@ -218,8 +218,8 @@
 }
 
 TEST_F(HttpCacheDataRemoverTest, FilterKeepByDomainAndOrigin) {
-  mojom::ClearCacheUrlFilterPtr filter = mojom::ClearCacheUrlFilter::New();
-  filter->type = mojom::ClearCacheUrlFilter_Type::KEEP_MATCHES;
+  mojom::ClearDataFilterPtr filter = mojom::ClearDataFilter::New();
+  filter->type = mojom::ClearDataFilter_Type::KEEP_MATCHES;
   filter->domains.push_back("wikipedia.com");
   filter->origins.push_back(url::Origin::Create(GURL("http://localhost:1234")));
   RemoveData(std::move(filter), base::Time(), base::Time());
@@ -264,8 +264,8 @@
 }
 
 TEST_F(HttpCacheDataRemoverTest, FilterDeleteByDomainAndDate) {
-  mojom::ClearCacheUrlFilterPtr filter = mojom::ClearCacheUrlFilter::New();
-  filter->type = mojom::ClearCacheUrlFilter_Type::DELETE_MATCHES;
+  mojom::ClearDataFilterPtr filter = mojom::ClearDataFilter::New();
+  filter->type = mojom::ClearDataFilter_Type::DELETE_MATCHES;
   filter->domains.push_back("google.com");
   filter->domains.push_back("wikipedia.com");
 
@@ -282,8 +282,8 @@
 }
 
 TEST_F(HttpCacheDataRemoverTest, FilterKeepByDomainAndDate) {
-  mojom::ClearCacheUrlFilterPtr filter = mojom::ClearCacheUrlFilter::New();
-  filter->type = mojom::ClearCacheUrlFilter_Type::KEEP_MATCHES;
+  mojom::ClearDataFilterPtr filter = mojom::ClearDataFilter::New();
+  filter->type = mojom::ClearDataFilter_Type::KEEP_MATCHES;
   filter->domains.push_back("google.com");
   filter->domains.push_back("wikipedia.com");
 
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index e5977c3..b3ebce1 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -98,6 +98,17 @@
   }
 };
 
+// Predicate function to determine if the given |channel_id_server_id| matches
+// the |filter_type| and |filter_domains| from a |mojom::ClearDataFilter|.
+bool MatchesClearChannelIdFilter(mojom::ClearDataFilter_Type filter_type,
+                                 std::set<std::string> filter_domains,
+                                 const std::string& channel_id_server_id) {
+  bool found_domain =
+      filter_domains.find(channel_id_server_id) != filter_domains.end();
+  return (filter_type == mojom::ClearDataFilter_Type::DELETE_MATCHES) ==
+         found_domain;
+}
+
 }  // namespace
 
 constexpr bool NetworkContext::enable_resource_scheduler_;
@@ -497,7 +508,7 @@
 
 void NetworkContext::ClearHttpCache(base::Time start_time,
                                     base::Time end_time,
-                                    mojom::ClearCacheUrlFilterPtr filter,
+                                    mojom::ClearDataFilterPtr filter,
                                     ClearHttpCacheCallback callback) {
   // It's safe to use Unretained below as the HttpCacheDataRemover is owner by
   // |this| and guarantees it won't call its callback if deleted.
@@ -522,6 +533,32 @@
   std::move(callback).Run();
 }
 
+void NetworkContext::ClearChannelIds(base::Time start_time,
+                                     base::Time end_time,
+                                     mojom::ClearDataFilterPtr filter,
+                                     ClearChannelIdsCallback callback) {
+  base::RepeatingCallback<bool(const std::string& channel_id_server_id)>
+      filter_predicate;
+  if (filter) {
+    DCHECK(filter->origins.empty())
+        << "Origin filtering not allowed in a ClearChannelIds request as "
+           "channel IDs are only keyed by domain.";
+
+    std::set<std::string> filter_domains;
+    filter_domains.insert(filter->domains.begin(), filter->domains.end());
+    filter_predicate = base::BindRepeating(
+        &MatchesClearChannelIdFilter, filter->type, std::move(filter_domains));
+  } else {
+    filter_predicate =
+        base::BindRepeating([](const std::string&) { return true; });
+  }
+
+  url_request_context_->channel_id_service()
+      ->GetChannelIDStore()
+      ->DeleteForDomainsCreatedBetween(std::move(filter_predicate), start_time,
+                                       end_time, std::move(callback));
+}
+
 void NetworkContext::SetNetworkConditions(
     const std::string& profile_id,
     mojom::NetworkConditionsPtr conditions) {
diff --git a/services/network/network_context.h b/services/network/network_context.h
index f050d92..4728238c 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -117,8 +117,12 @@
       base::OnceClosure completion_callback) override;
   void ClearHttpCache(base::Time start_time,
                       base::Time end_time,
-                      mojom::ClearCacheUrlFilterPtr filter,
+                      mojom::ClearDataFilterPtr filter,
                       ClearHttpCacheCallback callback) override;
+  void ClearChannelIds(base::Time start_time,
+                       base::Time end_time,
+                       mojom::ClearDataFilterPtr filter,
+                       ClearChannelIdsCallback callback) override;
   void SetNetworkConditions(const std::string& profile_id,
                             mojom::NetworkConditionsPtr conditions) override;
   void SetAcceptLanguage(const std::string& new_accept_language) override;
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 07c6b188..1599bfe 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/run_loop.h"
 #include "base/strings/string_split.h"
+#include "base/test/gtest_util.h"
 #include "base/test/mock_entropy_provider.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
@@ -44,6 +45,8 @@
 #include "net/proxy_resolution/proxy_config.h"
 #include "net/proxy_resolution/proxy_info.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
+#include "net/ssl/channel_id_service.h"
+#include "net/ssl/channel_id_store.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/http_user_agent_settings.h"
@@ -57,6 +60,7 @@
 #include "services/network/public/mojom/proxy_config.mojom.h"
 #include "services/network/test/test_url_loader_client.h"
 #include "services/network/udp_socket_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 #include "url/scheme_host_port.h"
@@ -633,7 +637,7 @@
   ASSERT_EQ(nullptr, cache);
   base::RunLoop run_loop;
   network_context->ClearHttpCache(base::Time(), base::Time(),
-                                  /*filter=*/nullptr,
+                                  nullptr /* filter */,
                                   base::BindOnce(run_loop.QuitClosure()));
   run_loop.Run();
 }
@@ -679,7 +683,7 @@
   EXPECT_EQ(entry_urls.size(), static_cast<size_t>(backend->GetEntryCount()));
   base::RunLoop run_loop;
   network_context->ClearHttpCache(base::Time(), base::Time(),
-                                  /*filter=*/nullptr,
+                                  nullptr /* filter */,
                                   base::BindOnce(run_loop.QuitClosure()));
   run_loop.Run();
   EXPECT_EQ(0U, static_cast<size_t>(backend->GetEntryCount()));
@@ -702,16 +706,176 @@
 
   base::RunLoop run_loop;
   base::RepeatingClosure barrier_closure = base::BarrierClosure(
-      /*num_closures=*/kNumberOfClearCalls, run_loop.QuitClosure());
+      kNumberOfClearCalls /* num_closures */, run_loop.QuitClosure());
   for (int i = 0; i < kNumberOfClearCalls; i++) {
     network_context->ClearHttpCache(base::Time(), base::Time(),
-                                    /*filter=*/nullptr,
+                                    nullptr /* filter */,
                                     base::BindOnce(barrier_closure));
   }
   run_loop.Run();
   // If all the callbacks were invoked, we should terminate.
 }
 
+TEST_F(NetworkContextTest, ClearChannelIds) {
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
+
+  net::ChannelIDStore* store = network_context->url_request_context()
+                                   ->channel_id_service()
+                                   ->GetChannelIDStore();
+  store->SetChannelID(std::make_unique<net::ChannelIDStore::ChannelID>(
+      "google.com", base::Time::FromDoubleT(123),
+      crypto::ECPrivateKey::Create()));
+  store->SetChannelID(std::make_unique<net::ChannelIDStore::ChannelID>(
+      "chromium.org", base::Time::FromDoubleT(456),
+      crypto::ECPrivateKey::Create()));
+
+  ASSERT_EQ(2, store->GetChannelIDCount());
+
+  base::RunLoop run_loop;
+  network_context->ClearChannelIds(base::Time(), base::Time(),
+                                   nullptr /* filter */,
+                                   base::BindOnce(run_loop.QuitClosure()));
+  run_loop.Run();
+
+  EXPECT_EQ(0, store->GetChannelIDCount());
+}
+
+TEST_F(NetworkContextTest, ClearEmptyChannelIds) {
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
+
+  net::ChannelIDStore* store = network_context->url_request_context()
+                                   ->channel_id_service()
+                                   ->GetChannelIDStore();
+  ASSERT_EQ(0, store->GetChannelIDCount());
+
+  base::RunLoop run_loop;
+  network_context->ClearChannelIds(base::Time(), base::Time(),
+                                   nullptr /* filter */,
+                                   base::BindOnce(run_loop.QuitClosure()));
+  run_loop.Run();
+
+  EXPECT_EQ(0, store->GetChannelIDCount());
+}
+
+void GetAllChannelIdsCallback(
+    base::RunLoop* run_loop,
+    net::ChannelIDStore::ChannelIDList* dest,
+    const net::ChannelIDStore::ChannelIDList& result) {
+  *dest = result;
+  run_loop->Quit();
+}
+
+TEST_F(NetworkContextTest, ClearChannelIdsWithKeepFilter) {
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
+
+  net::ChannelIDStore* store = network_context->url_request_context()
+                                   ->channel_id_service()
+                                   ->GetChannelIDStore();
+  store->SetChannelID(std::make_unique<net::ChannelIDStore::ChannelID>(
+      "google.com", base::Time::FromDoubleT(123),
+      crypto::ECPrivateKey::Create()));
+  store->SetChannelID(std::make_unique<net::ChannelIDStore::ChannelID>(
+      "chromium.org", base::Time::FromDoubleT(456),
+      crypto::ECPrivateKey::Create()));
+
+  ASSERT_EQ(2, store->GetChannelIDCount());
+
+  mojom::ClearDataFilterPtr filter = mojom::ClearDataFilter::New();
+  filter->type = mojom::ClearDataFilter_Type::KEEP_MATCHES;
+  filter->domains.push_back("chromium.org");
+
+  base::RunLoop run_loop1;
+  network_context->ClearChannelIds(base::Time(), base::Time(),
+                                   std::move(filter),
+                                   base::BindOnce(run_loop1.QuitClosure()));
+  run_loop1.Run();
+
+  base::RunLoop run_loop2;
+  net::ChannelIDStore::ChannelIDList channel_ids;
+  store->GetAllChannelIDs(
+      base::BindRepeating(&GetAllChannelIdsCallback, &run_loop2, &channel_ids));
+  run_loop2.Run();
+  ASSERT_EQ(1u, channel_ids.size());
+  EXPECT_EQ("chromium.org", channel_ids.front().server_identifier());
+}
+
+TEST_F(NetworkContextTest, ClearChannelIdsWithDeleteFilter) {
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
+
+  net::ChannelIDStore* store = network_context->url_request_context()
+                                   ->channel_id_service()
+                                   ->GetChannelIDStore();
+  store->SetChannelID(std::make_unique<net::ChannelIDStore::ChannelID>(
+      "google.com", base::Time::FromDoubleT(123),
+      crypto::ECPrivateKey::Create()));
+  store->SetChannelID(std::make_unique<net::ChannelIDStore::ChannelID>(
+      "chromium.org", base::Time::FromDoubleT(456),
+      crypto::ECPrivateKey::Create()));
+
+  ASSERT_EQ(2, store->GetChannelIDCount());
+
+  mojom::ClearDataFilterPtr filter = mojom::ClearDataFilter::New();
+  filter->type = mojom::ClearDataFilter_Type::DELETE_MATCHES;
+  filter->domains.push_back("chromium.org");
+
+  base::RunLoop run_loop1;
+  network_context->ClearChannelIds(base::Time(), base::Time(),
+                                   std::move(filter),
+                                   base::BindOnce(run_loop1.QuitClosure()));
+  run_loop1.Run();
+
+  base::RunLoop run_loop2;
+  net::ChannelIDStore::ChannelIDList channel_ids;
+  store->GetAllChannelIDs(
+      base::BindRepeating(&GetAllChannelIdsCallback, &run_loop2, &channel_ids));
+  run_loop2.Run();
+  ASSERT_EQ(1u, channel_ids.size());
+  EXPECT_EQ("google.com", channel_ids.front().server_identifier());
+}
+
+TEST_F(NetworkContextTest, ClearChannelIdsWithTimeRange) {
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
+
+  net::ChannelIDStore* store = network_context->url_request_context()
+                                   ->channel_id_service()
+                                   ->GetChannelIDStore();
+  store->SetChannelID(std::make_unique<net::ChannelIDStore::ChannelID>(
+      "google.com", base::Time::FromDoubleT(123),
+      crypto::ECPrivateKey::Create()));
+  store->SetChannelID(std::make_unique<net::ChannelIDStore::ChannelID>(
+      "chromium.org", base::Time::FromDoubleT(456),
+      crypto::ECPrivateKey::Create()));
+  store->SetChannelID(std::make_unique<net::ChannelIDStore::ChannelID>(
+      "gmail.com", base::Time::FromDoubleT(789),
+      crypto::ECPrivateKey::Create()));
+
+  ASSERT_EQ(3, store->GetChannelIDCount());
+
+  base::RunLoop run_loop1;
+  network_context->ClearChannelIds(
+      base::Time::FromDoubleT(450), base::Time::FromDoubleT(460),
+      nullptr /* filter */, base::BindOnce(run_loop1.QuitClosure()));
+  run_loop1.Run();
+
+  base::RunLoop run_loop2;
+  net::ChannelIDStore::ChannelIDList channel_ids;
+  store->GetAllChannelIDs(
+      base::BindRepeating(&GetAllChannelIdsCallback, &run_loop2, &channel_ids));
+  run_loop2.Run();
+
+  std::vector<std::string> identifiers;
+  for (const auto& id : channel_ids) {
+    identifiers.push_back(id.server_identifier());
+  }
+  EXPECT_THAT(identifiers,
+              testing::UnorderedElementsAre("google.com", "gmail.com"));
+}
+
 void SetCookieCallback(base::RunLoop* run_loop, bool* result_out, bool result) {
   *result_out = result;
   run_loop->Quit();
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index f5e1e8b..13653cf6 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -133,9 +133,9 @@
   double upload_throughput;
 };
 
-// Used in NetworkContext.ClearHttpCache() to specify the resources to
-// keep/delete based on their URLs.
-struct ClearCacheUrlFilter {
+// Used in some clearing methods of URL-keyed data to specify the resources to
+// keep/delete.
+struct ClearDataFilter {
   enum Type {DELETE_MATCHES, KEEP_MATCHES};
 
   Type type;
@@ -182,7 +182,18 @@
   // in either direction by using null Time values for either argument.
   ClearHttpCache(mojo_base.mojom.Time start_time,
                  mojo_base.mojom.Time end_time,
-                 ClearCacheUrlFilter? filter) => ();
+                 ClearDataFilter? filter) => ();
+
+  // Clears channel IDs. A specific range of time can be specified with
+  // |start_time| and |end_time|. This supports unbounded deletes in either
+  // direction by using null Time values for either argument.
+  //
+  // If a non-null |filter| is specified, will clear only IDs matching the
+  // filter. Filtering by origins is not supported. If |filter| is non-null,
+  // |filter.origins| must be empty.
+  ClearChannelIds(mojo_base.mojom.Time start_time,
+                  mojo_base.mojom.Time end_time,
+                  ClearDataFilter? filter) => ();
 
   // Configures network conditions for the specified throttling profile.
   // The throttling will be applied only to requests that have
diff --git a/services/ui/ws/gpu_host.cc b/services/ui/ws/gpu_host.cc
index 29bd6d0..2394ce4 100644
--- a/services/ui/ws/gpu_host.cc
+++ b/services/ui/ws/gpu_host.cc
@@ -158,9 +158,13 @@
 
 void DefaultGpuHost::DidInitialize(
     const gpu::GPUInfo& gpu_info,
-    const gpu::GpuFeatureInfo& gpu_feature_info) {
+    const gpu::GpuFeatureInfo& gpu_feature_info,
+    const gpu::GPUInfo& gpu_info_for_hardware_gpu,
+    const gpu::GpuFeatureInfo& gpu_feature_info_for_hardware_gpu) {
   gpu_info_ = gpu_info;
   gpu_feature_info_ = gpu_feature_info;
+  gpu_info_for_hardware_gpu_ = gpu_info_for_hardware_gpu;
+  gpu_feature_info_for_hardware_gpu_ = gpu_feature_info_for_hardware_gpu;
   delegate_->OnGpuServiceInitialized();
 }
 
diff --git a/services/ui/ws/gpu_host.h b/services/ui/ws/gpu_host.h
index e2f8b25..b6024b3 100644
--- a/services/ui/ws/gpu_host.h
+++ b/services/ui/ws/gpu_host.h
@@ -96,8 +96,11 @@
 #endif  // defined(OS_CHROMEOS)
 
   // viz::mojom::GpuHost:
-  void DidInitialize(const gpu::GPUInfo& gpu_info,
-                     const gpu::GpuFeatureInfo& gpu_feature_info) override;
+  void DidInitialize(
+      const gpu::GPUInfo& gpu_info,
+      const gpu::GpuFeatureInfo& gpu_feature_info,
+      const gpu::GPUInfo& gpu_info_for_hardware_gpu,
+      const gpu::GpuFeatureInfo& gpu_feature_info_for_hardware_gpu) override;
   void DidFailInitialize() override;
   void DidCreateContextSuccessfully() override;
   void DidCreateOffscreenContext(const GURL& url) override;
@@ -122,6 +125,12 @@
   mojo::Binding<viz::mojom::GpuHost> gpu_host_binding_;
   gpu::GPUInfo gpu_info_;
   gpu::GpuFeatureInfo gpu_feature_info_;
+
+  // What we would have gotten if we haven't fallen back to SwiftShader or
+  // pure software (in the viz case).
+  gpu::GPUInfo gpu_info_for_hardware_gpu_;
+  gpu::GpuFeatureInfo gpu_feature_info_for_hardware_gpu_;
+
   std::unique_ptr<viz::ServerGpuMemoryBufferManager> gpu_memory_buffer_manager_;
 
   viz::mojom::VizMainPtr viz_main_;
diff --git a/services/ui/ws/gpu_host_unittest.cc b/services/ui/ws/gpu_host_unittest.cc
index 7da8f46..f7dbc5d 100644
--- a/services/ui/ws/gpu_host_unittest.cc
+++ b/services/ui/ws/gpu_host_unittest.cc
@@ -54,7 +54,9 @@
                      nullptr /* watchdog_thread */,
                      std::move(io_runner),
                      gpu::GpuFeatureInfo(),
-                     gpu::GpuPreferences()) {}
+                     gpu::GpuPreferences(),
+                     gpu::GPUInfo(),
+                     gpu::GpuFeatureInfo()) {}
 
 }  // namespace
 
diff --git a/services/viz/privileged/interfaces/gl/gpu_host.mojom b/services/viz/privileged/interfaces/gl/gpu_host.mojom
index 3c8d839..eee8440b 100644
--- a/services/viz/privileged/interfaces/gl/gpu_host.mojom
+++ b/services/viz/privileged/interfaces/gl/gpu_host.mojom
@@ -13,8 +13,13 @@
 // Communication channel from the gpu process to the gpu host. This interface
 // should never have any sync function calls.
 interface GpuHost {
+  // If |gpu_info| and |gpu_feature_info| are for hardware GPU, then
+  // |gpu_info_for_hardware_gpu| and |gpu_feature_info_for_hardware_gpu| can
+  // be uninitialized data.
   DidInitialize(gpu.mojom.GpuInfo gpu_info,
-                gpu.mojom.GpuFeatureInfo gpu_feature_info);
+                gpu.mojom.GpuFeatureInfo gpu_feature_info,
+                gpu.mojom.GpuInfo gpu_info_for_hardware_gpu,
+                gpu.mojom.GpuFeatureInfo gpu_feature_info_for_hardware_gpu);
   DidFailInitialize();
 
   DidCreateContextSuccessfully();
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index ef2591e..2417bd7 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -75,6 +75,7 @@
     ]
   }
 
+  defines += [ "SK_USE_SKCMS" ]
   include_dirs += [ "//third_party/skia/third_party/skcms" ]
 
   if (skia_support_gpu) {
diff --git a/storage/browser/quota/client_usage_tracker.cc b/storage/browser/quota/client_usage_tracker.cc
index 6d2e48cfc..2db8289 100644
--- a/storage/browser/quota/client_usage_tracker.cc
+++ b/storage/browser/quota/client_usage_tracker.cc
@@ -144,7 +144,7 @@
 
 void ClientUsageTracker::UpdateUsageCache(const GURL& origin, int64_t delta) {
   std::string host = net::GetHostOrSpecFromURL(origin);
-  if (cached_hosts_.find(host) != cached_hosts_.end()) {
+  if (base::ContainsKey(cached_hosts_, host)) {
     if (!IsUsageCacheEnabledForOrigin(origin))
       return;
 
diff --git a/storage/browser/quota/client_usage_tracker.h b/storage/browser/quota/client_usage_tracker.h
index a8f6e7e4..72460d2 100644
--- a/storage/browser/quota/client_usage_tracker.h
+++ b/storage/browser/quota/client_usage_tracker.h
@@ -73,12 +73,9 @@
   using HostUsageMap = std::map<std::string, UsageMap>;
 
   struct AccumulateInfo {
-    int pending_jobs;
-    int64_t limited_usage;
-    int64_t unlimited_usage;
-
-    AccumulateInfo()
-        : pending_jobs(0), limited_usage(0), unlimited_usage(0) {}
+    int pending_jobs = 0;
+    int64_t limited_usage = 0;
+    int64_t unlimited_usage = 0;
   };
 
   void AccumulateLimitedOriginUsage(AccumulateInfo* info,
diff --git a/storage/browser/quota/quota_callbacks.h b/storage/browser/quota/quota_callbacks.h
index 3c261f2..7a4a4e53 100644
--- a/storage/browser/quota/quota_callbacks.h
+++ b/storage/browser/quota/quota_callbacks.h
@@ -15,6 +15,7 @@
 
 #include "base/callback.h"
 #include "base/containers/flat_map.h"
+#include "base/stl_util.h"
 #include "storage/browser/quota/quota_client.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 
@@ -23,7 +24,7 @@
 namespace storage {
 
 struct UsageInfo;
-typedef std::vector<UsageInfo> UsageInfoEntries;
+using UsageInfoEntries = std::vector<UsageInfo>;
 
 // Common callback types that are used throughout in the quota module.
 using GlobalUsageCallback =
@@ -90,7 +91,7 @@
   }
 
   bool HasCallbacks(const Key& key) const {
-    return (callback_map_.find(key) != callback_map_.end());
+    return base::ContainsKey(callback_map_, key);
   }
 
   bool HasAnyCallbacks() const {
diff --git a/storage/browser/quota/quota_client.h b/storage/browser/quota/quota_client.h
index 9b3b31a2..2d81df7 100644
--- a/storage/browser/quota/quota_client.h
+++ b/storage/browser/quota/quota_client.h
@@ -79,7 +79,7 @@
 };
 
 // TODO(dmikurube): Replace it to std::vector for efficiency.
-typedef std::list<QuotaClient*> QuotaClientList;
+using QuotaClientList = std::list<QuotaClient*>;
 
 }  // namespace storage
 
diff --git a/storage/browser/quota/quota_database.cc b/storage/browser/quota/quota_database.cc
index caea73c..e789830 100644
--- a/storage/browser/quota/quota_database.cc
+++ b/storage/browser/quota/quota_database.cc
@@ -15,6 +15,7 @@
 #include "base/files/file_util.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
 #include "sql/connection.h"
 #include "sql/meta_table.h"
 #include "sql/statement.h"
@@ -341,14 +342,12 @@
   if (!LazyOpen(true))
     return false;
 
-  typedef std::set<GURL>::const_iterator itr_type;
-  for (itr_type itr = origins.begin(), end = origins.end();
-       itr != end; ++itr) {
+  for (const auto& origin : origins) {
     const char* kSql =
         "INSERT OR IGNORE INTO OriginInfoTable"
         " (origin, type) VALUES (?, ?)";
     sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
-    statement.BindString(0, itr->spec());
+    statement.BindString(0, origin.spec());
     statement.BindInt(1, static_cast<int>(type));
 
     if (!statement.Run())
@@ -456,7 +455,7 @@
 
   while (statement.Step()) {
     GURL url(statement.ColumnString(0));
-    if (exceptions.find(url) != exceptions.end()) {
+    if (base::ContainsKey(exceptions, url)) {
       HistogramOriginType(IN_USE);
       continue;
     }
@@ -687,7 +686,6 @@
 
   if (current_version == 2) {
     QuotaTableImporter importer;
-    typedef std::vector<QuotaTableEntry> QuotaTableEntries;
     if (!DumpQuotaTable(base::BindRepeating(&QuotaTableImporter::Append,
                                             base::Unretained(&importer)))) {
       return false;
@@ -697,9 +695,8 @@
     sql::Transaction transaction(db_.get());
     if (!transaction.Begin())
       return false;
-    for (QuotaTableEntries::const_iterator iter = importer.entries.begin();
-         iter != importer.entries.end(); ++iter) {
-      if (!InsertOrReplaceHostQuota(iter->host, iter->type, iter->quota))
+    for (const auto& entry : importer.entries) {
+      if (!InsertOrReplaceHostQuota(entry.host, entry.type, entry.quota))
         return false;
     }
     return transaction.Commit();
diff --git a/storage/browser/quota/quota_database_unittest.cc b/storage/browser/quota/quota_database_unittest.cc
index baec00ed..62fbcd91 100644
--- a/storage/browser/quota/quota_database_unittest.cc
+++ b/storage/browser/quota/quota_database_unittest.cc
@@ -74,7 +74,7 @@
     EXPECT_TRUE(db.LazyOpen(true));
     EXPECT_TRUE(db.db_.get());
 
-    typedef EntryVerifier<QuotaTableEntry> Verifier;
+    using Verifier = EntryVerifier<QuotaTableEntry>;
     Verifier verifier(entries, entries + arraysize(entries));
     EXPECT_TRUE(db.DumpQuotaTable(
         base::BindRepeating(&Verifier::Run, base::Unretained(&verifier))));
@@ -399,7 +399,7 @@
     AssignQuotaTable(db.db_.get(), begin, end);
     db.Commit();
 
-    typedef EntryVerifier<QuotaTableEntry> Verifier;
+    using Verifier = EntryVerifier<QuotaTableEntry>;
     Verifier verifier(begin, end);
     EXPECT_TRUE(db.DumpQuotaTable(
         base::BindRepeating(&Verifier::Run, base::Unretained(&verifier))));
@@ -408,7 +408,7 @@
 
   void DumpOriginInfoTable(const base::FilePath& kDbFile) {
     base::Time now(base::Time::Now());
-    typedef QuotaDatabase::OriginInfoTableEntry Entry;
+    using Entry = QuotaDatabase::OriginInfoTableEntry;
     Entry kTableEntries[] = {
         Entry(GURL("http://go/"), kTemporary, 2147483647, now, now),
         Entry(GURL("http://oo/"), kTemporary, 0, now, now),
@@ -422,7 +422,7 @@
     AssignOriginInfoTable(db.db_.get(), begin, end);
     db.Commit();
 
-    typedef EntryVerifier<Entry> Verifier;
+    using Verifier = EntryVerifier<Entry>;
     Verifier verifier(begin, end);
     EXPECT_TRUE(db.DumpOriginInfoTable(
         base::BindRepeating(&Verifier::Run, base::Unretained(&verifier))));
@@ -431,7 +431,7 @@
 
   void GetOriginInfo(const base::FilePath& kDbFile) {
     const GURL kOrigin = GURL("http://go/");
-    typedef QuotaDatabase::OriginInfoTableEntry Entry;
+    using Entry = QuotaDatabase::OriginInfoTableEntry;
     Entry kTableEntries[] = {
         Entry(kOrigin, kTemporary, 100, base::Time(), base::Time())};
     Entry* begin = kTableEntries;
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc
index c217f1e..d3315014 100644
--- a/storage/browser/quota/quota_manager.cc
+++ b/storage/browser/quota/quota_manager.cc
@@ -101,12 +101,10 @@
   *unlimited_origins = 0;
   if (!policy)
     return;
-  for (std::set<GURL>::const_iterator itr = origins.begin();
-       itr != origins.end();
-       ++itr) {
-    if (policy->IsStorageProtected(*itr))
+  for (const auto& origin : origins) {
+    if (policy->IsStorageProtected(origin))
       ++*protected_origins;
-    if (policy->IsStorageUnlimited(*itr))
+    if (policy->IsStorageUnlimited(origin))
       ++*unlimited_origins;
   }
 }
@@ -512,10 +510,9 @@
   void AddEntries(StorageType type, UsageTracker* tracker) {
     std::map<std::string, int64_t> host_usage;
     tracker->GetCachedHostsUsage(&host_usage);
-    for (std::map<std::string, int64_t>::const_iterator iter =
-             host_usage.begin();
-         iter != host_usage.end(); ++iter) {
-      entries_.push_back(UsageInfo(iter->first, type, iter->second));
+    for (const auto& host_usage_pair : host_usage) {
+      entries_.push_back(
+          UsageInfo(host_usage_pair.first, type, host_usage_pair.second));
     }
     if (--remaining_trackers_ == 0)
       CallCompleted();
@@ -561,10 +558,9 @@
   void Run() override {
     error_count_ = 0;
     remaining_clients_ = manager()->clients_.size();
-    for (QuotaClientList::iterator iter = manager()->clients_.begin();
-         iter != manager()->clients_.end(); ++iter) {
-      if (quota_client_mask_ & (*iter)->id()) {
-        (*iter)->DeleteOriginData(
+    for (auto* client : manager()->clients_) {
+      if (quota_client_mask_ & client->id()) {
+        client->DeleteOriginData(
             url::Origin::Create(origin_), type_,
             base::BindOnce(&OriginDataDeleter::DidDeleteOriginData,
                            weak_factory_.GetWeakPtr()));
@@ -649,9 +645,8 @@
   void Run() override {
     error_count_ = 0;
     remaining_clients_ = manager()->clients_.size();
-    for (QuotaClientList::iterator iter = manager()->clients_.begin();
-         iter != manager()->clients_.end(); ++iter) {
-      (*iter)->GetOriginsForHost(
+    for (auto* client : manager()->clients_) {
+      client->GetOriginsForHost(
           type_, host_,
           base::BindOnce(&HostDataDeleter::DidGetOriginsForHost,
                          weak_factory_.GetWeakPtr()));
@@ -696,11 +691,9 @@
 
   void ScheduleOriginsDeletion() {
     remaining_deleters_ = origins_.size();
-    for (std::set<GURL>::const_iterator p = origins_.begin();
-         p != origins_.end();
-         ++p) {
+    for (const auto& origin : origins_) {
       OriginDataDeleter* deleter = new OriginDataDeleter(
-          manager(), *p, type_, quota_client_mask_, false,
+          manager(), origin, type_, quota_client_mask_, false,
           base::BindOnce(&HostDataDeleter::DidDeleteOriginData,
                          weak_factory_.GetWeakPtr()));
       deleter->Start();
@@ -1078,9 +1071,9 @@
   if (temporary_storage_evictor_) {
     std::map<std::string, int64_t> stats;
     temporary_storage_evictor_->GetStatistics(&stats);
-    for (std::map<std::string, int64_t>::iterator p = stats.begin();
-         p != stats.end(); ++p) {
-      (*statistics)[p->first] = base::Int64ToString(p->second);
+    for (const auto& origin_usage_pair : stats) {
+      (*statistics)[origin_usage_pair.first] =
+          base::Int64ToString(origin_usage_pair.second);
     }
   }
 }
diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h
index 07512996..8dc6ffdc 100644
--- a/storage/browser/quota/quota_manager.h
+++ b/storage/browser/quota/quota_manager.h
@@ -24,6 +24,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/sequenced_task_runner_helpers.h"
+#include "base/stl_util.h"
 #include "storage/browser/quota/quota_callbacks.h"
 #include "storage/browser/quota/quota_client.h"
 #include "storage/browser/quota/quota_database.h"
@@ -185,7 +186,7 @@
   void NotifyOriginInUse(const GURL& origin);
   void NotifyOriginNoLongerInUse(const GURL& origin);
   bool IsOriginInUse(const GURL& origin) const {
-    return origins_in_use_.find(origin) != origins_in_use_.end();
+    return base::ContainsKey(origins_in_use_, origin);
   }
 
   void SetUsageCacheEnabled(QuotaClient::ID client_id,
diff --git a/storage/browser/quota/quota_manager_unittest.cc b/storage/browser/quota/quota_manager_unittest.cc
index b1b60d7..05853a1 100644
--- a/storage/browser/quota/quota_manager_unittest.cc
+++ b/storage/browser/quota/quota_manager_unittest.cc
@@ -80,9 +80,9 @@
 
 class QuotaManagerTest : public testing::Test {
  protected:
-  typedef QuotaManager::QuotaTableEntry QuotaTableEntry;
-  typedef QuotaManager::QuotaTableEntries QuotaTableEntries;
-  typedef QuotaManager::OriginInfoTableEntries OriginInfoTableEntries;
+  using QuotaTableEntry = QuotaManager::QuotaTableEntry;
+  using QuotaTableEntries = QuotaManager::QuotaTableEntries;
+  using OriginInfoTableEntries = QuotaManager::OriginInfoTableEntries;
 
  public:
   QuotaManagerTest()
@@ -1484,12 +1484,9 @@
   DumpOriginInfoTable();
   scoped_task_environment_.RunUntilIdle();
 
-  typedef OriginInfoTableEntries::const_iterator iterator;
-  for (iterator itr(origin_info_entries().begin()),
-                end(origin_info_entries().end());
-       itr != end; ++itr) {
-    if (itr->type == kTemp)
-      EXPECT_NE(std::string("http://foo.com/"), itr->origin.spec());
+  for (const auto& entry : origin_info_entries()) {
+    if (entry.type == kTemp)
+      EXPECT_NE(std::string("http://foo.com/"), entry.origin.spec());
   }
 
   GetGlobalUsage(kTemp);
@@ -1613,11 +1610,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   bool found_origin_in_database = false;
-  typedef OriginInfoTableEntries::const_iterator iterator;
-  for (iterator itr(origin_info_entries().begin()),
-                end(origin_info_entries().end());
-       itr != end; ++itr) {
-    if (itr->type == kTemp && itr->origin == "http://foo.com/") {
+  for (const auto& entry : origin_info_entries()) {
+    if (entry.type == kTemp && entry.origin == "http://foo.com/") {
       found_origin_in_database = true;
       break;
     }
@@ -1785,16 +1779,14 @@
   DumpOriginInfoTable();
   scoped_task_environment_.RunUntilIdle();
 
-  typedef OriginInfoTableEntries::const_iterator iterator;
-  for (iterator itr(origin_info_entries().begin()),
-                end(origin_info_entries().end());
-       itr != end; ++itr) {
-    if (itr->type == kTemp) {
-      EXPECT_NE(std::string("http://foo.com/"), itr->origin.spec());
-      EXPECT_NE(std::string("http://foo.com:1/"), itr->origin.spec());
-      EXPECT_NE(std::string("https://foo.com/"), itr->origin.spec());
-      EXPECT_NE(std::string("http://bar.com/"), itr->origin.spec());
-    }
+  for (const auto& entry : origin_info_entries()) {
+    if (entry.type != kTemp)
+      continue;
+
+    EXPECT_NE(std::string("http://foo.com/"), entry.origin.spec());
+    EXPECT_NE(std::string("http://foo.com:1/"), entry.origin.spec());
+    EXPECT_NE(std::string("https://foo.com/"), entry.origin.spec());
+    EXPECT_NE(std::string("http://bar.com/"), entry.origin.spec());
   }
 
   GetGlobalUsage(kTemp);
@@ -1881,14 +1873,12 @@
   DumpOriginInfoTable();
   scoped_task_environment_.RunUntilIdle();
 
-  typedef OriginInfoTableEntries::const_iterator iterator;
-  for (iterator itr(origin_info_entries().begin()),
-                end(origin_info_entries().end());
-       itr != end; ++itr) {
-    if (itr->type == kTemp) {
-      EXPECT_NE(std::string("http://foo.com/"), itr->origin.spec());
-      EXPECT_NE(std::string("http://bar.com/"), itr->origin.spec());
-    }
+  for (const auto& entry : origin_info_entries()) {
+    if (entry.type != kTemp)
+      continue;
+
+    EXPECT_NE(std::string("http://foo.com/"), entry.origin.spec());
+    EXPECT_NE(std::string("http://bar.com/"), entry.origin.spec());
   }
 
   GetGlobalUsage(kTemp);
@@ -1954,7 +1944,7 @@
 
   for (size_t i = 0; i < arraysize(kData); ++i) {
     if (kData[i].type == kTemp)
-      EXPECT_TRUE(origins.find(GURL(kData[i].origin)) != origins.end());
+      EXPECT_TRUE(base::ContainsKey(origins, GURL(kData[i].origin)));
   }
 }
 
@@ -2122,13 +2112,10 @@
   };
   std::set<QuotaTableEntry> entries(kEntries, kEntries + arraysize(kEntries));
 
-  typedef QuotaTableEntries::const_iterator iterator;
-  for (iterator itr(quota_entries().begin()), end(quota_entries().end());
-       itr != end; ++itr) {
-    SCOPED_TRACE(testing::Message()
-                 << "host = " << itr->host << ", "
-                 << "quota = " << itr->quota);
-    EXPECT_EQ(1u, entries.erase(*itr));
+  for (const auto& quota_entry : quota_entries()) {
+    SCOPED_TRACE(testing::Message() << "host = " << quota_entry.host << ", "
+                                    << "quota = " << quota_entry.quota);
+    EXPECT_EQ(1u, entries.erase(quota_entry));
   }
   EXPECT_TRUE(entries.empty());
 }
@@ -2153,25 +2140,22 @@
   DumpOriginInfoTable();
   scoped_task_environment_.RunUntilIdle();
 
-  typedef std::pair<GURL, StorageType> TypedOrigin;
-  typedef std::pair<TypedOrigin, int> Entry;
+  using TypedOrigin = std::pair<GURL, StorageType>;
+  using Entry = std::pair<TypedOrigin, int>;
   const Entry kEntries[] = {
     make_pair(make_pair(GURL("http://example.com/"), kTemp), 1),
     make_pair(make_pair(GURL("http://example.com/"), kPerm), 2),
   };
   std::set<Entry> entries(kEntries, kEntries + arraysize(kEntries));
 
-  typedef OriginInfoTableEntries::const_iterator iterator;
-  for (iterator itr(origin_info_entries().begin()),
-                end(origin_info_entries().end());
-       itr != end; ++itr) {
+  for (const auto& origin_info : origin_info_entries()) {
     SCOPED_TRACE(testing::Message()
-                 << "host = " << itr->origin << ", "
-                 << "type = " << static_cast<int>(itr->type) << ", "
-                 << "used_count = " << itr->used_count);
+                 << "host = " << origin_info.origin << ", "
+                 << "type = " << static_cast<int>(origin_info.type) << ", "
+                 << "used_count = " << origin_info.used_count);
     EXPECT_EQ(1u, entries.erase(
-        make_pair(make_pair(itr->origin, itr->type),
-                  itr->used_count)));
+                      make_pair(make_pair(origin_info.origin, origin_info.type),
+                                origin_info.used_count)));
   }
   EXPECT_TRUE(entries.empty());
 }
diff --git a/storage/browser/quota/quota_task.cc b/storage/browser/quota/quota_task.cc
index 5ec6145..8e10a880 100644
--- a/storage/browser/quota/quota_task.cc
+++ b/storage/browser/quota/quota_task.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 
 using base::TaskRunner;
@@ -68,7 +69,7 @@
 }
 
 void QuotaTaskObserver::UnregisterTask(QuotaTask* task) {
-  DCHECK(running_quota_tasks_.find(task) != running_quota_tasks_.end());
+  DCHECK(base::ContainsKey(running_quota_tasks_, task));
   running_quota_tasks_.erase(task);
 }
 
diff --git a/storage/browser/quota/quota_task.h b/storage/browser/quota/quota_task.h
index 2ae85f14..4ed23d5c 100644
--- a/storage/browser/quota/quota_task.h
+++ b/storage/browser/quota/quota_task.h
@@ -69,7 +69,7 @@
   void RegisterTask(QuotaTask* task);
   void UnregisterTask(QuotaTask* task);
 
-  typedef std::set<QuotaTask*> TaskSet;
+  using TaskSet = std::set<QuotaTask*>;
   TaskSet running_quota_tasks_;
 };
 }
diff --git a/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc b/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc
index 75353de..b4acd69 100644
--- a/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc
+++ b/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
+#include "base/stl_util.h"
 #include "base/test/scoped_task_environment.h"
 #include "storage/browser/quota/quota_manager.h"
 #include "storage/browser/quota/quota_temporary_storage_evictor.h"
@@ -75,9 +76,8 @@
 
   int64_t GetUsage() const {
     int64_t total_usage = 0;
-    for (std::map<GURL, int64_t>::const_iterator p = origins_.begin();
-         p != origins_.end(); ++p)
-      total_usage += p->second;
+    for (const auto& origin_usage_pair : origins_)
+      total_usage += origin_usage_pair.second;
     return total_usage;
   }
 
@@ -105,7 +105,7 @@
   // Simulates an access to |origin|.  It reorders the internal LRU list.
   // It internally uses AddOrigin().
   void AccessOrigin(const GURL& origin) {
-    std::map<GURL, int64_t>::iterator found = origins_.find(origin);
+    const auto& found = origins_.find(origin);
     EXPECT_TRUE(origins_.end() != found);
     AddOrigin(origin, found->second);
   }
@@ -122,7 +122,7 @@
  private:
   int64_t EnsureOriginRemoved(const GURL& origin) {
     int64_t origin_usage;
-    if (origins_.find(origin) == origins_.end())
+    if (!base::ContainsKey(origins_, origin))
       return -1;
     else
       origin_usage = origins_[origin];
diff --git a/storage/browser/quota/special_storage_policy.h b/storage/browser/quota/special_storage_policy.h
index f8a1253..dc0f37c 100644
--- a/storage/browser/quota/special_storage_policy.h
+++ b/storage/browser/quota/special_storage_policy.h
@@ -25,7 +25,7 @@
 class STORAGE_EXPORT SpecialStoragePolicy
     : public base::RefCountedThreadSafe<SpecialStoragePolicy> {
  public:
-  typedef int StoragePolicy;
+  using StoragePolicy = int;
   enum ChangeFlags {
     STORAGE_PROTECTED = 1 << 0,
     STORAGE_UNLIMITED = 1 << 1,
diff --git a/storage/browser/quota/storage_monitor.cc b/storage/browser/quota/storage_monitor.cc
index aa0d897..9665aac 100644
--- a/storage/browser/quota/storage_monitor.cc
+++ b/storage/browser/quota/storage_monitor.cc
@@ -27,17 +27,17 @@
 
 void StorageObserverList::AddObserver(
     StorageObserver* observer, const StorageObserver::MonitorParams& params) {
-  ObserverState& observer_state = observers_[observer];
+  ObserverState& observer_state = observer_state_map_[observer];
   observer_state.origin = params.filter.origin;
   observer_state.rate = params.rate;
 }
 
 void StorageObserverList::RemoveObserver(StorageObserver* observer) {
-  observers_.erase(observer);
+  observer_state_map_.erase(observer);
 }
 
 int StorageObserverList::ObserverCount() const {
-  return observers_.size();
+  return observer_state_map_.size();
 }
 
 void StorageObserverList::OnStorageChange(const StorageObserver::Event& event) {
@@ -45,10 +45,8 @@
   TRACE_EVENT0("io",
                "HostStorageObserversStorageObserverList::OnStorageChange");
 
-  for (StorageObserverStateMap::iterator it = observers_.begin();
-       it != observers_.end(); ++it) {
-    it->second.requires_update = true;
-  }
+  for (auto& observer_state_pair : observer_state_map_)
+    observer_state_pair.second.requires_update = true;
 
   MaybeDispatchEvent(event);
 }
@@ -62,24 +60,25 @@
   base::TimeDelta min_delay = base::TimeDelta::Max();
   bool all_observers_notified = true;
 
-  for (StorageObserverStateMap::iterator it = observers_.begin();
-       it != observers_.end(); ++it) {
-    if (!it->second.requires_update)
+  for (auto& observer_state_pair : observer_state_map_) {
+    StorageObserver* observer = observer_state_pair.first;
+    ObserverState& state = observer_state_pair.second;
+
+    if (!state.requires_update)
       continue;
 
     base::TimeTicks current_time = base::TimeTicks::Now();
-    base::TimeDelta delta = current_time - it->second.last_notification_time;
-    if (it->second.last_notification_time.is_null() ||
-        delta >= it->second.rate) {
-      it->second.requires_update = false;
-      it->second.last_notification_time = current_time;
+    base::TimeDelta delta = current_time - state.last_notification_time;
+    if (state.last_notification_time.is_null() || delta >= state.rate) {
+      state.requires_update = false;
+      state.last_notification_time = current_time;
 
-      if (it->second.origin == event.filter.origin) {
+      if (state.origin == event.filter.origin) {
         // crbug.com/349708
         TRACE_EVENT0("io",
                      "StorageObserverList::MaybeDispatchEvent OnStorageEvent1");
 
-        it->first->OnStorageEvent(event);
+        observer->OnStorageEvent(event);
       } else {
         // When the quota and usage of an origin is requested, QuotaManager
         // returns the quota and usage of the host. Multiple origins can map to
@@ -87,17 +86,17 @@
         // event matches the |origin| specified by the observer when it was
         // registered.
         StorageObserver::Event dispatch_event(event);
-        dispatch_event.filter.origin = it->second.origin;
+        dispatch_event.filter.origin = state.origin;
 
         // crbug.com/349708
         TRACE_EVENT0("io",
                      "StorageObserverList::MaybeDispatchEvent OnStorageEvent2");
 
-        it->first->OnStorageEvent(dispatch_event);
+        observer->OnStorageEvent(dispatch_event);
       }
     } else {
       all_observers_notified = false;
-      base::TimeDelta delay = it->second.rate - delta;
+      base::TimeDelta delay = state.rate - delta;
       if (delay < min_delay)
         min_delay = delay;
     }
@@ -118,8 +117,8 @@
 }
 
 void StorageObserverList::ScheduleUpdateForObserver(StorageObserver* observer) {
-  DCHECK(base::ContainsKey(observers_, observer));
-  observers_[observer].requires_update = true;
+  DCHECK(base::ContainsKey(observer_state_map_, observer));
+  observer_state_map_[observer].requires_update = true;
 }
 
 void StorageObserverList::DispatchPendingEvent() {
@@ -324,10 +323,8 @@
 }
 
 void StorageMonitor::RemoveObserver(StorageObserver* observer) {
-  for (auto it = storage_type_observers_map_.begin();
-       it != storage_type_observers_map_.end(); ++it) {
-    it->second->RemoveObserver(observer);
-  }
+  for (auto& type_observers_pair : storage_type_observers_map_)
+    type_observers_pair.second->RemoveObserver(observer);
 }
 
 const StorageTypeObservers* StorageMonitor::GetStorageTypeObservers(
diff --git a/storage/browser/quota/storage_monitor.h b/storage/browser/quota/storage_monitor.h
index ee90bf94..c17b249 100644
--- a/storage/browser/quota/storage_monitor.h
+++ b/storage/browser/quota/storage_monitor.h
@@ -60,11 +60,11 @@
 
     ObserverState();
   };
-  typedef std::map<StorageObserver*, ObserverState> StorageObserverStateMap;
+  using StorageObserverStateMap = std::map<StorageObserver*, ObserverState>;
 
   void DispatchPendingEvent();
 
-  StorageObserverStateMap observers_;
+  StorageObserverStateMap observer_state_map_;
   base::OneShotTimer notification_timer_;
   StorageObserver::Event pending_event_;
 
diff --git a/storage/browser/quota/storage_monitor_unittest.cc b/storage/browser/quota/storage_monitor_unittest.cc
index 5ba01b7..5d7b63ea 100644
--- a/storage/browser/quota/storage_monitor_unittest.cc
+++ b/storage/browser/quota/storage_monitor_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/stl_util.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "net/base/url_util.h"
@@ -128,10 +129,8 @@
 
   int GetRequiredUpdatesCount(const StorageObserverList& observer_list) {
     int count = 0;
-    for (StorageObserverList::StorageObserverStateMap::const_iterator it =
-            observer_list.observers_.begin();
-         it != observer_list.observers_.end(); ++it) {
-      if (it->second.requires_update)
+    for (const auto& observer_state_pair : observer_list.observer_state_map_) {
+      if (observer_state_pair.second.requires_update)
         ++count;
     }
 
@@ -144,11 +143,9 @@
 
   void SetLastNotificationTime(StorageObserverList& observer_list,
                                StorageObserver* observer) {
-    ASSERT_TRUE(observer_list.observers_.find(observer) !=
-                observer_list.observers_.end());
-
+    ASSERT_TRUE(base::ContainsKey(observer_list.observer_state_map_, observer));
     StorageObserverList::ObserverState& state =
-        observer_list.observers_[observer];
+        observer_list.observer_state_map_[observer];
     state.last_notification_time = base::TimeTicks::Now() - state.rate;
   }
 
@@ -184,7 +181,7 @@
 
 // Tests for StorageObserverList:
 
-typedef StorageMonitorTestBase StorageObserverListTest;
+using StorageObserverListTest = StorageMonitorTestBase;
 
 // Test dispatching events to one observer.
 TEST_F(StorageObserverListTest, DispatchEventToSingleObserver) {
@@ -309,7 +306,7 @@
 
 // Tests for HostStorageObservers:
 
-typedef StorageTestWithManagerBase HostStorageObserversTest;
+using HostStorageObserversTest = StorageTestWithManagerBase;
 
 // Verify that HostStorageObservers is initialized after the first usage change.
 TEST_F(HostStorageObserversTest, InitializeOnUsageChange) {
@@ -487,7 +484,7 @@
 
 // Tests for StorageTypeObservers:
 
-typedef StorageTestWithManagerBase StorageTypeObserversTest;
+using StorageTypeObserversTest = StorageTestWithManagerBase;
 
 // Test adding and removing observers.
 TEST_F(StorageTypeObserversTest, AddRemoveObservers) {
diff --git a/storage/browser/quota/usage_tracker_unittest.cc b/storage/browser/quota/usage_tracker_unittest.cc
index bdaa02f..3e641b8a 100644
--- a/storage/browser/quota/usage_tracker_unittest.cc
+++ b/storage/browser/quota/usage_tracker_unittest.cc
@@ -80,10 +80,8 @@
                          GetOriginsCallback callback) override {
     EXPECT_EQ(StorageType::kTemporary, type);
     std::set<url::Origin> origins;
-    for (UsageMap::const_iterator itr = usage_map_.begin();
-         itr != usage_map_.end(); ++itr) {
-      origins.insert(url::Origin::Create(itr->first));
-    }
+    for (const auto& origin_usage_pair : origin_usage_map_)
+      origins.insert(url::Origin::Create(origin_usage_pair.first));
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), origins));
   }
@@ -93,10 +91,9 @@
                          GetOriginsCallback callback) override {
     EXPECT_EQ(StorageType::kTemporary, type);
     std::set<url::Origin> origins;
-    for (UsageMap::const_iterator itr = usage_map_.begin();
-         itr != usage_map_.end(); ++itr) {
-      if (net::GetHostOrSpecFromURL(itr->first) == host)
-        origins.insert(url::Origin::Create(itr->first));
+    for (const auto& origin_usage_pair : origin_usage_map_) {
+      if (net::GetHostOrSpecFromURL(origin_usage_pair.first) == host)
+        origins.insert(url::Origin::Create(origin_usage_pair.first));
     }
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), origins));
@@ -106,7 +103,7 @@
                         StorageType type,
                         DeletionCallback callback) override {
     EXPECT_EQ(StorageType::kTemporary, type);
-    usage_map_.erase(origin.GetURL());
+    origin_usage_map_.erase(origin.GetURL());
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), QuotaStatusCode::kOk));
   }
@@ -116,24 +113,22 @@
   }
 
   int64_t GetUsage(const GURL& origin) {
-    UsageMap::const_iterator found = usage_map_.find(origin);
-    if (found == usage_map_.end())
+    auto found = origin_usage_map_.find(origin);
+    if (found == origin_usage_map_.end())
       return 0;
     return found->second;
   }
 
   void SetUsage(const GURL& origin, int64_t usage) {
-    usage_map_[origin] = usage;
+    origin_usage_map_[origin] = usage;
   }
 
   int64_t UpdateUsage(const GURL& origin, int64_t delta) {
-    return usage_map_[origin] += delta;
+    return origin_usage_map_[origin] += delta;
   }
 
  private:
-  typedef std::map<GURL, int64_t> UsageMap;
-
-  UsageMap usage_map_;
+  std::map<GURL, int64_t> origin_usage_map_;
 
   DISALLOW_COPY_AND_ASSIGN(MockQuotaClient);
 };
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 40c1d708..a9837b26 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -3610,9 +3610,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_browser_tests",
+        "name": "not_site_per_process_browser_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4159,9 +4159,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_interactive_ui_tests",
+        "name": "not_site_per_process_interactive_ui_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4493,9 +4493,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_sync_integration_tests",
+        "name": "not_site_per_process_sync_integration_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4552,9 +4552,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_unit_tests",
+        "name": "not_site_per_process_unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8197,6 +8197,31 @@
             }
           ]
         },
+        "test": "cacheinvalidation_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04"
+            }
+          ]
+        },
+        "test": "capture_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04"
+            }
+          ],
+          "shards": 2
+        },
         "test": "crypto_unittests"
       },
       {
@@ -8209,6 +8234,30 @@
             }
           ]
         },
+        "test": "google_apis_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04"
+            }
+          ]
+        },
+        "test": "midi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04"
+            }
+          ]
+        },
         "test": "sql_unittests"
       },
       {
@@ -8228,12 +8277,164 @@
   "linux-annotator-rel": {
     "scripts": [
       {
-        "name": "check_network_annotation_auditor",
-        "script": "check_network_annotation_auditor.py"
+        "name": "test_traffic_annotation_auditor",
+        "script": "test_traffic_annotation_auditor.py"
       }
     ]
   },
   "linux-blink-heap-incremental-marking": {
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "blink_heap_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cacheinvalidation_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "capture_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "components_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "crypto_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "google_apis_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gpu_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ipc_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "jingle_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_blink_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_service_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "net_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "services_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "skia_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sql_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ui_base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "url_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "webkit_unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "wtf_unittests"
+      }
+    ],
     "isolated_scripts": [
       {
         "args": [
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 64eca9d..033c096 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -5800,6 +5800,26 @@
       {
         "args": [
           "--test-launcher-batch-limit=400",
+          "--deqp-egl-display-type=angle-vulkan"
+        ],
+        "name": "angle_deqp_gles2_vulkan_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-384.90",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "angle_deqp_gles2_tests",
+        "use_xvfb": false
+      },
+      {
+        "args": [
+          "--test-launcher-batch-limit=400",
           "--deqp-egl-display-type=angle-gl"
         ],
         "name": "angle_deqp_gles31_gl_tests",
@@ -15226,6 +15246,26 @@
       {
         "args": [
           "--test-launcher-batch-limit=400",
+          "--deqp-egl-display-type=angle-vulkan"
+        ],
+        "name": "angle_deqp_gles2_vulkan_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-23.21.13.8816",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "angle_deqp_gles2_tests",
+        "use_xvfb": false
+      },
+      {
+        "args": [
+          "--test-launcher-batch-limit=400",
           "--deqp-egl-display-type=angle-d3d11"
         ],
         "name": "angle_deqp_gles31_d3d11_tests",
@@ -18377,6 +18417,26 @@
         },
         "test": "angle_deqp_gles2_tests",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--test-launcher-batch-limit=400",
+          "--deqp-egl-display-type=angle-vulkan"
+        ],
+        "name": "angle_deqp_gles2_vulkan_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "angle_deqp_gles2_tests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": []
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 1a394a1a..103b005 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -695,9 +695,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_browser_tests",
+        "name": "not_site_per_process_browser_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -1023,9 +1023,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_interactive_ui_tests",
+        "name": "not_site_per_process_interactive_ui_tests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1189,9 +1189,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_sync_integration_tests",
+        "name": "not_site_per_process_sync_integration_tests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1223,9 +1223,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_unit_tests",
+        "name": "not_site_per_process_unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1505,9 +1505,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_browser_tests",
+        "name": "not_site_per_process_browser_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -1834,9 +1834,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_interactive_ui_tests",
+        "name": "not_site_per_process_interactive_ui_tests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -2003,9 +2003,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_sync_integration_tests",
+        "name": "not_site_per_process_sync_integration_tests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -2031,9 +2031,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_unit_tests",
+        "name": "not_site_per_process_unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 0f45ef3..4866f29 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -57,9 +57,6 @@
         "test": "boringssl_ssl_tests"
       },
       {
-        "args": [
-          "--test-launcher-jobs=1"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -539,9 +536,6 @@
         "test": "boringssl_ssl_tests"
       },
       {
-        "args": [
-          "--test-launcher-jobs=1"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -997,9 +991,6 @@
         "test": "blink_platform_unittests"
       },
       {
-        "args": [
-          "--test-launcher-jobs=1"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -1480,9 +1471,6 @@
         "test": "boringssl_ssl_tests"
       },
       {
-        "args": [
-          "--test-launcher-jobs=1"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
diff --git a/testing/buildbot/client.v8.chromium.json b/testing/buildbot/client.v8.chromium.json
index f46b991..c1b8bfb 100644
--- a/testing/buildbot/client.v8.chromium.json
+++ b/testing/buildbot/client.v8.chromium.json
@@ -18,9 +18,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_browser_tests",
+        "name": "not_site_per_process_browser_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -212,9 +212,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_unit_tests",
+        "name": "not_site_per_process_unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -292,9 +292,9 @@
       },
       {
         "args": [
-          "--site-per-process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_browser_tests",
+        "name": "not_site_per_process_browser_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -469,9 +469,9 @@
       },
       {
         "args": [
-          "--site_per_process"
+          "--disable-site-isolation-trials"
         ],
-        "name": "site_per_process_unit_tests",
+        "name": "not_site_per_process_unit_tests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
diff --git a/testing/buildbot/filters/mash.ash_unittests.filter b/testing/buildbot/filters/mash.ash_unittests.filter
index a1da907a..4b97800 100644
--- a/testing/buildbot/filters/mash.ash_unittests.filter
+++ b/testing/buildbot/filters/mash.ash_unittests.filter
@@ -39,6 +39,8 @@
 -DisplayManagerTest.SoftwareMirrorModeBasics
 -DisplayManagerTest.UpdateMouseCursorAfterRotateZoom
 -DisplayManagerTestDisableMultiMirroring.SoftwareMirroringWithCompositingCursor
+-DisplayManagerTest.SoftwareMirrorRotationForTablet
+-DisplayManagerTest.SoftwareMirrorRotationForNonTablet
 
 # TODO: Docked magnifier needs reflector to work in mash.
 # https://crbug.com/814481.
@@ -47,6 +49,7 @@
 -AccessibilityControllerSigninTest.EnableOnLoginScreenAndLogin/2
 -DockedMagnifierTest.AddRemoveDisplays
 -DockedMagnifierTest.DisplaysWorkAreas
+-DockedMagnifierTest.FocusChangeEvents
 -DockedMagnifierTest.HighContrastMode
 -DockedMagnifierTest.MutuallyExclusiveMagnifiers
 -DockedMagnifierTest.TestEnableAndDisable
diff --git a/testing/buildbot/filters/mash.browser_tests.filter b/testing/buildbot/filters/mash.browser_tests.filter
index dad8300..54895a4 100644
--- a/testing/buildbot/filters/mash.browser_tests.filter
+++ b/testing/buildbot/filters/mash.browser_tests.filter
@@ -295,6 +295,7 @@
 -*ECKEncryptedMediaTest.*
 -MSE_ClearKey/EncryptedMediaTest.*
 -MSE_ExternalClearKey/EncryptedMediaTest.*
+-AudioPlayerBrowserTest.*
 -AudioPlayerBrowserTestInGuestMode.OpenAudioOnDownloads
 -AutoplayExtensionBrowserTest.AutoplayAllowed
 -MediaEngagementBrowserTest.*
@@ -305,6 +306,7 @@
 -ExtensionResourceRequestPolicyTest.Video
 -DeferredMediaBrowserTest.BackgroundMediaIsDeferred
 -DeclarativeNetRequestResourceTypeBrowserTest.Test1/0
+-VideoPlayerBrowserTest.*
 -VideoPlayerBrowserTestInGuestMode.OpenSingleVideoOnDownloads
 -IsolatedAppTest.SubresourceCookieIsolation
 -PageLoadMetricsBrowserTest.*
@@ -329,6 +331,7 @@
 -OpenFileDialog/FileManagerBrowserTest.*
 -GearMenu/FileManagerBrowserTest.Test/3
 -GearMenu/FileManagerBrowserTest.Test/0
+-CreateNewFolder/FileManagerBrowserTest.*
 -TabindexFocusDownloads/FileManagerBrowserTestWithLegacyEventDispatch.Test/0
 -TabindexFocusDownloads/FileManagerBrowserTestWithLegacyEventDispatch.Test/1
 -DeclarativeNetRequestResourceTypeBrowserTest.Test1/1
@@ -336,3 +339,4 @@
 -DeclarativeNetRequestResourceTypeBrowserTest.Test2/1
 -MediaEngagementSessionRestoreBrowserTest.RestoredSession_Playback_MEI
 -AutoplayExtensionBrowserTest.*
+-ChromeTracingDelegateBrowserTestOnStartup.StartupTracingThrottle
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 0d3a3ae3..9b5a178a 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -303,31 +303,6 @@
           '--gtest_filter=-SaveType/SavePageMultiFrameBrowserTest.ObjectElements/0',
         ],
       },
-      # chromium.mac
-      'Mac10.10 Tests': {
-        # TODO(crbug.com/828031): Remove once diagnosed and fixed.
-        'args': [
-          '--test-launcher-jobs=1',
-        ],
-      },
-      'Mac10.11 Tests': {
-        # TODO(crbug.com/828031): Remove once diagnosed and fixed.
-        'args': [
-          '--test-launcher-jobs=1',
-        ],
-      },
-      'Mac10.12 Tests': {
-        # TODO(crbug.com/828031): Remove once diagnosed and fixed.
-        'args': [
-          '--test-launcher-jobs=1',
-        ],
-      },
-      'Mac10.13 Tests': {
-        # TODO(crbug.com/828031): Remove once diagnosed and fixed.
-        'args': [
-          '--test-launcher-jobs=1',
-        ],
-      },
       # chromium.memory
       'Linux ASan LSan Tests (1)': {
         # These are very slow on the ASAN trybot for some reason.
@@ -2661,7 +2636,7 @@
       'Linux MSan Tests',  # https://crbug.com/831676
     ],
   },
-  'site_per_process_browser_tests': {
+  'not_site_per_process_browser_tests': {
     'remove_from': [
       # chromium.fyi
       'Site Isolation Android',
@@ -2726,38 +2701,25 @@
       'Linux Tests (dbg)(1)(32)',
     ],
   },
-  'site_per_process_interactive_ui_tests': {
+  'not_site_per_process_interactive_ui_tests': {
     'remove_from': [
       # chromium.linux
       'Linux Tests (dbg)(1)(32)',
     ],
   },
-  'site_per_process_sync_integration_tests': {
+  'not_site_per_process_sync_integration_tests': {
     'remove_from': [
       # chromium.linux
       'Linux Tests (dbg)(1)(32)',
     ],
   },
-  'site_per_process_unit_tests': {
+  'not_site_per_process_unit_tests': {
     'remove_from': [
       # chromium.fyi
       'Site Isolation Android',
       # chromium.linux
       'Linux Tests (dbg)(1)(32)',
     ],
-    'modifications': {
-      'Linux - Future': {
-        'args': [
-          '--site-per-process',
-        ],
-      },
-      'Linux - Future (dbg)': {
-        # TODO(dpranke): this should be --site-per-process.
-        'args': [
-          '--site_per_process',
-        ],
-      },
-    },
   },
   'site_per_process_webkit_layout_tests': {
     'remove_from': [
@@ -3496,7 +3458,7 @@
         },
       },
       'Mac10.13 Tests': {
-        # TODO (crbug.com/833020)(jbudorick,dpranke): Switch this to 10.13.
+        # TODO(jbudorick,dpranke): Switch this to 10.13.
 
         # TODO(kbr): if the Swarming dimensions were explicitly specified for
         # all jobs then this wouldn't be needed. However, note that this bot
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 5b796a7..1289271f 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -328,9 +328,9 @@
     }
   },
 
-  'check_network_annotation_auditor_script': {
-    'check_network_annotation_auditor': {
-      'script': 'check_network_annotation_auditor.py',
+  'test_traffic_annotation_auditor_script': {
+    'test_traffic_annotation_auditor': {
+      'script': 'test_traffic_annotation_auditor.py',
     },
   },
 
@@ -349,7 +349,15 @@
   },
 
   'chromeos_gtests': {
-    'crypto_unittests': {},
+    'cacheinvalidation_unittests': {},
+    'capture_unittests': {},
+    'crypto_unittests': {
+       'swarming': {
+         'shards': 2,
+       },
+    },
+    'midi_unittests': {},
+    'google_apis_unittests': {},
     'sql_unittests': {},
     'url_unittests': {},
   },
@@ -712,9 +720,9 @@
     'remoting_unittests': {},
     'services_unittests': {},
 
-    'site_per_process_browser_tests': {
+    'not_site_per_process_browser_tests': {
       'args': [
-        '--site-per-process'
+        '--disable-site-isolation-trials'
       ],
       'swarming': {
         'shards': 10,
@@ -734,7 +742,10 @@
       ],
       'test': 'content_unittests',
     },
-    'site_per_process_unit_tests': {
+    'not_site_per_process_unit_tests': {
+      'args': [
+        '--disable-site-isolation-trials'
+      ],
       'test': 'unit_tests',
     },
     'sync_integration_tests': {},
@@ -1465,9 +1476,9 @@
   },
 
   'site_isolation_chromium_gtests': {
-    'site_per_process_browser_tests': {
+    'not_site_per_process_browser_tests': {
       'args': [
-        '--site-per-process'
+        '--disable-site-isolation-trials'
       ],
       'swarming': {
         'shards': 10,
@@ -1487,9 +1498,9 @@
       ],
       'test': 'content_unittests',
     },
-    'site_per_process_unit_tests': {
+    'not_site_per_process_unit_tests': {
       'args': [
-        '--site-per-process',
+        '--disable-site-isolation-trials'
       ],
       'test': 'unit_tests',
     },
@@ -1520,15 +1531,15 @@
       ],
       'test': 'extensions_unittests',
     },
-    'site_per_process_interactive_ui_tests': {
+    'not_site_per_process_interactive_ui_tests': {
       'args': [
-        '--site-per-process',
+        '--disable-site-isolation-trials'
       ],
       'test': 'interactive_ui_tests',
     },
-    'site_per_process_sync_integration_tests': {
+    'not_site_per_process_sync_integration_tests': {
       'args': [
-        '--site-per-process',
+        '--disable-site-isolation-trials'
       ],
       'test': 'sync_integration_tests',
     },
diff --git a/testing/buildbot/trybot_analyze_config.json b/testing/buildbot/trybot_analyze_config.json
index c0985e2..14b49bc 100644
--- a/testing/buildbot/trybot_analyze_config.json
+++ b/testing/buildbot/trybot_analyze_config.json
@@ -61,7 +61,6 @@
       "third_party/jstemplate/.*(css|html|js)",
       "third_party/mocha/.*(css|html|js)",
       "third_party/polymer/v1_0/components-chromium/.*(css|html|js)",
-      "third_party/typ/.*",
       "third_party/web-animations-js/.*(css|html|js)",
       "third_party/zlib/google/test/data/.*",
       "tools/clang/scripts/update.py",
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index ebca56d..7e83785 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -905,7 +905,7 @@
       },
       'linux-annotator-rel': {
         'test_suites': {
-          'scripts': 'check_network_annotation_auditor_script',
+          'scripts': 'test_traffic_annotation_auditor_script',
         }
       },
       'mac-views-rel': {
@@ -1026,6 +1026,7 @@
       },
       'linux-blink-heap-incremental-marking': {
         'test_suites': {
+          'gtest_tests': 'chromium_gtests',
           'isolated_scripts': 'chromium_webkit_isolated_scripts',
         },
       },
@@ -1218,14 +1219,19 @@
         },
       },
       'Site Isolation Linux': {
-        # TODO(dpranke): Remove this builder once the tests are running on
-        # the main 'Linux Tests' bot; base_unittests is a placeholder
+        # TODO(lukasza, dpranke): Remove this bot once site-per-process has
+        # been turned on by default for a while (e.g. once
+        # https://crrev.com/c/981019 "sticks").
+        # base_unittests is a placeholder
         # to keep the builder from building "all".
         'additional_compile_targets': [
           'base_unittests',
         ],
       },
       'Site Isolation Win': {
+        # TODO(lukasza, dpranke): Remove this bot once site-per-process has
+        # been turned on by default for a while (e.g. once
+        # https://crrev.com/c/981019 "sticks").
         'test_suites': {
           'gtest_tests': 'site_isolation_win_fyi_gtests',
         },
diff --git a/testing/scripts/check_network_annotations.py b/testing/scripts/check_network_annotations.py
index 1edccf1..8aeeae78d 100755
--- a/testing/scripts/check_network_annotations.py
+++ b/testing/scripts/check_network_annotations.py
@@ -3,7 +3,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""//testing/scripts wrapper for the network traffic annotations checks."""
+"""//testing/scripts wrapper for the network traffic annotations checks.
+This script is used to run check_annotations.py on the trybots to ensure that
+all network traffic annotations have correct syntax and semantics, and all
+functions requiring annotations have one."""
 
 import json
 import os
diff --git a/testing/scripts/headless_python_unittests.py b/testing/scripts/headless_python_unittests.py
index f551b162..05a2f94 100755
--- a/testing/scripts/headless_python_unittests.py
+++ b/testing/scripts/headless_python_unittests.py
@@ -14,7 +14,7 @@
 def main_run(args):
   typ_path = os.path.abspath(os.path.join(
       os.path.dirname(__file__), os.path.pardir, os.path.pardir,
-      'third_party', 'typ'))
+      'third_party', 'catapult', 'third_party', 'typ'))
   _AddToPathIfNeeded(typ_path)
   import typ
 
diff --git a/testing/scripts/check_network_annotation_auditor.py b/testing/scripts/test_traffic_annotation_auditor.py
similarity index 81%
rename from testing/scripts/check_network_annotation_auditor.py
rename to testing/scripts/test_traffic_annotation_auditor.py
index 5002383..279d020 100755
--- a/testing/scripts/check_network_annotation_auditor.py
+++ b/testing/scripts/test_traffic_annotation_auditor.py
@@ -3,8 +3,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""//testing/scripts wrapper for the network traffic annotation auditor
-checks."""
+"""//testing/scripts wrapper for the network traffic annotation auditor checks.
+This script is used to run traffic_annotation_auditor_tests.py on an FYI bot to
+check that traffic_annotation_auditor has the same results when heuristics that
+help it run fast and spam free on trybots are disabled."""
 
 import json
 import os
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 799f1511..a9f06b3 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3480,6 +3480,24 @@
             ]
         }
     ],
+    "SitePerProcess": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "win",
+                "mac"
+            ],
+            "experiments": [
+                {
+                    "name": "SitePerProcess_Enabled",
+                    "enable_features": [
+                        "site-per-process"
+                    ]
+                }
+            ]
+        }
+    ],
     "SocketReadIfReady": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 68614183..1ec8781 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -145,7 +145,9 @@
 crbug.com/591099 css2.1/t1205-c564-list-img-00-b-g.html [ Failure ]
 crbug.com/591099 css3/blending/background-blend-mode-overlapping-accelerated-elements.html [ Failure ]
 crbug.com/591099 css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change.html [ Failure ]
-crbug.com/714962 css3/filters/effect-reference-zoom-hw.html [ Failure Timeout ]
+crbug.com/591099 css3/filters/effect-brightness-clamping.html [ Failure ]
+crbug.com/591099 css3/filters/effect-brightness.html [ Failure ]
+crbug.com/714962 css3/filters/effect-reference-zoom-hw.html [ Failure ]
 crbug.com/591099 css3/filters/multiple-references-id-mutate-crash-2.html [ Crash ]
 crbug.com/591099 css3/flexbox/child-overflow.html [ Failure ]
 crbug.com/591099 css3/flexbox/flex-flow-border.html [ Failure ]
@@ -212,8 +214,6 @@
 crbug.com/591099 editing/selection/linux_selection_color.html [ Failure ]
 crbug.com/591099 editing/selection/mixed-editability-10.html [ Failure ]
 crbug.com/591099 editing/selection/modify_extend/extend_by_character.html [ Failure ]
-crbug.com/714962 editing/selection/modify_extend/extend_forward_line_crash.html [ Failure Pass ]
-crbug.com/714962 editing/selection/modify_move/move-by-paragraph.html [ Failure Pass ]
 crbug.com/714962 editing/selection/modify_move/move-forward-after-line-break.html [ Failure ]
 crbug.com/591099 editing/selection/move-left-right.html [ Pass Timeout ]
 crbug.com/714962 editing/selection/offset-from-point-complex-scripts.html [ Failure ]
@@ -632,7 +632,7 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/wm-propagation-body-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/cssom-view/elementFromPoint-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/cssom-view/elementFromPoint-003.html [ Failure ]
-crbug.com/591099 external/wpt/css/cssom/interfaces.html [ Timeout ]
+crbug.com/591099 external/wpt/css/cssom/interfaces.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/css/geometry/interfaces.worker.html [ Pass ]
 crbug.com/591099 external/wpt/css/selectors/focus-within-004.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-vert-001a.xhtml [ Failure ]
@@ -801,7 +801,7 @@
 crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-fieldset-element-0/legend-block-formatting-context.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-percentage.html [ Failure ]
-crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-inline-sizing/svg-inline.html [ Timeout ]
+crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-inline-sizing/svg-inline.html [ Failure Timeout ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-menu.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-skip-no-boxes.html [ Failure ]
@@ -816,7 +816,6 @@
 crbug.com/591099 external/wpt/media-source/mediasource-getvideoplaybackquality.html [ Timeout ]
 crbug.com/591099 external/wpt/mimesniff/mime-types/parsing.any.html [ Timeout ]
 crbug.com/591099 external/wpt/mimesniff/mime-types/parsing.any.worker.html [ Timeout ]
-crbug.com/591099 external/wpt/offscreen-canvas/compositing/2d.composite.globalAlpha.canvaspattern.worker.html [ Crash Pass ]
 crbug.com/591099 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html [ Crash ]
 crbug.com/591099 external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.getcontext.worker.html [ Pass ]
 crbug.com/591099 external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html [ Pass ]
@@ -1393,7 +1392,7 @@
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-border-box-sized-cell-with-collapsed-border-on-table.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-border-box-sized-cell-with-collapsed-border.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-content-box-sized-cell.html [ Failure ]
-crbug.com/591099 fast/table/percent-height-overflow-auto-content-in-cell.html [ Failure Pass ]
+crbug.com/591099 fast/table/percent-height-overflow-auto-content-in-cell.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-overflow-scroll-content-in-cell.html [ Failure Pass ]
 crbug.com/591099 fast/table/percent-height-replaced-content-in-cell.html [ Failure ]
 crbug.com/591099 fast/table/percent-widths-stretch-vertical.html [ Failure ]
@@ -1531,7 +1530,7 @@
 crbug.com/591099 fast/text/whitespace/normal-after-nowrap-breaking.html [ Failure ]
 crbug.com/591099 fast/text/zero-width-characters-complex-script.html [ Failure ]
 crbug.com/591099 fast/text/zero-width-characters.html [ Failure ]
-crbug.com/591099 fast/webgl/canvas-toDataURL-premul-overflow.html [ Failure Pass ]
+crbug.com/591099 fast/webgl/texImage-imageBitmap-from-video-resize.html [ Timeout ]
 crbug.com/591099 fast/writing-mode/Kusa-Makura-background-canvas.html [ Failure ]
 crbug.com/591099 fast/writing-mode/auto-sizing-orthogonal-flows.html [ Failure ]
 crbug.com/714962 fast/writing-mode/background-vertical-lr.html [ Failure ]
@@ -1593,14 +1592,14 @@
 crbug.com/591099 http/tests/devtools/console/console-search.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/console/console-uncaught-promise.js [ Failure ]
 crbug.com/591099 http/tests/devtools/console/console-viewport-control.js [ Failure ]
-crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Pass Timeout ]
-crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Pass Timeout ]
 crbug.com/714962 http/tests/devtools/editor/text-editor-formatter.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-indent-autodetection.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-word-jumps.js [ Pass ]
 crbug.com/714962 http/tests/devtools/elements/edit/edit-dom-actions-4.js [ Crash ]
-crbug.com/591099 http/tests/devtools/elements/elements-inspect-iframe-from-different-domain.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/elements/elements-inspect-iframe-from-different-domain.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/elements/elements-panel-rewrite-href.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/elements/highlight/highlight-css-shapes-outside-scroll.js [ Failure ]
 crbug.com/591099 http/tests/devtools/elements/highlight/highlight-css-shapes-outside.js [ Failure ]
@@ -1619,7 +1618,7 @@
 crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js [ Failure ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js [ Failure ]
 crbug.com/591099 http/tests/images/restyle-decode-error.html [ Failure ]
-crbug.com/783102 http/tests/incremental/frame-focus-before-load.html [ Pass Timeout ]
+crbug.com/783102 http/tests/incremental/frame-focus-before-load.html [ Timeout ]
 crbug.com/591099 http/tests/incremental/slow-utf8-text.pl [ Pass Timeout ]
 crbug.com/591099 http/tests/loading/nested_bad_objects.php [ Failure ]
 crbug.com/591099 http/tests/loading/preload-picture-nested.html [ Failure ]
@@ -1650,7 +1649,9 @@
 crbug.com/591099 ietestcenter/css3/bordersbackgrounds/border-radius-applies-to-001.htm [ Failure ]
 crbug.com/824918 ietestcenter/css3/multicolumn/column-width-applies-to-010.htm [ Failure ]
 crbug.com/714962 images/color-profile-background-clip-text.html [ Failure ]
+crbug.com/591099 images/color-profile-image-filter-all.html [ Failure ]
 crbug.com/591099 images/color-profile-image-shape.html [ Failure ]
+crbug.com/591099 images/color-profile-munsell-adobe-to-srgb.html [ Failure ]
 crbug.com/591099 images/percent-height-image.html [ Failure ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-ignoredNodes.js [ Timeout ]
 crbug.com/714962 inspector-protocol/accessibility/accessibility-ignoredNodesModal.js [ Failure ]
@@ -2057,9 +2058,12 @@
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-shape.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-layer-filter.html [ Timeout ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-layer.html [ Failure ]
+crbug.com/591099 virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-reflection.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/percent-height-image.html [ Failure ]
 crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-2d-pattern-in-worker.html [ Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-filter.html [ Timeout ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-composite-video-shadow.html [ Timeout ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-drawImage-video-imageSmoothingEnabled.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-imageSmoothingQuality.html [ Pass ]
 crbug.com/591099 virtual/incremental-shadow-dom/external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html [ Failure ]
@@ -2072,14 +2076,13 @@
 crbug.com/714962 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-with-delegatesFocus.html [ Timeout ]
 crbug.com/591099 virtual/layout_ng/ [ Skip ]
 crbug.com/824918 virtual/layout_ng_experimental/ [ Skip ]
-crbug.com/591099 virtual/modern-media-controls/media/controls/modern/doubletap-to-jump-forwards-too-short.html [ Failure Pass ]
 crbug.com/591099 virtual/modern-media-controls/media/controls/modern/tap-to-hide-controls.html [ Failure ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/drag-in-frames.html [ Failure ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/event-on-culled_inline.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/hr-timestamp/input-events.html [ Failure Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/keyboardevent-getModifierState.html [ Timeout ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-latching.html [ Pass Timeout ]
-crbug.com/714962 virtual/mouseevent_fractional/fast/events/mouse-down-on-pseudo-element-remove-crash.html [ Failure ]
+crbug.com/714962 virtual/mouseevent_fractional/fast/events/mouse-down-on-pseudo-element-remove-crash.html [ Failure Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouse-event-buttons-attribute.html [ Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouse-relative-position.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouseevent-getModifierState.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index c433964c..ce38a1d 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -1225,6 +1225,7 @@
 crbug.com/738613 paint/invalidation/compositing/background-attachment-local-composited.html [ Failure ]
 crbug.com/738613 paint/invalidation/compositing/background-attachment-local-equivalent.html [ Failure ]
 crbug.com/738613 paint/invalidation/compositing/new-stacking-context.html [ Failure ]
+crbug.com/738613 paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited.html [ Failure ]
 crbug.com/738613 paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer.html [ Failure ]
 crbug.com/738613 paint/invalidation/compositing/updating-scrolling-content.html [ Failure ]
 crbug.com/738613 paint/invalidation/scroll/flipped-blocks-writing-mode-scroll.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index 515ecd6..f7798f6 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -1827,9 +1827,6 @@
 crbug.com/457718 external/wpt/css/css-pseudo/marker-color.html [ WontFix ]
 crbug.com/457718 external/wpt/css/css-pseudo/marker-font-properties.html [ WontFix ]
 
-# https://github.com/w3c/web-platform-tests/issues/8633
-external/wpt/css/css-style-attr/style-attr-braces-002-quirks.htm [ WontFix ]
-
 # Requires --use-fake-ui-for-media-stream to run.
 external/wpt/mediacapture-streams/MediaStream-default-feature-policy.https.html [ WontFix ]
 
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 8a7756c..68b1708 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -4102,3 +4102,6 @@
 crbug.com/833100 [ Mac ] external/wpt/battery-status/battery-full-manual.https.html [ Failure ]
 
 crbug.com/834446 [ Linux ] http/tests/misc/performance-memory.html [ Pass Failure ]
+
+# Sheriff 2018-04-23
+crbug.com/833331 [ Win10 ] inspector-protocol/page/pageNavigateToFragment.js [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/css3/filters/effect-brightness-clamping-expected.png b/third_party/WebKit/LayoutTests/css3/filters/effect-brightness-clamping-expected.png
new file mode 100644
index 0000000..b854fe31
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/filters/effect-brightness-clamping-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-clamping-expected.txt b/third_party/WebKit/LayoutTests/css3/filters/effect-brightness-clamping-expected.txt
similarity index 72%
rename from third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-clamping-expected.txt
rename to third_party/WebKit/LayoutTests/css3/filters/effect-brightness-clamping-expected.txt
index 6f6a6a4..f2711c3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-clamping-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/filters/effect-brightness-clamping-expected.txt
@@ -3,20 +3,28 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
+      LayoutImage {IMG} at (0,0) size 160x90
       LayoutText {#text} at (160,75) size 4x19
         text run at (160,75) width 4: " "
+      LayoutImage {IMG} at (164,0) size 160x90
       LayoutText {#text} at (324,75) size 4x19
         text run at (324,75) width 4: " "
+      LayoutImage {IMG} at (328,0) size 160x90
       LayoutText {#text} at (488,75) size 4x19
         text run at (488,75) width 4: " "
+      LayoutImage {IMG} at (492,0) size 160x90
       LayoutText {#text} at (652,75) size 4x19
         text run at (652,75) width 4: " "
+      LayoutImage {IMG} at (0,95) size 160x90
       LayoutText {#text} at (160,170) size 4x19
         text run at (160,170) width 4: " "
+      LayoutImage {IMG} at (164,95) size 160x90
       LayoutText {#text} at (324,170) size 4x19
         text run at (324,170) width 4: " "
+      LayoutImage {IMG} at (328,95) size 160x90
       LayoutText {#text} at (488,170) size 4x19
         text run at (488,170) width 4: " "
+      LayoutImage {IMG} at (492,95) size 160x90
       LayoutText {#text} at (652,170) size 4x19
         text run at (652,170) width 4: " "
       LayoutText {#text} at (160,265) size 4x19
@@ -26,22 +34,6 @@
       LayoutText {#text} at (488,265) size 4x19
         text run at (488,265) width 4: " "
       LayoutText {#text} at (0,0) size 0x0
-layer at (8,8) size 160x90
-  LayoutImage {IMG} at (0,0) size 160x90
-layer at (172,8) size 160x90
-  LayoutImage {IMG} at (164,0) size 160x90
-layer at (336,8) size 160x90
-  LayoutImage {IMG} at (328,0) size 160x90
-layer at (500,8) size 160x90
-  LayoutImage {IMG} at (492,0) size 160x90
-layer at (8,103) size 160x90
-  LayoutImage {IMG} at (0,95) size 160x90
-layer at (172,103) size 160x90
-  LayoutImage {IMG} at (164,95) size 160x90
-layer at (336,103) size 160x90
-  LayoutImage {IMG} at (328,95) size 160x90
-layer at (500,103) size 160x90
-  LayoutImage {IMG} at (492,95) size 160x90
 layer at (8,198) size 160x90
   LayoutImage {IMG} at (0,190) size 160x90
 layer at (172,198) size 160x90
diff --git a/third_party/WebKit/LayoutTests/css3/filters/effect-brightness-expected.png b/third_party/WebKit/LayoutTests/css3/filters/effect-brightness-expected.png
new file mode 100644
index 0000000..c55ea7364
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/css3/filters/effect-brightness-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-expected.txt b/third_party/WebKit/LayoutTests/css3/filters/effect-brightness-expected.txt
similarity index 83%
rename from third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-expected.txt
rename to third_party/WebKit/LayoutTests/css3/filters/effect-brightness-expected.txt
index 404ad28..dc33dfb6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/filters/effect-brightness-expected.txt
@@ -3,10 +3,13 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
+      LayoutImage {IMG} at (0,0) size 160x90
       LayoutText {#text} at (160,75) size 4x19
         text run at (160,75) width 4: " "
+      LayoutImage {IMG} at (164,0) size 160x90
       LayoutText {#text} at (324,75) size 4x19
         text run at (324,75) width 4: " "
+      LayoutImage {IMG} at (328,0) size 160x90
       LayoutText {#text} at (488,75) size 4x19
         text run at (488,75) width 4: " "
       LayoutText {#text} at (652,75) size 4x19
@@ -16,12 +19,6 @@
       LayoutText {#text} at (324,170) size 4x19
         text run at (324,170) width 4: " "
       LayoutText {#text} at (0,0) size 0x0
-layer at (8,8) size 160x90
-  LayoutImage {IMG} at (0,0) size 160x90
-layer at (172,8) size 160x90
-  LayoutImage {IMG} at (164,0) size 160x90
-layer at (336,8) size 160x90
-  LayoutImage {IMG} at (328,0) size 160x90
 layer at (500,8) size 160x90
   LayoutImage {IMG} at (492,0) size 160x90
 layer at (8,103) size 160x90
diff --git a/third_party/WebKit/LayoutTests/css3/filters/filter-property-parsing-invalid.html b/third_party/WebKit/LayoutTests/css3/filters/filter-property-parsing-invalid.html
index b5bfc37..3f31679b 100644
--- a/third_party/WebKit/LayoutTests/css3/filters/filter-property-parsing-invalid.html
+++ b/third_party/WebKit/LayoutTests/css3/filters/filter-property-parsing-invalid.html
@@ -49,6 +49,7 @@
 assert_invalid_value("filter", "brightness(0.5 0.5)"); // Too many parameters
 assert_invalid_value("filter", "brightness(0.5, 0.5)"); // Too many parameters and commas
 assert_invalid_value("filter", "brightness(0.5,)"); // Trailing comma
+assert_invalid_value("filter", "brightness(-1.1)"); // Parameter is negative
 
 assert_invalid_value("filter", "contrast(10px)"); // Length instead of number
 assert_invalid_value("filter", "contrast(0.5 0.5)"); // Too many parameters
diff --git a/third_party/WebKit/LayoutTests/css3/filters/filter-property-parsing.html b/third_party/WebKit/LayoutTests/css3/filters/filter-property-parsing.html
index b84155a..4f37c948 100644
--- a/third_party/WebKit/LayoutTests/css3/filters/filter-property-parsing.html
+++ b/third_party/WebKit/LayoutTests/css3/filters/filter-property-parsing.html
@@ -68,7 +68,6 @@
 assert_valid_value("filter", "brightness(0)"); // Zero value
 assert_valid_value("filter", "brightness()"); // No arguments
 assert_valid_value("filter", "brightness(0.5) brightness(0.25)"); // Multiple values
-assert_valid_value("filter", "brightness(-1.1)"); // Parameter less than -100%
 assert_valid_value("filter", "brightness(101%)"); // Parameter more than 100%
 
 assert_valid_value("filter", "contrast(1)"); // Integer value
diff --git a/third_party/WebKit/LayoutTests/css3/filters/usecounter-negative-brightness-number.html b/third_party/WebKit/LayoutTests/css3/filters/usecounter-negative-brightness-number.html
deleted file mode 100644
index 192a004..0000000
--- a/third_party/WebKit/LayoutTests/css3/filters/usecounter-negative-brightness-number.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<style></style>
-<script>
-'use strict';
-
-test(() => {
-    const CSSFilterFunctionNegativeBrightness = 2193; // From web_feature.mojom
-    var style = document.querySelector('style');
-    style.textContent = "* { filter: brightness(1); }";
-    assert_false(internals.isUseCounted(document, CSSFilterFunctionNegativeBrightness));
-    style.textContent = "* { filter: brightness(0); }";
-    assert_false(internals.isUseCounted(document, CSSFilterFunctionNegativeBrightness));
-    style.textContent = "* { filter: brightness(-1); }";
-    assert_true(internals.isUseCounted(document, CSSFilterFunctionNegativeBrightness));
-}, "'filter' with negative brightness is use counted.");
-</script>
diff --git a/third_party/WebKit/LayoutTests/css3/filters/usecounter-negative-brightness-percentage.html b/third_party/WebKit/LayoutTests/css3/filters/usecounter-negative-brightness-percentage.html
deleted file mode 100644
index a903835..0000000
--- a/third_party/WebKit/LayoutTests/css3/filters/usecounter-negative-brightness-percentage.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<style></style>
-<script>
-'use strict';
-
-test(() => {
-    const CSSFilterFunctionNegativeBrightness = 2193; // From enums.xml
-    var style = document.querySelector('style');
-    style.textContent = "* { filter: brightness(1%); }";
-    assert_false(internals.isUseCounted(document, CSSFilterFunctionNegativeBrightness));
-    style.textContent = "* { filter: brightness(0%); }";
-    assert_false(internals.isUseCounted(document, CSSFilterFunctionNegativeBrightness));
-    style.textContent = "* { filter: brightness(-1%); }";
-    assert_true(internals.isUseCounted(document, CSSFilterFunctionNegativeBrightness));
-}, "'filter' with negative brightness percentage is use counted.");
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index aebef17..3560c34 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -100159,6 +100159,16 @@
      {}
     ]
    ],
+   "console/console-tests-historical.any-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "console/console-tests-historical.any.worker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "content-security-policy/OWNERS": [
     [
      {}
@@ -117624,11 +117634,6 @@
      {}
     ]
    ],
-   "css/css-fonts/variations/font-variation-settings-parsing-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "css/css-fonts/variations/font-weight-parsing-expected.txt": [
     [
      {}
@@ -162909,6 +162914,11 @@
      {}
     ]
    ],
+   "webaudio/resources/biquad-testing.js": [
+    [
+     {}
+    ]
+   ],
    "webaudio/resources/convolution-testing.js": [
     [
      {}
@@ -177287,6 +177297,16 @@
      {}
     ]
    ],
+   "console/console-tests-historical.any.js": [
+    [
+     "/console/console-tests-historical.any.html",
+     {}
+    ],
+    [
+     "/console/console-tests-historical.any.worker.html",
+     {}
+    ]
+   ],
    "console/console-time-label-conversion.any.js": [
     [
      "/console/console-time-label-conversion.any.html",
@@ -177297,16 +177317,6 @@
      {}
     ]
    ],
-   "console/console-timeline-timelineEnd-historical.any.js": [
-    [
-     "/console/console-timeline-timelineEnd-historical.any.html",
-     {}
-    ],
-    [
-     "/console/console-timeline-timelineEnd-historical.any.worker.html",
-     {}
-    ]
-   ],
    "content-security-policy/base-uri/base-uri-allow.sub.html": [
     [
      "/content-security-policy/base-uri/base-uri-allow.sub.html",
@@ -205299,6 +205309,12 @@
      {}
     ]
    ],
+   "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html": [
+    [
+     "/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html",
+     {}
+    ]
+   ],
    "html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html": [
     [
      "/html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html",
@@ -233424,7 +233440,9 @@
    "upgrade-insecure-requests/link-upgrade.sub.https.html": [
     [
      "/upgrade-insecure-requests/link-upgrade.sub.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "upgrade-insecure-requests/websocket-upgrade.https.html": [
@@ -234663,6 +234681,90 @@
      {}
     ]
    ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-allpass.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-allpass.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-automation.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-automation.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-bandpass.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-bandpass.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-getFrequencyResponse.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-getFrequencyResponse.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highpass.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highpass.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highshelf.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highshelf.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowshelf.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowshelf.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-notch.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-notch.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-peaking.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-peaking.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-tail.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-tail.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/biquadfilternode-basic.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/biquadfilternode-basic.html",
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-biquadfilternode-interface/no-dezippering.html": [
+    [
+     "/webaudio/the-audio-api/the-biquadfilternode-interface/no-dezippering.html",
+     {}
+    ]
+   ],
    "webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-basic.html": [
     [
      "/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-basic.html",
@@ -256204,12 +256306,20 @@
    "9ad845184a6dd40b1ab64992ca514dbf4736c930",
    "testharness"
   ],
-  "console/console-time-label-conversion.any.js": [
-   "5e2ca9e9dca88c6de32408b461f3f4c54c586031",
+  "console/console-tests-historical.any-expected.txt": [
+   "6dfddeb4f5e1664d0d01b5b0009972541416124d",
+   "support"
+  ],
+  "console/console-tests-historical.any.js": [
+   "ee18f8a672534b478ca15990026638a73588fcf4",
    "testharness"
   ],
-  "console/console-timeline-timelineEnd-historical.any.js": [
-   "ca938829b5946f26348e237379a4f3e9ec945e40",
+  "console/console-tests-historical.any.worker-expected.txt": [
+   "6dfddeb4f5e1664d0d01b5b0009972541416124d",
+   "support"
+  ],
+  "console/console-time-label-conversion.any.js": [
+   "5e2ca9e9dca88c6de32408b461f3f4c54c586031",
    "testharness"
   ],
   "content-security-policy/OWNERS": [
@@ -289125,11 +289235,11 @@
    "testharness"
   ],
   "css/css-fonts/variations/font-shorthand-expected.txt": [
-   "ebc1d4d3ccac459d39cf416f0caccb6cb512d048",
+   "156c1b3adc21bc9082e7c50e2a92a9400dead394",
    "support"
   ],
   "css/css-fonts/variations/font-shorthand.html": [
-   "7e193d5e25424699652e64b419e1d1384370e3a4",
+   "683248c8b0e361e82d59df2ba3b94b4d9ee20479",
    "testharness"
   ],
   "css/css-fonts/variations/font-stretch-expected.txt": [
@@ -289156,12 +289266,8 @@
    "ec4b475a9bd04601161398ae21207967881a8f28",
    "testharness"
   ],
-  "css/css-fonts/variations/font-variation-settings-parsing-expected.txt": [
-   "a390811f0a3c8361d132226e914c18e78bc3cee1",
-   "support"
-  ],
   "css/css-fonts/variations/font-variation-settings-parsing.html": [
-   "bc12bf7fdec6a81a95df8c66c6387f4857b4a284",
+   "0b43e98e0151065bc60d82fd6f00ae0fbeb966d5",
    "testharness"
   ],
   "css/css-fonts/variations/font-weight-interpolation.html": [
@@ -334557,7 +334663,7 @@
    "support"
   ],
   "html/browsers/browsing-the-web/unloading-documents/unload/007.html": [
-   "bfb39279cb1e49176f4c77e0253dd92642f53f34",
+   "ac12d25b792d284b377e889565351f626df7627e",
    "testharness"
   ],
   "html/browsers/browsing-the-web/unloading-documents/unload/008-1.html": [
@@ -349852,6 +349958,10 @@
    "93f2cc8f3e88e0cbf508acd64f9a28bdcaff25b0",
    "testharness"
   ],
+  "html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html": [
+   "b579ff5a32f582bc6baf42bfff08d36dafc94c8f",
+   "testharness"
+  ],
   "html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html": [
    "32455a1418d94fa68368bae3b1c0291204f6b4e3",
    "testharness"
@@ -378761,7 +378871,7 @@
    "testharness"
   ],
   "upgrade-insecure-requests/link-upgrade.sub.https.html": [
-   "0c7c3915c24e355f3353a242843c76bb17b13c62",
+   "d8279d5c8b46259643bd960374398ea4d8a455f8",
    "testharness"
   ],
   "upgrade-insecure-requests/link-upgrade/basic-link-no-upgrade.sub.html": [
@@ -380176,6 +380286,10 @@
    "914a0268776de98f3b608babfa5699a93a2cd723",
    "support"
   ],
+  "webaudio/resources/biquad-testing.js": [
+   "148a402f0a212c8b37bc377c5c9f7091d653bb7c",
+   "support"
+  ],
   "webaudio/resources/convolution-testing.js": [
    "4a0ae6b3701147d16cb91e5660e1f4909d022d06",
    "support"
@@ -380440,6 +380554,62 @@
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-allpass.html": [
+   "5e614c338cde7788c8f88200c8e5540c8ddd7fe0",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-automation.html": [
+   "13549ae0edffb8b64ad57a0767cf1eaa98a45c48",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-bandpass.html": [
+   "85b51950563a14ec76a971d79b31b42c677d6185",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html": [
+   "3675c5430229774a8079eae866a355ca0793103b",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-getFrequencyResponse.html": [
+   "68a2545839beaacebaf65286829174375435a83f",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highpass.html": [
+   "f20705cb15906fa78f3db321d57b568478ffdb1c",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highshelf.html": [
+   "9fa170eb3b99552faf418b7efb84cb9e39ddf5d0",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html": [
+   "8e300cd5b95c753ee234cb1256f5ec1295492d2e",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowshelf.html": [
+   "8addf4c6790feaeb028f31224cccd98c6e5fb7ee",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-notch.html": [
+   "0fe79eda36594125827af62d3a8abfd884b0a1d3",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-peaking.html": [
+   "8b66bfd29e8ea0b6405810d9d738331a7869e9a0",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-tail.html": [
+   "e15e696492076d522c1052ae890b37f52e7bd27b",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/biquadfilternode-basic.html": [
+   "f24a473f695c2d10788ba7d50728259a08ed53c8",
+   "testharness"
+  ],
+  "webaudio/the-audio-api/the-biquadfilternode-interface/no-dezippering.html": [
+   "348376a643b765700342e9620e1346d432a28131",
+   "testharness"
+  ],
   "webaudio/the-audio-api/the-channelmergernode-interface/.gitkeep": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/console/console-tests-historical.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/console/console-tests-historical.any-expected.txt
new file mode 100644
index 0000000..dea7bb5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/console/console-tests-historical.any-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+FAIL 'timeline' function should not exist on the console object assert_equals: console.timeline should be undefined expected (undefined) undefined but got (function) function "function timeline() { [native code] }"
+FAIL 'timelineEnd' function should not exist on the console object assert_equals: console.timelineEnd should be undefined expected (undefined) undefined but got (function) function "function timelineEnd() { [native code] }"
+FAIL 'markTimeline' function should not exist on the console object assert_equals: console.markTimeline should be undefined expected (undefined) undefined but got (function) function "function markTimeline() { [native code] }"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/console/console-tests-historical.any.js b/third_party/WebKit/LayoutTests/external/wpt/console/console-tests-historical.any.js
new file mode 100644
index 0000000..4c4d4c2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/console/console-tests-historical.any.js
@@ -0,0 +1,19 @@
+/**
+ * These tests assert the non-existence of certain
+ * legacy Console methods that are not included in
+ * the specification: http://console.spec.whatwg.org/
+ */
+
+"use strict";
+
+test(() => {
+  assert_equals(console.timeline, undefined, "console.timeline should be undefined");
+}, "'timeline' function should not exist on the console object");
+
+test(() => {
+  assert_equals(console.timelineEnd, undefined, "console.timelineEnd should be undefined");
+}, "'timelineEnd' function should not exist on the console object");
+
+test(() => {
+  assert_equals(console.markTimeline, undefined, "console.markTimeline should be undefined");
+}, "'markTimeline' function should not exist on the console object");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/console/console-tests-historical.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/console/console-tests-historical.any.worker-expected.txt
new file mode 100644
index 0000000..dea7bb5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/console/console-tests-historical.any.worker-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+FAIL 'timeline' function should not exist on the console object assert_equals: console.timeline should be undefined expected (undefined) undefined but got (function) function "function timeline() { [native code] }"
+FAIL 'timelineEnd' function should not exist on the console object assert_equals: console.timelineEnd should be undefined expected (undefined) undefined but got (function) function "function timelineEnd() { [native code] }"
+FAIL 'markTimeline' function should not exist on the console object assert_equals: console.markTimeline should be undefined expected (undefined) undefined but got (function) function "function markTimeline() { [native code] }"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/console/console-timeline-timelineEnd-historical.any.js b/third_party/WebKit/LayoutTests/external/wpt/console/console-timeline-timelineEnd-historical.any.js
deleted file mode 100644
index 038c715..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/console/console-timeline-timelineEnd-historical.any.js
+++ /dev/null
@@ -1,9 +0,0 @@
-"use strict";
-
-test(() => {
-  assert_equals(console.timeline, undefined, "console.timeline should be undefined");
-}, "'timeline' function should not exist on the console object");
-
-test(() => {
-  assert_equals(console.timelineEnd, undefined, "console.timelineEnd should be undefined");
-}, "'timelineEnd' function should not exist on the console object");
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-shorthand-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-shorthand-expected.txt
index 81811c1b..06ed337 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-shorthand-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-shorthand-expected.txt
@@ -7,10 +7,10 @@
 FAIL Font shorthand: Font weight specified as calc(), value smaller than 1 assert_equals: Font shorthand expected weight: Font weight specified as calc(), value smaller than 1 expected "1" but got "400"
 FAIL Font shorthand: Font weight specified as calc(), value greater than 1000 assert_equals: Font shorthand expected weight: Font weight specified as calc(), value greater than 1000 expected "1000" but got "400"
 PASS Font shorthand: 'oblique' with positive angle
-PASS Font shorthand: 'oblique' with hegative angle
+PASS Font shorthand: 'oblique' with negative angle
 FAIL Font shorthand: 'oblique' without slant angle assert_equals: Font shorthand expected style: 'oblique' without slant angle expected "oblique" but got "italic"
-FAIL Font shorthand: 'oblique' with negative angle, value out of range assert_equals: Font shorthand: 'oblique' with negative angle, value out of range expected false but got true
 FAIL Font shorthand: 'oblique' with positive angle, value out of range assert_equals: Font shorthand: 'oblique' with positive angle, value out of range expected false but got true
+FAIL Font shorthand: 'oblique' with negative angle, value out of range assert_equals: Font shorthand: 'oblique' with negative angle, value out of range expected false but got true
 FAIL Font shorthand: 'oblique' followed by valid small weight assert_equals: Font shorthand expected style: 'oblique' followed by valid small weight expected "oblique" but got "italic"
 FAIL Font shorthand: 'oblique' followed by valid large weight assert_equals: Font shorthand expected style: 'oblique' followed by valid large weight expected "oblique" but got "italic"
 PASS Font shorthand: 'oblique' with positive angle followed by valid weight
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-shorthand.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-shorthand.html
index 1b15957..33ce74f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-shorthand.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-shorthand.html
@@ -26,10 +26,10 @@
 
             // font-style
             { value: "oblique 45deg 24px Arial",                            isValid:true,   expectedStyle: "oblique 45deg",  message: "'oblique' with positive angle" },
-            { value: "oblique -45deg 24px Arial",                           isValid:true,   expectedStyle: "oblique -45deg", message: "'oblique' with hegative angle" },
+            { value: "oblique -45deg 24px Arial",                           isValid:true,   expectedStyle: "oblique -45deg", message: "'oblique' with negative angle" },
             { value: "oblique 24px Arial",                                  isValid:true,   expectedStyle: "oblique",        message: "'oblique' without slant angle" },
-            { value: "oblique 100deg 24px Arial",                           isValid:false,                                   message: "'oblique' with negative angle, value out of range" },
-            { value: "oblique -100deg 24px Arial",                          isValid:false,                                   message: "'oblique' with positive angle, value out of range" },
+            { value: "oblique 100deg 24px Arial",                           isValid:false,                                   message: "'oblique' with positive angle, value out of range" },
+            { value: "oblique -100deg 24px Arial",                          isValid:false,                                   message: "'oblique' with negative angle, value out of range" },
 
             // font-weight and font-style combined
             { value: "oblique 50 24px Arial",                               isValid:true,   expectedStyle: "oblique",        expectedWeight:"50",    message: "'oblique' followed by valid small weight" },
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-variation-settings-parsing-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-variation-settings-parsing-expected.txt
deleted file mode 100644
index 13100bb..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-variation-settings-parsing-expected.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-This is a testharness.js-based test.
-FAIL Property value: Axis tag with valid non-letter ascii characters assert_equals: Axis tag with valid non-letter ascii characters expected "\"9 ~A\" -45, \"wght\" 1000" but got "\"wght\" 1000, \"9 ~A\" -45"
-FAIL Property value: Invalid character below allowed range (first char) assert_equals: Invalid character below allowed range (first char) expected "normal" but got "\"wght\" 1000, \"9 ~A\" -45"
-FAIL Property value: Invalid character above allowed range (mid char) assert_equals: Invalid character above allowed range (mid char) expected "normal" but got "\"wght\" 1000, \"9 ~A\" -45"
-FAIL Property value: Axis values in scientific form are valid assert_equals: Axis values in scientific form are valid expected "\"slnt\" -45, \"wght\" 1000" but got "\"wght\" 1000, \"slnt\" -45"
-PASS Property value: 'normal' value is valid
-PASS Property value: Tag with less than 4 characters is invalid
-PASS Property value: Tag with more than 4 characters is invalid
-PASS Property value: Trailing comma is invalid
-PASS Property value: Unquoted tags are invalid
-PASS Property value: Unmatched quotes around tag are invalid
-PASS Property value: Tag without value isinvalid
-PASS Property value: Value without tag is invalid
-PASS Property value: Value before tag is invalid
-PASS Property value: Missing comma between axes is invalid
-PASS Property value: Calculations should be supported
-PASS Property value: Units should not be supported
-PASS Property value: Units should not be supported (in calc)
-PASS Property value: Percentages should not be supported
-PASS Property value: Percentages should not be supported (in calc)
-PASS @supports: Axis tag with valid non-letter ascii characters
-PASS @supports: Invalid character below allowed range (first char)
-PASS @supports: Invalid character above allowed range (mid char)
-PASS @supports: Axis values in scientific form are valid
-PASS @supports: 'normal' value is valid
-PASS @supports: Tag with less than 4 characters is invalid
-PASS @supports: Tag with more than 4 characters is invalid
-PASS @supports: Trailing comma is invalid
-PASS @supports: Unquoted tags are invalid
-PASS @supports: Unmatched quotes around tag are invalid
-PASS @supports: Tag without value isinvalid
-PASS @supports: Value without tag is invalid
-PASS @supports: Value before tag is invalid
-PASS @supports: Missing comma between axes is invalid
-PASS @supports: Calculations should be supported
-PASS @supports: Units should not be supported
-PASS @supports: Units should not be supported (in calc)
-PASS @supports: Percentages should not be supported
-PASS @supports: Percentages should not be supported (in calc)
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-variation-settings-parsing.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-variation-settings-parsing.html
index 93c6ec0..3d6bc5f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-variation-settings-parsing.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/variations/font-variation-settings-parsing.html
@@ -11,10 +11,10 @@
     <script>
 
         var valueParserTests = [
-            { value: "'wght' 1000, '9 ~A' -45",           expectedComputedValue: "\"9 ~A\" -45, \"wght\" 1000",    isValid: true,  message: "Axis tag with valid non-letter ascii characters" },
+            { value: "'wght' 1000, '9 ~A' -45",           expectedComputedValue: "\"wght\" 1000, \"9 ~A\" -45",    isValid: true,  message: "Axis tag with valid non-letter ascii characters" },
             { value: "'\u001Fbdc' 123",                   expectedComputedValue: "",                               isValid: false, message: "Invalid character below allowed range (first char)"},
             { value: "'abc\u007F' 123",                   expectedComputedValue: "",                               isValid: false, message: "Invalid character above allowed range (mid char)"},
-            { value: "'wght' 1e3, 'slnt' -450.0e-1 ",     expectedComputedValue: "\"slnt\" -45, \"wght\" 1000",    isValid: true,  message: "Axis values in scientific form are valid" },
+            { value: "'wght' 1e3, 'slnt' -450.0e-1 ",     expectedComputedValue: "\"wght\" 1000, \"slnt\" -45",    isValid: true,  message: "Axis values in scientific form are valid" },
             { value: "normal",                            expectedComputedValue: "normal",                         isValid: true,  message: "'normal' value is valid" },
             { value: "'a' 1234",                          expectedComputedValue: "",                               isValid: false, message: "Tag with less than 4 characters is invalid"},
             { value: "'abcde' 1234",                      expectedComputedValue: "",                               isValid: false, message: "Tag with more than 4 characters is invalid"},
@@ -35,6 +35,8 @@
         valueParserTests.forEach(function (testCase) {
             test(() => {
                 var element = document.getElementById("value-parser-test");
+                // Reset to empty in order for testing to continue in case the next test would not parse as valid
+                element.style.fontVariationSettings = "";
                 element.style.fontVariationSettings = testCase.value;
                 var computed = window.getComputedStyle(element).fontVariationSettings;
                 if (testCase.isValid) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/unload/007.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/unload/007.html
index 0d5b72e0..4a2fed5f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/unload/007.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/unload/007.html
@@ -4,17 +4,17 @@
 <script src="/resources/testharnessreport.js"></script>
 <div id="log"></div>
 <script>
-var t = async_test(undefined, {timeout:2000});
+var t = async_test();
 
 var loaded = false;
 var unload_fired = false;
 var timeout_fired = false;
 
 function start_test() {
-  setTimeout(t.step_func(function() {
-                           assert_true(unload_fired);
-                           assert_false(timeout_fired);
-                           t.done()
+  step_timeout(t.step_func(function() {
+                             assert_true(unload_fired);
+                             assert_false(timeout_fired);
+                             t.done()
                          }), 1000);
 }
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html
new file mode 100644
index 0000000..e0e3ec8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>import() inside compiled strings inside a classic script</title>
+<link rel="help" href="https://github.com/whatwg/html/pull/3163">
+<link rel="help" href="https://github.com/tc39/ecma262/issues/871#issuecomment-292493142">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+"use strict";
+
+self.ran = false;
+
+promise_test(t => {
+  t.add_cleanup(() => {
+    self.ran = false;
+  })
+
+  return Promise.resolve(`import("../imports-a.js?1").then(() => { self.ran = true; })`)
+    .then(eval)
+    .then(() => {
+      assert_true(self.ran);
+    });
+}, "Evaled the script via eval, successful import");
+
+promise_test(t => {
+  t.add_cleanup(() => {
+    self.ran = false;
+  })
+
+  return Promise.resolve(`import("bad-specifier?1").catch(() => { self.ran = true; })`)
+    .then(eval)
+    .then(() => {
+      assert_true(self.ran);
+    });
+}, "Evaled the script via eval, failed import");
+
+promise_test(t => {
+  t.add_cleanup(() => {
+    self.ran = false;
+  })
+
+  return Promise.resolve(`return import("../imports-a.js?2").then(() => { self.ran = true; })`)
+    .then(Function)
+    .then(Function.prototype.call.bind(Function.prototype.call))
+    .then(() => {
+      assert_true(self.ran);
+    });
+}, "Evaled the script via Function, successful import");
+
+promise_test(t => {
+  t.add_cleanup(() => {
+    self.ran = false;
+  })
+
+  return Promise.resolve(`return import("bad-specifier?2").catch(() => { self.ran = true; })`)
+    .then(Function)
+    .then(Function.prototype.call.bind(Function.prototype.call))
+    .then(() => {
+      assert_true(self.ran);
+    });
+}, "Evaled the script via Function, failed import");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/Service-Worker-Allowed-header.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/Service-Worker-Allowed-header.https.html
new file mode 100644
index 0000000..316067c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/Service-Worker-Allowed-header.https.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<title>Service Worker: Service-Worker-Allowed header</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+const host_info = get_host_info();
+
+// Returns a URL for a service worker script whose Service-Worker-Allowed
+// header value is set to |allowed_path|. If |origin| is specified, that origin
+// is used.
+function build_script_url(allowed_path, origin) {
+  const script = 'resources/empty-worker.js';
+  const url = origin ? `${origin}${base_path()}${script}` : script;
+  return `${url}?pipe=header(Service-Worker-Allowed,${allowed_path})`;
+}
+
+promise_test(async t => {
+  const script = build_script_url('/allowed-path');
+  const scope = '/allowed-path';
+  const registration = await service_worker_unregister_and_register(
+      t, script, scope);
+  assert_true(registration instanceof ServiceWorkerRegistration, 'registered');
+  assert_equals(registration.scope, normalizeURL(scope));
+  return registration.unregister();
+}, 'Registering within Service-Worker-Allowed path');
+
+promise_test(async t => {
+  const script = build_script_url(new URL('/allowed-path', document.location));
+  const scope = '/allowed-path';
+  const registration = await service_worker_unregister_and_register(
+      t, script, scope);
+  assert_true(registration instanceof ServiceWorkerRegistration, 'registered');
+  assert_equals(registration.scope, normalizeURL(scope));
+  return registration.unregister();
+}, 'Registering within Service-Worker-Allowed path (absolute URL)');
+
+promise_test(async t => {
+  const script = build_script_url('../allowed-path-with-parent');
+  const scope = 'allowed-path-with-parent';
+  const registration = await service_worker_unregister_and_register(
+      t, script, scope);
+  assert_true(registration instanceof ServiceWorkerRegistration, 'registered');
+  assert_equals(registration.scope, normalizeURL(scope));
+  return registration.unregister();
+}, 'Registering within Service-Worker-Allowed path with parent reference');
+
+promise_test(async t => {
+  const script = build_script_url('../allowed-path');
+  const scope = '/disallowed-path';
+  await service_worker_unregister(t, scope);
+  return promise_rejects(t,
+      'SecurityError',
+      navigator.serviceWorker.register(script, {scope: scope}),
+      'register should fail');
+}, 'Registering outside Service-Worker-Allowed path');
+
+promise_test(async t => {
+  const script = build_script_url('../allowed-path-with-parent');
+  const scope = '/allowed-path-with-parent';
+  await service_worker_unregister(t, scope);
+  return promise_rejects(t,
+      'SecurityError',
+      navigator.serviceWorker.register(script, {scope: scope}),
+      'register should fail');
+}, 'Registering outside Service-Worker-Allowed path with parent reference');
+
+promise_test(async t => {
+  const script = build_script_url(
+      host_info.HTTPS_REMOTE_ORIGIN + '/');
+  const scope = 'resources/this-scope-is-normally-allowed'
+  const registration = await service_worker_unregister_and_register(
+      t, script, scope);
+  assert_true(registration instanceof ServiceWorkerRegistration, 'registered');
+  assert_equals(registration.scope, normalizeURL(scope));
+  return registration.unregister();
+}, 'Service-Worker-Allowed is cross-origin to script, registering on a normally allowed scope');
+
+promise_test(async t => {
+  const script = build_script_url(
+      host_info.HTTPS_REMOTE_ORIGIN + '/');
+  const scope = '/this-scope-is-normally-disallowed'
+  const registration = await service_worker_unregister_and_register(
+      t, script, scope);
+  assert_true(registration instanceof ServiceWorkerRegistration, 'registered');
+  assert_equals(registration.scope, normalizeURL(scope));
+  return registration.unregister();
+}, 'Service-Worker-Allowed is cross-origin to script, registering on a normally disallowed scope');
+
+promise_test(async t => {
+  const script = build_script_url(
+      host_info.HTTPS_REMOTE_ORIGIN + '/cross-origin/',
+      host_info.HTTPS_REMOTE_ORIGIN);
+  const scope = '/cross-origin/';
+  await service_worker_unregister(t, scope);
+  return promise_rejects(t,
+      'SecurityError',
+      navigator.serviceWorker.register(script, {scope: scope}),
+      'register should fail');
+}, 'Service-Worker-Allowed is cross-origin to page, same-origin to script');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/worker-interception-redirect-serviceworker.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/worker-interception-redirect-serviceworker.js
index b815442..f5ba5a3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/worker-interception-redirect-serviceworker.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/worker-interception-redirect-serviceworker.js
@@ -31,9 +31,18 @@
     return;
   }
 
-  // (3) The worker does a fetch() to simple.txt. Indicate that this service
+  // (3) The worker does an importScripts() to import-scripts-echo.py. Indicate
+  // that this service worker handled the request.
+  if (evt.request.url.indexOf('import-scripts-echo.py') != -1) {
+    const msg = encodeURIComponent(`${name} saw importScripts from the worker`);
+    evt.respondWith(fetch(`import-scripts-echo.py?msg=${msg}`));
+    return;
+  }
+
+  // (4) The worker does a fetch() to simple.txt. Indicate that this service
   // worker handled the request.
   if (evt.request.url.indexOf('simple.txt') != -1) {
     evt.respondWith(new Response(`${name} saw the fetch from the worker`));
+    return;
   }
 });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/worker-interception-redirect-webworker.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/worker-interception-redirect-webworker.js
index 7863af7..d602f23 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/worker-interception-redirect-webworker.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/worker-interception-redirect-webworker.js
@@ -18,11 +18,23 @@
 if (!greeting)
   greeting = 'the shared worker script was served from network';
 
+// Call importScripts() which fills |echo_output| with a string indicating
+// whether a service worker intercepted the importScripts() request.
+let echo_output;
+const import_scripts_msg = encodeURIComponent(
+    'importScripts: served from network');
+const import_scripts_url =
+    new URL(`import-scripts-echo.py?msg=${import_scripts_msg}`, resources_url);
+importScripts(import_scripts_url);
+const import_scripts_greeting = echo_output;
+
 self.onconnect = async function(e) {
   const port = e.ports[0];
   port.start();
   port.postMessage(greeting);
 
+  port.postMessage(import_scripts_greeting);
+
   const fetch_url = new URL('simple.txt', resources_url);
   const response = await fetch(fetch_url);
   const text = await response.text();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/worker-interception-redirect.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/worker-interception-redirect.https-expected.txt
index 1f76f58..2529f00e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/worker-interception-redirect.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/worker-interception-redirect.https-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 PASS initialize global state
 FAIL request to sw1 scope gets network redirect to sw2 scope assert_equals: expected "the shared worker script was served from network" but got "sw2 saw the request for the worker script"
-FAIL request to sw1 scope gets network redirect to out-of-scope assert_equals: expected "fetch(): sw1 saw the fetch from the worker" but got "fetch(): a simple text file\n"
+FAIL request to sw1 scope gets network redirect to out-of-scope assert_equals: expected "sw1 saw importScripts from the worker" but got "importScripts: served from network"
 PASS request to sw1 scope gets service-worker redirect to sw2 scope
-FAIL request to sw1 scope gets service-worker redirect to out-of-scope assert_equals: expected "fetch(): sw1 saw the fetch from the worker" but got "fetch(): a simple text file\n"
+FAIL request to sw1 scope gets service-worker redirect to out-of-scope assert_equals: expected "sw1 saw importScripts from the worker" but got "importScripts: served from network"
 PASS cleanup global state
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/worker-interception-redirect.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/worker-interception-redirect.https.html
index 4e79eac1..654495f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/worker-interception-redirect.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/worker-interception-redirect.https.html
@@ -32,8 +32,8 @@
 // 3. The request is redirected to scope2 or out-of-scope.
 // 4. The worker posts message to the page describing where the final response
 //   was served from (service worker or network).
-// 5. The worker does a fetch(), and posts back the response, which describes
-//   where the fetch response was served from.
+// 5. The worker does an importScripts() and fetch(), and posts back the
+//   responses, which describe where the responses where served from.
 //
 // Currently this only tests shared worker but dedicated worker tests should be
 // added in a future patch.
@@ -109,7 +109,8 @@
 
 function worker_redirect_test(worker_url,
                               expected_main_resource_message,
-                              expected_subresource_message,
+                              expected_import_scripts_message,
+                              expected_fetch_message,
                               description) {
   promise_test(async t => {
     // Create a frame to load the worker from. This way we can remove the frame
@@ -126,43 +127,44 @@
     const data = await get_message_from_worker(w);
     assert_equals(data, expected_main_resource_message);
 
-    // The worker does a fetch() after it starts up. Expect a message from the
-    // worker indicating which service worker provided the response for the
-    // fetch(), if any.
-    //
-    // Note: for some reason, Firefox would pass all these tests if a
-    // postMessage ping/pong step is added before the fetch(). I.e., if the
-    // page does postMessage() and the worker does fetch() in response to the
-    // ping, the fetch() is properly intercepted. See
-    // https://bugzilla.mozilla.org/show_bug.cgi?id=1452528. (Chrome can't pass
-    // the tests either way.)
-    const message = get_message_from_worker(w);
-    const data2 = await message;
-    assert_equals(data2, expected_subresource_message);
+    // The worker does an importScripts(). Expect a message from the worker
+    // indicating which service worker provided the response for the
+    // importScripts(), if any.
+    const import_scripts_message = await get_message_from_worker(w);
+    assert_equals(import_scripts_message, expected_import_scripts_message);
+
+    // The worker does a fetch(). Expect a message from the worker indicating
+    // which service worker provided the response for the fetch(), if any.
+    const fetch_message = await get_message_from_worker(w);
+    assert_equals(fetch_message, expected_fetch_message);
   }, description);
 }
 
 worker_redirect_test(
     build_worker_url('network', 'scope2'),
     'the shared worker script was served from network',
+    'sw1 saw importScripts from the worker',
     'fetch(): sw1 saw the fetch from the worker',
     'request to sw1 scope gets network redirect to sw2 scope');
 
 worker_redirect_test(
     build_worker_url('network', 'out-scope'),
     'the shared worker script was served from network',
+    'sw1 saw importScripts from the worker',
     'fetch(): sw1 saw the fetch from the worker',
     'request to sw1 scope gets network redirect to out-of-scope');
 
 worker_redirect_test(
     build_worker_url('serviceworker', 'scope2'),
     'sw2 saw the request for the worker script',
+    'sw2 saw importScripts from the worker',
     'fetch(): sw2 saw the fetch from the worker',
     'request to sw1 scope gets service-worker redirect to sw2 scope');
 
 worker_redirect_test(
     build_worker_url('serviceworker', 'out-scope'),
     'the shared worker script was served from network',
+    'sw1 saw importScripts from the worker',
     'fetch(): sw1 saw the fetch from the worker',
     'request to sw1 scope gets service-worker redirect to out-of-scope');
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/upgrade-insecure-requests/link-upgrade.sub.https.html b/third_party/WebKit/LayoutTests/external/wpt/upgrade-insecure-requests/link-upgrade.sub.https.html
index 6b315c8..46788e8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/upgrade-insecure-requests/link-upgrade.sub.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/upgrade-insecure-requests/link-upgrade.sub.https.html
@@ -2,6 +2,7 @@
 <html>
 
   <head>
+    <meta name="timeout" content="long">
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
   </head>
@@ -56,7 +57,7 @@
           });
         });
 
-        test.step_timeout(function(){test.force_timeout()}, 5000);
+        test.step_timeout(function(){test.force_timeout()}, 10000);
       }
     </script>
   </body>
diff --git a/third_party/WebKit/LayoutTests/fast/harness/results.html b/third_party/WebKit/LayoutTests/fast/harness/results.html
index c5777608..2fd1d29a 100644
--- a/third_party/WebKit/LayoutTests/fast/harness/results.html
+++ b/third_party/WebKit/LayoutTests/fast/harness/results.html
@@ -326,6 +326,7 @@
     <label id="CRASH"><input type="checkbox">Crash <span></span></label>
     <label id="TIMEOUT"><input type="checkbox">Timeout <span></span></label>
     <label id="TEXT"><input type="checkbox">Text failure <span></span></label>
+    <label id="HARNESS"><input type="checkbox">Harness failure <span></span></label>
     <label id="IMAGE"><input type="checkbox">Image failure <span></span></label>
     <label id="IMAGE_TEXT"><input type="checkbox">Image+text failure <span></span></label>
     <label id="SKIP"><input type="checkbox">Skipped <span></span></label>
@@ -873,10 +874,14 @@
     return test => {
       if (!queryFilter(test) || !textFilter(test))
         return false;
+      let resultKey = test.is_testharness_test ? "HARNESS" : test.actualFinal;
       // Ignore all results except final one, or not?
-      if (!(test.actualFinal in this.resultCounts))
-        this.resultCounts[test.actualFinal] = 0;
-      this.resultCounts[test.actualFinal]++;
+      if (!(resultKey in this.resultCounts))
+        this.resultCounts[resultKey] = 0;
+      this.resultCounts[resultKey]++;
+      if (test.actualFinal == "TEXT" && test.is_testharness_test) {
+        return filterMap.has("HARNESS");
+      }
       return filterMap.has(test.actualFinal);
     };
   },
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/opacity-from-zero-to-non-zero-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/opacity-from-zero-to-non-zero-expected.txt
new file mode 100644
index 0000000..e7fea51
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/opacity-from-zero-to-non-zero-expected.txt
@@ -0,0 +1,18 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow DIV id='target'",
+          "rect": [8, 8, 100, 100],
+          "reason": "appeared"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/hdr/color-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/hdr/color-jpeg-with-color-profile-expected.png
deleted file mode 100644
index 010e16b5..0000000
--- a/third_party/WebKit/LayoutTests/hdr/color-jpeg-with-color-profile-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-correct-suggestions-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-correct-suggestions-expected.txt
index 6cfaf4b..e50f0c6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-correct-suggestions-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-correct-suggestions-expected.txt
@@ -107,7 +107,7 @@
 Found: body
 
 Checking 'document   [    'bo'
-Not Found: 'body']
+Found: 'body'], displayed as 'body'
 
 Checking 'function hey(should'
 Not Found: shouldNotFindThisFunction
@@ -161,4 +161,77 @@
 Checking 'fun'
 Found: function
 
+Checking '"stringwithscary!@#$%^&*()\"'`~+-=".char'
+Found: charAt
+
+Checking '("hello" + "goodbye").char'
+Found: charAt
+
+Checking '({7: "string"})[3 + 4].char'
+Found: charAt
+
+Checking 'cantTouchThis++; "string".char'
+Found: charAt
+
+Checking 'cantTouchThis++ + "string".char'
+Found: charAt
+
+Checking 'var x = "string".char'
+Found: charAt
+
+Checking '({abc: 123}).a'
+Found: abc
+
+Checking '{dontFindLabels: 123}.dont'
+Not Found: dontFindLabels
+
+Checking 'const x = 5; {dontFindLabels: 123}.dont'
+Not Found: dontFindLabels
+
+Checking 'const x = {abc: 123}.a'
+Found: abc
+
+Checking 'x = {abc: 123}.'
+Found: abc
+
+Checking '[1,2,3].j'
+Found: join
+
+Checking 'document.body[{abc: "children"}.abc].'
+Found: length
+
+Checking 'new Date.'
+Found: UTC
+Not Found: toUTCString
+
+Checking 'new Date().'
+Not Found: UTC
+Found: toUTCString
+
+Checking 'const x = {7: "hi"}[3+4].'
+Found: anchor
+
+Checking '["length"]["length"].'
+Found: toExponential
+
+Checking '(await "no completions").'
+Not Found: toString
+
+Checking '(++cantTouchThis).'
+
+Checking '(cantTouchThis -= 2).'
+
+Checking 'new dontRunThis.'
+
+Checking 'new dontRunThis().'
+
+Checking '(new dontRunThis).'
+
+Checking '(dontRunThis`asdf`).'
+
+Checking 'dontRunThis().'
+
+Checking 'stall().'
+error: Execution was terminated
+
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-correct-suggestions.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-correct-suggestions.js
index 1da6a99a..abc03fe 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-correct-suggestions.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-correct-suggestions.js
@@ -26,6 +26,13 @@
         "'single-qouted'": true,
         "notDangerous();": true
     }
+    var cantTouchThis = false;
+    function dontRunThis() {
+      cantTouchThis = true;
+    }
+    function stall() {
+      while(true);
+    }
   `);
 
   var consoleEditor;
@@ -35,7 +42,7 @@
    * @param {!Array<string>} expected
    * @param {boolean=} force
    */
-  function testCompletions(text, expected, force) {
+  async function testCompletions(text, expected, force) {
     var cursorPosition = text.indexOf('|');
 
     if (cursorPosition < 0)
@@ -44,35 +51,40 @@
     consoleEditor.setText(text.replace('|', ''));
     consoleEditor.setSelection(TextUtils.TextRange.createFromLocation(0, cursorPosition));
     consoleEditor._autocompleteController.autocomplete(force);
-    return TestRunner.addSnifferPromise(consoleEditor._autocompleteController, '_onSuggestionsShownForTest').then(checkExpected);
+    var message =
+        'Checking \'' + text.replace('\n', '\\n').replace('\r', '\\r') + '\'';
 
-    /**
-     * @param {!Array<{text: string, title: string}>} suggestions
-     */
-    function checkExpected(suggestions) {
-      var completions = new Map(suggestions.map(suggestion => [suggestion, suggestion.text])).inverse();
-      var message = 'Checking \'' + text.replace('\n', '\\n').replace('\r', '\\r') + '\'';
+    if (force)
+      message += ' forcefully';
 
-      if (force)
-        message += ' forcefully';
+    TestRunner.addResult(message);
+    const suggestions = await TestRunner.addSnifferPromise(
+        consoleEditor._autocompleteController, '_onSuggestionsShownForTest');
+    var completions =
+        new Map(suggestions.map(suggestion => [suggestion, suggestion.text]))
+            .inverse();
 
-      TestRunner.addResult(message);
 
-      for (var i = 0; i < expected.length; i++) {
-        if (completions.has(expected[i])) {
-          for (var completion of completions.get(expected[i])) {
-            if (completion.title)
-              TestRunner.addResult('Found: ' + expected[i] + ', displayed as ' + completion.title);
-            else
-              TestRunner.addResult('Found: ' + expected[i]);
-          }
-        } else {
-          TestRunner.addResult('Not Found: ' + expected[i]);
+    for (var i = 0; i < expected.length; i++) {
+      if (completions.has(expected[i])) {
+        for (var completion of completions.get(expected[i])) {
+          if (completion.title)
+            TestRunner.addResult(
+                'Found: ' + expected[i] + ', displayed as ' + completion.title);
+          else
+            TestRunner.addResult('Found: ' + expected[i]);
         }
+      } else {
+        TestRunner.addResult('Not Found: ' + expected[i]);
       }
-
-      TestRunner.addResult('');
     }
+
+    if (await TestRunner.evaluateInPagePromise('cantTouchThis') !== false) {
+      TestRunner.addResult('ERROR! Side effects were detected!');
+      await TestRunner.evaluateInPagePromise('cantTouchThis = false');
+    }
+
+    TestRunner.addResult('');
   }
 
   function sequential(tests) {
@@ -85,7 +97,8 @@
   }
 
   sequential([
-    () => ConsoleTestRunner.waitUntilConsoleEditorLoaded().then(e => consoleEditor = e),
+    () => ConsoleTestRunner.waitUntilConsoleEditorLoaded().then(
+        e => consoleEditor = e),
     () => testCompletions('window.do', ['document']),
     () => testCompletions('win', ['window']),
     () => testCompletions('window["doc', ['"document"]']),
@@ -93,7 +106,9 @@
     () => testCompletions('window["document"]["body"].textC', ['textContent']),
     () => testCompletions('document.body.inner', ['innerText', 'innerHTML']),
     () => testCompletions('document["body"][window.do', ['document']),
-    () => testCompletions('document["body"][window["document"].body.childNodes[0].text', ['textContent']),
+    () => testCompletions(
+        'document["body"][window["document"].body.childNodes[0].text',
+        ['textContent']),
     () => testCompletions('templateString`asdf`should', ['shouldNotFindThis']),
     () => testCompletions('window.document.BODY', ['body']),
     () => testCompletions('window.dOcUmE', ['document']),
@@ -109,10 +124,16 @@
     () => testCompletions('["should', ['shouldNotFindThisFunction']),
     () => testCompletions('shou', ['should not find this']),
     () => testCompletions('myMap.get(', ['"first")', '"second")', '"third")']),
-    () => testCompletions('myMap.get(\'', ['\'first\')', '\'second\')', '\'third\')']),
+    () => testCompletions(
+        'myMap.get(\'', ['\'first\')', '\'second\')', '\'third\')']),
     () => testCompletions('myMap.set(\'firs', ['\'first\', ']),
-    () => testCompletions('myMap.set(should', ['shouldFindThisFunction', 'shouldNotFindThis', '"shouldNotFindThis")']),
-    () => testCompletions('myMap.delete(\'', ['\'first\')', '\'second\')', '\'third\')']),
+    () => testCompletions(
+        'myMap.set(should',
+        [
+          'shouldFindThisFunction', 'shouldNotFindThis', '"shouldNotFindThis")'
+        ]),
+    () => testCompletions(
+        'myMap.delete(\'', ['\'first\')', '\'second\')', '\'third\')']),
     () => testCompletions('document.   bo', ['body']),
     () => testCompletions('document.\tbo', ['body']),
     () => testCompletions('document.\nbo', ['body']),
@@ -128,12 +149,44 @@
     () => testCompletions('complicatedObject["foo', ['"foo-bar"]']),
     () => testCompletions('complicatedObject["foo-', ['"foo-bar"]']),
     () => testCompletions('complicatedObject["foo-bar', ['"foo-bar"]']),
-    () => testCompletions('complicatedObject["\'sing', ['"\'single-qouted\'"]']),
-    () => testCompletions('complicatedObject[\'\\\'sing', ['\'\\\'single-qouted\\\'\']']),
-    () => testCompletions('complicatedObject["\'single-qou', ['"\'single-qouted\'"]']),
-    () => testCompletions('complicatedObject["\\"double-qouted\\"', ['"\\"double-qouted\\""]']),
-    () => testCompletions('complicatedObject["notDangerous();', ['"notDangerous();"]']),
-    () => testCompletions('queryOb', ["queryObjects"]),
-    () => testCompletions('fun', ['function'])
+    () =>
+        testCompletions('complicatedObject["\'sing', ['"\'single-qouted\'"]']),
+    () => testCompletions(
+        'complicatedObject[\'\\\'sing', ['\'\\\'single-qouted\\\'\']']),
+    () => testCompletions(
+        'complicatedObject["\'single-qou', ['"\'single-qouted\'"]']),
+    () => testCompletions(
+        'complicatedObject["\\"double-qouted\\"', ['"\\"double-qouted\\""]']),
+    () => testCompletions(
+        'complicatedObject["notDangerous();', ['"notDangerous();"]']),
+    () => testCompletions('queryOb', ['queryObjects']),
+    () => testCompletions('fun', ['function']),
+    () => testCompletions(
+        '"stringwithscary!@#$%^&*()\\"\'`~+-=".char', ['charAt']),
+    () => testCompletions('("hello" + "goodbye").char', ['charAt']),
+    () => testCompletions('({7: "string"})[3 + 4].char', ['charAt']),
+    () => testCompletions('cantTouchThis++; "string".char', ['charAt']),
+    () => testCompletions('cantTouchThis++ + "string".char', ['charAt']),
+    () => testCompletions('var x = "string".char', ['charAt']),
+    () => testCompletions('({abc: 123}).a', ['abc']),
+    () => testCompletions('{dontFindLabels: 123}.dont', ['dontFindLabels']),
+    () => testCompletions('const x = 5; {dontFindLabels: 123}.dont', ['dontFindLabels']),
+    () => testCompletions('const x = {abc: 123}.a', ['abc']),
+    () => testCompletions('x = {abc: 123}.', ['abc']),
+    () => testCompletions('[1,2,3].j', ['join']),
+    () => testCompletions('document.body[{abc: "children"}.abc].', ['length']),
+    () => testCompletions('new Date.', ['UTC', 'toUTCString']),
+    () => testCompletions('new Date().', ['UTC', 'toUTCString']),
+    () => testCompletions('const x = {7: "hi"}[3+4].', ['anchor']),
+    () => testCompletions('["length"]["length"].', ['toExponential']),
+    () => testCompletions('(await "no completions").', ['toString']),
+    () => testCompletions('(++cantTouchThis).', []),
+    () => testCompletions('(cantTouchThis -= 2).', []),
+    () => testCompletions('new dontRunThis.', []),
+    () => testCompletions('new dontRunThis().', []),
+    () => testCompletions('(new dontRunThis).', []),
+    () => testCompletions('(dontRunThis`asdf`).', []),
+    () => testCompletions('dontRunThis().', []),
+    () => testCompletions('stall().', []),
   ]).then(TestRunner.completeTest);
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/modules-load-elements-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/modules-load-elements-expected.txt
index 7874819..6f84aa0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/modules-load-elements-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/modules-load-elements-expected.txt
@@ -4,6 +4,7 @@
     color_picker
     elements
     event_listeners
+    formatter
     inline_editor
     object_ui
 Now with animations pane
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/service-worker-allowed-worker.php b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/service-worker-allowed-worker.php
deleted file mode 100644
index 0bd5d72c..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/service-worker-allowed-worker.php
+++ /dev/null
@@ -1,6 +0,0 @@
-<?php
-header('Content-Type: application/javascript');
-if (isset($_GET['ServiceWorkerAllowed'])) {
-  header('Service-Worker-Allowed: ' . $_GET['ServiceWorkerAllowed']);
-}
-?>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/service-worker-allowed.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/service-worker-allowed.html
deleted file mode 100644
index 419b8a4..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/service-worker-allowed.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<!DOCTYPE html>
-<!-- This test should be upstreamed to WPT if an existing test
-     isn't there yet.
--->
-<title>Service Worker: Service-Worker-Allowed header</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/get-host-info.js"></script>
-<script src="resources/test-helpers.js"></script>
-<script>
-
-var host_info = get_host_info();
-
-promise_test(function(t) {
-    var script = 'resources/service-worker-allowed-worker.php' +
-      '?ServiceWorkerAllowed=/allowed-path';
-    var scope = '/allowed-path';
-    return navigator.serviceWorker.register(script, {scope: scope})
-      .then(function(registration) {
-          assert_true(
-            registration instanceof ServiceWorkerRegistration,
-            'Successfully registered.');
-          assert_equals(
-            registration.scope,
-            normalizeURL(scope),
-            'Registering within Service-Worker-Allowed path should pass');
-          service_worker_unregister_and_done(t, scope);
-        })
-  }, 'Registering within Service-Worker-Allowed path');
-
-promise_test(function(t) {
-    var script = 'resources/service-worker-allowed-worker.php' +
-      '?ServiceWorkerAllowed=../allowed-path-with-parent';
-    var scope = 'allowed-path-with-parent';
-    return navigator.serviceWorker.register(script, {scope: scope})
-      .then(function(registration) {
-          assert_true(
-            registration instanceof ServiceWorkerRegistration,
-            'Successfully registered.');
-          assert_equals(
-            registration.scope,
-            normalizeURL(scope),
-            'Registering within Service-Worker-Allowed path with parent ' +
-            'reference should pass');
-          service_worker_unregister_and_done(t, scope);
-        })
-  }, 'Registering within Service-Worker-Allowed path with parent reference');
-
-promise_test(function(t) {
-    var script = 'resources/service-worker-allowed-worker.php' +
-      '?ServiceWorkerAllowed=/allowed-path';
-    var scope = '/disallowed-path';
-    return promise_rejects(t,
-        'SecurityError',
-        navigator.serviceWorker.register(script, {scope: scope}),
-        'Registering outside Service-Worker-Allowed path should fail');
-  }, 'Registering outside Service-Worker-Allowed path');
-
-promise_test(function(t) {
-    var script = 'resources/service-worker-allowed-worker.php' +
-      '?ServiceWorkerAllowed=../allowed-path-with-parent';
-    var scope = '/allowed-path-with-parent';
-    return promise_rejects(t,
-        'SecurityError',
-        navigator.serviceWorker.register(script, {scope: scope}),
-        'Registering outside Service-Worker-Allowed path with parent ' +
-          'reference should fail');
-  }, 'Registering outside Service-Worker-Allowed path with parent reference');
-
-promise_test(function(t) {
-    var script = host_info.HTTPS_REMOTE_ORIGIN +
-      '/serviceworker/resources/' +
-      'service-worker-allowed-worker.php' +
-      '?ServiceWorkerAllowed=' +
-      host_info.HTTP_REMOTE_ORIGIN + '/cross-origin/';
-    var scope = '/cross-origin/';
-    return promise_rejects(t,
-        'SecurityError',
-        navigator.serviceWorker.register(script, {scope: scope}),
-        'Registering cross-origin Service-Worker-Allowed should fail');
-  }, 'Registering cross-origin Service-Worker-Allowed');
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/images/cHRM_color_spin-expected.png b/third_party/WebKit/LayoutTests/images/cHRM_color_spin-expected.png
index a05298a..8f77312 100644
--- a/third_party/WebKit/LayoutTests/images/cHRM_color_spin-expected.png
+++ b/third_party/WebKit/LayoutTests/images/cHRM_color_spin-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/images/color-jpeg-with-color-profile-expected.png
index 977c381c..d416a0f 100644
--- a/third_party/WebKit/LayoutTests/images/color-jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-animate-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-animate-expected.png
index c34bf0f7..e2a4f45 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-animate-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-animate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-animate-rotate-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-animate-rotate-expected.png
index cc3f2d5..b440db7 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-animate-rotate-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-animate-rotate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-background-clip-text-expected.png
index 12bc6570..ddc3ed7 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-background-image-cover-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-background-image-cover-expected.png
index e0786182..ea3c052 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-background-image-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-background-image-repeat-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-background-image-repeat-expected.png
index 7d888d9..96e0e064bf 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-background-image-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-background-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-background-image-space-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-background-image-space-expected.png
index c5d0b0f0..6616565 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-background-image-space-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-background-image-space-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-border-fade-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-border-fade-expected.png
index 5ae5650..f205c5e 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-border-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-border-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-border-image-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-border-image-expected.png
index e9925129..4dcd852 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-clip-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-clip-expected.png
index 91aac89..485c157 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-clip-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-clip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-iframe-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-iframe-expected.png
index 3c24c8e..4a74339 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-iframe-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-iframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-image-canvas-expected.png
index 218f124d..69c072a 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-image-canvas-pattern-expected.png
index 6f07c20..606ef99 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-image-object-fit-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-image-object-fit-expected.png
index ec2a82d..74b48b6 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-image-object-fit-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-image-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-image-pseudo-content-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-image-pseudo-content-expected.png
index 385f12f..91cf9a2 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-image-pseudo-content-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-image-pseudo-content-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-image-svg-resource-url-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-image-svg-resource-url-expected.png
index a7328d1d..1fda3c6 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-image-svg-resource-url-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-image-svg-resource-url-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-layer-filter-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-layer-filter-expected.png
deleted file mode 100644
index 3a67f62..0000000
--- a/third_party/WebKit/LayoutTests/images/color-profile-layer-filter-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-mask-image-svg-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-mask-image-svg-expected.png
index 5a804fa..2652c65 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-mask-image-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-mask-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-munsell-adobe-to-srgb-expected.txt b/third_party/WebKit/LayoutTests/images/color-profile-munsell-adobe-to-srgb-expected.txt
index 33aac4f..d5d9e0d21 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-munsell-adobe-to-srgb-expected.txt
+++ b/third_party/WebKit/LayoutTests/images/color-profile-munsell-adobe-to-srgb-expected.txt
@@ -1,36 +1,36 @@
 
 Color         Actual        Expected      dE
 --------------------------------------------
-Dark Skin     114,80,64     115,80,64     1
+Dark Skin     115,80,64     115,80,64     0
 Light Skin    195,150,130   195,151,130   1
-Blue Sky      94,123,156    94,123,156    0
-Foliage       88,108,65     88,108,65     0
+Blue Sky      94,123,157    94,123,156    1
+Foliage       89,108,65     88,108,65     1
 Blue Flower   130,129,177   130,129,177   0
 Bluish Green  100,190,171   100,190,171   0
 --------------------------------------------
-Orange        217,121,37    217,122,37    1
-Purplish Blue 72,90,166     72,91,165     1
+Orange        216,122,37    217,122,37    1
+Purplish Blue 72,91,166     72,91,165     1
 Moderate Red  194,84,97     194,84,98     1
-Purple        90,60,106     91,59,107     2
-Yellow Green  160,188,60    160,188,60    0
-Orange Yellow 231,163,42    230,163,42    1
+Purple        91,60,107     91,59,107     1
+Yellow Green  160,187,60    160,188,60    1
+Orange Yellow 230,163,42    230,163,42    0
 --------------------------------------------
 Blue          47,60,153     46,60,153     1
 Green         70,149,69     71,150,69     1
-Red           177,45,56     177,44,56     1
+Red           177,44,56     177,44,56     0
 Yellow        239,200,27    238,200,27    1
 Magenta       187,82,147    187,82,148    1
-Cyan (*)      0,135,165     0,135,166     1
+Cyan (*)      0,135,166     0,135,166     0
 --------------------------------------------
-White         243,242,236   243,242,237   1
-Neutral 8     202,202,200   201,201,201   2
+White         243,241,236   243,242,237   1
+Neutral 8     201,201,200   201,201,201   1
 Neutral 6.5   160,161,160   161,161,161   1
-Neutral 5     123,121,120   122,122,121   2
+Neutral 5     123,122,121   122,122,121   1
 Neutral 3.5   83,83,83      83,83,83      0
 Black         50,50,50      50,49,50      1
 --------------------------------------------
 
-Result: total RMS color error: 1.06
+Result: total RMS color error: 0.84
  * Munsell Cyan is outside 255 sRGB gamut
 
   
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-object-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-object-expected.png
index 01bf3fd..0fc900f 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-object-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-svg-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-svg-expected.png
index 13240f5..1b3b00f 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/color-profile-svg-foreign-object-expected.png b/third_party/WebKit/LayoutTests/images/color-profile-svg-foreign-object-expected.png
index b9d0f32..1f6702f 100644
--- a/third_party/WebKit/LayoutTests/images/color-profile-svg-foreign-object-expected.png
+++ b/third_party/WebKit/LayoutTests/images/color-profile-svg-foreign-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/paletted-png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/images/paletted-png-with-color-profile-expected.png
index 46dcb35..2d73757 100644
--- a/third_party/WebKit/LayoutTests/images/paletted-png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/images/paletted-png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/webp-color-profile-lossless-expected.png b/third_party/WebKit/LayoutTests/images/webp-color-profile-lossless-expected.png
index b2eac244..07427f3e 100644
--- a/third_party/WebKit/LayoutTests/images/webp-color-profile-lossless-expected.png
+++ b/third_party/WebKit/LayoutTests/images/webp-color-profile-lossless-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/webp-color-profile-lossy-alpha-expected.png b/third_party/WebKit/LayoutTests/images/webp-color-profile-lossy-alpha-expected.png
index 647765f..e110b42 100644
--- a/third_party/WebKit/LayoutTests/images/webp-color-profile-lossy-alpha-expected.png
+++ b/third_party/WebKit/LayoutTests/images/webp-color-profile-lossy-alpha-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/webp-color-profile-lossy-expected.png b/third_party/WebKit/LayoutTests/images/webp-color-profile-lossy-expected.png
index 340a356..ef6f7f2 100644
--- a/third_party/WebKit/LayoutTests/images/webp-color-profile-lossy-expected.png
+++ b/third_party/WebKit/LayoutTests/images/webp-color-profile-lossy-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/media/color-profile-munsell-bt601-smpte-to-srgb-expected.txt b/third_party/WebKit/LayoutTests/media/color-profile-munsell-bt601-smpte-to-srgb-expected.txt
index 9b66622..023204c 100644
--- a/third_party/WebKit/LayoutTests/media/color-profile-munsell-bt601-smpte-to-srgb-expected.txt
+++ b/third_party/WebKit/LayoutTests/media/color-profile-munsell-bt601-smpte-to-srgb-expected.txt
@@ -3,24 +3,24 @@
 --------------------------------------------
 Dark Skin     115,80,64     115,80,64     0
 Light Skin    195,151,130   195,151,130   0
-Blue Sky      93,123,156    94,123,156    1
+Blue Sky      94,123,156    94,123,156    0
 Foliage       88,108,65     88,108,65     0
-Blue Flower   130,128,177   130,129,177   1
+Blue Flower   130,129,177   130,129,177   0
 Bluish Green  100,190,171   100,190,171   0
 --------------------------------------------
 Orange        217,122,37    217,122,37    0
-Purplish Blue 71,91,165     72,91,165     1
-Moderate Red  194,83,98     194,84,98     1
-Purple        90,59,107     91,59,107     1
+Purplish Blue 72,91,165     72,91,165     0
+Moderate Red  194,84,98     194,84,98     0
+Purple        91,59,107     91,59,107     0
 Yellow Green  160,188,60    160,188,60    0
 Orange Yellow 230,163,42    230,163,42    0
 --------------------------------------------
-Blue          47,60,153     46,60,153     1
+Blue          46,60,153     46,60,153     0
 Green         71,150,69     71,150,69     0
 Red           177,44,56     177,44,56     0
 Yellow        238,200,27    238,200,27    0
 Magenta       187,82,148    187,82,148    0
-Cyan (*)      35,134,166    0,135,166     35
+Cyan (*)      34,135,166    0,135,166     34
 --------------------------------------------
 White         243,242,237   243,242,237   0
 Neutral 8     201,201,201   201,201,201   0
@@ -34,8 +34,8 @@
 SG White 1/4  74,74,74      74,74,74      0
 SG Black 4x   79,79,79      79,79,79      0
 SG Black 2x   48,48,48      48,48,48      0
-SG Black      32,32,32      31,31,31      2
+SG Black      31,31,31      31,31,31      0
 --------------------------------------------
 
-Result: total RMS color error: 0.58
+Result: total RMS color error: 0.00
 
diff --git a/third_party/WebKit/LayoutTests/media/color-profile-munsell-bt709-to-srgb-expected.txt b/third_party/WebKit/LayoutTests/media/color-profile-munsell-bt709-to-srgb-expected.txt
index d34b900..28fb191f 100644
--- a/third_party/WebKit/LayoutTests/media/color-profile-munsell-bt709-to-srgb-expected.txt
+++ b/third_party/WebKit/LayoutTests/media/color-profile-munsell-bt709-to-srgb-expected.txt
@@ -1,28 +1,28 @@
 
 Color         Actual        Expected      dE
 --------------------------------------------
-Dark Skin     114,80,64     115,80,64     1
-Light Skin    195,151,129   195,151,130   1
-Blue Sky      93,123,155    94,123,156    1
+Dark Skin     115,80,64     115,80,64     0
+Light Skin    195,151,130   195,151,130   0
+Blue Sky      94,123,156    94,123,156    0
 Foliage       88,108,65     88,108,65     0
-Blue Flower   129,128,177   130,129,177   1
+Blue Flower   130,129,177   130,129,177   0
 Bluish Green  100,190,171   100,190,171   0
 --------------------------------------------
-Orange        218,122,37    217,122,37    1
-Purplish Blue 72,90,165     72,91,165     1
+Orange        217,122,37    217,122,37    0
+Purplish Blue 72,91,165     72,91,165     0
 Moderate Red  194,84,98     194,84,98     0
-Purple        90,59,107     91,59,107     1
+Purple        91,59,107     91,59,107     0
 Yellow Green  160,188,60    160,188,60    0
 Orange Yellow 230,163,42    230,163,42    0
 --------------------------------------------
 Blue          46,60,153     46,60,153     0
-Green         71,150,68     71,150,69     1
+Green         72,150,69     71,150,69     1
 Red           177,44,56     177,44,56     0
 Yellow        238,200,28    238,200,27    1
 Magenta       187,82,148    187,82,148    0
 Cyan (*)      0,135,166     0,135,166     0
 --------------------------------------------
-White         244,242,237   243,242,237   1
+White         243,242,237   243,242,237   0
 Neutral 8     201,201,201   201,201,201   0
 Neutral 6.5   161,161,161   161,161,161   0
 Neutral 5     122,122,121   122,122,121   0
@@ -34,8 +34,8 @@
 SG White 1/4  74,74,74      74,74,74      0
 SG Black 4x   79,79,79      79,79,79      0
 SG Black 2x   48,48,48      48,48,48      0
-SG Black      32,32,32      31,31,31      2
+SG Black      31,31,31      31,31,31      0
 --------------------------------------------
 
-Result: total RMS color error: 0.68
+Result: total RMS color error: 0.26
 
diff --git a/third_party/WebKit/LayoutTests/media/color-profile-video-poster-image-expected.png b/third_party/WebKit/LayoutTests/media/color-profile-video-poster-image-expected.png
index 6831dcc..459702f5 100644
--- a/third_party/WebKit/LayoutTests/media/color-profile-video-poster-image-expected.png
+++ b/third_party/WebKit/LayoutTests/media/color-profile-video-poster-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/immersive-mode-adds-css-class.html b/third_party/WebKit/LayoutTests/media/controls/modern/immersive-mode-adds-css-class.html
new file mode 100644
index 0000000..e221204d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/controls/modern/immersive-mode-adds-css-class.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<title>Test that enabling immersive mode adds the immersive mode CSS class.</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../media-controls.js"></script>
+<video controls width=400 preload=metadata src="../../content/60_sec_video.webm"></video>
+<script>
+async_test(t => {
+  const video = document.querySelector('video');
+  const controls = mediaControls(video);
+  const immersiveModeCSSClass = "immersive-mode";
+
+  window.onload = t.step_func_done(() => {
+    assert_false(controls.classList.contains(immersiveModeCSSClass));
+    enableImmersiveMode(t);
+    assert_true(controls.classList.contains(immersiveModeCSSClass));
+  });
+});
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/media/media-controls.js b/third_party/WebKit/LayoutTests/media/media-controls.js
index 7276a0b..9cf97e5b 100644
--- a/third_party/WebKit/LayoutTests/media/media-controls.js
+++ b/third_party/WebKit/LayoutTests/media/media-controls.js
@@ -512,3 +512,14 @@
   if (window.internals)
     window.internals.setMediaControlsTestMode(video, true);
 }
+
+function enableImmersiveMode(t) {
+  if (!window.internals)
+    return;
+
+  const oldImmersive = internals.settings.immersiveModeEnabled;
+  internals.settings.setImmersiveModeEnabled(true);
+  t.add_cleanup(() => {
+    window.internals.settings.setImmersiveModeEnabled(oldImmersive);
+  });
+}
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited-expected.html
new file mode 100644
index 0000000..b94a0d1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited-expected.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div id="target" style="width: 100px; height: 100px; background: green; opacity: 0.5; will-change: transform"></div>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited-expected.txt
new file mode 100644
index 0000000..ecf68fdd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited-expected.txt
@@ -0,0 +1,30 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutBlockFlow DIV id='target'",
+      "position": [8, 8],
+      "bounds": [100, 100],
+      "opacity": 0.5,
+      "contentsOpaque": true,
+      "backgroundColor": "#008000"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited.html b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited.html
new file mode 100644
index 0000000..6bb40bda
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<div id="target" style="width: 100px; height: 100px; background: green; opacity: 0; will-change: opacity"></div>
+<script src="../resources/text-based-repaint.js"></script>
+<script>
+function repaintTest() {
+  target.style.opacity = 0.5;
+};
+onload = runRepaintAndPixelTest;
+</script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/opacity-from-zero-to-non-zero-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/opacity-from-zero-to-non-zero-expected.html
new file mode 100644
index 0000000..7b1d9694
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/opacity-from-zero-to-non-zero-expected.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div id="target" style="width: 100px; height: 100px; background: green; opacity: 0.5"></div>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/opacity-from-zero-to-non-zero-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/opacity-from-zero-to-non-zero-expected.txt
new file mode 100644
index 0000000..4bd0fc5f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/opacity-from-zero-to-non-zero-expected.txt
@@ -0,0 +1,29 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow DIV id='target'",
+          "rect": [8, 8, 100, 100],
+          "reason": "appeared"
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/opacity-from-zero-to-non-zero.html b/third_party/WebKit/LayoutTests/paint/invalidation/opacity-from-zero-to-non-zero.html
new file mode 100644
index 0000000..80fb10dc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/opacity-from-zero-to-non-zero.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<div id="target" style="width: 100px; height: 100px; background: green; opacity: 0"></div>
+<script src="resources/text-based-repaint.js"></script>
+<script>
+function repaintTest() {
+  target.style.opacity = 0.5;
+};
+onload = runRepaintAndPixelTest;
+</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/color-matching/image-color-matching-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/color-matching/image-color-matching-expected.png
index 4841a87..fb4433a7 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/color-matching/image-color-matching-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/color-matching/image-color-matching-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-image-filter-all-expected.png
index 723f8df..913be2b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-image-shape-expected.png b/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-image-shape-expected.png
index 0d869b19c..f1a95e0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-image-shape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-image-shape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-munsell-adobe-to-srgb-expected.png
index 2e5f8b90..46b2d26e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-svg-fill-text-expected.png b/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-svg-fill-text-expected.png
index 9882b271..4823308 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-svg-fill-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-svg-fill-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/images/jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/linux/images/jpeg-with-color-profile-expected.png
index 6697ab3..8fb52af 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/images/jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/images/jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/images/png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/linux/images/png-with-color-profile-expected.png
index 6697ab3..8fb52af 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/images/png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/images/png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png
index 76955539..cdce972 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-munsell-bt709-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-munsell-bt709-to-srgb-expected.png
index 652b7737..392453f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-munsell-bt709-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-munsell-bt709-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/relative-sized-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/relative-sized-image-expected.png
index d3186cd..c96075f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/relative-sized-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/relative-sized-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index a3b73b5..609b97d3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/linux/scrollbars/listbox-scrollbar-combinations-expected.png
index 46ab63e..3393729 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png
index d1b1832..68c9ffb 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png
index 4eefb21..b6235f4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
index 8d19156..a1ae12c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-03-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
index b224436e..238407ab 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-06-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
index 909a964..b960b019 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-use-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-use-01-t-expected.png
index 013dee13..c69f29e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-use-01-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/struct-use-01-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
index ebe27866..659d31bc 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
index 0ba5f13..fa08e8c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
index 0ba5f13..fa08e8c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
index ce9e386..7c9749a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/compositing/color-matching/image-color-matching-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/compositing/color-matching/image-color-matching-expected.png
index 4841a87..fb4433a7 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/compositing/color-matching/image-color-matching-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/compositing/color-matching/image-color-matching-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/relative-sized-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/relative-sized-image-expected.png
index d3186cd..c96075f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/relative-sized-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/relative-sized-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index eddae93..3d5cc67 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spv175/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png
index 5acdf50f..76129de 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/12-55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/182-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/182-expected.png
index e6dd827a..8990f01 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/182-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/182-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/2-dht-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/2-dht-expected.png
index 6021ce36e..64a6d47 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/2-dht-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/2-dht-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/23-55-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/23-55-expected.png
index 919d5262..b6d4fa3a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/23-55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/23-55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/55-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/55-expected.png
index 4a87365..f4dff0b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/alt-text-wrapping-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/alt-text-wrapping-expected.png
index 1623f55..c63299c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/alt-text-wrapping-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/alt-text-wrapping-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png
index 49a5215..3f1ea99 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-image-shape-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-image-shape-expected.png
index 2d7fb3e..ef85bd5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-image-shape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-image-shape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
index cbdd646d..146fb0c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
index 1f0c7f9..b6d0183e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
index f4aaabc..5f1ce9a9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png
index 5f8e12e..43f64621 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png
index 6ab0387..fb927f7 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-css-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-css-expected.png
index e203d9c..02f84f3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-css-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-css-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-expected.png
index 2b62469..4a6e8ab 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png
index 557780d..f8e945294 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/image-map-anchor-children-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/image-map-anchor-children-expected.png
index 186f75d..5ed844d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/image-map-anchor-children-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/image-map-anchor-children-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png
index b31a1555..c7dbd7d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
index 3f82e16..d11b4b18 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
index d0f0a82..651f10e0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png
index c37de0c..f3e5e7c2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
index 222cdc0..c6bad0b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/png-with-color-profile-expected.png
index c37de0c..f3e5e7c2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png
index ecc77c5..815fa00 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png
index 123d4cc..1220492 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png
index 6a0fc82b..379a0ff 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png
index 77f19e9..f01d135 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png
index a9185ba..e096b1a9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png
index 8b99842..f19511ae 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png
index 06d5b77..bcda162b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-images-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-images-expected.png
index 51cf7a48..c448dc7 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/rendering-broken-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
index 0ee153b..b62f060 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
index 46ab63e..3393729 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/images/color-profile-munsell-adobe-to-srgb-expected.png
index 81ed3529..d784298 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/images/color-profile-svg-fill-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/images/color-profile-svg-fill-text-expected.png
index 08343bfa..0116084e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/images/color-profile-svg-fill-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/images/color-profile-svg-fill-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/12-55-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/12-55-expected.png
index 28f50cd0..d519c40 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/12-55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/12-55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/182-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/182-expected.png
index 778d6e47..c6e501582 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/182-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/182-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/2-dht-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/2-dht-expected.png
index cbe4ccc..cdc744ff 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/2-dht-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/2-dht-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/23-55-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/23-55-expected.png
index 1d062a1..159be384 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/23-55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/23-55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/55-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/55-expected.png
index b72a10f5..19a279a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
index be03ed5a..465ab0f0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
index b40aea6f..1e03484 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
index 1c785bd..87e7fb20 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
index e00db5a..c31892b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/12-55-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/12-55-expected.png
index 591353d..3fbb622b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/12-55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/12-55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/182-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/182-expected.png
index c401715..fd5780f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/182-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/182-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/2-dht-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/2-dht-expected.png
index 8c665b5..eaa1507 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/2-dht-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/2-dht-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/23-55-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/23-55-expected.png
index 63a6c77..7db18a5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/23-55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/23-55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/55-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/55-expected.png
index 15cc6a27..33b6f83 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/exotic-color-space/images/55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/color-matching/image-color-matching-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/color-matching/image-color-matching-expected.png
index 46ef26a..e3d8337e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/color-matching/image-color-matching-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/color-matching/image-color-matching-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-clamping-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-clamping-expected.png
index 576c31e..616c172 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-clamping-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-clamping-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-clamping-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-clamping-expected.txt
index a7360dab..91f30ef 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-clamping-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-clamping-expected.txt
@@ -3,20 +3,28 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
+      LayoutImage {IMG} at (0,0) size 160x90
       LayoutText {#text} at (160,76) size 4x18
         text run at (160,76) width 4: " "
+      LayoutImage {IMG} at (164,0) size 160x90
       LayoutText {#text} at (324,76) size 4x18
         text run at (324,76) width 4: " "
+      LayoutImage {IMG} at (328,0) size 160x90
       LayoutText {#text} at (488,76) size 4x18
         text run at (488,76) width 4: " "
+      LayoutImage {IMG} at (492,0) size 160x90
       LayoutText {#text} at (652,76) size 4x18
         text run at (652,76) width 4: " "
+      LayoutImage {IMG} at (0,94) size 160x90
       LayoutText {#text} at (160,170) size 4x18
         text run at (160,170) width 4: " "
+      LayoutImage {IMG} at (164,94) size 160x90
       LayoutText {#text} at (324,170) size 4x18
         text run at (324,170) width 4: " "
+      LayoutImage {IMG} at (328,94) size 160x90
       LayoutText {#text} at (488,170) size 4x18
         text run at (488,170) width 4: " "
+      LayoutImage {IMG} at (492,94) size 160x90
       LayoutText {#text} at (652,170) size 4x18
         text run at (652,170) width 4: " "
       LayoutText {#text} at (160,264) size 4x18
@@ -26,22 +34,6 @@
       LayoutText {#text} at (488,264) size 4x18
         text run at (488,264) width 4: " "
       LayoutText {#text} at (0,0) size 0x0
-layer at (8,8) size 160x90
-  LayoutImage {IMG} at (0,0) size 160x90
-layer at (172,8) size 160x90
-  LayoutImage {IMG} at (164,0) size 160x90
-layer at (336,8) size 160x90
-  LayoutImage {IMG} at (328,0) size 160x90
-layer at (500,8) size 160x90
-  LayoutImage {IMG} at (492,0) size 160x90
-layer at (8,102) size 160x90
-  LayoutImage {IMG} at (0,94) size 160x90
-layer at (172,102) size 160x90
-  LayoutImage {IMG} at (164,94) size 160x90
-layer at (336,102) size 160x90
-  LayoutImage {IMG} at (328,94) size 160x90
-layer at (500,102) size 160x90
-  LayoutImage {IMG} at (492,94) size 160x90
 layer at (8,196) size 160x90
   LayoutImage {IMG} at (0,188) size 160x90
 layer at (172,196) size 160x90
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-expected.png
index 4e87f450..e31882c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-expected.txt
index 0b04f481..f9f99a4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/effect-brightness-expected.txt
@@ -3,10 +3,13 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
+      LayoutImage {IMG} at (0,0) size 160x90
       LayoutText {#text} at (160,76) size 4x18
         text run at (160,76) width 4: " "
+      LayoutImage {IMG} at (164,0) size 160x90
       LayoutText {#text} at (324,76) size 4x18
         text run at (324,76) width 4: " "
+      LayoutImage {IMG} at (328,0) size 160x90
       LayoutText {#text} at (488,76) size 4x18
         text run at (488,76) width 4: " "
       LayoutText {#text} at (652,76) size 4x18
@@ -16,12 +19,6 @@
       LayoutText {#text} at (324,170) size 4x18
         text run at (324,170) width 4: " "
       LayoutText {#text} at (0,0) size 0x0
-layer at (8,8) size 160x90
-  LayoutImage {IMG} at (0,0) size 160x90
-layer at (172,8) size 160x90
-  LayoutImage {IMG} at (164,0) size 160x90
-layer at (336,8) size 160x90
-  LayoutImage {IMG} at (328,0) size 160x90
 layer at (500,8) size 160x90
   LayoutImage {IMG} at (492,0) size 160x90
 layer at (8,102) size 160x90
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-landscape-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-landscape-expected.png
index b709b30..bdee278 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-landscape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-landscape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-portrait-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-portrait-expected.png
index 9cde360..2450010f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-portrait-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-portrait-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/hdr/color-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/hdr/color-jpeg-with-color-profile-expected.png
index dc798e6..b0157304 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/hdr/color-jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/hdr/color-jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-expected.png
index 730f5689..3f444f3b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-png-expected.png
index 730f5689..3f444f3b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-border-radius-expected.png
index 75b980ef..536ad6b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-drag-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-drag-image-expected.png
index 4041fbf..1877f1a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-drag-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-drag-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-filter-expected.png
index f35a381..0a1cce7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-group-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-group-expected.png
index 04354ed..4599e3a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-group-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-group-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-canvas-svg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-canvas-svg-expected.png
index fa863df7..b74c1f2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-canvas-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-canvas-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-expected.png
index fdb2bd3..ce87d12 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-filter-all-expected.png
index 1dcba1c..21762069 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-shape-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-shape-expected.png
index 18e442a..36f844d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-shape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-image-shape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-layer-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-layer-expected.png
index 62a796c..6be5860b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-layer-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-layer-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-layer-filter-expected.png
index 0328d65..bc98a2d98 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-layer-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-layer-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-munsell-adobe-to-srgb-expected.png
index e271aa1..70e5c536 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-svg-fill-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-svg-fill-text-expected.png
index 5773e7e..0420e36 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-svg-fill-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-svg-fill-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/cross-fade-background-size-expected.png
index a8d5804..59603e2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/jpeg-with-color-profile-expected.png
index a910e01..081fb43d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/png-suite/test-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/png-suite/test-expected.png
index 52971d4..1ba0f6a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/png-suite/test-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/png-suite/test-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/png-with-color-profile-expected.png
index a910e01..081fb43d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png
index e5b63e7..c47cc4b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-munsell-bt709-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-munsell-bt709-to-srgb-expected.png
index ef22cc73..00f1817 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-munsell-bt709-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-munsell-bt709-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/relative-sized-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/relative-sized-image-expected.png
index 264692c9..98f9c11 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/relative-sized-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/relative-sized-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index 7b62bbe..0c178899 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png
index ef18458..5c6a2d6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png
index 338ab9c9..2d06e16 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png
index c6305ab0..1081f954 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
index 64fe637..feab784 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-03-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
index 1eacfb57..9656eb97 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-06-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
index 5512436..5c624f3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-use-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-use-01-t-expected.png
index 8989246..e42df63 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-use-01-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/struct-use-01-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
index 33fbbe3c..2a707a8a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
index 33fbbe3c..2a707a8a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
index 48d301818..dc07743 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/12-55-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/12-55-expected.png
index b97be9a..81624be4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/12-55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/12-55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/182-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/182-expected.png
index 9151d5cf..e95d6ba 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/182-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/182-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/2-comp-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/2-comp-expected.png
index a9fd056..41cbc00 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/2-comp-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/2-comp-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/2-dht-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/2-dht-expected.png
index 0e84053..1dfbbac2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/2-dht-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/2-dht-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/23-55-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/23-55-expected.png
index 42a15c7..219b98c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/23-55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/23-55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/55-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/55-expected.png
index 8052391..009168c9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/alt-text-wrapping-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/alt-text-wrapping-expected.png
index 45b76a9..66552c89 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/alt-text-wrapping-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/alt-text-wrapping-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cHRM_color_spin-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cHRM_color_spin-expected.png
index ee9fc669..3cb080e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cHRM_color_spin-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cHRM_color_spin-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-jpeg-with-color-profile-expected.png
index 7c21747..c701ee4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-animate-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-animate-expected.png
index 0997ad0..f3d9aa21 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-animate-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-animate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-animate-rotate-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-animate-rotate-expected.png
index 93f8770..daab984 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-animate-rotate-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-animate-rotate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-clip-text-expected.png
index 64946df..e8fb9f9d9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cover-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cover-expected.png
index da1c765..0781009 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
index b98803b..278d2e6df 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
index b98803b..278d2e6df 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-repeat-expected.png
index 138fb41..8634ca6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-space-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-space-expected.png
index d99d4a1..be583ed 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-space-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-space-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-fade-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-fade-expected.png
index 406b718..6262b35 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-expected.png
index ca30f5d..d1aca332 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
index 656f25aa..eba2d9c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-radius-expected.png
index 932bd71..f85bc2a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-clip-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-clip-expected.png
index 680b124..297bba0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-clip-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-clip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-drag-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-drag-image-expected.png
deleted file mode 100644
index 4041fbf..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-drag-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-filter-expected.png
index 5a70f85..4302394e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-group-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-group-expected.png
index e225a5f..1856caf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-group-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-group-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-iframe-expected.png
index 4f70dc0..bf161fcc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-iframe-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-iframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-expected.png
index ef1be3c..ac35d8e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-pattern-expected.png
index c6a4f79..1acaed7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-svg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-svg-expected.png
index 7267722..a3c2794 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-canvas-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-expected.png
index 4bed735..a381e34 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png
index 0279054..e95f500 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-object-fit-expected.png
index df3e270ca..5a0af8e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-object-fit-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-profile-match-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-profile-match-expected.png
index 9003dca..2aa916d1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-profile-match-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-profile-match-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-pseudo-content-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-pseudo-content-expected.png
index 0a170e9..f2898ec0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-pseudo-content-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-pseudo-content-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-shape-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-shape-expected.png
index 4680b08..d37198ed 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-shape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-shape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-svg-resource-url-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-svg-resource-url-expected.png
index 3cbd3d7..c9e2d6f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-svg-resource-url-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-image-svg-resource-url-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-layer-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-layer-expected.png
index 2f510006..9d78f301 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-layer-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png
index b48bc5a6..a6d7edc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-mask-image-svg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-mask-image-svg-expected.png
index 7449e80..e4b8d82 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-mask-image-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-mask-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
index 7f4acd95..3db5261 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
index 1133257..d9f6c808 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-object-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-object-expected.png
index 5c3be24..4d3b985e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-expected.png
index 36269ac3..578b7a2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
index 9acc6c6..a04312d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-foreign-object-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-foreign-object-expected.png
index cbce017..2e453376 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-foreign-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-svg-foreign-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
index 2e8c738..3bba5d2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-invalidation-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-invalidation-expected.png
index 11bca861..c49ba960 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-invalidation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-invalidation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png
index 5e39cd2..7320fa0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png
index 3d332f5..5b61c57 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/embed-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/embed-image-expected.png
index 557fbb3..d000f36 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/embed-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/embed-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-css-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-css-expected.png
index 7697c5a..b8414e68 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-css-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-css-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-expected.png
index 4662b0e3..789fe889 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-height-image-document-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-height-image-document-expected.png
index acd6518..d50d8724 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-height-image-document-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-height-image-document-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png
index 8755b31..c74b396 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/gray-scale-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/gray-scale-jpeg-with-color-profile-expected.png
index da8ac52..ee14aa9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/gray-scale-jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/gray-scale-jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/gray-scale-png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/gray-scale-png-with-color-profile-expected.png
index 2e5e3e9b..dd8768a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/gray-scale-png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/gray-scale-png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/icon-decoding-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/icon-decoding-expected.png
index 52febaa..8a57593e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/icon-decoding-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/icon-decoding-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/image-in-map-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/image-in-map-expected.png
index bde325f..4ff8833 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/image-in-map-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/image-in-map-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/image-map-anchor-children-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/image-map-anchor-children-expected.png
index b34c61e..2cb722d6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/image-map-anchor-children-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/image-map-anchor-children-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png
index 316c7d1c..efcc8723 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
index 30303d4..88db8a08 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
index 0071cba..b94f296 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png
index d0b7a86..f3ef323 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
index f8c7ce0..ce0bc62e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-progressive-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-progressive-image-expected.png
index 1d27571..1dae169b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-progressive-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-progressive-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/missing-image-border-zoom-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/missing-image-border-zoom-expected.png
index 60a01a45..ff0cbdec 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/missing-image-border-zoom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/missing-image-border-zoom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/motion-jpeg-single-frame-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/motion-jpeg-single-frame-expected.png
index d4419933..6b76056 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/motion-jpeg-single-frame-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/motion-jpeg-single-frame-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/object-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/object-image-expected.png
index 557fbb3..d000f36 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/object-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/object-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/optimize-contrast-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/optimize-contrast-image-expected.png
index 31a5791..85002138 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/optimize-contrast-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/optimize-contrast-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/paletted-png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/paletted-png-with-color-profile-expected.png
index 0ef5ffa..04a2e9f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/paletted-png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/paletted-png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-background-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-background-image-expected.png
index e935025..1fb2cb9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-background-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-background-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-image-expected.png
index 96a38aca..f9f84b5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-svg-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-svg-image-expected.png
index 96a38aca..f9f84b5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-svg-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/pixelated-svg-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/png-suite/test-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/png-suite/test-expected.png
index d9bbf08..155f1acf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/png-suite/test-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/png-suite/test-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/png-with-color-profile-expected.png
index d0b7a86..f3ef323 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png
index 37b3534..e7605307 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png
index 3c2cd91..4548b6a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png
index e9252f82..3db20885 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png
index ad5e60d..8b4b1a69 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png
index 88ac75a..2bc7ee52 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png
index 9e7c7b93..26c72e27 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png
index c23e220..307b3c4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-images-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-images-expected.png
index a682476..659d9a8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rendering-broken-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rgb-jpeg-with-adobe-marker-only-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rgb-jpeg-with-adobe-marker-only-expected.png
index a73dfa00..d08b972 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rgb-jpeg-with-adobe-marker-only-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rgb-jpeg-with-adobe-marker-only-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rgb-png-with-cmyk-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rgb-png-with-cmyk-color-profile-expected.png
index 55ccac0..9477d1c0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rgb-png-with-cmyk-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/rgb-png-with-cmyk-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossless-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossless-expected.png
index 4768b44b..e2c3a47b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossless-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossless-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossy-alpha-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossy-alpha-expected.png
index 8def3fc1..3291d1c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossy-alpha-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossy-alpha-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossy-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossy-expected.png
index e80354db..e092eae 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossy-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/webp-color-profile-lossy-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/ycbcr-with-cmyk-color-profile-expected.png
index 39fad3f0..90b6c01c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/ycbcr-with-cmyk-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/ycbcr-with-cmyk-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-drag-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-drag-image-expected.png
deleted file mode 100644
index 4041fbf..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-drag-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
index b07fb43b..d5a320b2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
index a247452..2c7240b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
index 91e8ebe..56bc7239 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/color-matching/image-color-matching-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/color-matching/image-color-matching-expected.png
index 6629831..95cfee37 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/color-matching/image-color-matching-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/color-matching/image-color-matching-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-clamping-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-clamping-expected.png
deleted file mode 100644
index 7ff4f1fb..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-clamping-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-expected.png
deleted file mode 100644
index bc170793..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/css3/filters/effect-brightness-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-landscape-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-landscape-expected.png
index e1a9ecf..2c8735a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-landscape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-landscape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-portrait-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-portrait-expected.png
index a336166..990e6aa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-portrait-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-portrait-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/hdr/color-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/hdr/color-jpeg-with-color-profile-expected.png
new file mode 100644
index 0000000..4b4f516
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/hdr/color-jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-expected.png
index 462ff19..1791e22 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-png-expected.png
index 462ff19..1791e22 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-border-radius-expected.png
index 6bd21bd4..8819722 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-drag-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-drag-image-expected.png
index 2cabbc5..559bc71 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-drag-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-drag-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-filter-expected.png
index 1006e4e8..e4ebd49 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-group-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-group-expected.png
index 61f2f036..9509441 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-group-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-group-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-canvas-svg-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-canvas-svg-expected.png
index c6175ef..37d1018 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-canvas-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-canvas-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-expected.png
index 41f18a4..b626c2fd 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-filter-all-expected.png
index cc8f2a8..33e8b7a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-shape-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-shape-expected.png
index 73bfa97..ba91fe5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-shape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-image-shape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-layer-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-layer-expected.png
index 773fe03..9ba26be 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-layer-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-layer-filter-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-layer-filter-expected.png
new file mode 100644
index 0000000..f8474a4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-layer-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-munsell-adobe-to-srgb-expected.png
index adc1e7e..945f5f86 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-svg-fill-text-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-svg-fill-text-expected.png
index 7d0f474..0fc6fb9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-svg-fill-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-svg-fill-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png
index 110f0905..2e31f1d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/jpeg-with-color-profile-expected.png
index dc6e487..73fc748 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/png-suite/test-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/png-suite/test-expected.png
index 6a46e06..d87ed9d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/png-suite/test-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/png-suite/test-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/png-with-color-profile-expected.png
index dc6e487..73fc748 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png
index b39df69..56fed97 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-munsell-bt601-smpte-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-munsell-bt709-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-munsell-bt709-to-srgb-expected.png
index 7536943..a57a704 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-munsell-bt709-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-munsell-bt709-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/relative-sized-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/relative-sized-image-expected.png
index c6982de6..4032f40 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/relative-sized-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/relative-sized-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index 1438968..b3c4353 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/win/scrollbars/listbox-scrollbar-combinations-expected.png
index bca7646..db7c0fa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png
index e16c166..3d68e10 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1-SE/filters-image-03-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png
index 4cfc291bc..3ef52ff 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1-SE/filters-image-05-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
index 2d01404..dea0407 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-03-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
index 189e179..5fac091a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-06-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
index 294778293..3b360771 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-image-06-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-use-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-use-01-t-expected.png
index 0c9c64a..0817841 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-use-01-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/struct-use-01-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
index f93e22e..a741647 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
index 32621864..321b79b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
index 32621864..321b79b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
index fb208257..7ad92b8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/embed-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/color_space/fast/canvas/color-space/toDataURL-color-managed-round-trip-expected.png
similarity index 62%
rename from third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/embed-image-expected.png
rename to third_party/WebKit/LayoutTests/platform/win/virtual/color_space/fast/canvas/color-space/toDataURL-color-managed-round-trip-expected.png
index 7de47b7..82a9934 100644
--- a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/embed-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/color_space/fast/canvas/color-space/toDataURL-color-managed-round-trip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/12-55-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/12-55-expected.png
index 85d800d..a4fa8ba9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/12-55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/12-55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/182-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/182-expected.png
index dcd5193..bb007d7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/182-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/182-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/2-comp-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/2-comp-expected.png
index f91ad61..ed6cabc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/2-comp-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/2-comp-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/2-dht-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/2-dht-expected.png
index 355a5ef..5644139 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/2-dht-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/2-dht-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/23-55-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/23-55-expected.png
index 1c51798..7ce6c74 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/23-55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/23-55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/55-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/55-expected.png
index 1a56e13..7d6d863 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/55-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/55-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/alt-text-wrapping-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/alt-text-wrapping-expected.png
index d686f21c..f25fae3a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/alt-text-wrapping-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/alt-text-wrapping-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cHRM_color_spin-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cHRM_color_spin-expected.png
index 416770e..ba190996 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cHRM_color_spin-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cHRM_color_spin-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-jpeg-with-color-profile-expected.png
index 55facf1..625cebe6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-animate-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-animate-expected.png
index b97b58cb..b89a6cea 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-animate-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-animate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-animate-rotate-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-animate-rotate-expected.png
index b9539943..43d32f378 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-animate-rotate-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-animate-rotate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-clip-text-expected.png
index a510c6a..604b6ba 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cover-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cover-expected.png
index 05fa6fd..e034550f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
index f088e1c6..aa09b7e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
index f088e1c6..aa09b7e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-repeat-expected.png
index a0985bef..9efd713 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-space-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-space-expected.png
index dcb0a110..82de4cc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-space-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-space-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-expected.png
index b6f705a..3698134 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
index e5e9afe..d3c5f894 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-radius-expected.png
index e3f1e4f6b..1af2cae 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-clip-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-clip-expected.png
index 4b95886..71bd9eb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-clip-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-clip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-drag-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-drag-image-expected.png
deleted file mode 100644
index 2cabbc5..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-drag-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-filter-expected.png
index 1131e67..edf22e9d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-group-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-group-expected.png
index d6af957..da83da3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-group-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-group-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-iframe-expected.png
index ef00d05..51ba7d8c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-iframe-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-iframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-expected.png
index 7ad48ab..a06941a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-pattern-expected.png
index 8795e47..984d56f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-svg-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-svg-expected.png
index f7b6c8c9..df7348e5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-canvas-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-expected.png
index 0f4d904..e10c55fa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png
index a66da2f..ab61329 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-object-fit-expected.png
index 8de832b..8c2dc00 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-object-fit-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-profile-match-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-profile-match-expected.png
index ba531d4f..472e5b1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-profile-match-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-profile-match-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-pseudo-content-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-pseudo-content-expected.png
index 8dafd58b2..5edd28c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-pseudo-content-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-pseudo-content-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-shape-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-shape-expected.png
index 03d92b9..a315ecb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-shape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-shape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-svg-resource-url-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-svg-resource-url-expected.png
index b23c684b..884bb811 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-svg-resource-url-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-image-svg-resource-url-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-expected.png
index cb1053e..7feaec5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png
index 18116b2..0cf8fae 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-mask-image-svg-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-mask-image-svg-expected.png
index 63e8efb..dc59b33 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-mask-image-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-mask-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
index 4510056d..159484f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
index 4f2d82d..b47a2070 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-munsell-srgb-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-object-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-object-expected.png
index d62b027..d2212ca 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-expected.png
index 215a67b..def379a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
index d23c017..c39c534 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-fill-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-foreign-object-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-foreign-object-expected.png
index 57e0e8e..f739a06 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-foreign-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-svg-foreign-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
index 18f3390..1cd9f2d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-invalidation-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-invalidation-expected.png
index d002a41f..40e51f7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-invalidation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-invalidation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png
index 810abe1..5bdaf81 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-svg-size-diff-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png
index 833ec0f..c631562 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-svg-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/pixelated-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/embed-image-expected.png
similarity index 64%
rename from third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/pixelated-border-image-expected.png
rename to third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/embed-image-expected.png
index e9ab31c5d..7271cb0 100644
--- a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/pixelated-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/embed-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-css-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-css-expected.png
index 968dab9..f2fa05b87 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-css-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-css-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-expected.png
index 2b5db08..f834a47c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-height-image-document-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-height-image-document-expected.png
index 0f12397..0e7c0995 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-height-image-document-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-height-image-document-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png
index 8582f36..bb4dc1f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/exif-orientation-image-document-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/gray-scale-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/gray-scale-jpeg-with-color-profile-expected.png
index 91aa9b1..488290b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/gray-scale-jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/gray-scale-jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/gray-scale-png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/gray-scale-png-with-color-profile-expected.png
index 5e295e4..628dd7a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/gray-scale-png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/gray-scale-png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/icon-decoding-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/icon-decoding-expected.png
index f0a0074..7177158 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/icon-decoding-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/icon-decoding-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/image-in-map-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/image-in-map-expected.png
index bff28676..c886d37 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/image-in-map-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/image-in-map-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/image-map-anchor-children-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/image-map-anchor-children-expected.png
index 450008d15..608f7225 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/image-map-anchor-children-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/image-map-anchor-children-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png
index 8e50d8e7..0b2b524 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
index ef4d877..36691a2f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
index ea2ebfa6..bae8603 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png
index 7281be9c8..97400ee 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
index ae99322..16a687b8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-progressive-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-progressive-image-expected.png
index 665b7b2b..d2d3a16 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-progressive-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-progressive-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/missing-image-border-zoom-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/missing-image-border-zoom-expected.png
index 2eaf859..ae862e5e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/missing-image-border-zoom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/missing-image-border-zoom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/motion-jpeg-single-frame-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/motion-jpeg-single-frame-expected.png
index 2920bca..ea84319 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/motion-jpeg-single-frame-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/motion-jpeg-single-frame-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/pixelated-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/object-image-expected.png
similarity index 64%
copy from third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/pixelated-border-image-expected.png
copy to third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/object-image-expected.png
index e9ab31c5d..7271cb0 100644
--- a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/pixelated-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/object-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/optimize-contrast-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/optimize-contrast-image-expected.png
index 1ea2d6c9..5fd83fd 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/optimize-contrast-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/optimize-contrast-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/paletted-png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/paletted-png-with-color-profile-expected.png
index 466af017..c0e6c3f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/paletted-png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/paletted-png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-background-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-background-image-expected.png
index 453b2e7..bd9bf417 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-background-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-background-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-image-expected.png
index fefe80ea..c29bcde 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-svg-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-svg-image-expected.png
index fefe80ea..c29bcde 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-svg-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/pixelated-svg-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/png-suite/test-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/png-suite/test-expected.png
index 72214f2..5ec9c68a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/png-suite/test-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/png-suite/test-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/png-with-color-profile-expected.png
index 7281be9c8..97400ee 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png
index 2c0ba59..c43a2b2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-0px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png
index 3174ad71..dd6d96b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-0px-images-quirk-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png
index 897bc47..5af1de591 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-10px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png
index e1ee6ed4..698e209 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-16px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png
index 6ba45f7..2472af7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-1px-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png
index a224c58a..613ac8d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-block-flow-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png
index aa100b88..3b020b45 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-images-empty-alt-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-images-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-images-expected.png
index 145aaba..b3f5833 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rendering-broken-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rgb-jpeg-with-adobe-marker-only-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rgb-jpeg-with-adobe-marker-only-expected.png
index 3e222979..33c62b9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rgb-jpeg-with-adobe-marker-only-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rgb-jpeg-with-adobe-marker-only-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rgb-png-with-cmyk-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rgb-png-with-cmyk-color-profile-expected.png
index 3756bd7d..4ed84b7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rgb-png-with-cmyk-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/rgb-png-with-cmyk-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossless-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossless-expected.png
index a469759b..f5bdfa6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossless-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossless-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossy-alpha-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossy-alpha-expected.png
index e72e869..1a1eef6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossy-alpha-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossy-alpha-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossy-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossy-expected.png
index 86c0697..e6f4d463 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossy-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/webp-color-profile-lossy-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/ycbcr-with-cmyk-color-profile-expected.png
index e4524ab..cb484f3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/ycbcr-with-cmyk-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/ycbcr-with-cmyk-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
index a2299bd..42c21f6d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
index dd08d51..968c9ff 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
index 3f5a57e..c60e8a8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
index dc25387..b984ef5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index dde633d..e7145f7 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/win7/scrollbars/listbox-scrollbar-combinations-expected.png
index 5b79efb..d0df32fc 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
index 5b79efb..d0df32fc 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/as-image/image-preserveAspectRatio-all-expected.png b/third_party/WebKit/LayoutTests/svg/as-image/image-preserveAspectRatio-all-expected.png
index 5e28f16..9156792 100644
--- a/third_party/WebKit/LayoutTests/svg/as-image/image-preserveAspectRatio-all-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/as-image/image-preserveAspectRatio-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/custom/group-opacity-expected.png b/third_party/WebKit/LayoutTests/svg/custom/group-opacity-expected.png
index 98607db..b0a2d82 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/group-opacity-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/custom/group-opacity-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feImage-preserveAspectRatio-all-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feImage-preserveAspectRatio-all-expected.png
index 85036846..14251b69 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feImage-preserveAspectRatio-all-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/feImage-preserveAspectRatio-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feImage-preserveAspectratio-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feImage-preserveAspectratio-expected.png
index 3d0de88b..9c05380 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feImage-preserveAspectratio-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/feImage-preserveAspectratio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/filter-source-position-expected.png b/third_party/WebKit/LayoutTests/svg/filters/filter-source-position-expected.png
index 15b5d1c5..3392c33 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/filter-source-position-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/filter-source-position-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/filteredImage-expected.png b/third_party/WebKit/LayoutTests/svg/filters/filteredImage-expected.png
index ade998f..ebceb68b 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/filteredImage-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/filteredImage-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/toDataURL-color-managed-round-trip-expected.png b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/toDataURL-color-managed-round-trip-expected.png
deleted file mode 100644
index 9d4fec8..0000000
--- a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/toDataURL-color-managed-round-trip-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/disable-spv175/paint/invalidation/opacity-from-zero-to-non-zero-expected.txt b/third_party/WebKit/LayoutTests/virtual/disable-spv175/paint/invalidation/opacity-from-zero-to-non-zero-expected.txt
new file mode 100644
index 0000000..14e45807
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/disable-spv175/paint/invalidation/opacity-from-zero-to-non-zero-expected.txt
@@ -0,0 +1,35 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow DIV id='target'",
+          "rect": [8, 8, 100, 100],
+          "reason": "subtree"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow DIV id='target'",
+      "reason": "subtree"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/cross-fade-simple-expected.png b/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/cross-fade-simple-expected.png
index 8e7f901..5a8e74c 100644
--- a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/cross-fade-simple-expected.png
+++ b/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/cross-fade-simple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/cross-fade-sizing-expected.png b/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/cross-fade-sizing-expected.png
index 7352347..fafc52b0 100644
--- a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/cross-fade-sizing-expected.png
+++ b/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/cross-fade-sizing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/gif-short-app-extension-string-expected.png b/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/gif-short-app-extension-string-expected.png
index e6345867..f44ff0a6 100644
--- a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/gif-short-app-extension-string-expected.png
+++ b/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/gif-short-app-extension-string-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/object-image-expected.png b/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/object-image-expected.png
deleted file mode 100644
index 7de47b7..0000000
--- a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/object-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/png-color-profile-ignore-gamma-expected.png b/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/png-color-profile-ignore-gamma-expected.png
index 7afe737a..3017e77 100644
--- a/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/png-color-profile-ignore-gamma-expected.png
+++ b/third_party/WebKit/LayoutTests/virtual/exotic-color-space/images/png-color-profile-ignore-gamma-expected.png
Binary files differ
diff --git a/third_party/WebKit/Tools/Scripts/merge-layout-test-results b/third_party/WebKit/Tools/Scripts/merge-layout-test-results
index 1b0d6b0..41865e7f 100755
--- a/third_party/WebKit/Tools/Scripts/merge-layout-test-results
+++ b/third_party/WebKit/Tools/Scripts/merge-layout-test-results
@@ -4,226 +4,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import argparse
-import json
-import logging
-import os
-import stat
-import shutil
 import sys
-import tempfile
-import time
 
-from webkitpy.common.system.filesystem import FileSystem
-from webkitpy.common.system.log_utils import configure_logging
-from webkitpy.layout_tests import merge_results
+from webkitpy.layout_tests.merge_results import main
 
 
-# The output JSON has the following arguments overwritten with a value from
-# build properties. This occurs when '--build-properties' argument is provided
-# and is mainly used when merging on build bots to provide better information
-# about the build to the test results server.
-# Format is a list of ('result json key', 'build property key').
-RESULTS_JSON_VALUE_OVERRIDE_WITH_BUILD_PROPERTY = [
-    ("build_number", "buildnumber"),
-    ("builder_name", "buildername"),
-    ("chromium_revision", "got_revision_cp"),
-]
-
-
-# ------------------------------------------------------------------------
-def ensure_empty_dir(fs, directory, allow_existing, remove_existing):
-    """Ensure an empty directory exists.
-
-    Args:
-        allow_existing (bool): Allow the empty directory to already exist.
-        remove_existing (bool): Remove the contents if the directory
-            already exists.
-    """
-    if not fs.exists(directory):
-        fs.maybe_make_directory(directory)
-        return
-
-    logging.warning('Output directory exists %r', directory)
-    if not allow_existing:
-        raise IOError(
-            ('Output directory %s exists!\n'
-             'Use --allow-existing-output-directory to continue') % directory)
-
-    if remove_existing and not fs.remove_contents(directory):
-        raise IOError(
-            ('Unable to remove output directory %s contents!\n'
-             'See log output for errors.') % directory)
-
-
-def main(argv):
-
-    parser = argparse.ArgumentParser()
-    parser.description = """\
-Merges sharded layout test results into a single output directory.
-"""
-    parser.epilog = """\
-
-If a post merge script is given, it will be run on the resulting merged output
-directory. The script will be given the arguments plus
-'--results_dir <output_directory>'.
-"""
-
-    parser.add_argument(
-        '-v', '--verbose', action='store_true',
-        help='Output information about merging progress.')
-
-    parser.add_argument(
-        '--results-json-override-value',
-        nargs=2, metavar=('KEY', 'VALUE'), default=[],
-        action='append',
-        help='Override the value of a value in the result style JSON file '
-             '(--result-jsons-override-value layout_test_dirs /tmp/output).')
-    parser.add_argument(
-        '--results-json-allow-unknown-if-matching',
-        action='store_true', default=False,
-        help='Allow unknown values in the result.json file as long as the '
-             'value match on all shards.')
-
-    parser.add_argument(
-        '--output-directory',
-        help='Directory to create the merged results in.')
-    parser.add_argument(
-        '--allow-existing-output-directory',
-        action='store_true', default=False,
-        help='Allow merging results into a directory which already exists.')
-    parser.add_argument(
-        '--remove-existing-output-directory',
-        action='store_true', default=False,
-        help='Remove merging results into a directory which already exists.')
-    parser.add_argument(
-        '--input-directories', nargs='+',
-        help='Directories to merge the results from.')
-
-    # Swarming Isolated Merge Script API
-    # script.py \
-    #     --build-properties /s/build.json \
-    #     --output-json /tmp/output.json \
-    #     --task-output-dir /path/to/task/output/dir \
-    #     shard0/output.json \
-    #     shard1/output.json
-    parser.add_argument(
-        '-o', '--output-json',
-        help='(Swarming Isolated Merge Script API) Output JSON file to create.')
-    parser.add_argument(
-        '--build-properties',
-        help='(Swarming Isolated Merge Script API) Build property JSON file provided by recipes.')
-    parser.add_argument(
-        '--task-output-dir',
-        help='(Swarming Isolated Merge Script API) Directory containing all swarming task results.')
-    parser.add_argument(
-        '--results-json-override-with-build-property',
-        nargs=2, metavar=('RESULT_JSON_KEY', 'BUILD_PROPERTY_KEY'), default=[],
-        action='append',
-        help='Override the value of a value in the result style JSON file '
-             '(--result-jsons-override-value layout_test_dirs /tmp/output).')
-    parser.add_argument(
-        '--summary-json',
-        help='(Swarming Isolated Merge Script API) Summary of shard state running on swarming.'
-             '(Output of the swarming.py collect --task-summary-json=XXX command.)')
-
-    # Script to run after merging the directories together. Normally used with archive_layout_test_results.py
-    # scripts/slave/chromium/archive_layout_test_results.py \
-    #     --results-dir /b/rr/tmpIcChUS/w/layout-test-results \
-    #     --build-dir /b/rr/tmpIcChUS/w/src/out \
-    #     --build-number 3665 \
-    #     --builder-name 'WebKit Linux - RandomOrder' \
-    #     --gs-bucket gs://chromium-layout-test-archives \
-    #     --staging-dir /b/c/chrome_staging \
-    #     --slave-utils-gsutil-py-path /b/rr/tmpIcChUS/rw/scripts/slave/.recipe_deps/depot_tools/gsutil.py
-    # in dir /b/rr/tmpIcChUS/w
-    parser.add_argument(
-        '--post-merge-script',
-        nargs='*',
-        help='Script to call after the results have been merged.')
-
-    # The position arguments depend on if we are using the isolated merge
-    # script API mode or not.
-    parser.add_argument(
-        'positional', nargs='*',
-        help='output.json from shards.')
-
-    args = parser.parse_args(argv)
-    if args.verbose:
-        logging_level = logging.DEBUG
-    else:
-        logging_level = logging.INFO
-    configure_logging(logging_level=logging_level)
-
-    # Map the isolate arguments back to our output / input arguments.
-    if args.output_json:
-        logging.info('Running with isolated arguments')
-        assert args.positional
-
-        # TODO(tansell): Once removed everywhere, these lines can be removed.
-        # For now we just check nobody is supply arguments we didn't expect.
-        if args.results_json_override_with_build_property:
-            for result_key, build_prop_key in args.results_json_override_with_build_property:
-                assert (result_key, build_prop_key) in RESULTS_JSON_VALUE_OVERRIDE_WITH_BUILD_PROPERTY, (
-                    "%s not in %s" % (result_key, RESULTS_JSON_VALUE_OVERRIDE_WITH_BUILD_PROPERTY))
-
-        if not args.output_directory:
-            args.output_directory = os.getcwd()
-            args.allow_existing_output_directory = True
-            args.remove_existing_output_directory = True
-
-        assert not args.input_directories
-        args.input_directories = [os.path.dirname(f) for f in args.positional]
-        args.positional = []
-
-    # Allow skipping the --input-directories bit, for example,
-    #   merge-layout-test-results -o outputdir shard0 shard1 shard2
-    if args.positional and not args.input_directories:
-        args.input_directories = args.positional
-
-    if not args.output_directory:
-        args.output_directory = tempfile.mkdtemp(suffix='webkit_layout_test_results.')
-
-    assert args.output_directory
-    assert args.input_directories
-
-    results_json_value_overrides = {}
-    if args.build_properties:
-        build_properties = json.loads(args.build_properties)
-
-        for result_key, build_prop_key in RESULTS_JSON_VALUE_OVERRIDE_WITH_BUILD_PROPERTY:
-            if build_prop_key not in build_properties:
-                logging.warn('Required build property key "%s" was not found!', build_prop_key)
-                continue
-            results_json_value_overrides[result_key] = build_properties[build_prop_key]
-        logging.debug('results_json_value_overrides: %r', results_json_value_overrides)
-
-    merger = merge_results.LayoutTestDirMerger(
-        results_json_value_overrides=results_json_value_overrides,
-        results_json_allow_unknown_if_matching=args.results_json_allow_unknown_if_matching)
-
-    ensure_empty_dir(
-        FileSystem(),
-        args.output_directory,
-        allow_existing=args.allow_existing_output_directory,
-        remove_existing=args.remove_existing_output_directory)
-
-    merger.merge(args.output_directory, args.input_directories)
-
-    merged_output_json = os.path.join(args.output_directory, 'output.json')
-    if os.path.exists(merged_output_json) and args.output_json:
-        logging.debug(
-            'Copying output.json from %s to %s', merged_output_json, args.output_json)
-        shutil.copyfile(merged_output_json, args.output_json)
-
-    if args.post_merge_script:
-        logging.debug('Changing directory to %s', args.output_directory)
-        os.chdir(args.output_directory)
-
-        post_script = list(args.post_merge_script)
-        post_script.append('--result-dir', args.output_directory)
-
-        logging.info('Running post merge script %r', post_script)
-        os.execlp(post_script)
-
 main(sys.argv[1:])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder.py
index 8ed9abd0..9539cef 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/path_finder.py
@@ -72,7 +72,8 @@
 
 
 def get_typ_dir():
-    return os.path.join(get_chromium_src_dir(), 'third_party', 'typ')
+    return os.path.join(get_chromium_src_dir(), 'third_party', 'catapult',
+                        'third_party', 'typ')
 
 
 def get_blinkpy_thirdparty_dir():
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/merge_results.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/merge_results.py
index 3caa944..a53054d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/merge_results.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/merge_results.py
@@ -28,18 +28,34 @@
 objects work together is to look at the unit tests.
 """
 
+import argparse
 import collections
 import json
 import logging
+import os
 import pprint
 import re
+import shutil
+import tempfile
 import types
 
 from webkitpy.common.system.filesystem import FileSystem
+from webkitpy.common.system.log_utils import configure_logging
 
 
 _log = logging.getLogger(__name__)
 
+# The output JSON has the following arguments overwritten with a value from
+# build properties. This occurs when '--build-properties' argument is provided
+# and is mainly used when merging on build bots to provide better information
+# about the build to the test results server.
+# Format is a list of ('result json key', 'build property key').
+RESULTS_JSON_VALUE_OVERRIDE_WITH_BUILD_PROPERTY = [
+    ("build_number", "buildnumber"),
+    ("builder_name", "buildername"),
+    ("chromium_revision", "got_revision_cp"),
+]
+
 
 # Classes for recursively merging a JSON like dictionary together.
 # ------------------------------------------------------------------------
@@ -625,3 +641,199 @@
         self.add_helper(
             FilenameRegexMatch(r'full_results_jsonp\.js$'),
             results_json_file_merger)
+
+
+# ------------------------------------------------------------------------
+def ensure_empty_dir(fs, directory, allow_existing, remove_existing):
+    """Ensure an empty directory exists.
+
+    Args:
+        allow_existing (bool): Allow the empty directory to already exist.
+        remove_existing (bool): Remove the contents if the directory
+            already exists.
+    """
+    if not fs.exists(directory):
+        fs.maybe_make_directory(directory)
+        return
+
+    logging.warning('Output directory exists %r', directory)
+    if not allow_existing:
+        raise IOError(
+            ('Output directory %s exists!\n'
+             'Use --allow-existing-output-directory to continue') % directory)
+
+    if remove_existing and not fs.remove_contents(directory):
+        raise IOError(
+            ('Unable to remove output directory %s contents!\n'
+             'See log output for errors.') % directory)
+
+
+def main(argv):
+
+    parser = argparse.ArgumentParser()
+    parser.description = """\
+Merges sharded layout test results into a single output directory.
+"""
+    parser.epilog = """\
+
+If a post merge script is given, it will be run on the resulting merged output
+directory. The script will be given the arguments plus
+'--results_dir <output_directory>'.
+"""
+
+    parser.add_argument(
+        '-v', '--verbose', action='store_true',
+        help='Output information about merging progress.')
+
+    parser.add_argument(
+        '--results-json-override-value',
+        nargs=2, metavar=('KEY', 'VALUE'), default=[],
+        action='append',
+        help='Override the value of a value in the result style JSON file '
+             '(--result-jsons-override-value layout_test_dirs /tmp/output).')
+    parser.add_argument(
+        '--results-json-allow-unknown-if-matching',
+        action='store_true', default=False,
+        help='Allow unknown values in the result.json file as long as the '
+             'value match on all shards.')
+
+    parser.add_argument(
+        '--output-directory',
+        help='Directory to create the merged results in.')
+    parser.add_argument(
+        '--allow-existing-output-directory',
+        action='store_true', default=False,
+        help='Allow merging results into a directory which already exists.')
+    parser.add_argument(
+        '--remove-existing-output-directory',
+        action='store_true', default=False,
+        help='Remove merging results into a directory which already exists.')
+    parser.add_argument(
+        '--input-directories', nargs='+',
+        help='Directories to merge the results from.')
+
+    # Swarming Isolated Merge Script API
+    # script.py \
+    #     --build-properties /s/build.json \
+    #     --output-json /tmp/output.json \
+    #     --task-output-dir /path/to/task/output/dir \
+    #     shard0/output.json \
+    #     shard1/output.json
+    parser.add_argument(
+        '-o', '--output-json',
+        help='(Swarming Isolated Merge Script API) Output JSON file to create.')
+    parser.add_argument(
+        '--build-properties',
+        help='(Swarming Isolated Merge Script API) Build property JSON file provided by recipes.')
+    parser.add_argument(
+        '--task-output-dir',
+        help='(Swarming Isolated Merge Script API) Directory containing all swarming task results.')
+    parser.add_argument(
+        '--results-json-override-with-build-property',
+        nargs=2, metavar=('RESULT_JSON_KEY', 'BUILD_PROPERTY_KEY'), default=[],
+        action='append',
+        help='Override the value of a value in the result style JSON file '
+             '(--result-jsons-override-value layout_test_dirs /tmp/output).')
+    parser.add_argument(
+        '--summary-json',
+        help='(Swarming Isolated Merge Script API) Summary of shard state running on swarming.'
+             '(Output of the swarming.py collect --task-summary-json=XXX command.)')
+
+    # Script to run after merging the directories together. Normally used with archive_layout_test_results.py
+    # scripts/slave/chromium/archive_layout_test_results.py \
+    #     --results-dir /b/rr/tmpIcChUS/w/layout-test-results \
+    #     --build-dir /b/rr/tmpIcChUS/w/src/out \
+    #     --build-number 3665 \
+    #     --builder-name 'WebKit Linux - RandomOrder' \
+    #     --gs-bucket gs://chromium-layout-test-archives \
+    #     --staging-dir /b/c/chrome_staging \
+    #     --slave-utils-gsutil-py-path /b/rr/tmpIcChUS/rw/scripts/slave/.recipe_deps/depot_tools/gsutil.py
+    # in dir /b/rr/tmpIcChUS/w
+    parser.add_argument(
+        '--post-merge-script',
+        nargs='*',
+        help='Script to call after the results have been merged.')
+
+    # The position arguments depend on if we are using the isolated merge
+    # script API mode or not.
+    parser.add_argument(
+        'positional', nargs='*',
+        help='output.json from shards.')
+
+    args = parser.parse_args(argv)
+    if args.verbose:
+        logging_level = logging.DEBUG
+    else:
+        logging_level = logging.INFO
+    configure_logging(logging_level=logging_level)
+
+    # Map the isolate arguments back to our output / input arguments.
+    if args.output_json:
+        logging.info('Running with isolated arguments')
+        assert args.positional
+
+        # TODO(tansell): Once removed everywhere, these lines can be removed.
+        # For now we just check nobody is supply arguments we didn't expect.
+        if args.results_json_override_with_build_property:
+            for result_key, build_prop_key in args.results_json_override_with_build_property:
+                assert (result_key, build_prop_key) in RESULTS_JSON_VALUE_OVERRIDE_WITH_BUILD_PROPERTY, (
+                    "%s not in %s" % (result_key, RESULTS_JSON_VALUE_OVERRIDE_WITH_BUILD_PROPERTY))
+
+        if not args.output_directory:
+            args.output_directory = os.getcwd()
+            args.allow_existing_output_directory = True
+            args.remove_existing_output_directory = True
+
+        assert not args.input_directories
+        args.input_directories = [os.path.dirname(f) for f in args.positional]
+        args.positional = []
+
+    # Allow skipping the --input-directories bit, for example,
+    #   merge-layout-test-results -o outputdir shard0 shard1 shard2
+    if args.positional and not args.input_directories:
+        args.input_directories = args.positional
+
+    if not args.output_directory:
+        args.output_directory = tempfile.mkdtemp(suffix='webkit_layout_test_results.')
+
+    assert args.output_directory
+    assert args.input_directories
+
+    results_json_value_overrides = {}
+    if args.build_properties:
+        build_properties = json.loads(args.build_properties)
+
+        for result_key, build_prop_key in RESULTS_JSON_VALUE_OVERRIDE_WITH_BUILD_PROPERTY:
+            if build_prop_key not in build_properties:
+                logging.warn('Required build property key "%s" was not found!', build_prop_key)
+                continue
+            results_json_value_overrides[result_key] = build_properties[build_prop_key]
+        logging.debug('results_json_value_overrides: %r', results_json_value_overrides)
+
+    merger = LayoutTestDirMerger(
+        results_json_value_overrides=results_json_value_overrides,
+        results_json_allow_unknown_if_matching=args.results_json_allow_unknown_if_matching)
+
+    ensure_empty_dir(
+        FileSystem(),
+        args.output_directory,
+        allow_existing=args.allow_existing_output_directory,
+        remove_existing=args.remove_existing_output_directory)
+
+    merger.merge(args.output_directory, args.input_directories)
+
+    merged_output_json = os.path.join(args.output_directory, 'output.json')
+    if os.path.exists(merged_output_json) and args.output_json:
+        logging.debug(
+            'Copying output.json from %s to %s', merged_output_json, args.output_json)
+        shutil.copyfile(merged_output_json, args.output_json)
+
+    if args.post_merge_script:
+        logging.debug('Changing directory to %s', args.output_directory)
+        os.chdir(args.output_directory)
+
+        post_script = list(args.post_merge_script)
+        post_script.append('--result-dir', args.output_directory)
+
+        logging.info('Running post merge script %r', post_script)
+        os.execlp(post_script)
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 0c4d98df..88b247d3 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1674,7 +1674,6 @@
   kPaintTimingObserved = 2190,
   kPaintTimingRequested = 2191,
   kHTMLMediaElementMediaPlaybackRateOutOfRange = 2192,
-  kCSSFilterFunctionNegativeBrightness = 2193,
   kCookieSet = 2194,
   kCookieGet = 2195,
   kGeolocationDisabledByFeaturePolicy = 2196,
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index 8330424..8330794a 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -122,7 +122,7 @@
     timeline_->ResetForTesting();
     element_ = GetDocument().CreateElementForBinding("test");
 
-    helper_.Initialize(nullptr, nullptr, nullptr, &ConfigureSettings);
+    helper_.Initialize(nullptr, nullptr, nullptr);
     base_url_ = "http://www.test.com/";
   }
 
@@ -333,9 +333,6 @@
   }
 
  private:
-  static void ConfigureSettings(WebSettings* settings) {
-    settings->SetAcceleratedCompositingEnabled(true);
-  }
   FrameTestHelpers::WebViewHelper helper_;
   std::string base_url_;
 };
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
index d00f16f..f28dd5c 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
@@ -100,13 +100,8 @@
       parsed_value =
           CSSPropertyParserHelpers::ConsumePercent(args, kValueRangeAll);
       if (!parsed_value) {
-        parsed_value =
-            CSSPropertyParserHelpers::ConsumeNumber(args, kValueRangeAll);
-      }
-      if (parsed_value &&
-          ToCSSPrimitiveValue(parsed_value)->GetDoubleValue() < 0) {
-        // crbug.com/776208: Negative values are not allowed by spec.
-        context.Count(WebFeature::kCSSFilterFunctionNegativeBrightness);
+        parsed_value = CSSPropertyParserHelpers::ConsumeNumber(
+            args, kValueRangeNonNegative);
       }
     } else if (filter_type == CSSValueHueRotate) {
       parsed_value = CSSPropertyParserHelpers::ConsumeAngle(
diff --git a/third_party/blink/renderer/core/css/style_property_serializer.cc b/third_party/blink/renderer/core/css/style_property_serializer.cc
index de65d552..9416c98f 100644
--- a/third_party/blink/renderer/core/css/style_property_serializer.cc
+++ b/third_party/blink/renderer/core/css/style_property_serializer.cc
@@ -418,7 +418,7 @@
     case CSSPropertyAnimation:
       return GetLayeredShorthandValue(animationShorthand());
     case CSSPropertyBorderSpacing:
-      return BorderSpacingValue(borderSpacingShorthand());
+      return Get2Values(borderSpacingShorthand());
     case CSSPropertyBackgroundPosition:
       return GetLayeredShorthandValue(backgroundPositionShorthand());
     case CSSPropertyBackgroundRepeat:
@@ -462,11 +462,11 @@
     case CSSPropertyGap:
       return GetShorthandValue(gapShorthand());
     case CSSPropertyPlaceContent:
-      return GetAlignmentShorthandValue(placeContentShorthand());
+      return Get2Values(placeContentShorthand());
     case CSSPropertyPlaceItems:
-      return GetAlignmentShorthandValue(placeItemsShorthand());
+      return Get2Values(placeItemsShorthand());
     case CSSPropertyPlaceSelf:
-      return GetAlignmentShorthandValue(placeSelfShorthand());
+      return Get2Values(placeSelfShorthand());
     case CSSPropertyFont:
       return FontValue();
     case CSSPropertyFontVariant:
@@ -530,20 +530,6 @@
   }
 }
 
-String StylePropertySerializer::BorderSpacingValue(
-    const StylePropertyShorthand& shorthand) const {
-  const CSSValue* horizontal_value =
-      property_set_.GetPropertyCSSValue(*shorthand.properties()[0]);
-  const CSSValue* vertical_value =
-      property_set_.GetPropertyCSSValue(*shorthand.properties()[1]);
-
-  String horizontal_value_css_text = horizontal_value->CssText();
-  String vertical_value_css_text = vertical_value->CssText();
-  if (horizontal_value_css_text == vertical_value_css_text)
-    return horizontal_value_css_text;
-  return horizontal_value_css_text + ' ' + vertical_value_css_text;
-}
-
 void StylePropertySerializer::AppendFontLonghandValueIfNotNormal(
     const CSSProperty& property,
     StringBuilder& result) const {
@@ -965,14 +951,6 @@
   return res;
 }
 
-String StylePropertySerializer::GetAlignmentShorthandValue(
-    const StylePropertyShorthand& shorthand) const {
-  String value = GetCommonValue(shorthand);
-  if (value.IsNull() || value.IsEmpty())
-    return GetShorthandValue(shorthand);
-  return value;
-}
-
 String StylePropertySerializer::BorderPropertyValue() const {
   const StylePropertyShorthand properties[3] = {
       borderWidthShorthand(), borderStyleShorthand(), borderColorShorthand()};
diff --git a/third_party/blink/renderer/core/css/style_property_serializer.h b/third_party/blink/renderer/core/css/style_property_serializer.h
index a8d15f6..f558b99 100644
--- a/third_party/blink/renderer/core/css/style_property_serializer.h
+++ b/third_party/blink/renderer/core/css/style_property_serializer.h
@@ -44,13 +44,11 @@
 
  private:
   String GetCommonValue(const StylePropertyShorthand&) const;
-  String GetAlignmentShorthandValue(const StylePropertyShorthand&) const;
   String BorderPropertyValue() const;
   String BorderImagePropertyValue() const;
   String GetLayeredShorthandValue(const StylePropertyShorthand&) const;
   String Get2Values(const StylePropertyShorthand&) const;
   String Get4Values(const StylePropertyShorthand&) const;
-  String BorderSpacingValue(const StylePropertyShorthand&) const;
   String PageBreakPropertyValue(const StylePropertyShorthand&) const;
   String GetShorthandValue(const StylePropertyShorthand&,
                            String separator = " ") const;
diff --git a/third_party/blink/renderer/core/dom/document.idl b/third_party/blink/renderer/core/dom/document.idl
index b2f7201a..3ce64bd 100644
--- a/third_party/blink/renderer/core/dom/document.idl
+++ b/third_party/blink/renderer/core/dom/document.idl
@@ -191,7 +191,7 @@
     // Custom Elements
     // https://w3c.github.io/webcomponents/spec/custom/#extensions-to-document-interface-to-register
     // FIXME: The registerElement return type should be Function.
-    [CallWith=ScriptState, CustomElementCallbacks, RaisesException, MeasureAs=DocumentRegisterElement] CustomElementConstructor registerElement(DOMString type, optional ElementRegistrationOptions options);
+    [RuntimeEnabled=CustomElementsV0, CallWith=ScriptState, CustomElementCallbacks, RaisesException, MeasureAs=DocumentRegisterElement] CustomElementConstructor registerElement(DOMString type, optional ElementRegistrationOptions options);
     // https://w3c.github.io/webcomponents/spec/custom/#extensions-to-document-interface-to-instantiate
     // FIXME: The typeExtension arguments should not be nullable.
     [CustomElementCallbacks, PerWorldBindings, RaisesException, ImplementedAs=CreateElementForBinding] Element createElement(DOMString localName, (DOMString or Dictionary)? options);
diff --git a/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc b/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
index 6298bb2..de16957 100644
--- a/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
@@ -288,7 +288,7 @@
     EditingState* editing_state,
     ShouldAssumeContentIsAlwaysEditable
         should_assume_content_is_always_editable) {
-  DCHECK_NE(GetDocument().body(), ref_child);
+  ABORT_EDITING_COMMAND_IF(GetDocument().body() == ref_child);
   ABORT_EDITING_COMMAND_IF(!ref_child->parentNode());
   // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets
   // needs to be audited.  See http://crbug.com/590369 for more details.
diff --git a/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command_test.cc b/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command_test.cc
index a3ebbda..fab7d12 100644
--- a/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command_test.cc
+++ b/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command_test.cc
@@ -4,9 +4,11 @@
 
 #include "third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command.h"
 
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/editing/selection_template.h"
 #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
+#include "third_party/blink/renderer/core/editing/testing/selection_sample.h"
 
 namespace blink {
 
@@ -55,4 +57,32 @@
       GetSelectionTextFromBody());
 }
 
+// https://crbug.com/835020
+TEST_F(InsertParagraphSeparatorCommandTest, CrashWithCaptionBeforeBody) {
+  // The bug reproduces only with |designMode == 'on'|
+  GetDocument().setDesignMode("on");
+  InsertStyleElement("");
+  SetBodyContent("<style>*{max-width:inherit;display:initial;}</style>");
+
+  // Insert <caption> between head and body
+  Element* caption = GetDocument().CreateElementForBinding("caption");
+  caption->SetInnerHTMLFromString("AxBxC");
+  GetDocument().documentElement()->insertBefore(caption, GetDocument().body());
+
+  Selection().SetSelection(
+      SelectionInDOMTree::Builder()
+          .SetBaseAndExtent(EphemeralRange::RangeOfContents(*caption))
+          .Build(),
+      SetSelectionOptions());
+
+  InsertParagraphSeparatorCommand* command =
+      InsertParagraphSeparatorCommand::Create(GetDocument());
+  // Shouldn't crash inside.
+  EXPECT_FALSE(command->Apply());
+  EXPECT_EQ(
+      "<body><style><br>|*{max-width:inherit;display:initial;}</style></body>",
+      SelectionSample::GetSelectionText(*GetDocument().documentElement(),
+                                        Selection().GetSelectionInDOMTree()));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/iterators/character_iterator.cc b/third_party/blink/renderer/core/editing/iterators/character_iterator.cc
index 0e80978..fd957f4 100644
--- a/third_party/blink/renderer/core/editing/iterators/character_iterator.cc
+++ b/third_party/blink/renderer/core/editing/iterators/character_iterator.cc
@@ -58,7 +58,7 @@
 }
 
 template <typename Strategy>
-Document* CharacterIteratorAlgorithm<Strategy>::OwnerDocument() const {
+const Document& CharacterIteratorAlgorithm<Strategy>::OwnerDocument() const {
   return text_iterator_.OwnerDocument();
 }
 
@@ -90,12 +90,13 @@
 template <typename Strategy>
 PositionTemplate<Strategy>
 CharacterIteratorAlgorithm<Strategy>::GetPositionBefore() const {
-  const Node& node = *text_iterator_.CurrentContainer();
   if (text_iterator_.AtEnd()) {
     DCHECK_EQ(run_offset_, 0);
     return PositionTemplate<Strategy>(
-        node, text_iterator_.StartOffsetInCurrentContainer());
+        text_iterator_.CurrentContainer(),
+        text_iterator_.StartOffsetInCurrentContainer());
   }
+  const Node& node = *text_iterator_.GetNode();
   DCHECK_GE(text_iterator_.length(), 1);
   if (node.IsTextNode()) {
     const int offset = text_iterator_.StartOffsetInCurrentContainer();
@@ -107,13 +108,14 @@
 template <typename Strategy>
 PositionTemplate<Strategy>
 CharacterIteratorAlgorithm<Strategy>::GetPositionAfter() const {
-  const Node& node = *text_iterator_.CurrentContainer();
   if (text_iterator_.AtEnd()) {
     DCHECK_EQ(run_offset_, 0);
     return PositionTemplate<Strategy>(
-        node, text_iterator_.EndOffsetInCurrentContainer());
+        text_iterator_.CurrentContainer(),
+        text_iterator_.EndOffsetInCurrentContainer());
   }
   DCHECK_GE(text_iterator_.length(), 1);
+  const Node& node = *text_iterator_.GetNode();
   if (node.IsTextNode()) {
     const int offset = text_iterator_.StartOffsetInCurrentContainer();
     return PositionTemplate<Strategy>(node, offset + run_offset_ + 1);
diff --git a/third_party/blink/renderer/core/editing/iterators/character_iterator.h b/third_party/blink/renderer/core/editing/iterators/character_iterator.h
index 180e55d..e3c8bdf 100644
--- a/third_party/blink/renderer/core/editing/iterators/character_iterator.h
+++ b/third_party/blink/renderer/core/editing/iterators/character_iterator.h
@@ -64,7 +64,7 @@
 
   int CharacterOffset() const { return offset_; }
 
-  Document* OwnerDocument() const;
+  const Document& OwnerDocument() const;
   const Node* CurrentContainer() const;
   int StartOffset() const;
   int EndOffset() const;
diff --git a/third_party/blink/renderer/core/editing/iterators/character_iterator_test.cc b/third_party/blink/renderer/core/editing/iterators/character_iterator_test.cc
index 3146a0a7..3022d0e 100644
--- a/third_party/blink/renderer/core/editing/iterators/character_iterator_test.cc
+++ b/third_party/blink/renderer/core/editing/iterators/character_iterator_test.cc
@@ -72,4 +72,43 @@
   EXPECT_EQ(Position(text_node, 3), result.EndPosition());
 }
 
+TEST_F(CharacterIteratorTest, GetPositionWithBR) {
+  SetBodyContent("a<br>b");
+
+  const Element& body = *GetDocument().body();
+  CharacterIterator it(EphemeralRange::RangeOfContents(body));
+
+  const Node& text_a = *body.firstChild();
+  const Node& br = *GetDocument().QuerySelector("br");
+  const Node& text_b = *body.lastChild();
+
+  EXPECT_EQ(Position(text_a, 0), it.GetPositionBefore());
+  EXPECT_EQ(Position(text_a, 1), it.GetPositionAfter());
+  EXPECT_EQ(Position(text_a, 0), it.StartPosition());
+  EXPECT_EQ(Position(text_a, 1), it.EndPosition());
+
+  ASSERT_FALSE(it.AtEnd());
+  it.Advance(1);
+  EXPECT_EQ(Position::BeforeNode(br), it.GetPositionBefore());
+  EXPECT_EQ(Position::AfterNode(br), it.GetPositionAfter());
+  EXPECT_EQ(Position(body, 1), it.StartPosition());
+  EXPECT_EQ(Position(body, 2), it.EndPosition());
+
+  ASSERT_FALSE(it.AtEnd());
+  it.Advance(1);
+  EXPECT_EQ(Position(text_b, 0), it.GetPositionBefore());
+  EXPECT_EQ(Position(text_b, 1), it.GetPositionAfter());
+  EXPECT_EQ(Position(text_b, 0), it.StartPosition());
+  EXPECT_EQ(Position(text_b, 1), it.EndPosition());
+
+  ASSERT_FALSE(it.AtEnd());
+  it.Advance(1);
+  EXPECT_EQ(Position(body, 3), it.GetPositionBefore());
+  EXPECT_EQ(Position(body, 3), it.GetPositionAfter());
+  EXPECT_EQ(Position(body, 3), it.StartPosition());
+  EXPECT_EQ(Position(body, 3), it.EndPosition());
+
+  EXPECT_TRUE(it.AtEnd());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/iterators/search_buffer.cc b/third_party/blink/renderer/core/editing/iterators/search_buffer.cc
index 94451b5..8a66dd1 100644
--- a/third_party/blink/renderer/core/editing/iterators/search_buffer.cc
+++ b/third_party/blink/renderer/core/editing/iterators/search_buffer.cc
@@ -334,7 +334,7 @@
     for (SimplifiedBackwardsTextIteratorAlgorithm<Strategy> backwards_iterator(
              EphemeralRangeTemplate<Strategy>(
                  PositionTemplate<Strategy>::FirstPositionInNode(
-                     *it.OwnerDocument()),
+                     it.OwnerDocument()),
                  PositionTemplate<Strategy>(it.CurrentContainer(),
                                             it.StartOffset())));
          !backwards_iterator.AtEnd(); backwards_iterator.Advance()) {
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
index e6e63a9..e2bb42e 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
@@ -219,9 +219,7 @@
 TextIteratorAlgorithm<Strategy>::~TextIteratorAlgorithm() {
   if (!handle_shadow_root_)
     return;
-  Document* document = OwnerDocument();
-  if (!document)
-    return;
+  const Document& document = OwnerDocument();
   if (behavior_.ForInnerText())
     UseCounter::Count(document, WebFeature::kInnerTextWithShadowTree);
   if (behavior_.ForSelectionToString())
@@ -825,31 +823,21 @@
   }
 
   // otherwise, return the end of the overall range we were given
-  if (end_container_)
-    return EphemeralRangeTemplate<Strategy>(
-        PositionTemplate<Strategy>(end_container_, end_offset_));
-
-  return EphemeralRangeTemplate<Strategy>();
+  return EphemeralRangeTemplate<Strategy>(
+      PositionTemplate<Strategy>(end_container_, end_offset_));
 }
 
 template <typename Strategy>
-Document* TextIteratorAlgorithm<Strategy>::OwnerDocument() const {
-  if (text_state_.PositionNode())
-    return &text_state_.PositionNode()->GetDocument();
-  if (end_container_)
-    return &end_container_->GetDocument();
-  return nullptr;
+const Document& TextIteratorAlgorithm<Strategy>::OwnerDocument() const {
+  return end_container_->GetDocument();
 }
 
 template <typename Strategy>
 const Node* TextIteratorAlgorithm<Strategy>::GetNode() const {
-  if (text_state_.PositionNode() || end_container_) {
-    const Node* node = CurrentContainer();
-    if (node->IsCharacterDataNode())
-      return node;
-    return Strategy::ChildAt(*node, StartOffsetInCurrentContainer());
-  }
-  return nullptr;
+  const Node* node = CurrentContainer();
+  if (node->IsCharacterDataNode())
+    return node;
+  return Strategy::ChildAt(*node, StartOffsetInCurrentContainer());
 }
 
 template <typename Strategy>
@@ -858,7 +846,6 @@
     text_state_.FlushPositionOffsets();
     return text_state_.PositionStartOffset();
   }
-  DCHECK(end_container_);
   return end_offset_;
 }
 
@@ -868,7 +855,6 @@
     text_state_.FlushPositionOffsets();
     return text_state_.PositionEndOffset();
   }
-  DCHECK(end_container_);
   return end_offset_;
 }
 
@@ -877,7 +863,6 @@
   if (text_state_.PositionNode()) {
     return text_state_.PositionNode();
   }
-  DCHECK(end_container_);
   return end_container_;
 }
 
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator.h b/third_party/blink/renderer/core/editing/iterators/text_iterator.h
index fb296dc5..76031a378 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator.h
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator.h
@@ -74,7 +74,7 @@
   EphemeralRangeTemplate<Strategy> Range() const;
   const Node* GetNode() const;
 
-  Document* OwnerDocument() const;
+  const Document& OwnerDocument() const;
   const Node* CurrentContainer() const;
   int StartOffsetInCurrentContainer() const;
   int EndOffsetInCurrentContainer() const;
diff --git a/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc b/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
index f3d9a1df..09e14ca 100644
--- a/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
+++ b/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
@@ -359,6 +359,7 @@
       }
 
       if (!n->GetLayoutObject() &&
+          (!n->IsElementNode() || !ToElement(n)->HasDisplayContentsStyle()) &&
           !EnclosingElementWithTag(FirstPositionInOrBeforeNode(*n),
                                    selectTag)) {
         next = Strategy::NextSkippingChildren(*n);
diff --git a/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc b/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc
index 1208a0f..25c3c35 100644
--- a/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc
+++ b/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer_test.cc
@@ -292,4 +292,15 @@
   EXPECT_EQ("", SerializePart<EditingInFlatTreeStrategy>(start_ict, end_ict));
 }
 
+TEST_F(StyledMarkupSerializerTest, DisplayContentsStyle) {
+  const char* body_content = "1<span style='display: contents'>2</span>3";
+  const char* expected_result =
+      "<span style=\"display: inline !important; float: none;\">1</span><span "
+      "style=\"display: contents;\">2</span><span style=\"display: inline "
+      "!important; float: none;\">3</span>";
+  SetBodyContent(body_content);
+  EXPECT_EQ(expected_result, Serialize<EditingStrategy>());
+  EXPECT_EQ(expected_result, Serialize<EditingInFlatTreeStrategy>());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index 5d8701b3..6db494b 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -248,7 +248,6 @@
   }
 
   static void ConfigureCompositingWebView(WebSettings* settings) {
-    settings->SetAcceleratedCompositingEnabled(true);
     settings->SetPreferCompositingToLCDTextEnabled(true);
   }
 
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 4ddb6f5..fb5ee37 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3659,19 +3659,21 @@
 void WebViewImpl::InitializeLayerTreeView() {
   if (client_) {
     layer_tree_view_ = client_->InitializeLayerTreeView();
-    if (layer_tree_view_ && layer_tree_view_->CompositorAnimationHost()) {
-      animation_host_ = std::make_unique<CompositorAnimationHost>(
-          layer_tree_view_->CompositorAnimationHost());
-    }
-  }
+    // TODO(dcheng): All WebViewImpls should have an associated LayerTreeView,
+    // but for various reasons, that's not the case...
+    page_->GetSettings().SetAcceleratedCompositingEnabled(layer_tree_view_);
+    if (layer_tree_view_) {
+      if (layer_tree_view_->CompositorAnimationHost()) {
+        animation_host_ = std::make_unique<CompositorAnimationHost>(
+            layer_tree_view_->CompositorAnimationHost());
+      }
 
-  page_->GetSettings().SetAcceleratedCompositingEnabled(layer_tree_view_);
-  if (layer_tree_view_) {
-    page_->LayerTreeViewInitialized(*layer_tree_view_, nullptr);
-    // We don't yet have a page loaded at this point of the initialization of
-    // WebViewImpl, so don't allow cc to commit any frames Blink might
-    // try to create in the meantime.
-    layer_tree_view_->SetDeferCommits(true);
+      page_->LayerTreeViewInitialized(*layer_tree_view_, nullptr);
+      // We don't yet have a page loaded at this point of the initialization of
+      // WebViewImpl, so don't allow cc to commit any frames Blink might
+      // try to create in the meantime.
+      layer_tree_view_->SetDeferCommits(true);
+    }
   }
 
   // FIXME: only unittests, click to play, Android printing, and printing (for
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index 839a9b5..3d91c0e5 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -3217,7 +3217,6 @@
 }
 
 static void ConfigueCompositingWebView(WebSettings* settings) {
-  settings->SetAcceleratedCompositingEnabled(true);
   settings->SetPreferCompositingToLCDTextEnabled(true);
 }
 
diff --git a/third_party/blink/renderer/core/frame/browser_controls_test.cc b/third_party/blink/renderer/core/frame/browser_controls_test.cc
index 1ad655d..356b4899 100644
--- a/third_party/blink/renderer/core/frame/browser_controls_test.cc
+++ b/third_party/blink/renderer/core/frame/browser_controls_test.cc
@@ -83,7 +83,6 @@
 
   static void ConfigureSettings(WebSettings* settings) {
     settings->SetJavaScriptEnabled(true);
-    settings->SetAcceleratedCompositingEnabled(true);
     settings->SetPreferCompositingToLCDTextEnabled(true);
     // Android settings
     settings->SetViewportEnabled(true);
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h
index deb42b37..738b19e 100644
--- a/third_party/blink/renderer/core/frame/frame.h
+++ b/third_party/blink/renderer/core/frame/frame.h
@@ -100,6 +100,12 @@
   Page* GetPage() const;  // Null when the frame is detached.
   virtual FrameView* View() const = 0;
 
+  // Before using this, make sure you really want the top-level frame in the
+  // entire page, as opposed to a top-level local frame in a sub-tree, e.g.
+  // one representing a cross-process iframe in a renderer separate from the
+  // main frame's renderer. For layout and compositing code, often
+  // LocalFrame::IsLocalRoot() is more appropriate. If you are unsure, please
+  // reach out to site-isolation-dev@chromium.org.
   bool IsMainFrame() const;
 
   FrameOwner* Owner() const;
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5
index 57f5f4b0..a10a48d 100644
--- a/third_party/blink/renderer/core/frame/settings.json5
+++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -240,7 +240,7 @@
     {
       name: "immersiveModeEnabled",
       initial: false,
-      invalidate: "MediaQuery",
+      invalidate: "MediaControls",
     },
 
     {
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index 4826719..771a66bf 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -1020,29 +1020,22 @@
   DCHECK(Client());
   DCHECK(!mutator_);
   layer_tree_view_ = Client()->InitializeLayerTreeView();
-  if (layer_tree_view_ && layer_tree_view_->CompositorAnimationHost()) {
+  DCHECK(layer_tree_view_);
+  if (layer_tree_view_->CompositorAnimationHost()) {
     animation_host_ = std::make_unique<CompositorAnimationHost>(
         layer_tree_view_->CompositorAnimationHost());
   }
 
-  GetPage()->GetSettings().SetAcceleratedCompositingEnabled(layer_tree_view_);
-  if (layer_tree_view_) {
-    GetPage()->LayerTreeViewInitialized(*layer_tree_view_,
-                                        LocalRootImpl()->GetFrame()->View());
+  GetPage()->LayerTreeViewInitialized(*layer_tree_view_,
+                                      LocalRootImpl()->GetFrame()->View());
 
-    // TODO(kenrb): Currently GPU rasterization is always enabled for OOPIFs.
-    // This is okay because it is only necessarily to set the trigger to false
-    // for certain cases that affect the top-level frame, but it would be better
-    // to be consistent with the top-level frame. Ideally the logic should
-    // be moved from WebViewImpl into WebFrameWidget and used for all local
-    // frame roots. https://crbug.com/712794
-    layer_tree_view_->HeuristicsForGpuRasterizationUpdated(true);
-  }
-
-  // FIXME: only unittests, click to play, Android priting, and printing (for
-  // headers and footers) make this assert necessary. We should make them not
-  // hit this code and then delete allowsBrokenNullLayerTreeView.
-  DCHECK(layer_tree_view_ || Client()->AllowsBrokenNullLayerTreeView());
+  // TODO(kenrb): Currently GPU rasterization is always enabled for OOPIFs.
+  // This is okay because it is only necessarily to set the trigger to false
+  // for certain cases that affect the top-level frame, but it would be better
+  // to be consistent with the top-level frame. Ideally the logic should
+  // be moved from WebViewImpl into WebFrameWidget and used for all local
+  // frame roots. https://crbug.com/712794
+  layer_tree_view_->HeuristicsForGpuRasterizationUpdated(true);
 }
 
 void WebFrameWidgetImpl::SetIsAcceleratedCompositingActive(bool active) {
diff --git a/third_party/blink/renderer/core/layout/layout_geometry_map.cc b/third_party/blink/renderer/core/layout/layout_geometry_map.cc
index 176f44d4..d13ed7a 100644
--- a/third_party/blink/renderer/core/layout/layout_geometry_map.cc
+++ b/third_party/blink/renderer/core/layout/layout_geometry_map.cc
@@ -398,7 +398,7 @@
   if (!(map_coordinates_flags_ & kTraverseDocumentBoundaries))
     return true;
 
-  return layout_object->GetFrame()->IsMainFrame();
+  return layout_object->GetFrame()->IsLocalRoot();
 }
 #endif
 
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
index b8862df..93f9f56 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
@@ -86,7 +86,6 @@
 
   static void ConfigureSettings(WebSettings* settings) {
     settings->SetJavaScriptEnabled(true);
-    settings->SetAcceleratedCompositingEnabled(true);
     settings->SetPreferCompositingToLCDTextEnabled(true);
     // Android settings.
     settings->SetViewportEnabled(true);
diff --git a/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc b/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc
index 32c210b..604acc1 100644
--- a/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scroll_metrics_test.cc
@@ -170,7 +170,6 @@
     </div>
   )HTML");
 
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
   GetDocument().View()->SetParentVisible(true);
   GetDocument().View()->SetSelfVisible(true);
   GetDocument().View()->UpdateAllLifecyclePhases();
@@ -246,7 +245,6 @@
     </div>
   )HTML");
 
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
   GetDocument().View()->SetParentVisible(true);
   GetDocument().View()->SetSelfVisible(true);
   GetDocument().View()->UpdateAllLifecyclePhases();
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc
index af58bc6c..ee68453e 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_test.cc
@@ -127,7 +127,6 @@
 
  private:
   static void ConfigureSettings(WebSettings* settings) {
-    settings->SetAcceleratedCompositingEnabled(true);
     settings->SetPreferCompositingToLCDTextEnabled(true);
   }
 
diff --git a/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc b/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
index 81ffbe14..62ed498 100644
--- a/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
@@ -53,7 +53,6 @@
 
   FrameSettingOverrideFunction SettingOverrider() const override {
     return [](Settings& settings) {
-      settings.SetAcceleratedCompositingEnabled(true);
       // LayoutHTMLCanvas doesn't exist if script is disabled.
       settings.SetScriptEnabled(true);
     };
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 0d935c9..a46cd86 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -77,6 +77,7 @@
 #include "third_party/blink/renderer/core/paint/filter_effect_builder.h"
 #include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
 #include "third_party/blink/renderer/platform/bindings/runtime_call_stats.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
@@ -3085,13 +3086,25 @@
   SetNeedsCompositingInputsUpdate();
   GetLayoutObject().SetNeedsPaintPropertyUpdate();
 
-  // We don't need to invalidate paint of objects on SPv175 when paint order
-  // changes. However, we do need to repaint the containing stacking context,
-  // in order to generate new paint chunks in the correct order. Raster
-  // invalidation will be issued if needed during paint.
-  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
-      diff.ZIndexChanged())
-    SetNeedsRepaint();
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() && !NeedsRepaint()) {
+    if (diff.ZIndexChanged()) {
+      // We don't need to invalidate paint of objects on SPv175 when paint order
+      // changes. However, we do need to repaint the containing stacking
+      // context, in order to generate new paint chunks in the correct order.
+      // Raster invalidation will be issued if needed during paint.
+      SetNeedsRepaint();
+    } else if (old_style) {
+      // Change of PaintedOutputInvisible() will affect existence of paint
+      // chunks, so needs repaint.
+      PaintLayerPainter painter(*this);
+      // It's fine for PaintedOutputInvisible() to access the current
+      // compositing state.
+      DisableCompositingQueryAsserts disable;
+      if (painter.PaintedOutputInvisible(*old_style) !=
+          painter.PaintedOutputInvisible(GetLayoutObject().StyleRef()))
+        SetNeedsRepaint();
+    }
+  }
 }
 
 LayoutPoint PaintLayer::LocationInternal() const {
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter.cc b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
index 3adafae0..f4866f3 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
@@ -67,23 +67,25 @@
 }
 
 bool PaintLayerPainter::PaintedOutputInvisible(
-    const PaintLayerPaintingInfo& painting_info) {
-  const LayoutObject& layout_object = paint_layer_.GetLayoutObject();
-  if (layout_object.HasBackdropFilter())
+    const ComputedStyle& style,
+    GlobalPaintFlags global_paint_flags) const {
+  if (style.HasBackdropFilter())
     return false;
 
   // Always paint when 'will-change: opacity' is present. Reduces jank for
   // common animation implementation approaches, for example, an element that
   // starts with opacity zero and later begins to animate.
-  if (layout_object.StyleRef().HasWillChangeOpacityHint())
+  if (style.HasWillChangeOpacityHint())
     return false;
 
   if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
-    if (layout_object.StyleRef().Opacity())
+    if (style.Opacity())
       return false;
 
-    const EffectPaintPropertyNode* effect =
-        layout_object.FirstFragment().PaintProperties()->Effect();
+    const auto* effect = paint_layer_.GetLayoutObject()
+                             .FirstFragment()
+                             .PaintProperties()
+                             ->Effect();
     if (effect && effect->RequiresCompositingForAnimation()) {
       return false;
     }
@@ -94,9 +96,8 @@
   // less leads to a color output of less than 0.5 in all channels, hence
   // not visible.
   static const float kMinimumVisibleOpacity = 0.0004f;
-  if (paint_layer_.PaintsWithTransparency(
-          painting_info.GetGlobalPaintFlags())) {
-    if (layout_object.StyleRef().Opacity() < kMinimumVisibleOpacity) {
+  if (paint_layer_.PaintsWithTransparency(global_paint_flags)) {
+    if (style.Opacity() < kMinimumVisibleOpacity) {
       return true;
     }
   }
@@ -138,7 +139,8 @@
   // but skipping the painted content during layerization in
   // PaintArtifactCompositor.
   if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
-      PaintedOutputInvisible(painting_info)) {
+      PaintedOutputInvisible(paint_layer_.GetLayoutObject().StyleRef(),
+                             painting_info.GetGlobalPaintFlags())) {
     return kFullyPainted;
   }
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter.h b/third_party/blink/renderer/core/paint/paint_layer_painter.h
index 79ccbc94..346f363f 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter.h
@@ -14,6 +14,7 @@
 namespace blink {
 
 class ClipRect;
+class ComputedStyle;
 class DisplayItemClient;
 class PaintLayer;
 class GraphicsContext;
@@ -54,6 +55,11 @@
                               const LayoutRect& damage_rect,
                               const GlobalPaintFlags);
 
+  // Returns true if the painted output of this PaintLayer and its children is
+  // invisible and therefore can't impact painted output.
+  bool PaintedOutputInvisible(const ComputedStyle&,
+                              GlobalPaintFlags = kGlobalPaintNormalPhase) const;
+
  private:
   friend class PaintLayerPainterTest;
 
@@ -147,10 +153,6 @@
                           const PaintLayerFlags&,
                           const LayoutBoxModelObject&);
 
-  // Returns true if the painted output of this PaintLayer and its children is
-  // invisible and therefore can't impact painted output.
-  bool PaintedOutputInvisible(const PaintLayerPaintingInfo&);
-
   void AdjustForPaintProperties(PaintLayerPaintingInfo&, PaintLayerFlags&);
 
   PaintLayer& paint_layer_;
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc b/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
index e4d6b84b..100cbbfe 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
@@ -28,7 +28,9 @@
     PaintLayerPaintingInfo painting_info(nullptr, LayoutRect(),
                                          kGlobalPaintNormalPhase, LayoutSize());
     bool invisible =
-        PaintLayerPainter(*target_layer).PaintedOutputInvisible(painting_info);
+        PaintLayerPainter(*target_layer)
+            .PaintedOutputInvisible(target_layer->GetLayoutObject().StyleRef(),
+                                    painting_info.GetGlobalPaintFlags());
     EXPECT_EQ(expected_value, invisible)
         << "Failed painted output visibility [spv175_enabled="
         << RuntimeEnabledFeatures::SlimmingPaintV175Enabled()
diff --git a/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc b/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc
index 3e3cc45..c862d924 100644
--- a/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc
+++ b/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc
@@ -529,7 +529,6 @@
 
 TEST_P(FrameThrottlingTest, ThrottledFrameWithFocus) {
   WebView().GetSettings()->SetJavaScriptEnabled(true);
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
   ScopedCompositedSelectionUpdateForTest composited_selection_update(true);
 
   // Create a hidden frame which is throttled and has a text selection.
@@ -571,8 +570,6 @@
   if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
     return;
 
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
-
   // Create a hidden frame which is throttled.
   SimRequest main_resource("https://example.com/", "text/html");
   SimRequest frame_resource("https://example.com/iframe.html", "text/html");
@@ -637,7 +634,6 @@
 
 TEST_P(FrameThrottlingTest, ScrollingCoordinatorShouldSkipThrottledLayer) {
   WebView().GetSettings()->SetJavaScriptEnabled(true);
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
   WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
 
   // Create a hidden frame which is throttled and has a touch handler inside a
@@ -684,7 +680,6 @@
 
 TEST_P(FrameThrottlingTest,
        ScrollingCoordinatorShouldSkipCompositedThrottledFrame) {
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
   WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
 
   // Create a hidden frame which is throttled.
@@ -736,8 +731,6 @@
 }
 
 TEST_P(FrameThrottlingTest, UnthrottleByTransformingWithoutLayout) {
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
-
   // Create a hidden frame which is throttled.
   SimRequest main_resource("https://example.com/", "text/html");
   SimRequest frame_resource("https://example.com/iframe.html", "text/html");
@@ -768,7 +761,6 @@
   if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
     return;
 
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
   WebView().GetSettings()->SetJavaScriptEnabled(true);
   EXPECT_EQ(0u, TouchHandlerRegionSize());
 
@@ -809,7 +801,6 @@
   if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
     return;
 
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
   WebView().GetSettings()->SetJavaScriptEnabled(true);
   EXPECT_EQ(0u, TouchHandlerRegionSize());
 
@@ -878,7 +869,6 @@
   if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
     return;
 
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
   WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
 
   // Create a hidden frame which is throttled.
@@ -915,7 +905,6 @@
   if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
     return;
 
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
   WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
 
   // Create a hidden frame which is throttled.
@@ -1061,7 +1050,6 @@
 }
 
 TEST_P(FrameThrottlingTest, SkipPaintingLayersInThrottledFrames) {
-  WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
   WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
 
   SimRequest main_resource("https://example.com/", "text/html");
diff --git a/third_party/blink/renderer/core/workers/worker_thread.h b/third_party/blink/renderer/core/workers/worker_thread.h
index f771467..0cb7504 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.h
+++ b/third_party/blink/renderer/core/workers/worker_thread.h
@@ -157,7 +157,7 @@
   // Only callable on the main thread.
   void AppendDebuggerTask(CrossThreadClosure);
 
-  // Only callable on the main thread.
+  // Callable on both the main thread and the worker thread.
   const base::UnguessableToken& GetDevToolsWorkerToken() const {
     return devtools_worker_token_;
   }
@@ -310,7 +310,7 @@
   TimeDelta forcible_termination_delay_;
 
   scoped_refptr<InspectorTaskRunner> inspector_task_runner_;
-  base::UnguessableToken devtools_worker_token_;
+  const base::UnguessableToken devtools_worker_token_;
 
   // Created on the main thread, passed to the worker thread but should kept
   // being accessed only on the main thread.
diff --git a/third_party/blink/renderer/devtools/front_end/formatter/FormatterWorkerPool.js b/third_party/blink/renderer/devtools/front_end/formatter/FormatterWorkerPool.js
index c63d32f..6890f50 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter/FormatterWorkerPool.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter/FormatterWorkerPool.js
@@ -230,6 +230,15 @@
               rule => ({line: rule.lineNumber, column: rule.columnNumber, title: rule.selectorText || rule.atRule})));
     }
   }
+
+  /**
+   * @param {string} content
+   * @return {!Promise<?{baseExpression: string, possibleSideEffects:boolean}>}
+   */
+  findLastExpression(content) {
+    return /** @type {!Promise<?{baseExpression: string, possibleSideEffects:boolean}>} */ (
+        this._runTask('findLastExpression', {content}));
+  }
 };
 
 Formatter.FormatterWorkerPool.MaxWorkers = 2;
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js
index 8463752..e4528c0d 100644
--- a/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js
+++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js
@@ -84,6 +84,9 @@
     case 'preprocessTopLevelAwaitExpressions':
       FormatterWorker.preprocessTopLevelAwaitExpressions(params.content);
       break;
+    case 'findLastExpression':
+      postMessage(FormatterWorker.findLastExpression(params.content));
+      break;
     default:
       console.error('Unsupport method name: ' + method);
   }
@@ -318,6 +321,72 @@
 };
 
 /**
+ * @param {string} content
+ * @return {?{baseExpression: string, possibleSideEffects:boolean}}
+ */
+FormatterWorker.findLastExpression = function(content) {
+  if (content.length > 10000)
+    return null;
+  try {
+    const tokenizer = acorn.tokenizer(content, {ecmaVersion: 9});
+    while (tokenizer.getToken().type !== acorn.tokTypes.eof) {
+    }
+  } catch (e) {
+    return null;
+  }
+
+  /** @type {!ESTree.Node} */
+  let ast;
+  const suffix = '.DEVTOOLS';
+  try {
+    acorn.parse(content + suffix, {ecmaVersion: 9});
+  } catch (parseError) {
+    // If this is an invalid location for a '.', don't attempt to give autocomplete
+    if (parseError.message.startsWith('Unexpected token') && parseError.pos === content.length)
+      return null;
+  }
+  let parsedContent = '';
+  for (let i = 0; i < content.length; i++) {
+    try {
+      // Wrap content in paren to successfully parse object literals
+      parsedContent = content[i] === '{' ? `(${content.substring(i)})${suffix}` : `${content.substring(i)}${suffix}`;
+      ast = acorn.parse(parsedContent, {ecmaVersion: 9});
+      break;
+    } catch (e) {
+    }
+  }
+  if (!ast)
+    return null;
+  const types = new Set(['MemberExpression', 'Identifier']);
+  let baseNode = null;
+  const walker = new FormatterWorker.ESTreeWalker(node => {
+    if (baseNode || node.end < ast.end)
+      return FormatterWorker.ESTreeWalker.SkipSubtree;
+    if (types.has(node.type))
+      baseNode = node;
+  });
+  walker.walk(ast);
+  if (!baseNode)
+    return null;
+  let baseExpression = parsedContent.substring(baseNode.start, parsedContent.length - suffix.length);
+  if (baseExpression.startsWith('{'))
+    baseExpression = `(${baseExpression})`;
+  const sideEffectFreeTypes = new Set([
+    'MemberExpression', 'Identifier', 'BinaryExpression', 'Literal', 'TemplateLiteral', 'TemplateElement',
+    'ObjectExpression', 'ArrayExpression', 'Property'
+  ]);
+  let possibleSideEffects = false;
+  const sideEffectwalker = new FormatterWorker.ESTreeWalker(node => {
+    if (!possibleSideEffects && !sideEffectFreeTypes.has(node.type))
+      possibleSideEffects = true;
+    if (possibleSideEffects)
+      return FormatterWorker.ESTreeWalker.SkipSubtree;
+  });
+  sideEffectwalker.walk(/** @type {!ESTree.Node} */ (baseNode));
+  return {baseExpression, possibleSideEffects};
+};
+
+/**
  * @interface
  */
 FormatterWorker.FormatterWorkerContentParser = function() {};
diff --git a/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptAutocomplete.js b/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptAutocomplete.js
index 4a2850d..33de221 100644
--- a/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptAutocomplete.js
+++ b/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptAutocomplete.js
@@ -18,52 +18,17 @@
   }
 
   /**
-   * @param {string} text
+   * @param {string} fullText
    * @param {string} query
    * @param {boolean=} force
    * @return {!Promise<!UI.SuggestBox.Suggestions>}
    */
-  completionsForTextInCurrentContext(text, query, force) {
-    const clippedExpression = this._clipExpression(text, true);
-    const mapCompletionsPromise = this._mapCompletions(text, query);
-    return this._completionsForExpression(clippedExpression, query, force)
-        .then(completions => mapCompletionsPromise.then(mapCompletions => mapCompletions.concat(completions)));
-  }
+  async completionsForTextInCurrentContext(fullText, query, force) {
+    const trimmedText = fullText.trim();
 
-  /**
-   * @param {string} text
-   * @param {boolean=} allowEndingBracket
-   * @return {string}
-   */
-  _clipExpression(text, allowEndingBracket) {
-    let index;
-    const stopChars = new Set('=:({;,!+-*/&|^<>`'.split(''));
-    const whiteSpaceChars = new Set(' \r\n\t'.split(''));
-    const continueChars = new Set('[. \r\n\t'.split(''));
-
-    for (index = text.length - 1; index >= 0; index--) {
-      if (stopChars.has(text.charAt(index)))
-        break;
-      if (whiteSpaceChars.has(text.charAt(index)) && !continueChars.has(text.charAt(index - 1)))
-        break;
-    }
-    const clippedExpression = text.substring(index + 1).trim();
-    let bracketCount = 0;
-
-    index = clippedExpression.length - 1;
-    while (index >= 0) {
-      const character = clippedExpression.charAt(index);
-      if (character === ']')
-        bracketCount++;
-      // Allow an open bracket at the end for property completion.
-      if (character === '[' && (index < clippedExpression.length - 1 || !allowEndingBracket)) {
-        bracketCount--;
-        if (bracketCount < 0)
-          break;
-      }
-      index--;
-    }
-    return clippedExpression.substring(index + 1).trim();
+    const [mapCompletions, expressionCompletions] = await Promise.all(
+        [this._mapCompletions(trimmedText, query), this._completionsForExpression(trimmedText, query, force)]);
+    return mapCompletions.concat(expressionCompletions);
   }
 
   /**
@@ -77,15 +42,20 @@
     if (!executionContext || !mapMatch)
       return [];
 
-    const clippedExpression = this._clipExpression(text.substring(0, mapMatch.index));
+    const expression = await Formatter.formatterWorkerPool().findLastExpression(text.substring(0, mapMatch.index));
+    if (!expression)
+      return [];
+
     const result = await executionContext.evaluate(
         {
-          expression: clippedExpression,
-          objectGroup: 'completion',
+          expression: expression.baseExpression,
+          objectGroup: 'mapCompletion',
           includeCommandLineAPI: true,
           silent: true,
           returnByValue: false,
-          generatePreview: false
+          generatePreview: false,
+          throwOnSideEffect: expression.possibleSideEffects,
+          timeout: expression.possibleSideEffects ? 500 : undefined
         },
         /* userGesture */ false, /* awaitPromise */ false);
     if (result.error || !!result.exceptionDetails || result.object.subtype !== 'map')
@@ -96,6 +66,7 @@
     if (!entriesProperty)
       return [];
     const keysObj = await entriesProperty.value.callFunctionJSONPromise(getEntries);
+    executionContext.runtimeModel.releaseObjectGroup('mapCompletion');
     return gotKeys(Object.keys(keysObj));
 
     /**
@@ -158,25 +129,29 @@
   }
 
   /**
-   * @param {string} expressionString
+   * @param {string} fullText
    * @param {string} query
    * @param {boolean=} force
    * @return {!Promise<!UI.SuggestBox.Suggestions>}
    */
-  async _completionsForExpression(expressionString, query, force) {
+  async _completionsForExpression(fullText, query, force) {
     const executionContext = UI.context.flavor(SDK.ExecutionContext);
     if (!executionContext)
       return [];
+    let expression;
+    if (fullText.endsWith('.') || fullText.endsWith('['))
+      expression = await Formatter.formatterWorkerPool().findLastExpression(fullText.substring(0, fullText.length - 1));
+    if (!expression) {
+      if (fullText.endsWith('.'))
+        return [];
+      expression = {baseExpression: '', possibleSideEffects: false};
+    }
+    const needsNoSideEffects = expression.possibleSideEffects;
+    const expressionString = expression.baseExpression;
 
-    const lastIndex = expressionString.length - 1;
 
-    const dotNotation = (expressionString[lastIndex] === '.');
-    const bracketNotation = (expressionString.length > 1 && expressionString[lastIndex] === '[');
-
-    if (dotNotation || bracketNotation)
-      expressionString = expressionString.substr(0, lastIndex);
-    else
-      expressionString = '';
+    const dotNotation = fullText.endsWith('.');
+    const bracketNotation = !!expressionString && fullText.endsWith('[');
 
     // User is entering float value, do not suggest anything.
     if ((expressionString && !isNaN(expressionString)) || (!expressionString && query && !isNaN(query)))
@@ -203,7 +178,9 @@
             includeCommandLineAPI: true,
             silent: true,
             returnByValue: false,
-            generatePreview: false
+            generatePreview: false,
+            throwOnSideEffect: needsNoSideEffects,
+            timeout: needsNoSideEffects ? 500 : undefined
           },
           /* userGesture */ false, /* awaitPromise */ false);
       cache = {date: Date.now(), value: resultPromise.then(result => completionsOnGlobal.call(this, result))};
diff --git a/third_party/blink/renderer/devtools/front_end/object_ui/module.json b/third_party/blink/renderer/devtools/front_end/object_ui/module.json
index 216588d..3cfab83 100644
--- a/third_party/blink/renderer/devtools/front_end/object_ui/module.json
+++ b/third_party/blink/renderer/devtools/front_end/object_ui/module.json
@@ -11,7 +11,8 @@
     "dependencies": [
         "ui",
         "sdk",
-        "components"
+        "components",
+        "formatter"
     ],
     "scripts": [
         "CustomPreviewComponent.js",
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
index 632beee..b2d5554 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -127,6 +127,7 @@
 const char kActAsAudioControlsCSSClass[] = "audio-only";
 const char kScrubbingMessageCSSClass[] = "scrubbing-message";
 const char kTestModeCSSClass[] = "test-mode";
+const char kImmersiveModeCSSClass[] = "immersive-mode";
 
 bool ShouldShowFullscreenButton(const HTMLMediaElement& media_element) {
   // Unconditionally allow the user to exit fullscreen if we are in it
@@ -688,6 +689,12 @@
     builder.Append(kActAsAudioControlsCSSClass);
   }
 
+  if (ShouldShowVideoControls() && GetDocument().GetSettings() &&
+      GetDocument().GetSettings()->GetImmersiveModeEnabled()) {
+    builder.Append(" ");
+    builder.Append(kImmersiveModeCSSClass);
+  }
+
   if (is_test_mode_) {
     builder.Append(" ");
     builder.Append(kTestModeCSSClass);
diff --git a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
index 6357354..3c9a6fe 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
@@ -821,80 +821,80 @@
 /**
  * VR styling.
  */
-@media (immersive) {
-  video::-webkit-media-controls-timeline,
-  video::-internal-media-controls-button-panel {
-    padding-left: 32px;
-    padding-right: 32px;
-  }
-  /* Timeline sizing does not include padding in max width. */
-  video::-webkit-media-controls-timeline {
-    max-width: 471px;
-    height: 5px;
-    margin-bottom: 20px;
-    padding-top: 19px;
-    padding-bottom: 19px;
-  }
-  /* Button panel sizing does include padding in max width. */
-  video::-internal-media-controls-button-panel {
-    max-width: 535px; /* 471px + 64px padding. */
-  }
-
-  video::-webkit-media-controls-panel {
-    /* Centering the button panel and timeline within the controls. */
-    text-align: -webkit-center;
-
-    /* Taller scrim. */
-    background:
-      -webkit-image-set(url('default_100_percent/modern/vr_gradient_bg.png') 1x)
-      repeat-x bottom left;
-  }
-
-  input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before,
-  input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after,
-  input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-background,
-  input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-buffering {
-    height: 5px;
-  }
-
-  input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb {
-    width: 16px;
-    height: 16px;
-    border-radius: 8px;
-    margin-top: -5px;
-  }
-
-  input[pseudo="-webkit-media-controls-overlay-play-button" i]::-internal-media-controls-overlay-play-button-internal {
-    width: 64px;
-    height: 64px;
-    border-radius: 32px;
-    background-size: 36px;
-  }
-
-  video::-webkit-media-controls-mute-button,
-  video::-webkit-media-controls-fullscreen-button,
-  video::-internal-media-controls-overflow-button {
-    width: 43px;
-    height: 43px;
-    min-width: 43px;
-    margin-left: 5px;
-  }
-
-  video::-internal-media-controls-button-panel {
-    height: 43px;
-  }
-
-  /* Hover highlighting. */
-  video::-webkit-media-controls-mute-button:hover,
-  video::-webkit-media-controls-fullscreen-button:hover,
-  video::-internal-media-controls-overflow-button:hover {
-    background-color: rgba(255, 255, 255, 0.2);
-    border-radius: 4px;
-  }
+.immersive-mode input[pseudo="-webkit-media-controls-timeline" i],
+.immersive-mode div[pseudo="-internal-media-controls-button-panel" i] {
+  padding-left: 32px;
+  padding-right: 32px;
 }
 
-@media (immersive) and (-webkit-min-device-pixel-ratio: 2) {
-  video::-webkit-media-controls-panel {
+/* Timeline sizing does not include padding in max width. */
+.immersive-mode input[pseudo="-webkit-media-controls-timeline" i] {
+  max-width: 471px;
+  height: 5px;
+  margin-bottom: 20px;
+  padding-top: 19px;
+  padding-bottom: 19px;
+}
+
+/* Button panel sizing does include padding in max width. */
+.immersive-mode div[pseudo="-internal-media-controls-button-panel" i] {
+  max-width: 535px; /* 471px + 64px padding. */
+}
+
+.immersive-mode div[pseudo="-webkit-media-controls-panel" i] {
+  /* Centering the button panel and timeline within the controls. */
+  text-align: -webkit-center;
+
+  /* Taller scrim. */
+  background:
+    -webkit-image-set(url('default_100_percent/modern/vr_gradient_bg.png') 1x)
+    repeat-x bottom left;
+}
+
+.immersive-mode input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-before,
+.immersive-mode input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-highlight-after,
+.immersive-mode input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-background,
+.immersive-mode input[pseudo="-webkit-media-controls-timeline" i]::-internal-track-segment-buffering {
+  height: 5px;
+}
+
+.immersive-mode input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb {
+  width: 16px;
+  height: 16px;
+  border-radius: 8px;
+  margin-top: -5px;
+}
+
+.immersive-mode input[pseudo="-webkit-media-controls-overlay-play-button" i]::-internal-media-controls-overlay-play-button-internal {
+  width: 64px;
+  height: 64px;
+  border-radius: 32px;
+  background-size: 36px;
+}
+
+.immersive-mode input[pseudo="-webkit-media-controls-mute-button" i],
+.immersive-mode input[pseudo="-webkit-media-controls-fullscreen-button" i],
+.immersive-mode input[pseudo="-internal-media-controls-overflow-button" i] {
+  width: 43px;
+  height: 43px;
+  min-width: 43px;
+  margin-left: 5px;
+}
+
+.immersive-mode div[pseudo="-internal-media-controls-button-panel" i] {
+  height: 43px;
+}
+
+/* Hover highlighting. */
+.immersive-mode input[pseudo="-webkit-media-controls-mute-button" i]:hover,
+.immersive-mode input[pseudo="-webkit-media-controls-fullscreen-button" i]:hover,
+.immersive-mode input[pseudo="-internal-media-controls-overflow-button" i]:hover {
+  background-color: rgba(255, 255, 255, 0.2);
+  border-radius: 4px;
+}
+
+@media (-webkit-min-device-pixel-ratio: 2) {
+  .immersive-mode div[pseudo="-webkit-media-controls-panel" i] {
     background:
       -webkit-image-set(url('default_200_percent/modern/vr_gradient_bg.png') 1x)
       repeat-x bottom left auto 198px;
diff --git a/third_party/blink/renderer/modules/websockets/inspector_web_socket_events.cc b/third_party/blink/renderer/modules/websockets/inspector_web_socket_events.cc
index 46c84728..a19f16c 100644
--- a/third_party/blink/renderer/modules/websockets/inspector_web_socket_events.cc
+++ b/third_party/blink/renderer/modules/websockets/inspector_web_socket_events.cc
@@ -9,6 +9,8 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/core/workers/worker_thread.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 
 namespace blink {
@@ -18,15 +20,21 @@
     unsigned long identifier,
     const KURL& url,
     const String& protocol) {
+  DCHECK(execution_context->IsContextThread());
   std::unique_ptr<TracedValue> value = TracedValue::Create();
   value->SetInteger("identifier", identifier);
   value->SetString("url", url.GetString());
   if (execution_context->IsDocument()) {
     value->SetString("frame", IdentifiersFactory::FrameId(
                                   ToDocument(execution_context)->GetFrame()));
+  } else if (execution_context->IsWorkerGlobalScope()) {
+    value->SetString("workerId", IdentifiersFactory::IdFromToken(
+                                     ToWorkerGlobalScope(execution_context)
+                                         ->GetThread()
+                                         ->GetDevToolsWorkerToken()));
   } else {
-    // TODO(nhiroki): Support WorkerGlobalScope (https://crbug.com/825740).
-    NOTREACHED();
+    NOTREACHED()
+        << "WebSocket is available only in Document and WorkerGlobalScope";
   }
   if (!protocol.IsNull())
     value->SetString("webSocketProtocol", protocol);
@@ -37,14 +45,20 @@
 std::unique_ptr<TracedValue> InspectorWebSocketEvent::Data(
     ExecutionContext* execution_context,
     unsigned long identifier) {
+  DCHECK(execution_context->IsContextThread());
   std::unique_ptr<TracedValue> value = TracedValue::Create();
   value->SetInteger("identifier", identifier);
   if (execution_context->IsDocument()) {
     value->SetString("frame", IdentifiersFactory::FrameId(
                                   ToDocument(execution_context)->GetFrame()));
+  } else if (execution_context->IsWorkerGlobalScope()) {
+    value->SetString("workerId", IdentifiersFactory::IdFromToken(
+                                     ToWorkerGlobalScope(execution_context)
+                                         ->GetThread()
+                                         ->GetDevToolsWorkerToken()));
   } else {
-    // TODO(nhiroki): Support WorkerGlobalScope (https://crbug.com/825740).
-    NOTREACHED();
+    NOTREACHED()
+        << "WebSocket is available only in Document and WorkerGlobalScope";
   }
   SetCallStack(value.get());
   return value;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 454b035..43ed87e5 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -347,6 +347,12 @@
       name: "CustomElementsBuiltin",
       status: "stable",
     },
+    // Introduced this flag as stable so web developers can test their sites
+    // without native Custom Elements v0 support.
+    {
+      name: "CustomElementsV0",
+      status: "stable",
+    },
     {
       name: "CustomUserTiming",
     },
@@ -930,7 +936,7 @@
     },
     {
       name: "PictureInPictureAPI",
-      status: "test",
+      status: "experimental",
     },
     {
       name: "PreciseMemoryInfo",
diff --git a/third_party/closure_compiler/compiled_resources2.gyp b/third_party/closure_compiler/compiled_resources2.gyp
index bd2f692..011818d 100644
--- a/third_party/closure_compiler/compiled_resources2.gyp
+++ b/third_party/closure_compiler/compiled_resources2.gyp
@@ -23,7 +23,6 @@
         '<(DEPTH)/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/chromeos/switch_access/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/chromeos/sys_internals/compiled_resources2.gyp:*',
-        '<(DEPTH)/chrome/browser/resources/extensions/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/media_router/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/ntp4/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/pdf/compiled_resources2.gyp:*',
diff --git a/third_party/closure_compiler/externs/automation.js b/third_party/closure_compiler/externs/automation.js
index 7f7c9832..1cf0050 100644
--- a/third_party/closure_compiler/externs/automation.js
+++ b/third_party/closure_compiler/externs/automation.js
@@ -278,6 +278,7 @@
   NODE_CHANGED: 'nodeChanged',
   TEXT_CHANGED: 'textChanged',
   NODE_REMOVED: 'nodeRemoved',
+  SUBTREE_UPDATE_END: 'subtreeUpdateEnd',
 };
 
 /**
diff --git a/third_party/fuchsia-sdk/BUILD.gn b/third_party/fuchsia-sdk/BUILD.gn
index ec5c942b..b25fb8c 100644
--- a/third_party/fuchsia-sdk/BUILD.gn
+++ b/third_party/fuchsia-sdk/BUILD.gn
@@ -19,7 +19,7 @@
 # async-default keep a per-thread dispatcher for async.
 fuchsia_sdk_pkg("async_default") {
   name = "async-default"
-  libs = [ "async.default" ]
+  libs = [ "async-default" ]
 }
 
 fuchsia_sdk_pkg("zx") {
diff --git a/third_party/polymer/v1_0/bower.json b/third_party/polymer/v1_0/bower.json
index 0f1e6e42..4374166 100644
--- a/third_party/polymer/v1_0/bower.json
+++ b/third_party/polymer/v1_0/bower.json
@@ -26,7 +26,7 @@
     "iron-overlay-behavior": "PolymerElements/iron-overlay-behavior#2.3.2",
     "iron-pages": "PolymerElements/iron-pages#2.0.1",
     "iron-range-behavior": "PolymerElements/iron-range-behavior#2.0.0",
-    "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#1.0.5",
+    "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#2.1.0",
     "iron-scroll-target-behavior": "PolymerElements/iron-scroll-target-behavior#1.1.0",
     "iron-scroll-threshold": "PolymerElements/iron-scroll-threshold#2.0.0",
     "iron-selector": "PolymerElements/iron-selector#2.0.1",
diff --git a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/bower.json b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/bower.json
index 77d1968..845aeb9 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "iron-resizable-behavior",
-  "version": "1.0.5",
+  "version": "2.0.1",
   "license": "http://polymer.github.io/LICENSE.txt",
   "description": "Coordinates the flow of resizeable elements",
   "private": true,
@@ -19,13 +19,30 @@
     "url": "git://github.com/PolymerElements/iron-resizable-behavior.git"
   },
   "dependencies": {
-    "polymer": "Polymer/polymer#^1.1.0"
+    "polymer": "Polymer/polymer#1.9 - 2"
   },
   "devDependencies": {
-    "iron-component-page": "polymerelements/iron-component-page#^1.0.0",
-    "test-fixture": "polymerelements/test-fixture#^1.0.0",
-    "web-component-tester": "^4.0.0",
-    "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+    "iron-component-page": "PolymerElements/iron-component-page#1 - 2",
+    "web-component-tester": "^6.0.0",
+    "webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0"
   },
-  "ignore": []
+  "variants": {
+    "1.x": {
+      "dependencies": {
+        "polymer": "Polymer/polymer#^1.9"
+      },
+      "devDependencies": {
+        "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+        "web-component-tester": "^4.0.0",
+        "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+      },
+      "resolutions": {
+        "webcomponentsjs": "^0.7"
+      }
+    }
+  },
+  "ignore": [],
+  "resolutions": {
+    "webcomponentsjs": "^1.0.0"
+  }
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/iron-resizable-behavior-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/iron-resizable-behavior-extracted.js
index d882cae..527fda5 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/iron-resizable-behavior-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/iron-resizable-behavior-extracted.js
@@ -27,7 +27,7 @@
       },
 
       /**
-       * True if this element is currently notifying its descedant elements of
+       * True if this element is currently notifying its descendant elements of
        * resize.
        */
       _notifyingDescendant: {
@@ -48,16 +48,7 @@
     },
 
     attached: function() {
-      this.fire('iron-request-resize-notifications', null, {
-        node: this,
-        bubbles: true,
-        cancelable: true
-      });
-
-      if (!this._parentResizable) {
-        window.addEventListener('resize', this._boundNotifyResize);
-        this.notifyResize();
-      }
+      this._requestResizeNotifications();
     },
 
     detached: function() {
@@ -126,7 +117,7 @@
         return;
       }
 
-      // NOTE(cdata): In ShadowDOM, event retargetting makes echoing of the
+      // NOTE(cdata): In ShadowDOM, event retargeting makes echoing of the
       // otherwise non-bubbling event "just work." We do it manually here for
       // the case where Polymer is not using shadow roots for whatever reason:
       if (!Polymer.Settings.useShadow) {
@@ -142,8 +133,7 @@
     },
 
     _onIronRequestResizeNotifications: function(event) {
-      var target = event.path ? event.path[0] : event.target;
-
+      var target = /** @type {!EventTarget} */ (Polymer.dom(event).rootTarget);
       if (target === this) {
         return;
       }
@@ -176,5 +166,35 @@
       this._notifyingDescendant = true;
       descendant.notifyResize();
       this._notifyingDescendant = false;
+    },
+    
+    _requestResizeNotifications: function() {
+      if (!this.isAttached)
+        return;
+      
+      // NOTE(valdrin) In CustomElements v1 with native HTMLImports, the order
+      // of imports affects the order of `attached` callbacks (see webcomponents/custom-elements#15).
+      // This might cause a child to notify parents too early (as the parent
+      // still has to be upgraded), resulting in a parent not able to keep track
+      // of the `_interestedResizables`. To solve this, we wait for the document
+      // to be done loading before firing the event.
+      if (document.readyState === 'loading') {
+        var _requestResizeNotifications = this._requestResizeNotifications.bind(this);
+        document.addEventListener('readystatechange', function readystatechanged() {
+          document.removeEventListener('readystatechange', readystatechanged);
+          _requestResizeNotifications();
+        });
+      } else {
+        this.fire('iron-request-resize-notifications', null, {
+          node: this,
+          bubbles: true,
+          cancelable: true
+        });
+
+        if (!this._parentResizable) {
+          window.addEventListener('resize', this._boundNotifyResize);
+          this.notifyResize();
+        } 
+      }
     }
   };
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components_summary.txt b/third_party/polymer/v1_0/components_summary.txt
index 554ef1d1..b1f4935 100644
--- a/third_party/polymer/v1_0/components_summary.txt
+++ b/third_party/polymer/v1_0/components_summary.txt
@@ -144,9 +144,9 @@
 
 Name: iron-resizable-behavior
 Repository: https://github.com/PolymerElements/iron-resizable-behavior.git
-Tree: v1.0.5
-Revision: 354f287922e497b79797348b31596eebaccb9761
-Tree link: https://github.com/PolymerElements/iron-resizable-behavior/tree/v1.0.5
+Tree: v2.1.0
+Revision: 806e0807bd4253f446f8be624acf853069e36919
+Tree link: https://github.com/PolymerElements/iron-resizable-behavior/tree/v2.1.0
 
 Name: iron-scroll-target-behavior
 Repository: https://github.com/PolymerElements/iron-scroll-target-behavior.git
diff --git a/third_party/typ/LICENSE b/third_party/typ/LICENSE
deleted file mode 100644
index ad410e11..0000000
--- a/third_party/typ/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
-Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "{}"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright {yyyy} {name of copyright owner}
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
\ No newline at end of file
diff --git a/third_party/typ/OWNERS b/third_party/typ/OWNERS
deleted file mode 100644
index ac3cc58b0..0000000
--- a/third_party/typ/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-dpranke@chromium.org
-dtu@chromium.org
-eseidel@chromium.org
-ojan@chromium.org
diff --git a/third_party/typ/README.chromium b/third_party/typ/README.chromium
deleted file mode 100644
index 0b3264e..0000000
--- a/third_party/typ/README.chromium
+++ /dev/null
@@ -1,32 +0,0 @@
-Name: typ
-URL: https://github.com/dpranke/typ.git
-Version: 0.10.0
-Revision: 1e254b3ef4d14dee6109d8c3a58ab64d1500e3c2
-Security Critical: no
-License: Apache 2.0
-License File: NOT_SHIPPED
-
-Description:
-
-typ is a simple wrapper around Python's unittest library that provides a
-somewhat nicer command-line interface, parallel test execution,
-code coverage support, and support for Chromium's JSON Results format.
-
-This code is not considered security critical since it is only to be linked
-into test binaries! This should never be linked into chrome or any production
-code.
-
-To update this copy of typ from the source repo (assuming you are in 
-src/third_party/typ):
-
-    # can just do "sed -n '/^   /p' README.chromium | bash -e"
-    cd ..
-    git clone https://github.com/dpranke/typ.git typ_new
-    revision=$(cd typ_new && git log -1 | head -1 | awk '{ print $2 }')
-    version=$(cd typ_new && python -m typ --version)
-    cp typ/OWNERS typ_new
-    cat typ/README.chromium | sed -e "s/^Version: .*/Version: $version/" \
-                                  -e "s/^Revision: .*/Revision: $revision/" \
-                                  > typ_new/README.chromium
-    rm -fr typ_new/.git typ_new/.gitignore typ/
-    mv typ_new typ
diff --git a/third_party/typ/README.rst b/third_party/typ/README.rst
deleted file mode 100644
index dc03841..0000000
--- a/third_party/typ/README.rst
+++ /dev/null
@@ -1,68 +0,0 @@
-typ (Test Your Program)
-=======================
-typ is a simple program for testing command line executables and Python code.
-
-When testing Python code, it is basically a wrapper around the standard
-unittest module, but it provides the following bits of additional
-functionality:
-
-* Parallel test execution.
-* Clean output in the style of the Ninja build tool.
-* A more flexible mechanism for discovering tests from the
-  command line and controlling how they are run:
-
-  * Support for importing tests by directory, filename, or module.
-  * Support for specifying tests to skip, tests to run in parallel,
-    and tests that need to be run by themselves
-
-* Support for producing traces of test times compatible with Chrome's
-  tracing infrastructure (trace_viewer).
-* Integrated test coverage reporting (including parallel coverage).
-* Integrated support for debugging tests.
-* Support for uploading test results automatically to a server
-  (useful for continuous integration monitoring of test results).
-* An abstraction of operating system functionality called the
-  Host class. This can be used by other python code to write more
-  portable and easily testable code by wrapping the multiprocessing,
-  os, subprocess, and time modules.
-* Simple libraries for integrating Ninja-style statistics and line
-  printing into your own code (the Stats and Printer classes).
-* Support for processing arbitrary arguments from calling code to
-  test cases.
-* Support for once-per-process setup and teardown hooks.
-
-(These last two bullet points allow one to write tests that do not require
-Python globals).
-
-History
--------
-
-typ originated out of work on the Blink and Chromium projects, as a way to
-provide a friendlier interface to the Python unittest modules.
-
-Work remaining
---------------
-
-typ is still a work in progress, but it's getting close to being done.
-Things remaining for 1.0, roughly in priority order:
-
-- Implement a non-python file format for testing command line interfaces
-- Write documentation
-
-Possible future work
---------------------
-
-- MainTestCase.check() improvements:
-
-  - check all arguments and show all errors at once?
-  - make multi-line regexp matches easier to follow?
-
-- --debugger improvements:
-
-  - make it skip the initial breakpoint?
-
-- Support testing javascript, java, c++/gtest-style binaries?
-- Support for test sharding in addition to parallel execution (so that
-  run-webkit-tests can re-use as much of the code as possible)?
-- Support for non-unittest runtest invocation (for run-webkit-tests,
-  other harnesses?)
diff --git a/third_party/typ/codereview.settings b/third_party/typ/codereview.settings
deleted file mode 100644
index 8fbef92..0000000
--- a/third_party/typ/codereview.settings
+++ /dev/null
@@ -1,3 +0,0 @@
-# This file is used by gcl to get repository specific information.
-CODE_REVIEW_SERVER: codereview.chromium.org
-PROJECT: typ
diff --git a/third_party/typ/pylintrc b/third_party/typ/pylintrc
deleted file mode 100644
index 9ccea6f..0000000
--- a/third_party/typ/pylintrc
+++ /dev/null
@@ -1,272 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-[MASTER]
-
-# Specify a configuration file.
-#rcfile=
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Profiled execution.
-profile=no
-
-# Add files or directories to the blacklist. They should be base names, not
-# paths.
-ignore=CVS
-
-# Pickle collected data for later comparisons.
-persistent=yes
-
-# List of plugins (as comma separated values of python modules names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-
-[MESSAGES CONTROL]
-
-# Enable the message, report, category or checker with the given id(s). You can
-# either give multiple identifier separated by comma (,) or put this option
-# multiple time.
-#enable=
-
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifier separated by comma (,) or put this option
-# multiple time (only on the command line, not in the configuration file where
-# it should appear only once).
-# CHANGED:
-# C0111: Missing docstring
-# I0011: Locally disabling WNNNN
-# R0201: Method could be a function
-# R0801: Similar lines
-# W0141: Used builtin function 'map'
-# W0142: Used * or ** magic
-# W0511: TODO
-# W0703: Catch "Exception"
-disable=C0111,I0011,R0201,R0801,W0141,W0142,W0511,W0703
-
-
-[REPORTS]
-
-# Set the output format. Available formats are text, parseable, colorized, msvs
-# (visual studio) and html
-output-format=text
-
-# Put messages in a separate file for each module / package specified on the
-# command line instead of printing them on stdout. Reports (if any) will be
-# written in a file name "pylint_global.[txt|html]".
-files-output=no
-
-# Tells whether to display a full report or only the messages
-# CHANGED:
-reports=no
-
-# Python expression which should return a note less than 10 (10 is the highest
-# note). You have access to the variables errors warning, statement which
-# respectively contain the number of errors / warnings messages and the total
-# number of statements analyzed. This is used by the global evaluation report
-# (RP0004).
-evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
-
-# Add a comment according to your evaluation note. This is used by the global
-# evaluation report (RP0004).
-comment=no
-
-
-[VARIABLES]
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# A regular expression matching the beginning of the name of dummy variables
-# (i.e. not used).
-dummy-variables-rgx=_|dummy
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
-
-
-[TYPECHECK]
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# List of classes names for which member attributes should not be checked
-# (useful for classes with attributes dynamically set).
-ignored-classes=
-
-# When zope mode is activated, add a predefined set of Zope acquired attributes
-# to generated-members.
-zope=no
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E0201 when accessed. Python regular
-# expressions are accepted.
-generated-members=
-
-
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,XXX,TODO
-
-
-[SIMILARITIES]
-
-# Minimum lines number of a similarity.
-min-similarity-lines=4
-
-# Ignore comments when computing similarities.
-ignore-comments=yes
-
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
-
-
-[FORMAT]
-
-# Maximum number of characters on a single line.
-# max-line-length=200
-max-line-length=80
-
-# Maximum number of lines in a module
-# max-module-lines=1000
-
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-# CHANGED:
-indent-string='    '
-
-
-[BASIC]
-
-# Required attributes for module, separated by a comma
-required-attributes=
-
-# List of builtins function names that should not be used, separated by a comma
-bad-functions=map,filter,apply,input
-
-# Regular expression which should only match correct module names
-module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-
-# Regular expression which should only match correct module level names
-const-rgx=(([a-zA-Z_][a-zA-Z0-9_]*)|(__.*__))$
-
-# Regular expression which should only match correct class names
-class-rgx=[A-Z_][a-zA-Z0-9]+$
-
-# Regular expression which should only match correct function names
-function-rgx=[a-z_][a-z0-9_]{0,40}$
-
-# Regular expression which should only match correct method names
-method-rgx=[a-z_][a-z0-9_]{0,48}$
-
-# Regular expression which should only match correct instance attribute names
-attr-rgx=[a-z_][a-z0-9_]{0,30}$
-
-# Regular expression which should only match correct argument names
-argument-rgx=[a-z_][a-z0-9_]{0,30}$
-
-# Regular expression which should only match correct variable names
-variable-rgx=[a-zA-Z0-9_]{0,30}$
-
-# Regular expression which should only match correct list comprehension /
-# generator expression variable names
-inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
-
-# Good variable names which should always be accepted, separated by a comma
-good-names=i,j,k,ex,Run,_
-
-# Bad variable names which should always be refused, separated by a comma
-bad-names=foo,bar,baz,toto,tutu,tata
-
-# Regular expression which should only match functions or classes name which do
-# not require a docstring
-no-docstring-rgx=__.*__
-
-
-[DESIGN]
-
-# Maximum number of arguments for function / method
-max-args=8
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore
-ignored-argument-names=_.*
-
-# Maximum number of locals for function / method body
-max-locals=32
-
-# Maximum number of return / yield for function / method body
-max-returns=32
-
-# Maximum number of branch for function / method body
-max-branches=32
-
-# Maximum number of statements in function / method body
-max-statements=65
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=16
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=0
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=100
-
-
-[CLASSES]
-
-# List of interface methods to ignore, separated by a comma. This is used for
-# instance to not check methods defines in Zope's Interface base class.
-ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,__new__,setUp
-
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
-
-
-[IMPORTS]
-
-# Deprecated modules which should not be used, separated by a comma
-deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
-
-# Create a graph of every (i.e. internal and external) dependencies in the
-# given file (report RP0402 must not be disabled)
-import-graph=
-
-# Create a graph of external dependencies in the given file (report RP0402 must
-# not be disabled)
-ext-import-graph=
-
-# Create a graph of internal dependencies in the given file (report RP0402 must
-# not be disabled)
-int-import-graph=
-
-
-[EXCEPTIONS]
-
-# Exceptions that will emit a warning when being caught. Defaults to
-# "Exception"
-overgeneral-exceptions=Exception
diff --git a/third_party/typ/run b/third_party/typ/run
deleted file mode 100755
index 401296bd..0000000
--- a/third_party/typ/run
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function
-
-import argparse
-import os
-import subprocess
-import sys
-
-from tools import cov
-
-
-class Runner(object):
-
-    def __init__(self):
-        self._verbose = False
-        self._repo_dir = os.path.abspath(os.path.dirname(__file__))
-        self._path_to_cov = os.path.join(self._repo_dir, 'tools', 'cov.py')
-        self._path_to_runner = os.path.join(self._repo_dir, 'typ', 'runner.py')
-        self._python = sys.executable
-
-    def main(self, argv):
-        parser = argparse.ArgumentParser(prog='run')
-        parser.add_argument('-v', '--verbose', action='store_true')
-        subps = parser.add_subparsers()
-
-        subp = subps.add_parser('clean', help='Remove any local files.')
-        subp.set_defaults(func=self.run_clean)
-
-        subp = subps.add_parser('coverage',
-                                help='Run the tests and report code coverage.')
-        subp.set_defaults(func=self.run_coverage)
-        cov.add_arguments(subp)
-
-        subp = subps.add_parser('help',
-                                help='Get help on a subcommand.')
-        subp.add_argument(nargs='?', action='store', dest='subcommand',
-                        help='The command to get help for.')
-        subp.set_defaults(func=self.run_help)
-
-        subp = subps.add_parser('lint',
-                                help='run lint over the source')
-        subp.set_defaults(func=self.run_lint)
-
-        subp = subps.add_parser('tests',
-                                help='run the tests')
-        subp.set_defaults(func=self.run_tests)
-
-        args = parser.parse_args(argv)
-
-        self._verbose = args.verbose
-        args.func(args)
-
-    def call(self, *args, **kwargs):
-        if self._verbose:
-            print(' '.join(args[0]))
-        ret = subprocess.call(*args, **kwargs)
-        if ret != 0:
-            sys.exit(ret)
-
-    def run_clean(self, _args):
-        self.call(['git', 'clean', '-fxd'])
-
-    def run_coverage(self, args):
-        if not args.path:
-            args.path = [self._repo_dir]
-        if not args.source:
-            args.source = [os.path.join(self._repo_dir, 'typ')]
-        argv = cov.argv_from_args(args)
-        cov_args = [self._path_to_runner, '-j', '1']
-        self.call([self._python, self._path_to_cov] + argv + cov_args)
-
-    def run_help(self, args):
-        if args.subcommand:
-            self.main([args.subcommand, '--help'])
-        self.main(['--help'])
-
-    def run_lint(self, _args):
-        self.call('pylint --rcfile=pylintrc */*.py */*/*.py', shell=True)
-
-    def run_tests(self, _args):
-        # Test running the typ module directly if it is in sys.path.
-        self.call([
-            self._python, '-m', 'typ',
-            'typ.tests.main_test.TestMain.test_basic',
-        ])
-
-        # Testing running the runner directly if nothing is in sys.path.
-        home_dir = os.environ['HOME']
-        self.call([self._python, self._path_to_runner,
-                   'typ.tests.main_test.TestMain.test_basic'], cwd=home_dir)
-
-        # Run the remaining tests.
-        self.call([self._python, self._path_to_runner])
-
-
-if __name__ == '__main__':
-    sys.exit(Runner().main(sys.argv[1:]))
diff --git a/third_party/typ/setup.cfg b/third_party/typ/setup.cfg
deleted file mode 100644
index 3c6e79c..0000000
--- a/third_party/typ/setup.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[bdist_wheel]
-universal=1
diff --git a/third_party/typ/setup.py b/third_party/typ/setup.py
deleted file mode 100644
index f03f444..0000000
--- a/third_party/typ/setup.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import sys
-
-from setuptools import setup, find_packages
-
-here = os.path.abspath(os.path.dirname(__file__))
-if here not in sys.path:
-    sys.path.insert(0, here)
-
-from typ.version import VERSION
-
-with open(os.path.join(here, 'README.rst')) as fp:
-    readme = fp.read().strip()
-
-readme_lines = readme.splitlines()
-
-setup(
-    name='typ',
-    packages=find_packages(),
-    package_data={'': ['../README.rst']},
-    entry_points={
-        'console_scripts': [
-            'typ=typ.runner:main',
-        ]
-    },
-    install_requires=[
-    ],
-    version=VERSION,
-    author='Dirk Pranke',
-    author_email='dpranke@chromium.org',
-    description=readme_lines[3],
-    long_description=('\n' + '\n'.join(readme_lines)),
-    url='https://github.com/dpranke/typ',
-    license='Apache',
-    classifiers=[
-        'Development Status :: 3 - Alpha',
-        'Intended Audience :: Developers',
-        'License :: OSI Approved :: Apache Software License',
-        'Programming Language :: Python :: 2',
-        'Programming Language :: Python :: 2.7',
-        'Programming Language :: Python :: 3',
-        'Programming Language :: Python :: 3.5',
-        'Topic :: Software Development :: Testing',
-    ],
-)
diff --git a/third_party/typ/tools/__init__.py b/third_party/typ/tools/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/third_party/typ/tools/__init__.py
+++ /dev/null
diff --git a/third_party/typ/tools/cov.py b/third_party/typ/tools/cov.py
deleted file mode 100755
index ff97728..0000000
--- a/third_party/typ/tools/cov.py
+++ /dev/null
@@ -1,142 +0,0 @@
-#!/usr/bin/python
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import print_function
-
-import argparse
-import sys
-import textwrap
-
-is_python3 = bool(sys.version_info.major == 3)
-
-
-ALL_PRAGMAS = ['no cover', 'no win32', 'python2', 'python3', 'untested',
-               'win32']
-DEFAULT_PRAGMAS = ALL_PRAGMAS[:]
-
-if is_python3:
-    DEFAULT_PRAGMAS.remove('python3')
-else:
-    DEFAULT_PRAGMAS.remove('python2')
-
-if sys.platform == 'win32':
-    DEFAULT_PRAGMAS.remove('win32')
-else:
-    DEFAULT_PRAGMAS.remove('no win32')
-
-
-def add_arguments(parser):
-    parser.add_argument('--no-pragmas', action='store_true', default=False,
-                        help='Show all uncovered lines (no pragmas).')
-    parser.add_argument('--path', action='append', default=[],
-                        help='Prepend given directories to sys.path.')
-    parser.add_argument('--pragma', action='append', default=[],
-                        help=('The coverage pragmas to honor '
-                              '(defaults to %s).' % DEFAULT_PRAGMAS))
-    parser.add_argument('--show', action='append', default=[],
-                        help='Show code protected by the specified pragmas '
-                             '(uses all pragmas *except* for the ones '
-                             'specified).')
-    parser.add_argument('--show-missing', action='store_true',
-                        default=False, help='Show missing lines.')
-    parser.add_argument('--source', action='append', default=[],
-                        help='Limit coverage data to the given directories.')
-
-    parser.formatter_class = argparse.RawTextHelpFormatter
-    parser.epilog = textwrap.dedent("""
-    Valid pragma values are:
-        'no cover': The default coverage pragma, this now means we
-                    truly cannot cover it.
-        'no win32': Code that only executes when not on Windows.
-        'python2':  Code that only executes under Python2.
-        'python3':  Code that only executes under Python3.
-        'untested': Code that does not yet have tests.
-        'win32':    Code that only executes on Windows.
-
-    In typ, we aim for 'no cover' to only apply to code that executes only
-    when coverage is not available (and hence can never be counted). Most
-    code, if annotated at all, should be 'untested', and we should strive
-    for 'untested' to not be used, either.
-    """)
-
-
-def argv_from_args(args):
-    argv = []
-    if args.no_pragmas:
-        argv.append('--no-pragmas')
-    for arg in args.path:
-        argv.extend(['--path', arg])
-    for arg in args.show:
-        argv.extend(['--show', arg])
-    if args.show_missing:
-        argv.append('--show-missing')
-    for arg in args.source:
-        argv.extend(['--source', arg])
-    for arg in args.pragma:
-        argv.extend(['--pragma', arg])
-    return argv
-
-
-def main(argv=None):
-    parser = argparse.ArgumentParser()
-    add_arguments(parser)
-    args, remaining_args = parser.parse_known_args(argv)
-
-    for path in args.path:
-        if path not in sys.path:
-            sys.path.append(path)
-
-    try:
-        import coverage
-        from coverage.execfile import run_python_module, run_python_file
-    except ImportError:
-        print("Error: coverage is not available.")
-        sys.exit(1)
-
-    cov = coverage.coverage(source=args.source)
-    cov.erase()
-    cov.clear_exclude()
-
-    if args.no_pragmas:
-        args.pragma = []
-
-    args.pragma = args.pragma or DEFAULT_PRAGMAS
-
-    if args.show:
-        args.show_missing = True
-    for pragma in args.show:
-        if pragma in args.pragma:
-            args.pragma.remove(pragma)
-
-    for pragma in args.pragma:
-        cov.exclude('pragma: %s' % pragma)
-
-    ret = 0
-    cov.start()
-    try:
-        if remaining_args[0] == '-m':
-            run_python_module(remaining_args[1], remaining_args[1:])
-        else:
-            run_python_file(remaining_args[0], remaining_args)
-    except SystemExit as e:
-        ret = e.code
-    cov.stop()
-    cov.save()
-    cov.report(show_missing=args.show_missing)
-    return ret
-
-
-if __name__ == '__main__':
-    sys.exit(main())
diff --git a/third_party/typ/typ/__init__.py b/third_party/typ/typ/__init__.py
deleted file mode 100644
index ab04414..0000000
--- a/third_party/typ/typ/__init__.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Test Your Project
-
-typ is a simple program for testing command line executables and Python code.
-
-When testing Python code, it is basically a wrapper around the standard
-unittest module, but it provides the following bits of additional
-functionality:
-
-    * Parallel test execution.
-
-    * Clean output in the style of the Ninja build tool.
-
-    * A more flexible mechanism for discovering tests from the
-      command line and controlling how they are run:
-      * Support for importing tests by directory, filename, or module.
-      * Support for specifying tests to skip, tests to run in parallel,
-        and tests that need to be run by themselves
-
-    * Support for producing traces of test times compatible with Chrome's
-      tracing infrastructure (trace_viewer).
-
-    * Integrated test coverage reporting.
-
-    * Integrated support for debugging tests.
-
-    * Support for uploading test results automatically to a server
-      (useful for continuous integration monitoring of test results).
-
-    * An abstraction of operating system functionality called the
-      Host class. This can be used by other python code to write more
-      portable and easily testable code by wrapping the multiprocessing,
-      os, subprocess, and time modules.
-
-    * Simple libraries for integrating Ninja-style statistics and line
-      printing into your own code (the Stats and Printer classes).
-
-    * Support for processing arbitrary arguments from calling code to
-      test cases.
-
-    * Support for once-per-process setup and teardown hooks.
-      (These last two bullet points allow one to write tests that do not
-       require Python globals).
-"""
-
-from typ.arg_parser import ArgumentParser
-from typ.fakes.host_fake import FakeHost
-from typ.host import Host
-from typ.json_results import exit_code_from_full_results
-from typ.json_results import make_full_results, make_upload_request
-from typ.json_results import Result, ResultSet, ResultType
-from typ.runner import Runner, TestInput, TestSet, WinMultiprocessing, main
-from typ.stats import Stats
-from typ.printer import Printer
-from typ.test_case import convert_newlines, TestCase, MainTestCase
-from typ.version import VERSION
-
-
-__all__ = [
-    'ArgumentParser',
-    'FakeHost',
-    'Host',
-    'MainTestCase',
-    'Printer',
-    'Result',
-    'ResultSet',
-    'ResultType',
-    'Runner',
-    'Stats',
-    'TestCase',
-    'TestInput',
-    'TestSet',
-    'VERSION',
-    'WinMultiprocessing',
-    'convert_newlines',
-    'exit_code_from_full_results',
-    'main',
-    'make_full_results',
-    'make_upload_request',
-]
diff --git a/third_party/typ/typ/__main__.py b/third_party/typ/typ/__main__.py
deleted file mode 100644
index 0e026e8..0000000
--- a/third_party/typ/typ/__main__.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import sys  # pragma: no cover
-
-from typ import main  # pragma: no cover
-
-
-if __name__ == '__main__':  # pragma: no cover
-    sys.exit(main())
diff --git a/third_party/typ/typ/arg_parser.py b/third_party/typ/typ/arg_parser.py
deleted file mode 100644
index 707adab0..0000000
--- a/third_party/typ/typ/arg_parser.py
+++ /dev/null
@@ -1,342 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import argparse
-import optparse
-
-from typ.host import Host
-
-
-class _Bailout(Exception):
-    pass
-
-
-DEFAULT_COVERAGE_OMIT = ['*/typ/*', '*/site-packages/*']
-DEFAULT_STATUS_FORMAT = '[%f/%t] '
-DEFAULT_SUFFIXES = ['*_test.py', '*_unittest.py']
-
-
-class ArgumentParser(argparse.ArgumentParser):
-
-    @staticmethod
-    def add_option_group(parser, title, discovery=False,
-                         running=False, reporting=False, skip=None):
-        # TODO: Get rid of this when telemetry upgrades to argparse.
-        ap = ArgumentParser(add_help=False, version=False, discovery=discovery,
-                            running=running, reporting=reporting)
-        optlist = ap.optparse_options(skip=skip)
-        group = optparse.OptionGroup(parser, title)
-        group.add_options(optlist)
-        parser.add_option_group(group)
-
-    def __init__(self, host=None, add_help=True, version=True, discovery=True,
-                 reporting=True, running=True):
-        super(ArgumentParser, self).__init__(prog='typ', add_help=add_help)
-
-        self._host = host or Host()
-        self.exit_status = None
-
-        self.usage = '%(prog)s [options] [tests...]'
-
-        if version:
-            self.add_argument('-V', '--version', action='store_true',
-                              help='Print the typ version and exit.')
-
-        if discovery:
-            self.add_argument('-f', '--file-list', metavar='FILENAME',
-                              action='store',
-                              help=('Takes the list of tests from the file '
-                                    '(use "-" for stdin).'))
-            self.add_argument('--all', action='store_true',
-                              help=('Run all the tests, including the ones '
-                                    'normally skipped.'))
-            self.add_argument('--isolate', metavar='glob', default=[],
-                              action='append',
-                              help=('Globs of tests to run in isolation '
-                                    '(serially).'))
-            self.add_argument('--skip', metavar='glob', default=[],
-                              action='append',
-                              help=('Globs of test names to skip ('
-                                    'defaults to %(default)s).'))
-            self.add_argument('--suffixes', metavar='glob', default=[],
-                              action='append',
-                              help=('Globs of test filenames to look for ('
-                                    'can specify multiple times; defaults '
-                                    'to %s).' % DEFAULT_SUFFIXES))
-
-        if reporting:
-            self.add_argument('--builder-name',
-                              help=('Builder name to include in the '
-                                    'uploaded data.'))
-            self.add_argument('-c', '--coverage', action='store_true',
-                              help='Reports coverage information.')
-            self.add_argument('--coverage-source', action='append',
-                              default=[],
-                              help=('Directories to include when running and '
-                                    'reporting coverage (defaults to '
-                                    '--top-level-dirs plus --path)'))
-            self.add_argument('--coverage-omit', action='append',
-                              default=[],
-                              help=('Globs to omit when reporting coverage '
-                                    '(defaults to %s).' %
-                                    DEFAULT_COVERAGE_OMIT))
-            self.add_argument('--coverage-annotate', action='store_true',
-                              help=('Produce an annotate source report.'))
-            self.add_argument('--coverage-show-missing', action='store_true',
-                              help=('Show missing line ranges in coverage '
-                                    'report.'))
-            self.add_argument('--master-name',
-                              help=('Buildbot master name to include in the '
-                                    'uploaded data.'))
-            self.add_argument('--metadata', action='append', default=[],
-                              help=('Optional key=value metadata that will '
-                                    'be included in the results.'))
-            self.add_argument('--test-results-server',
-                              help=('If specified, uploads the full results '
-                                    'to this server.'))
-            self.add_argument('--test-type',
-                              help=('Name of test type to include in the '
-                                    'uploaded data (e.g., '
-                                    '"telemetry_unittests").'))
-            self.add_argument('--write-full-results-to', metavar='FILENAME',
-                              action='store',
-                              help=('If specified, writes the full results to '
-                                    'that path.'))
-            self.add_argument('--write-trace-to', metavar='FILENAME',
-                              action='store',
-                              help=('If specified, writes the trace to '
-                                    'that path.'))
-            self.add_argument('tests', nargs='*', default=[],
-                              help=argparse.SUPPRESS)
-
-        if running:
-            self.add_argument('-d', '--debugger', action='store_true',
-                              help='Runs the tests under the debugger.')
-            self.add_argument('-j', '--jobs', metavar='N', type=int,
-                              default=self._host.cpu_count(),
-                              help=('Runs N jobs in parallel '
-                                    '(defaults to %(default)s).'))
-            self.add_argument('-l', '--list-only', action='store_true',
-                              help='Lists all the test names found and exits.')
-            self.add_argument('-n', '--dry-run', action='store_true',
-                              help=argparse.SUPPRESS)
-            self.add_argument('-q', '--quiet', action='store_true',
-                              default=False,
-                              help=('Runs as quietly as possible '
-                                    '(only prints errors).'))
-            self.add_argument('-s', '--status-format',
-                              default=self._host.getenv('NINJA_STATUS',
-                                                        DEFAULT_STATUS_FORMAT),
-                              help=argparse.SUPPRESS)
-            self.add_argument('-t', '--timing', action='store_true',
-                              help='Prints timing info.')
-            self.add_argument('-v', '--verbose', action='count', default=0,
-                              help=('Prints more stuff (can specify multiple '
-                                    'times for more output).'))
-            self.add_argument('--passthrough', action='store_true',
-                              default=False,
-                              help='Prints all output while running.')
-            self.add_argument('--total-shards', default=1, type=int,
-                              help=('Total number of shards being used for '
-                                    'this test run. (The user of '
-                                    'this script is responsible for spawning '
-                                    'all of the shards.)'))
-            self.add_argument('--shard-index', default=0, type=int,
-                              help=('Shard index (0..total_shards-1) of this '
-                                    'test run.'))
-            self.add_argument('--retry-limit', type=int, default=0,
-                              help='Retries each failure up to N times.')
-            self.add_argument('--terminal-width', type=int,
-                              default=self._host.terminal_width(),
-                              help=argparse.SUPPRESS)
-            self.add_argument('--overwrite', action='store_true',
-                              default=None,
-                              help=argparse.SUPPRESS)
-            self.add_argument('--no-overwrite', action='store_false',
-                              dest='overwrite', default=None,
-                              help=argparse.SUPPRESS)
-
-        if discovery or running:
-            self.add_argument('-P', '--path', action='append', default=[],
-                              help=('Adds dir to sys.path (can specify '
-                                    'multiple times).'))
-            self.add_argument('--top-level-dir', action='store', default=None,
-                              help=argparse.SUPPRESS)
-            self.add_argument('--top-level-dirs', action='append', default=[],
-                              help=('Sets the top directory of project '
-                                    '(used when running subdirs).'))
-
-    def parse_args(self, args=None, namespace=None):
-        try:
-            rargs = super(ArgumentParser, self).parse_args(args=args,
-                                                           namespace=namespace)
-        except _Bailout:
-            return None
-
-        for val in rargs.metadata:
-            if '=' not in val:
-                self._print_message('Error: malformed --metadata "%s"' % val)
-                self.exit_status = 2
-
-        if rargs.test_results_server:
-            if not rargs.builder_name:
-                self._print_message('Error: --builder-name must be specified '
-                                    'along with --test-result-server')
-                self.exit_status = 2
-            if not rargs.master_name:
-                self._print_message('Error: --master-name must be specified '
-                                    'along with --test-result-server')
-                self.exit_status = 2
-            if not rargs.test_type:
-                self._print_message('Error: --test-type must be specified '
-                                    'along with --test-result-server')
-                self.exit_status = 2
-
-        if rargs.total_shards < 1:
-            self._print_message('Error: --total-shards must be at least 1')
-            self.exit_status = 2
-
-        if rargs.shard_index < 0:
-            self._print_message('Error: --shard-index must be at least 0')
-            self.exit_status = 2
-
-        if rargs.shard_index >= rargs.total_shards:
-            self._print_message('Error: --shard-index must be no more than '
-                                'the number of shards (%i) minus 1' %
-                                rargs.total_shards)
-            self.exit_status = 2
-
-        if not rargs.suffixes:
-            rargs.suffixes = DEFAULT_SUFFIXES
-
-        if not rargs.coverage_omit:
-            rargs.coverage_omit = DEFAULT_COVERAGE_OMIT
-
-        if rargs.debugger:  # pragma: no cover
-            rargs.jobs = 1
-            rargs.passthrough = True
-
-        if rargs.overwrite is None:
-            rargs.overwrite = self._host.stdout.isatty() and not rargs.verbose
-
-        return rargs
-
-    # Redefining built-in 'file' pylint: disable=W0622
-
-    def _print_message(self, msg, file=None):
-        self._host.print_(msg=msg, stream=file, end='\n')
-
-    def print_help(self, file=None):
-        self._print_message(msg=self.format_help(), file=file)
-
-    def error(self, message, bailout=True):  # pylint: disable=W0221
-        self.exit(2, '%s: error: %s\n' % (self.prog, message), bailout=bailout)
-
-    def exit(self, status=0, message=None,  # pylint: disable=W0221
-             bailout=True):
-        self.exit_status = status
-        if message:
-            self._print_message(message, file=self._host.stderr)
-        if bailout:
-            raise _Bailout()
-
-    def optparse_options(self, skip=None):
-        skip = skip or []
-        options = []
-        for action in self._actions:
-            args = [flag for flag in action.option_strings if flag not in skip]
-            if not args or action.help == '==SUPPRESS==':
-                # must either be a positional argument like 'tests'
-                # or an option we want to skip altogether.
-                continue
-
-            kwargs = {
-                'default': action.default,
-                'dest': action.dest,
-                'help': action.help,
-                'metavar': action.metavar,
-                'type': action.type,
-                'action': _action_str(action)
-            }
-            options.append(optparse.make_option(*args, **kwargs))
-        return options
-
-    def argv_from_args(self, args):
-        default_parser = ArgumentParser(host=self._host)
-        default_args = default_parser.parse_args([])
-        argv = []
-        tests = []
-        d = vars(args)
-        for k in sorted(d.keys()):
-            v = d[k]
-            argname = _argname_from_key(k)
-            action = self._action_for_key(k)
-            if not action:
-                continue
-            action_str = _action_str(action)
-            if k == 'tests':
-                tests = v
-                continue
-            if getattr(default_args, k) == v:
-                # this arg has the default value, so skip it.
-                continue
-
-            assert action_str in ['append', 'count', 'store', 'store_true']
-            if action_str == 'append':
-                for el in v:
-                    argv.append(argname)
-                    argv.append(el)
-            elif action_str == 'count':
-                for _ in range(v):
-                    argv.append(argname)
-            elif action_str == 'store':
-                argv.append(argname)
-                argv.append(str(v))
-            else:
-                # action_str == 'store_true'
-                argv.append(argname)
-
-        return argv + tests
-
-    def _action_for_key(self, key):
-        for action in self._actions:
-            if action.dest == key:
-                return action
-
-        # Assume foreign argument: something used by the embedder of typ, for
-        # example.
-        return None
-
-
-def _action_str(action):
-    # Access to a protected member pylint: disable=W0212
-    assert action.__class__ in (
-        argparse._AppendAction,
-        argparse._CountAction,
-        argparse._StoreAction,
-        argparse._StoreTrueAction
-    )
-
-    if isinstance(action, argparse._AppendAction):
-        return 'append'
-    if isinstance(action, argparse._CountAction):
-        return 'count'
-    if isinstance(action, argparse._StoreAction):
-        return 'store'
-    if isinstance(action, argparse._StoreTrueAction):
-        return 'store_true'
-
-
-def _argname_from_key(key):
-    return '--' + key.replace('_', '-')
diff --git a/third_party/typ/typ/fakes/__init__.py b/third_party/typ/typ/fakes/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/third_party/typ/typ/fakes/__init__.py
+++ /dev/null
diff --git a/third_party/typ/typ/fakes/host_fake.py b/third_party/typ/typ/fakes/host_fake.py
deleted file mode 100644
index 89c0075..0000000
--- a/third_party/typ/typ/fakes/host_fake.py
+++ /dev/null
@@ -1,292 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import copy
-import io
-import logging
-import sys
-
-from typ.host import _TeedStream
-
-
-is_python3 = bool(sys.version_info.major == 3)
-
-if is_python3:  # pragma: python3
-    # pylint: disable=redefined-builtin,invalid-name
-    unicode = str
-
-
-class FakeHost(object):
-    # "too many instance attributes" pylint: disable=R0902
-    # "redefining built-in" pylint: disable=W0622
-    # "unused arg" pylint: disable=W0613
-
-    python_interpreter = 'python'
-    is_python3 = bool(sys.version_info.major == 3)
-
-    def __init__(self):
-        self.logger = logging.getLogger()
-        self.stdin = io.StringIO()
-        self.stdout = io.StringIO()
-        self.stderr = io.StringIO()
-        self.platform = 'linux2'
-        self.env = {}
-        self.sep = '/'
-        self.dirs = set([])
-        self.files = {}
-        self.fetches = []
-        self.fetch_responses = {}
-        self.written_files = {}
-        self.last_tmpdir = None
-        self.current_tmpno = 0
-        self.mtimes = {}
-        self.cmds = []
-        self.cwd = '/tmp'
-        self._orig_logging_handlers = []
-
-    def __getstate__(self):
-        d = copy.copy(self.__dict__)
-        del d['stderr']
-        del d['stdout']
-        del d['stdin']
-        del d['logger']
-        del d['_orig_logging_handlers']
-        return d
-
-    def __setstate__(self, d):
-        for k, v in d.items():
-            setattr(self, k, v)
-        self.logger = logging.getLogger()
-        self.stdin = io.StringIO()
-        self.stdout = io.StringIO()
-        self.stderr = io.StringIO()
-
-    def abspath(self, *comps):
-        relpath = self.join(*comps)
-        if relpath.startswith('/'):
-            return relpath
-        return self.join(self.cwd, relpath)
-
-    def add_to_path(self, *comps):
-        absolute_path = self.abspath(*comps)
-        if absolute_path not in sys.path:
-            sys.path.append(absolute_path)
-
-    def basename(self, path):
-        return path.split(self.sep)[-1]
-
-    def call(self, argv, stdin=None, env=None):
-        self.cmds.append(argv)
-        return 0, '', ''
-
-    def call_inline(self, argv):
-        return self.call(argv)[0]
-
-    def chdir(self, *comps):
-        path = self.join(*comps)
-        if not path.startswith('/'):
-            path = self.join(self.cwd, path)
-        self.cwd = path
-
-    def cpu_count(self):
-        return 1
-
-    def dirname(self, path):
-        return '/'.join(path.split('/')[:-1])
-
-    def exists(self, *comps):
-        path = self.abspath(*comps)
-        return ((path in self.files and self.files[path] is not None) or
-                path in self.dirs)
-
-    def files_under(self, top):
-        files = []
-        top = self.abspath(top)
-        for f in self.files:
-            if self.files[f] is not None and f.startswith(top):
-                files.append(self.relpath(f, top))
-        return files
-
-    def for_mp(self):
-        return self
-
-    def getcwd(self):
-        return self.cwd
-
-    def getenv(self, key, default=None):
-        return self.env.get(key, default)
-
-    def getpid(self):
-        return 1
-
-    def isdir(self, *comps):
-        path = self.abspath(*comps)
-        return path in self.dirs
-
-    def isfile(self, *comps):
-        path = self.abspath(*comps)
-        return path in self.files and self.files[path] is not None
-
-    def join(self, *comps):
-        p = ''
-        for c in comps:
-            if c in ('', '.'):
-                continue
-            elif c.startswith('/'):
-                p = c
-            elif p:
-                p += '/' + c
-            else:
-                p = c
-
-        # Handle ./
-        p = p.replace('/./', '/')
-
-        # Handle ../
-        while '/..' in p:
-            comps = p.split('/')
-            idx = comps.index('..')
-            comps = comps[:idx-1] + comps[idx+1:]
-            p = '/'.join(comps)
-        return p
-
-    def maybe_mkdir(self, *comps):
-        path = self.abspath(self.join(*comps))
-        if path not in self.dirs:
-            self.dirs.add(path)
-
-    def mktempfile(self, delete=True):
-        curno = self.current_tmpno
-        self.current_tmpno += 1
-        f = io.StringIO()
-        f.name = '__im_tmp/tmpfile_%u' % curno
-        return f
-
-    def mkdtemp(self, suffix='', prefix='tmp', dir=None, **_kwargs):
-        if dir is None:
-            dir = self.sep + '__im_tmp'
-        curno = self.current_tmpno
-        self.current_tmpno += 1
-        self.last_tmpdir = self.join(dir, '%s_%u_%s' % (prefix, curno, suffix))
-        self.dirs.add(self.last_tmpdir)
-        return self.last_tmpdir
-
-    def mtime(self, *comps):
-        return self.mtimes.get(self.join(*comps), 0)
-
-    def print_(self, msg='', end='\n', stream=None):
-        stream = stream or self.stdout
-        stream.write(msg + end)
-        stream.flush()
-
-    def read_binary_file(self, *comps):
-        return self._read(comps)
-
-    def read_text_file(self, *comps):
-        return self._read(comps)
-
-    def _read(self, comps):
-        return self.files[self.abspath(*comps)]
-
-    def realpath(self, *comps):
-        return self.abspath(*comps)
-
-    def relpath(self, path, start):
-        return path.replace(start + '/', '')
-
-    def remove(self, *comps):
-        path = self.abspath(*comps)
-        self.files[path] = None
-        self.written_files[path] = None
-
-    def rmtree(self, *comps):
-        path = self.abspath(*comps)
-        for f in self.files:
-            if f.startswith(path):
-                self.files[f] = None
-                self.written_files[f] = None
-        self.dirs.remove(path)
-
-    def terminal_width(self):
-        return 80
-
-    def splitext(self, path):
-        idx = path.rfind('.')
-        if idx == -1:
-            return (path, '')
-        return (path[:idx], path[idx:])
-
-    def time(self):
-        return 0
-
-    def write_binary_file(self, path, contents):
-        self._write(path, contents)
-
-    def write_text_file(self, path, contents):
-        self._write(path, contents)
-
-    def _write(self, path, contents):
-        full_path = self.abspath(path)
-        self.maybe_mkdir(self.dirname(full_path))
-        self.files[full_path] = contents
-        self.written_files[full_path] = contents
-
-    def fetch(self, url, data=None, headers=None):
-        resp = self.fetch_responses.get(url, FakeResponse(unicode(''), url))
-        self.fetches.append((url, data, headers, resp))
-        return resp
-
-    def _tap_output(self):
-        self.stdout = _TeedStream(self.stdout)
-        self.stderr = _TeedStream(self.stderr)
-        if True:
-            sys.stdout = self.stdout
-            sys.stderr = self.stderr
-
-    def _untap_output(self):
-        assert isinstance(self.stdout, _TeedStream)
-        self.stdout = self.stdout.stream
-        self.stderr = self.stderr.stream
-        if True:
-            sys.stdout = self.stdout
-            sys.stderr = self.stderr
-
-    def capture_output(self, divert=True):
-        self._tap_output()
-        self._orig_logging_handlers = self.logger.handlers
-        if self._orig_logging_handlers:
-            self.logger.handlers = [logging.StreamHandler(self.stderr)]
-        self.stdout.capture(divert=divert)
-        self.stderr.capture(divert=divert)
-
-    def restore_output(self):
-        assert isinstance(self.stdout, _TeedStream)
-        out, err = (self.stdout.restore(), self.stderr.restore())
-        self.logger.handlers = self._orig_logging_handlers
-        self._untap_output()
-        return out, err
-
-
-class FakeResponse(io.StringIO):
-
-    def __init__(self, response, url, code=200):
-        io.StringIO.__init__(self, response)
-        self._url = url
-        self.code = code
-
-    def geturl(self):
-        return self._url
-
-    def getcode(self):
-        return self.code
diff --git a/third_party/typ/typ/fakes/test_result_server_fake.py b/third_party/typ/typ/fakes/test_result_server_fake.py
deleted file mode 100644
index 2cc876c..0000000
--- a/third_party/typ/typ/fakes/test_result_server_fake.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""A fake implementation of test-results.appspot.com."""
-
-import io
-import sys
-import threading
-
-
-if sys.version_info.major == 2:  # pragma: python2
-    from SimpleHTTPServer import SimpleHTTPRequestHandler as HTTPRequestHandler
-    from SocketServer import TCPServer
-else:  # pragma: python3
-    assert sys.version_info.major == 3
-    # pylint: disable=invalid-name, redefined-builtin
-    unicode = str
-    from http.server import BaseHTTPRequestHandler  # pylint: disable=F0401
-    HTTPRequestHandler = BaseHTTPRequestHandler
-    from socketserver import TCPServer  # pylint: disable=F0401
-
-
-def start(code=200):
-    server = _Server(code=code)
-    thread = threading.Thread(target=_run, args=(server,))
-    server.main_thread = thread
-    thread.daemon = True
-    thread.start()
-    return server
-
-
-def _run(server):
-    server.serve_forever(0.05)
-
-
-class _Server(TCPServer):
-
-    def __init__(self, code):
-        self.allow_reuse_address = True
-        TCPServer.__init__(self, ('localhost', 0), _RequestHandler)
-        self.log = io.StringIO()
-        self.requests = []
-        self.main_thread = None
-        self.code = code
-
-    def stop(self):
-        self.shutdown()
-        self.main_thread.join()
-        return self.requests
-
-
-class _RequestHandler(HTTPRequestHandler):
-
-    def __init__(self, *args, **kwargs):
-        HTTPRequestHandler.__init__(self, *args, **kwargs)
-
-    # 'Invalid Name' pylint: disable=C0103
-    def do_POST(self):
-        path = self.path
-        length = int(self.headers['content-length'])
-        payload = self.rfile.read(length)
-        self.server.requests.append(('post', path, payload))
-        self.send_response(self.server.code)
-        self.end_headers()
-
-    # 'Redefining built-in' pylint: disable=W0622
-    def log_message(self, format, *args):
-        self.server.log.write(unicode('%s\n' % (format % args)))
diff --git a/third_party/typ/typ/fakes/tests/__init__.py b/third_party/typ/typ/fakes/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/third_party/typ/typ/fakes/tests/__init__.py
+++ /dev/null
diff --git a/third_party/typ/typ/fakes/tests/host_fake_test.py b/third_party/typ/typ/fakes/tests/host_fake_test.py
deleted file mode 100644
index a16b7ba1..0000000
--- a/third_party/typ/typ/fakes/tests/host_fake_test.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import sys
-
-from typ.tests import host_test
-from typ.fakes.host_fake import FakeHost, FakeResponse
-
-is_python3 = bool(sys.version_info.major == 3)
-
-if is_python3:  # pragma: python3
-    # redefining built-in 'unicode' pylint: disable=W0622
-    unicode = str
-
-class TestFakeHost(host_test.TestHost):
-
-    def host(self):
-        return FakeHost()
-
-    def test_add_to_path(self):
-        # TODO: FakeHost uses the real sys.path, and then gets
-        # confused becayse host.abspath() doesn't work right for
-        # windows-style paths.
-        if sys.platform != 'win32':
-            super(TestFakeHost, self).test_add_to_path()
-
-    def test_call(self):
-        h = self.host()
-        ret, out, err = h.call(['echo', 'hello, world'])
-        self.assertEqual(ret, 0)
-        self.assertEqual(out, '')
-        self.assertEqual(err, '')
-        self.assertEqual(h.cmds, [['echo', 'hello, world']])
-
-    def test_call_inline(self):
-        h = self.host()
-        ret = h.call_inline(['echo', 'hello, world'])
-        self.assertEqual(ret, 0)
-
-    def test_capture_output(self):
-        h = self.host()
-        self.host = lambda: h
-        super(TestFakeHost, self).test_capture_output()
-
-        # This tests that the super-method only tested the
-        # divert=True case, and things were diverted properly.
-        self.assertEqual(h.stdout.getvalue(), '')
-        self.assertEqual(h.stderr.getvalue(), '')
-
-        h.capture_output(divert=False)
-        h.print_('on stdout')
-        h.print_('on stderr', stream=h.stderr)
-        out, err = h.restore_output()
-        self.assertEqual(out, 'on stdout\n')
-        self.assertEqual(err, 'on stderr\n')
-        self.assertEqual(h.stdout.getvalue(), 'on stdout\n')
-        self.assertEqual(h.stderr.getvalue(), 'on stderr\n')
-
-    def test_for_mp(self):
-        h = self.host()
-        self.assertNotEqual(h.for_mp(), None)
-
-    def test_fetch(self):
-        h = self.host()
-        url = 'http://localhost/test'
-        resp = FakeResponse(unicode('foo'), url)
-        h.fetch_responses[url] = resp
-        actual_resp = h.fetch(url)
-        self.assertEqual(actual_resp.geturl(), url)
-        self.assertEqual(actual_resp.getcode(), 200)
-        self.assertEqual(resp, actual_resp)
-        self.assertEqual(h.fetches, [(url, None, None, actual_resp)])
diff --git a/third_party/typ/typ/fakes/tests/test_result_server_fake_test.py b/third_party/typ/typ/fakes/tests/test_result_server_fake_test.py
deleted file mode 100644
index 87316c87..0000000
--- a/third_party/typ/typ/fakes/tests/test_result_server_fake_test.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-
-from typ.fakes import test_result_server_fake
-from typ import Host
-
-
-class TestResultServerFakeTest(unittest.TestCase):
-    def test_basic_upload(self):
-        host = Host()
-        server = None
-        posts = []
-        try:
-            server = test_result_server_fake.start()
-            url = 'http://%s:%d/testfile/upload' % server.server_address
-            if server:
-                resp = host.fetch(url, 'foo=bar')
-        finally:
-            if server:
-                posts = server.stop()
-        self.assertEqual(posts, [('post', '/testfile/upload',
-                                  'foo=bar'.encode('utf8'))])
-        self.assertNotEqual(server.log.getvalue(), '')
diff --git a/third_party/typ/typ/host.py b/third_party/typ/typ/host.py
deleted file mode 100644
index 42890db5..0000000
--- a/third_party/typ/typ/host.py
+++ /dev/null
@@ -1,286 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import io
-import logging
-import multiprocessing
-import os
-import shutil
-import subprocess
-import sys
-import tempfile
-import time
-
-
-if sys.version_info.major == 2:  # pragma: python2
-    from urllib2 import urlopen, Request
-else:  # pragma: python3
-    # pylint: disable=E0611
-    assert sys.version_info.major == 3
-    from urllib.request import urlopen, Request  # pylint: disable=F0401,E0611
-
-
-class Host(object):
-    python_interpreter = sys.executable
-    is_python3 = bool(sys.version_info.major == 3)
-
-    pathsep = os.pathsep
-    sep = os.sep
-    env = os.environ
-
-    _orig_stdout = sys.stdout
-    _orig_stderr = sys.stderr
-
-    def __init__(self):
-        self.logger = logging.getLogger()
-        self._orig_logging_handlers = None
-        self.stdout = sys.stdout
-        self.stderr = sys.stderr
-        self.stdin = sys.stdin
-        self.env = os.environ
-        self.platform = sys.platform
-
-    def abspath(self, *comps):
-        return os.path.abspath(self.join(*comps))
-
-    def add_to_path(self, *comps):
-        absolute_path = self.abspath(*comps)
-        if absolute_path not in sys.path:
-            sys.path.insert(0, absolute_path)
-
-    def basename(self, path):
-        return os.path.basename(path)
-
-    def call(self, argv, stdin=None, env=None):
-        if stdin:
-            stdin_pipe = subprocess.PIPE
-        else:
-            stdin_pipe = None
-        proc = subprocess.Popen(argv, stdout=subprocess.PIPE,
-                                stderr=subprocess.PIPE, stdin=stdin_pipe,
-                                env=env)
-        if stdin_pipe:
-            proc.stdin.write(stdin.encode('utf-8'))
-        stdout, stderr = proc.communicate()
-
-        # pylint type checking bug - pylint: disable=E1103
-        return proc.returncode, stdout.decode('utf-8'), stderr.decode('utf-8')
-
-    def call_inline(self, argv, env=None):
-        if isinstance(self.stdout, _TeedStream):  # pragma: no cover
-            ret, out, err = self.call(argv, env)
-            self.print_(out, end='')
-            self.print_(err, end='', stream=self.stderr)
-            return ret
-        return subprocess.call(argv, stdin=self.stdin, stdout=self.stdout,
-                               stderr=self.stderr, env=env)
-
-    def chdir(self, *comps):
-        return os.chdir(self.join(*comps))
-
-    def cpu_count(self):
-        return multiprocessing.cpu_count()
-
-    def dirname(self, *comps):
-        return os.path.dirname(self.join(*comps))
-
-    def exists(self, *comps):
-        return os.path.exists(self.join(*comps))
-
-    def files_under(self, top):
-        all_files = []
-        for root, _, files in os.walk(top):
-            for f in files:
-                relpath = self.relpath(os.path.join(root, f), top)
-                all_files.append(relpath)
-        return all_files
-
-    def getcwd(self):
-        return os.getcwd()
-
-    def getenv(self, key, default=None):
-        return self.env.get(key, default)
-
-    def getpid(self):
-        return os.getpid()
-
-    def for_mp(self):
-        return None
-
-    def isdir(self, *comps):
-        return os.path.isdir(os.path.join(*comps))
-
-    def isfile(self, *comps):
-        return os.path.isfile(os.path.join(*comps))
-
-    def join(self, *comps):
-        return os.path.join(*comps)
-
-    def maybe_mkdir(self, *comps):
-        path = self.abspath(self.join(*comps))
-        if not self.exists(path):
-            os.makedirs(path)
-
-    def mktempfile(self, delete=True):
-        return tempfile.NamedTemporaryFile(delete=delete)
-
-    def mkdtemp(self, **kwargs):
-        return tempfile.mkdtemp(**kwargs)
-
-    def mtime(self, *comps):
-        return os.stat(self.join(*comps)).st_mtime
-
-    def print_(self, msg='', end='\n', stream=None):
-        stream = stream or self.stdout
-        stream.write(str(msg) + end)
-        stream.flush()
-
-    def read_text_file(self, *comps):
-        return self._read(comps, 'r')
-
-    def read_binary_file(self, *comps):
-        return self._read(comps, 'rb')
-
-    def _read(self, comps, mode):
-        path = self.join(*comps)
-        with open(path, mode) as f:
-            return f.read()
-
-    def realpath(self, *comps):
-        return os.path.realpath(os.path.join(*comps))
-
-    def relpath(self, path, start):
-        return os.path.relpath(path, start)
-
-    def remove(self, *comps):
-        os.remove(self.join(*comps))
-
-    def rmtree(self, path):
-        shutil.rmtree(path, ignore_errors=True)
-
-    def splitext(self, path):
-        return os.path.splitext(path)
-
-    def time(self):
-        return time.time()
-
-    def write_text_file(self, path, contents):
-        return self._write(path, contents, mode='w')
-
-    def write_binary_file(self, path, contents):
-        return self._write(path, contents, mode='wb')
-
-    def _write(self, path, contents, mode):
-        with open(path, mode) as f:
-            f.write(contents)
-
-    def fetch(self, url, data=None, headers=None):
-        headers = headers or {}
-        return urlopen(Request(url, data.encode('utf8'), headers))
-
-    def terminal_width(self):
-        """Returns 0 if the width cannot be determined."""
-        try:
-            if sys.platform == 'win32':  # pragma: win32
-                # From http://code.activestate.com/recipes/ \
-                #   440694-determine-size-of-console-window-on-windows/
-                from ctypes import windll, create_string_buffer
-
-                STDERR_HANDLE = -12
-                handle = windll.kernel32.GetStdHandle(STDERR_HANDLE)
-
-                SCREEN_BUFFER_INFO_SZ = 22
-                buf = create_string_buffer(SCREEN_BUFFER_INFO_SZ)
-
-                if windll.kernel32.GetConsoleScreenBufferInfo(handle, buf):
-                    import struct
-                    fields = struct.unpack("hhhhHhhhhhh", buf.raw)
-                    left = fields[5]
-                    right = fields[7]
-
-                    # Note that we return 1 less than the width since writing
-                    # into the rightmost column automatically performs a
-                    # line feed.
-                    return right - left
-                return 0
-            else:  # pragma: no win32
-                import fcntl
-                import struct
-                import termios
-                packed = fcntl.ioctl(self.stderr.fileno(),
-                                     termios.TIOCGWINSZ, '\0' * 8)
-                _, columns, _, _ = struct.unpack('HHHH', packed)
-                return columns
-        except Exception:
-            return 0
-
-    def _tap_output(self):
-        self.stdout = sys.stdout = _TeedStream(self.stdout)
-        self.stderr = sys.stderr = _TeedStream(self.stderr)
-
-    def _untap_output(self):
-        assert isinstance(self.stdout, _TeedStream)
-        self.stdout = sys.stdout = self.stdout.stream
-        self.stderr = sys.stderr = self.stderr.stream
-
-    def capture_output(self, divert=True):
-        self._tap_output()
-        self._orig_logging_handlers = self.logger.handlers
-        if self._orig_logging_handlers:
-            self.logger.handlers = [logging.StreamHandler(self.stderr)]
-        self.stdout.capture(divert)
-        self.stderr.capture(divert)
-
-    def restore_output(self):
-        assert isinstance(self.stdout, _TeedStream)
-        out, err = (self.stdout.restore(), self.stderr.restore())
-        self.logger.handlers = self._orig_logging_handlers
-        self._untap_output()
-        return out, err
-
-
-class _TeedStream(io.StringIO):
-
-    def __init__(self, stream):
-        super(_TeedStream, self).__init__()
-        self.stream = stream
-        self.capturing = False
-        self.diverting = False
-
-    def write(self, msg, *args, **kwargs):
-        if self.capturing:
-            if (sys.version_info.major == 2 and
-                    isinstance(msg, str)):  # pragma: python2
-                msg = unicode(msg)
-            super(_TeedStream, self).write(msg, *args, **kwargs)
-        if not self.diverting:
-            self.stream.write(msg, *args, **kwargs)
-
-    def flush(self):
-        if self.capturing:
-            super(_TeedStream, self).flush()
-        if not self.diverting:
-            self.stream.flush()
-
-    def capture(self, divert=True):
-        self.truncate(0)
-        self.capturing = True
-        self.diverting = divert
-
-    def restore(self):
-        msg = self.getvalue()
-        self.truncate(0)
-        self.capturing = False
-        self.diverting = False
-        return msg
diff --git a/third_party/typ/typ/json_results.py b/third_party/typ/typ/json_results.py
deleted file mode 100644
index f048d05..0000000
--- a/third_party/typ/typ/json_results.py
+++ /dev/null
@@ -1,212 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from collections import OrderedDict
-
-import json
-
-
-class ResultType(object):
-    Pass = 'Pass'
-    Failure = 'Failure'
-    ImageOnlyFailure = 'ImageOnlyFailure'
-    Timeout = 'Timeout'
-    Crash = 'Crash'
-    Skip = 'Skip'
-
-    values = (Pass, Failure, ImageOnlyFailure, Timeout, Crash, Skip)
-
-
-class Result(object):
-    # too many instance attributes  pylint: disable=R0902
-    # too many arguments  pylint: disable=R0913
-
-    def __init__(self, name, actual, started, took, worker,
-                 expected=None, unexpected=False,
-                 flaky=False, code=0, out='', err='', pid=0):
-        self.name = name
-        self.actual = actual
-        self.started = started
-        self.took = took
-        self.worker = worker
-        self.expected = expected or [ResultType.Pass]
-        self.unexpected = unexpected
-        self.flaky = flaky
-        self.code = code
-        self.out = out
-        self.err = err
-        self.pid = pid
-
-
-class ResultSet(object):
-
-    def __init__(self):
-        self.results = []
-
-    def add(self, result):
-        self.results.append(result)
-
-
-TEST_SEPARATOR = '.'
-
-
-def make_full_results(metadata, seconds_since_epoch, all_test_names, results):
-    """Convert the typ results to the Chromium JSON test result format.
-
-    See http://www.chromium.org/developers/the-json-test-results-format
-    """
-
-    # We use OrderedDicts here so that the output is stable.
-    full_results = OrderedDict()
-    full_results['version'] = 3
-    full_results['interrupted'] = False
-    full_results['path_delimiter'] = TEST_SEPARATOR
-    full_results['seconds_since_epoch'] = seconds_since_epoch
-
-    for md in metadata:
-        key, val = md.split('=', 1)
-        full_results[key] = val
-
-    passing_tests = _passing_test_names(results)
-    failed_tests = failed_test_names(results)
-    skipped_tests = set(all_test_names) - passing_tests - failed_tests
-
-    full_results['num_failures_by_type'] = OrderedDict()
-    full_results['num_failures_by_type']['FAIL'] = len(failed_tests)
-    full_results['num_failures_by_type']['PASS'] = len(passing_tests)
-    full_results['num_failures_by_type']['SKIP'] = len(skipped_tests)
-
-    full_results['tests'] = OrderedDict()
-
-    for test_name in all_test_names:
-        value = _results_for_test(test_name, results)
-        if test_name in skipped_tests:
-            value['expected'] = 'SKIP'
-        else:
-            value['expected'] = 'PASS'
-            if value['actual'].endswith('FAIL'):
-                value['is_unexpected'] = True
-        _add_path_to_trie(full_results['tests'], test_name, value)
-
-    return full_results
-
-
-def make_upload_request(test_results_server, builder, master, testtype,
-                        full_results):
-    if test_results_server.startswith('http'):
-        url = '%s/testfile/upload' % test_results_server
-    else:
-        url = 'https://%s/testfile/upload' % test_results_server
-    attrs = [('builder', builder),
-             ('master', master),
-             ('testtype', testtype)]
-    content_type, data = _encode_multipart_form_data(attrs, full_results)
-    return url, content_type, data
-
-
-def exit_code_from_full_results(full_results):
-    return 1 if num_failures(full_results) else 0
-
-
-def num_failures(full_results):
-    return full_results['num_failures_by_type']['FAIL']
-
-
-def num_passes(full_results):
-    return full_results['num_failures_by_type']['PASS']
-
-
-def num_skips(full_results):
-    return full_results['num_failures_by_type']['SKIP']
-
-
-def failed_test_names(results):
-    names = set()
-    for r in results.results:
-        if r.actual == ResultType.Failure:
-            names.add(r.name)
-        elif ((r.actual == ResultType.Pass or r.actual == ResultType.Skip)
-              and r.name in names):
-            # This check indicates that a test failed, and then either passed
-            # or was skipped on a retry. It is somewhat counterintuitive
-            # that a test that failed and then skipped wouldn't be considered
-            # failed, but that's at least consistent with a test that is
-            # skipped every time.
-            names.remove(r.name)
-    return names
-
-
-def _passing_test_names(results):
-    return set(r.name for r in results.results if r.actual == ResultType.Pass)
-
-
-def _results_for_test(test_name, results):
-    value = OrderedDict()
-    actuals = []
-    times = []
-    for r in results.results:
-        if r.name == test_name:
-            if r.actual == ResultType.Failure:
-                actuals.append('FAIL')
-            elif r.actual == ResultType.Pass:
-                actuals.append('PASS')
-            elif r.actual == ResultType.Skip:
-                actuals.append('SKIP')
-
-            # The time a test takes is a floating point number of seconds;
-            # if we were to encode this unmodified, then when we converted it
-            # to JSON it might make the file significantly larger. Instead
-            # we truncate the file to ten-thousandths of a second, which is
-            # probably more than good enough for most tests.
-            times.append(round(r.took, 4))
-    if not actuals:  # pragma: untested
-        actuals.append('SKIP')
-    value['actual'] = ' '.join(actuals)
-    value['times'] = times
-    return value
-
-def _add_path_to_trie(trie, path, value):
-    if TEST_SEPARATOR not in path:
-        trie[path] = value
-        return
-    directory, rest = path.split(TEST_SEPARATOR, 1)
-    if directory not in trie:
-        trie[directory] = {}
-    _add_path_to_trie(trie[directory], rest, value)
-
-
-def _encode_multipart_form_data(attrs, test_results):
-    # Cloned from webkitpy/common/net/file_uploader.py
-    BOUNDARY = '-J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-'
-    CRLF = '\r\n'
-    lines = []
-
-    for key, value in attrs:
-        lines.append('--' + BOUNDARY)
-        lines.append('Content-Disposition: form-data; name="%s"' % key)
-        lines.append('')
-        lines.append(value)
-
-    lines.append('--' + BOUNDARY)
-    lines.append('Content-Disposition: form-data; name="file"; '
-                 'filename="full_results.json"')
-    lines.append('Content-Type: application/json')
-    lines.append('')
-    lines.append(json.dumps(test_results))
-
-    lines.append('--' + BOUNDARY + '--')
-    lines.append('')
-    body = CRLF.join(lines)
-    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
-    return content_type, body
diff --git a/third_party/typ/typ/pool.py b/third_party/typ/typ/pool.py
deleted file mode 100644
index 6200a8a..0000000
--- a/third_party/typ/typ/pool.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import copy
-import multiprocessing
-import pickle
-import traceback
-
-from typ.host import Host
-
-
-def make_pool(host, jobs, callback, context, pre_fn, post_fn):
-    _validate_args(context, pre_fn, post_fn)
-    if jobs > 1:
-        return _ProcessPool(host, jobs, callback, context, pre_fn, post_fn)
-    else:
-        return _AsyncPool(host, jobs, callback, context, pre_fn, post_fn)
-
-
-class _MessageType(object):
-    Request = 'Request'
-    Response = 'Response'
-    Close = 'Close'
-    Done = 'Done'
-    Error = 'Error'
-    Interrupt = 'Interrupt'
-
-    values = [Request, Response, Close, Done, Error, Interrupt]
-
-
-def _validate_args(context, pre_fn, post_fn):
-    try:
-        _ = pickle.dumps(context)
-    except Exception as e:
-        raise ValueError('context passed to make_pool is not picklable: %s'
-                         % str(e))
-    try:
-        _ = pickle.dumps(pre_fn)
-    except pickle.PickleError:
-        raise ValueError('pre_fn passed to make_pool is not picklable')
-    try:
-        _ = pickle.dumps(post_fn)
-    except pickle.PickleError:
-        raise ValueError('post_fn passed to make_pool is not picklable')
-
-
-class _ProcessPool(object):
-
-    def __init__(self, host, jobs, callback, context, pre_fn, post_fn):
-        self.host = host
-        self.jobs = jobs
-        self.requests = multiprocessing.Queue()
-        self.responses = multiprocessing.Queue()
-        self.workers = []
-        self.discarded_responses = []
-        self.closed = False
-        self.erred = False
-        for worker_num in range(1, jobs + 1):
-            w = multiprocessing.Process(target=_loop,
-                                        args=(self.requests, self.responses,
-                                              host.for_mp(), worker_num,
-                                              callback, context,
-                                              pre_fn, post_fn))
-            w.start()
-            self.workers.append(w)
-
-    def send(self, msg):
-        self.requests.put((_MessageType.Request, msg))
-
-    def get(self):
-        msg_type, resp = self.responses.get()
-        if msg_type == _MessageType.Error:
-            self._handle_error(resp)
-        elif msg_type == _MessageType.Interrupt:
-            raise KeyboardInterrupt
-        assert msg_type == _MessageType.Response
-        return resp
-
-    def close(self):
-        for _ in self.workers:
-            self.requests.put((_MessageType.Close, None))
-        self.closed = True
-
-    def join(self):
-        # TODO: one would think that we could close self.requests in close(),
-        # above, and close self.responses below, but if we do, we get
-        # weird tracebacks in the daemon threads multiprocessing starts up.
-        # Instead, we have to hack the innards of multiprocessing. It
-        # seems likely that there's a bug somewhere, either in this module or
-        # in multiprocessing.
-        # pylint: disable=protected-access
-        if self.host.is_python3:  # pragma: python3
-            multiprocessing.queues.is_exiting = lambda: True
-        else:  # pragma: python2
-            multiprocessing.util._exiting = True
-
-        if not self.closed:
-            # We must be aborting; terminate the workers rather than
-            # shutting down cleanly.
-            for w in self.workers:
-                w.terminate()
-                w.join()
-            return []
-
-        final_responses = []
-        error = None
-        interrupted = None
-        for w in self.workers:
-            while True:
-                msg_type, resp = self.responses.get()
-                if msg_type == _MessageType.Error:
-                    error = resp
-                    break
-                if msg_type == _MessageType.Interrupt:
-                    interrupted = True
-                    break
-                if msg_type == _MessageType.Done:
-                    final_responses.append(resp[1])
-                    break
-                self.discarded_responses.append(resp)
-
-        for w in self.workers:
-            w.join()
-
-        # TODO: See comment above at the beginning of the function for
-        # why this is commented out.
-        # self.responses.close()
-
-        if error:
-            self._handle_error(error)
-        if interrupted:
-            raise KeyboardInterrupt
-        return final_responses
-
-    def _handle_error(self, msg):
-        worker_num, tb = msg
-        self.erred = True
-        raise Exception("Error from worker %d (traceback follows):\n%s" %
-                        (worker_num, tb))
-
-
-# 'Too many arguments' pylint: disable=R0913
-
-def _loop(requests, responses, host, worker_num,
-          callback, context, pre_fn, post_fn, should_loop=True):
-    host = host or Host()
-    try:
-        context_after_pre = pre_fn(host, worker_num, context)
-        keep_looping = True
-        while keep_looping:
-            message_type, args = requests.get(block=True)
-            if message_type == _MessageType.Close:
-                responses.put((_MessageType.Done,
-                               (worker_num, post_fn(context_after_pre))))
-                break
-            assert message_type == _MessageType.Request
-            resp = callback(context_after_pre, args)
-            responses.put((_MessageType.Response, resp))
-            keep_looping = should_loop
-    except KeyboardInterrupt as e:
-        responses.put((_MessageType.Interrupt, (worker_num, str(e))))
-    except Exception as e:
-        responses.put((_MessageType.Error,
-                       (worker_num, traceback.format_exc(e))))
-
-
-class _AsyncPool(object):
-
-    def __init__(self, host, jobs, callback, context, pre_fn, post_fn):
-        self.host = host or Host()
-        self.jobs = jobs
-        self.callback = callback
-        self.context = copy.deepcopy(context)
-        self.msgs = []
-        self.closed = False
-        self.post_fn = post_fn
-        self.context_after_pre = pre_fn(self.host, 1, self.context)
-        self.final_context = None
-
-    def send(self, msg):
-        self.msgs.append(msg)
-
-    def get(self):
-        return self.callback(self.context_after_pre, self.msgs.pop(0))
-
-    def close(self):
-        self.closed = True
-        self.final_context = self.post_fn(self.context_after_pre)
-
-    def join(self):
-        if not self.closed:
-            self.close()
-        return [self.final_context]
diff --git a/third_party/typ/typ/printer.py b/third_party/typ/typ/printer.py
deleted file mode 100644
index 473537b..0000000
--- a/third_party/typ/typ/printer.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-class Printer(object):
-
-    def __init__(self, print_, should_overwrite, cols):
-        self.print_ = print_
-        self.should_overwrite = should_overwrite
-        self.cols = cols
-        self.last_line = ''
-
-    def flush(self):
-        if self.last_line:
-            self.print_('')
-            self.last_line = ''
-
-    def update(self, msg, elide=True):
-        msg_len = len(msg)
-        if elide and self.cols and msg_len > self.cols - 5:
-            new_len = int((self.cols - 5) / 2)
-            msg = msg[:new_len] + '...' + msg[-new_len:]
-        if self.should_overwrite and self.last_line:
-            self.print_('\r' + ' ' * len(self.last_line) + '\r', end='')
-        elif self.last_line:
-            self.print_('')
-        self.print_(msg, end='')
-        last_nl = msg.rfind('\n')
-        self.last_line = msg[last_nl + 1:]
diff --git a/third_party/typ/typ/runner.py b/third_party/typ/typ/runner.py
deleted file mode 100644
index 62d92c7f..0000000
--- a/third_party/typ/typ/runner.py
+++ /dev/null
@@ -1,993 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import fnmatch
-import importlib
-import inspect
-import json
-import os
-import pdb
-import sys
-import unittest
-import traceback
-
-from collections import OrderedDict
-
-# This ensures that absolute imports of typ modules will work when
-# running typ/runner.py as a script even if typ is not installed.
-# We need this entry in addition to the one in __main__.py to ensure
-# that typ/runner.py works when invoked via subprocess on windows in
-# _spawn_main().
-path_to_file = os.path.realpath(__file__)
-if path_to_file.endswith('.pyc'):  # pragma: no cover
-    path_to_file = path_to_file[:-1]
-dir_above_typ = os.path.dirname(os.path.dirname(path_to_file))
-if dir_above_typ not in sys.path:  # pragma: no cover
-    sys.path.append(dir_above_typ)
-
-
-from typ import json_results
-from typ.arg_parser import ArgumentParser
-from typ.host import Host
-from typ.pool import make_pool
-from typ.stats import Stats
-from typ.printer import Printer
-from typ.test_case import TestCase as TypTestCase
-from typ.version import VERSION
-
-
-Result = json_results.Result
-ResultSet = json_results.ResultSet
-ResultType = json_results.ResultType
-
-
-def main(argv=None, host=None, win_multiprocessing=None, **defaults):
-    host = host or Host()
-    runner = Runner(host=host)
-    if win_multiprocessing is not None:
-        runner.win_multiprocessing = win_multiprocessing
-    return runner.main(argv, **defaults)
-
-
-class TestInput(object):
-
-    def __init__(self, name, msg='', timeout=None, expected=None):
-        self.name = name
-        self.msg = msg
-        self.timeout = timeout
-        self.expected = expected
-
-
-class TestSet(object):
-
-    def __init__(self, parallel_tests=None, isolated_tests=None,
-                 tests_to_skip=None):
-
-        def promote(tests):
-            tests = tests or []
-            return [test if isinstance(test, TestInput) else TestInput(test)
-                    for test in tests]
-
-        self.parallel_tests = promote(parallel_tests)
-        self.isolated_tests = promote(isolated_tests)
-        self.tests_to_skip = promote(tests_to_skip)
-
-
-class WinMultiprocessing(object):
-    ignore = 'ignore'
-    importable = 'importable'
-    spawn = 'spawn'
-
-    values = [ignore, importable, spawn]
-
-
-class _AddTestsError(Exception):
-    pass
-
-
-class Runner(object):
-
-    def __init__(self, host=None):
-        self.args = None
-        self.classifier = None
-        self.cov = None
-        self.context = None
-        self.coverage_source = None
-        self.host = host or Host()
-        self.loader = unittest.loader.TestLoader()
-        self.printer = None
-        self.setup_fn = None
-        self.stats = None
-        self.teardown_fn = None
-        self.top_level_dir = None
-        self.top_level_dirs = []
-        self.win_multiprocessing = WinMultiprocessing.spawn
-        self.final_responses = []
-
-        # initialize self.args to the defaults.
-        parser = ArgumentParser(self.host)
-        self.parse_args(parser, [])
-
-    def main(self, argv=None, **defaults):
-        parser = ArgumentParser(self.host)
-        self.parse_args(parser, argv, **defaults)
-        if parser.exit_status is not None:
-            return parser.exit_status
-
-        try:
-            ret, _, _ = self.run()
-            return ret
-        except KeyboardInterrupt:
-            self.print_("interrupted, exiting", stream=self.host.stderr)
-            return 130
-
-    def parse_args(self, parser, argv, **defaults):
-        for attrname in defaults:
-            if not hasattr(self.args, attrname):
-                parser.error("Unknown default argument name '%s'" % attrname,
-                             bailout=False)
-                return
-        parser.set_defaults(**defaults)
-        self.args = parser.parse_args(args=argv)
-        if parser.exit_status is not None:
-            return
-
-    def print_(self, msg='', end='\n', stream=None):
-        self.host.print_(msg, end, stream=stream)
-
-    def run(self, test_set=None):
-
-        ret = 0
-        h = self.host
-
-        if self.args.version:
-            self.print_(VERSION)
-            return ret, None, None
-
-        should_spawn = self._check_win_multiprocessing()
-        if should_spawn:
-            return self._spawn(test_set)
-
-        ret = self._set_up_runner()
-        if ret:
-            return ret, None, None
-
-        find_start = h.time()
-        if self.cov:  # pragma: no cover
-            self.cov.erase()
-            self.cov.start()
-
-        full_results = None
-        result_set = ResultSet()
-
-        if not test_set:
-            ret, test_set = self.find_tests(self.args)
-        find_end = h.time()
-
-        if not ret:
-            ret, full_results = self._run_tests(result_set, test_set)
-
-        if self.cov:  # pragma: no cover
-            self.cov.stop()
-            self.cov.save()
-        test_end = h.time()
-
-        trace = self._trace_from_results(result_set)
-        if full_results:
-            self._summarize(full_results)
-            self._write(self.args.write_full_results_to, full_results)
-            upload_ret = self._upload(full_results)
-            if not ret:
-                ret = upload_ret
-            reporting_end = h.time()
-            self._add_trace_event(trace, 'run', find_start, reporting_end)
-            self._add_trace_event(trace, 'discovery', find_start, find_end)
-            self._add_trace_event(trace, 'testing', find_end, test_end)
-            self._add_trace_event(trace, 'reporting', test_end, reporting_end)
-            self._write(self.args.write_trace_to, trace)
-            self.report_coverage()
-        else:
-            upload_ret = 0
-
-        return ret, full_results, trace
-
-    def _check_win_multiprocessing(self):
-        wmp = self.win_multiprocessing
-
-        ignore, importable, spawn = WinMultiprocessing.values
-
-        if wmp not in WinMultiprocessing.values:
-            raise ValueError('illegal value %s for win_multiprocessing' %
-                             wmp)
-
-        h = self.host
-        if wmp == ignore and h.platform == 'win32':  # pragma: win32
-            raise ValueError('Cannot use WinMultiprocessing.ignore for '
-                             'win_multiprocessing when actually running '
-                             'on Windows.')
-
-        if wmp == ignore or self.args.jobs == 1:
-            return False
-
-        if wmp == importable:
-            if self._main_is_importable():
-                return False
-            raise ValueError('The __main__ module (%s) '  # pragma: no cover
-                             'may not be importable' %
-                             sys.modules['__main__'].__file__)
-
-        assert wmp == spawn
-        return True
-
-    def _main_is_importable(self):  # pragma: untested
-        path = sys.modules['__main__'].__file__
-        if not path:
-            return False
-        if path.endswith('.pyc'):
-            path = path[:-1]
-        if not path.endswith('.py'):
-            return False
-        if path.endswith('__main__.py'):
-            # main modules are not directly importable.
-            return False
-
-        path = self.host.realpath(path)
-        for d in sys.path:
-            if path.startswith(self.host.realpath(d)):
-                return True
-        return False  # pragma: no cover
-
-    def _spawn(self, test_set):
-        # TODO: Handle picklable hooks, rather than requiring them to be None.
-        assert self.classifier is None
-        assert self.context is None
-        assert self.setup_fn is None
-        assert self.teardown_fn is None
-        assert test_set is None
-        h = self.host
-
-        if self.args.write_trace_to:  # pragma: untested
-            should_delete_trace = False
-        else:
-            should_delete_trace = True
-            fp = h.mktempfile(delete=False)
-            fp.close()
-            self.args.write_trace_to = fp.name
-
-        if self.args.write_full_results_to:  # pragma: untested
-            should_delete_results = False
-        else:
-            should_delete_results = True
-            fp = h.mktempfile(delete=False)
-            fp.close()
-            self.args.write_full_results_to = fp.name
-
-        argv = ArgumentParser(h).argv_from_args(self.args)
-        ret = h.call_inline([h.python_interpreter, path_to_file] + argv)
-
-        trace = self._read_and_delete(self.args.write_trace_to,
-                                      should_delete_trace)
-        full_results = self._read_and_delete(self.args.write_full_results_to,
-                                             should_delete_results)
-        return ret, full_results, trace
-
-    def _set_up_runner(self):
-        h = self.host
-        args = self.args
-
-        self.stats = Stats(args.status_format, h.time, args.jobs)
-        self.printer = Printer(
-            self.print_, args.overwrite, args.terminal_width)
-
-        if self.args.top_level_dirs and self.args.top_level_dir:
-            self.print_(
-                'Cannot specify both --top-level-dir and --top-level-dirs',
-                stream=h.stderr)
-            return 1
-
-        self.top_level_dirs = args.top_level_dirs
-        if not self.top_level_dirs and args.top_level_dir:
-            self.top_level_dirs = [args.top_level_dir]
-
-        if not self.top_level_dirs:
-            for test in [t for t in args.tests if h.exists(t)]:
-                if h.isdir(test):
-                    top_dir = test
-                else:
-                    top_dir = h.dirname(test)
-                while h.exists(top_dir, '__init__.py'):
-                    top_dir = h.dirname(top_dir)
-                top_dir = h.realpath(top_dir)
-                if not top_dir in self.top_level_dirs:
-                    self.top_level_dirs.append(top_dir)
-        if not self.top_level_dirs:
-            top_dir = h.getcwd()
-            while h.exists(top_dir, '__init__.py'):
-                top_dir = h.dirname(top_dir)
-            top_dir = h.realpath(top_dir)
-            self.top_level_dirs.append(top_dir)
-
-        if not self.top_level_dir and self.top_level_dirs:
-            self.top_level_dir = self.top_level_dirs[0]
-
-        for path in self.top_level_dirs:
-            h.add_to_path(path)
-
-        for path in args.path:
-            h.add_to_path(path)
-
-        if args.coverage:  # pragma: no cover
-            try:
-                import coverage
-            except ImportError:
-                return 1
-
-            source = self.args.coverage_source
-            if not source:
-                source = self.top_level_dirs + self.args.path
-            self.coverage_source = source
-            self.cov = coverage.coverage(source=self.coverage_source,
-                                         data_suffix=True)
-            self.cov.erase()
-        return 0
-
-    def find_tests(self, args):
-        test_set = TestSet()
-
-        orig_skip = unittest.skip
-        orig_skip_if = unittest.skipIf
-        if args.all:
-            unittest.skip = lambda reason: lambda x: x
-            unittest.skipIf = lambda condition, reason: lambda x: x
-
-        try:
-            names = self._name_list_from_args(args)
-            classifier = self.classifier or _default_classifier(args)
-
-            for name in names:
-                try:
-                    self._add_tests_to_set(test_set, args.suffixes,
-                                           self.top_level_dirs, classifier,
-                                           name)
-                except (AttributeError, ImportError, SyntaxError) as e:
-                    ex_str = traceback.format_exc()
-                    self.print_('Failed to load "%s" in find_tests: %s' %
-                                (name, e))
-                    self.print_('  %s' %
-                                '\n  '.join(ex_str.splitlines()))
-                    self.print_(ex_str)
-                    return 1, None
-                except _AddTestsError as e:
-                    self.print_(str(e))
-                    return 1, None
-
-            # TODO: Add support for discovering setupProcess/teardownProcess?
-
-            shard_index = args.shard_index
-            total_shards = args.total_shards
-            assert total_shards >= 1
-            assert shard_index >= 0 and shard_index < total_shards, (
-                'shard_index (%d) must be >= 0 and < total_shards (%d)' %
-                (shard_index, total_shards))
-            test_set.parallel_tests = _sort_inputs(
-                test_set.parallel_tests)[shard_index::total_shards]
-            test_set.isolated_tests = _sort_inputs(
-                test_set.isolated_tests)[shard_index::total_shards]
-            test_set.tests_to_skip = _sort_inputs(
-                test_set.tests_to_skip)[shard_index::total_shards]
-            return 0, test_set
-        finally:
-            unittest.skip = orig_skip
-            unittest.skipIf = orig_skip_if
-
-    def _name_list_from_args(self, args):
-        if args.tests:
-            names = args.tests
-        elif args.file_list:
-            if args.file_list == '-':
-                s = self.host.stdin.read()
-            else:
-                s = self.host.read_text_file(args.file_list)
-            names = [line.strip() for line in s.splitlines()]
-        else:
-            names = self.top_level_dirs
-        return names
-
-    def _add_tests_to_set(self, test_set, suffixes, top_level_dirs, classifier,
-                          name):
-        h = self.host
-        loader = self.loader
-        add_tests = _test_adder(test_set, classifier)
-
-        found = set()
-        for d in top_level_dirs:
-            if h.isfile(name):
-                rpath = h.relpath(name, d)
-                if rpath.startswith('..'):
-                    continue
-                if rpath.endswith('.py'):
-                    rpath = rpath[:-3]
-                module = rpath.replace(h.sep, '.')
-                if module not in found:
-                    found.add(module)
-                    add_tests(loader.loadTestsFromName(module))
-            elif h.isdir(name):
-                rpath = h.relpath(name, d)
-                if rpath.startswith('..'):
-                    continue
-                for suffix in suffixes:
-                    if not name in found:
-                        found.add(name + '/' + suffix)
-                        add_tests(loader.discover(name, suffix, d))
-            else:
-                possible_dir = name.replace('.', h.sep)
-                if h.isdir(d, possible_dir):
-                    for suffix in suffixes:
-                        path = h.join(d, possible_dir)
-                        if not path in found:
-                            found.add(path + '/' + suffix)
-                            suite = loader.discover(path, suffix, d)
-                            add_tests(suite)
-                elif not name in found:
-                    found.add(name)
-                    add_tests(loader.loadTestsFromName(name))
-
-        # pylint: disable=no-member
-        if hasattr(loader, 'errors') and loader.errors:  # pragma: python3
-            # In Python3's version of unittest, loader failures get converted
-            # into failed test cases, rather than raising exceptions. However,
-            # the errors also get recorded so you can err out immediately.
-            raise ImportError(loader.errors)
-
-    def _run_tests(self, result_set, test_set):
-        h = self.host
-
-        all_tests = [ti.name for ti in
-                     _sort_inputs(test_set.parallel_tests +
-                                  test_set.isolated_tests +
-                                  test_set.tests_to_skip)]
-
-        if self.args.list_only:
-            self.print_('\n'.join(all_tests))
-            return 0, None
-
-        self._run_one_set(self.stats, result_set, test_set)
-
-        failed_tests = sorted(json_results.failed_test_names(result_set))
-        retry_limit = self.args.retry_limit
-
-        while retry_limit and failed_tests:
-            if retry_limit == self.args.retry_limit:
-                self.flush()
-                self.args.overwrite = False
-                self.printer.should_overwrite = False
-                self.args.verbose = min(self.args.verbose, 1)
-
-            self.print_('')
-            self.print_('Retrying failed tests (attempt #%d of %d)...' %
-                        (self.args.retry_limit - retry_limit + 1,
-                         self.args.retry_limit))
-            self.print_('')
-
-            stats = Stats(self.args.status_format, h.time, 1)
-            stats.total = len(failed_tests)
-            tests_to_retry = TestSet(isolated_tests=list(failed_tests))
-            retry_set = ResultSet()
-            self._run_one_set(stats, retry_set, tests_to_retry)
-            result_set.results.extend(retry_set.results)
-            failed_tests = json_results.failed_test_names(retry_set)
-            retry_limit -= 1
-
-        if retry_limit != self.args.retry_limit:
-            self.print_('')
-
-        full_results = json_results.make_full_results(self.args.metadata,
-                                                      int(h.time()),
-                                                      all_tests, result_set)
-
-        return (json_results.exit_code_from_full_results(full_results),
-                full_results)
-
-    def _run_one_set(self, stats, result_set, test_set):
-        stats.total = (len(test_set.parallel_tests) +
-                       len(test_set.isolated_tests) +
-                       len(test_set.tests_to_skip))
-        self._skip_tests(stats, result_set, test_set.tests_to_skip)
-        self._run_list(stats, result_set,
-                       test_set.parallel_tests, self.args.jobs)
-        self._run_list(stats, result_set,
-                       test_set.isolated_tests, 1)
-
-    def _skip_tests(self, stats, result_set, tests_to_skip):
-        for test_input in tests_to_skip:
-            last = self.host.time()
-            stats.started += 1
-            self._print_test_started(stats, test_input)
-            now = self.host.time()
-            result = Result(test_input.name, actual=ResultType.Skip,
-                            started=last, took=(now - last), worker=0,
-                            expected=[ResultType.Skip],
-                            out=test_input.msg)
-            result_set.add(result)
-            stats.finished += 1
-            self._print_test_finished(stats, result)
-
-    def _run_list(self, stats, result_set, test_inputs, jobs):
-        h = self.host
-        running_jobs = set()
-
-        jobs = min(len(test_inputs), jobs)
-        if not jobs:
-            return
-
-        child = _Child(self)
-        pool = make_pool(h, jobs, _run_one_test, child,
-                         _setup_process, _teardown_process)
-        try:
-            while test_inputs or running_jobs:
-                while test_inputs and (len(running_jobs) < self.args.jobs):
-                    test_input = test_inputs.pop(0)
-                    stats.started += 1
-                    pool.send(test_input)
-                    running_jobs.add(test_input.name)
-                    self._print_test_started(stats, test_input)
-
-                result = pool.get()
-                running_jobs.remove(result.name)
-                result_set.add(result)
-                stats.finished += 1
-                self._print_test_finished(stats, result)
-            pool.close()
-        finally:
-            self.final_responses.extend(pool.join())
-
-    def _print_test_started(self, stats, test_input):
-        if self.args.quiet:
-            # Print nothing when --quiet was passed.
-            return
-
-        # If -vvv was passed, print when the test is queued to be run.
-        # We don't actually know when the test picked up to run, because
-        # that is handled by the child process (where we can't easily
-        # print things). Otherwise, only print when the test is started
-        # if we know we can overwrite the line, so that we do not
-        # get multiple lines of output as noise (in -vvv, we actually want
-        # the noise).
-        test_start_msg = stats.format() + test_input.name
-        if self.args.verbose > 2:
-            self.update(test_start_msg + ' queued', elide=False)
-        if self.args.overwrite:
-            self.update(test_start_msg, elide=(not self.args.verbose))
-
-    def _print_test_finished(self, stats, result):
-        stats.add_time()
-
-        assert result.actual in [ResultType.Failure, ResultType.Skip,
-                                 ResultType.Pass]
-        if result.actual == ResultType.Failure:
-            result_str = ' failed'
-        elif result.actual == ResultType.Skip:
-            result_str = ' was skipped'
-        elif result.actual == ResultType.Pass:
-            result_str = ' passed'
-
-        if result.unexpected:
-            result_str += ' unexpectedly'
-        if self.args.timing:
-            timing_str = ' %.4fs' % result.took
-        else:
-            timing_str = ''
-        suffix = '%s%s' % (result_str, timing_str)
-        out = result.out
-        err = result.err
-        if result.code:
-            if out or err:
-                suffix += ':\n'
-            self.update(stats.format() + result.name + suffix, elide=False)
-            for l in out.splitlines():
-                self.print_('  %s' % l)
-            for l in err.splitlines():
-                self.print_('  %s' % l)
-        elif not self.args.quiet:
-            if self.args.verbose > 1 and (out or err):
-                suffix += ':\n'
-            self.update(stats.format() + result.name + suffix,
-                        elide=(not self.args.verbose))
-            if self.args.verbose > 1:
-                for l in out.splitlines():
-                    self.print_('  %s' % l)
-                for l in err.splitlines():
-                    self.print_('  %s' % l)
-            if self.args.verbose:
-                self.flush()
-
-    def update(self, msg, elide):
-        self.printer.update(msg, elide)
-
-    def flush(self):
-        self.printer.flush()
-
-    def _summarize(self, full_results):
-        num_passes = json_results.num_passes(full_results)
-        num_failures = json_results.num_failures(full_results)
-        num_skips = json_results.num_skips(full_results)
-
-        if self.args.quiet and num_failures == 0:
-            return
-
-        if self.args.timing:
-            timing_clause = ' in %.1fs' % (self.host.time() -
-                                           self.stats.started_time)
-        else:
-            timing_clause = ''
-        self.update('%d test%s passed%s, %d skipped, %d failure%s.' %
-                    (num_passes,
-                     '' if num_passes == 1 else 's',
-                     timing_clause,
-                     num_skips,
-                     num_failures,
-                     '' if num_failures == 1 else 's'), elide=False)
-        self.print_()
-
-    def _read_and_delete(self, path, delete):
-        h = self.host
-        obj = None
-        if h.exists(path):
-            contents = h.read_text_file(path)
-            if contents:
-                obj = json.loads(contents)
-            if delete:
-                h.remove(path)
-        return obj
-
-    def _write(self, path, obj):
-        if path:
-            self.host.write_text_file(path, json.dumps(obj, indent=2) + '\n')
-
-    def _upload(self, full_results):
-        h = self.host
-        if not self.args.test_results_server:
-            return 0
-
-        url, content_type, data = json_results.make_upload_request(
-            self.args.test_results_server, self.args.builder_name,
-            self.args.master_name, self.args.test_type,
-            full_results)
-
-        try:
-            h.fetch(url, data, {'Content-Type': content_type})
-            return 0
-        except Exception as e:
-            h.print_('Uploading the JSON results raised "%s"' % str(e))
-            return 1
-
-    def report_coverage(self):
-        if self.args.coverage:  # pragma: no cover
-            self.host.print_()
-            import coverage
-            cov = coverage.coverage(data_suffix=True)
-            cov.combine()
-            cov.report(show_missing=self.args.coverage_show_missing,
-                       omit=self.args.coverage_omit)
-            if self.args.coverage_annotate:
-                cov.annotate(omit=self.args.coverage_omit)
-
-    def _add_trace_event(self, trace, name, start, end):
-        event = {
-            'name': name,
-            'ts': int((start - self.stats.started_time) * 1000000),
-            'dur': int((end - start) * 1000000),
-            'ph': 'X',
-            'pid': self.host.getpid(),
-            'tid': 0,
-        }
-        trace['traceEvents'].append(event)
-
-    def _trace_from_results(self, result_set):
-        trace = OrderedDict()
-        trace['traceEvents'] = []
-        trace['otherData'] = {}
-        for m in self.args.metadata:
-            k, v = m.split('=')
-            trace['otherData'][k] = v
-
-        for result in result_set.results:
-            started = int((result.started - self.stats.started_time) * 1000000)
-            took = int(result.took * 1000000)
-            event = OrderedDict()
-            event['name'] = result.name
-            event['dur'] = took
-            event['ts'] = started
-            event['ph'] = 'X'  # "Complete" events
-            event['pid'] = result.pid
-            event['tid'] = result.worker
-
-            args = OrderedDict()
-            args['expected'] = sorted(str(r) for r in result.expected)
-            args['actual'] = str(result.actual)
-            args['out'] = result.out
-            args['err'] = result.err
-            args['code'] = result.code
-            args['unexpected'] = result.unexpected
-            args['flaky'] = result.flaky
-            event['args'] = args
-
-            trace['traceEvents'].append(event)
-        return trace
-
-
-def _matches(name, globs):
-    return any(fnmatch.fnmatch(name, glob) for glob in globs)
-
-
-def _default_classifier(args):
-    def default_classifier(test_set, test):
-        name = test.id()
-        if not args.all and _matches(name, args.skip):
-            test_set.tests_to_skip.append(TestInput(name,
-                                                    'skipped by request'))
-        elif _matches(name, args.isolate):
-            test_set.isolated_tests.append(TestInput(name))
-        else:
-            test_set.parallel_tests.append(TestInput(name))
-    return default_classifier
-
-
-def _test_adder(test_set, classifier):
-    def add_tests(obj):
-        if isinstance(obj, unittest.suite.TestSuite):
-            for el in obj:
-                add_tests(el)
-        elif (obj.id().startswith('unittest.loader.LoadTestsFailure') or
-              obj.id().startswith('unittest.loader.ModuleImportFailure')):
-            # Access to protected member pylint: disable=W0212
-            module_name = obj._testMethodName
-            try:
-                method = getattr(obj, obj._testMethodName)
-                method()
-            except Exception as e:
-                if 'LoadTests' in obj.id():
-                    raise _AddTestsError('%s.load_tests() failed: %s'
-                                         % (module_name, str(e)))
-                else:
-                    raise _AddTestsError(str(e))
-        else:
-            assert isinstance(obj, unittest.TestCase)
-            classifier(test_set, obj)
-    return add_tests
-
-
-class _Child(object):
-
-    def __init__(self, parent):
-        self.host = None
-        self.worker_num = None
-        self.all = parent.args.all
-        self.debugger = parent.args.debugger
-        self.coverage = parent.args.coverage and parent.args.jobs > 1
-        self.coverage_source = parent.coverage_source
-        self.dry_run = parent.args.dry_run
-        self.loader = parent.loader
-        self.passthrough = parent.args.passthrough
-        self.context = parent.context
-        self.setup_fn = parent.setup_fn
-        self.teardown_fn = parent.teardown_fn
-        self.context_after_setup = None
-        self.top_level_dir = parent.top_level_dir
-        self.top_level_dirs = parent.top_level_dirs
-        self.loaded_suites = {}
-        self.cov = None
-
-
-def _setup_process(host, worker_num, child):
-    child.host = host
-    child.worker_num = worker_num
-    # pylint: disable=protected-access
-
-    if child.coverage:  # pragma: no cover
-        import coverage
-        child.cov = coverage.coverage(source=child.coverage_source,
-                                      data_suffix=True)
-        child.cov._warn_no_data = False
-        child.cov.start()
-
-    if child.setup_fn:
-        child.context_after_setup = child.setup_fn(child, child.context)
-    else:
-        child.context_after_setup = child.context
-    return child
-
-
-def _teardown_process(child):
-    res = None
-    e = None
-    if child.teardown_fn:
-        try:
-            res = child.teardown_fn(child, child.context_after_setup)
-        except Exception as e:
-            pass
-
-    if child.cov:  # pragma: no cover
-        child.cov.stop()
-        child.cov.save()
-
-    return (child.worker_num, res, e)
-
-
-def _run_one_test(child, test_input):
-    h = child.host
-    pid = h.getpid()
-    test_name = test_input.name
-
-    start = h.time()
-
-    # It is important to capture the output before loading the test
-    # to ensure that
-    # 1) the loader doesn't logs something we don't captured
-    # 2) neither the loader nor the test case grab a reference to the
-    #    uncaptured stdout or stderr that later is used when the test is run.
-    # This comes up when using the FakeTestLoader and testing typ itself,
-    # but could come up when testing non-typ code as well.
-    h.capture_output(divert=not child.passthrough)
-
-    ex_str = ''
-    try:
-        orig_skip = unittest.skip
-        orig_skip_if = unittest.skipIf
-        if child.all:
-            unittest.skip = lambda reason: lambda x: x
-            unittest.skipIf = lambda condition, reason: lambda x: x
-
-        try:
-            suite = child.loader.loadTestsFromName(test_name)
-        except Exception as e:
-            ex_str = ('loadTestsFromName("%s") failed: %s\n%s\n' %
-                      (test_name, e, traceback.format_exc()))
-            try:
-                suite = _load_via_load_tests(child, test_name)
-                ex_str += ('\nload_via_load_tests(\"%s\") returned %d tests\n' %
-                           (test_name, len(list(suite))))
-            except Exception as e:  # pragma: untested
-                suite = []
-                ex_str += ('\nload_via_load_tests("%s") failed: %s\n%s\n' %
-                           (test_name, e, traceback.format_exc()))
-    finally:
-        unittest.skip = orig_skip
-        unittest.skipIf = orig_skip_if
-
-    tests = list(suite)
-    if len(tests) != 1:
-        err = 'Failed to load "%s" in run_one_test' % test_name
-        if ex_str:  # pragma: untested
-            err += '\n  ' + '\n  '.join(ex_str.splitlines())
-
-        h.restore_output()
-        return Result(test_name, ResultType.Failure, start, 0,
-                      child.worker_num, unexpected=True, code=1,
-                      err=err, pid=pid)
-
-    test_case = tests[0]
-    if isinstance(test_case, TypTestCase):
-        test_case.child = child
-        test_case.context = child.context_after_setup
-
-    test_result = unittest.TestResult()
-    out = ''
-    err = ''
-    try:
-        if child.dry_run:
-            pass
-        elif child.debugger:  # pragma: no cover
-            _run_under_debugger(h, test_case, suite, test_result)
-        else:
-            suite.run(test_result)
-    finally:
-        out, err = h.restore_output()
-
-    took = h.time() - start
-    return _result_from_test_result(test_result, test_name, start, took, out,
-                                    err, child.worker_num, pid)
-
-
-def _run_under_debugger(host, test_case, suite,
-                        test_result):  # pragma: no cover
-    # Access to protected member pylint: disable=W0212
-    test_func = getattr(test_case, test_case._testMethodName)
-    fname = inspect.getsourcefile(test_func)
-    lineno = inspect.getsourcelines(test_func)[1] + 1
-    dbg = pdb.Pdb(stdout=host.stdout.stream)
-    dbg.set_break(fname, lineno)
-    dbg.runcall(suite.run, test_result)
-
-
-def _result_from_test_result(test_result, test_name, start, took, out, err,
-                             worker_num, pid):
-    flaky = False
-    if test_result.failures:
-        expected = [ResultType.Pass]
-        actual = ResultType.Failure
-        code = 1
-        unexpected = True
-        err = err + test_result.failures[0][1]
-    elif test_result.errors:
-        expected = [ResultType.Pass]
-        actual = ResultType.Failure
-        code = 1
-        unexpected = True
-        err = err + test_result.errors[0][1]
-    elif test_result.skipped:
-        expected = [ResultType.Skip]
-        actual = ResultType.Skip
-        err = err + test_result.skipped[0][1]
-        code = 0
-        unexpected = False
-    elif test_result.expectedFailures:
-        expected = [ResultType.Failure]
-        actual = ResultType.Failure
-        code = 1
-        err = err + test_result.expectedFailures[0][1]
-        unexpected = False
-    elif test_result.unexpectedSuccesses:
-        expected = [ResultType.Failure]
-        actual = ResultType.Pass
-        code = 0
-        unexpected = True
-    else:
-        expected = [ResultType.Pass]
-        actual = ResultType.Pass
-        code = 0
-        unexpected = False
-
-    return Result(test_name, actual, start, took, worker_num,
-                  expected, unexpected, flaky, code, out, err, pid)
-
-
-def _load_via_load_tests(child, test_name):
-    # If we couldn't import a test directly, the test may be only loadable
-    # via unittest's load_tests protocol. See if we can find a load_tests
-    # entry point that will work for this test.
-    loader = child.loader
-    comps = test_name.split('.')
-    new_suite = unittest.TestSuite()
-
-    while comps:
-        name = '.'.join(comps)
-        module = None
-        suite = None
-        if name not in child.loaded_suites:
-            try:
-                module = importlib.import_module(name)
-            except ImportError:
-                pass
-            if module:
-                suite = loader.loadTestsFromModule(module)
-            child.loaded_suites[name] = suite
-        suite = child.loaded_suites[name]
-        if suite:
-            for test_case in suite:
-                assert isinstance(test_case, unittest.TestCase)
-                if test_case.id() == test_name:  # pragma: untested
-                    new_suite.addTest(test_case)
-                    break
-        comps.pop()
-    return new_suite
-
-
-def _sort_inputs(inps):
-    return sorted(inps, key=lambda inp: inp.name)
-
-
-if __name__ == '__main__':  # pragma: no cover
-    sys.modules['__main__'].__file__ = path_to_file
-    sys.exit(main(win_multiprocessing=WinMultiprocessing.importable))
diff --git a/third_party/typ/typ/stats.py b/third_party/typ/typ/stats.py
deleted file mode 100644
index 0cd408dc..0000000
--- a/third_party/typ/typ/stats.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-class Stats(object):
-
-    def __init__(self, status_format, time_fn, size):
-        self.fmt = status_format
-        self.finished = 0
-        self.started = 0
-        self.total = 0
-        self.started_time = time_fn()
-        self._times = []
-        self._size = size
-        self._time = time_fn
-        self._times.append(self.started_time)
-
-    def add_time(self):
-        if len(self._times) > self._size:
-            self._times.pop(0)
-        self._times.append(self._time())
-
-    def format(self):
-        # Too many statements pylint: disable=R0915
-        out = ''
-        p = 0
-        end = len(self.fmt)
-        while p < end:
-            c = self.fmt[p]
-            if c == '%' and p < end - 1:
-                cn = self.fmt[p + 1]
-                if cn == 'c':
-                    elapsed = self._times[-1] - self._times[0]
-                    if elapsed > 0:
-                        out += '%5.1f' % ((len(self._times) - 1) / elapsed)
-                    else:
-                        out += '-'
-                elif cn == 'e':
-                    now = self._time()
-                    assert now >= self.started_time
-                    out += '%-5.3f' % (now - self.started_time)
-                elif cn == 'f':
-                    out += str(self.finished)
-                elif cn == 'o':
-                    now = self._time()
-                    if now > self.started_time:
-                        out += '%5.1f' % (self.finished * 1.0 /
-                                          (now - self.started_time))
-                    else:
-                        out += '-'
-                elif cn == 'p':
-                    if self.total:
-                        out += '%5.1f' % (self.started * 100.0 / self.total)
-                    else:
-                        out += '-'
-                elif cn == 'r':
-                    out += str(self.started - self.finished)
-                elif cn == 's':
-                    out += str(self.started)
-                elif cn == 't':
-                    out += str(self.total)
-                elif cn == 'u':
-                    out += str(self.total - self.finished)
-                elif cn == '%':
-                    out += '%'
-                else:
-                    out += c + cn
-                p += 2
-            else:
-                out += c
-                p += 1
-        return out
diff --git a/third_party/typ/typ/test_case.py b/third_party/typ/typ/test_case.py
deleted file mode 100644
index d709a57..0000000
--- a/third_party/typ/typ/test_case.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import fnmatch
-import shlex
-import unittest
-
-
-def convert_newlines(msg):
-    """A routine that mimics Python's universal_newlines conversion."""
-    return msg.replace('\r\n', '\n').replace('\r', '\n')
-
-
-class TestCase(unittest.TestCase):
-    child = None
-    context = None
-    maxDiff = 80 * 66
-
-
-class MainTestCase(TestCase):
-    prog = None
-    files_to_ignore = []
-
-    def _write_files(self, host, files):
-        for path, contents in list(files.items()):
-            dirname = host.dirname(path)
-            if dirname:
-                host.maybe_mkdir(dirname)
-            host.write_text_file(path, contents)
-
-    def _read_files(self, host, tmpdir):
-        out_files = {}
-        for f in host.files_under(tmpdir):
-            if any(fnmatch.fnmatch(f, pat) for pat in self.files_to_ignore):
-                continue
-            key = f.replace(host.sep, '/')
-            out_files[key] = host.read_text_file(tmpdir, f)
-        return out_files
-
-    def assert_files(self, expected_files, actual_files, files_to_ignore=None):
-        files_to_ignore = files_to_ignore or []
-        for k, v in expected_files.items():
-            self.assertMultiLineEqual(expected_files[k], v)
-        interesting_files = set(actual_files.keys()).difference(
-            files_to_ignore)
-        self.assertEqual(interesting_files, set(expected_files.keys()))
-
-    def make_host(self):
-        # If we are ever called by unittest directly, and not through typ,
-        # this will probably fail.
-        assert self.child
-        return self.child.host
-
-    def call(self, host, argv, stdin, env):
-        return host.call(argv, stdin=stdin, env=env)
-
-    def check(self, cmd=None, stdin=None, env=None, aenv=None, files=None,
-              prog=None, cwd=None, host=None,
-              ret=None, out=None, rout=None, err=None, rerr=None,
-              exp_files=None,
-              files_to_ignore=None, universal_newlines=True):
-        # Too many arguments pylint: disable=R0913
-        prog = prog or self.prog or []
-        host = host or self.make_host()
-        argv = shlex.split(cmd) if isinstance(cmd, str) else cmd or []
-
-        tmpdir = None
-        orig_wd = host.getcwd()
-        try:
-            tmpdir = host.mkdtemp()
-            host.chdir(tmpdir)
-            if files:
-                self._write_files(host, files)
-            if cwd:
-                host.chdir(cwd)
-            if aenv:
-                env = host.env.copy()
-                env.update(aenv)
-
-            if self.child.debugger:  # pragma: no cover
-                host.print_('')
-                host.print_('cd %s' % tmpdir, stream=host.stdout.stream)
-                host.print_(' '.join(prog + argv), stream=host.stdout.stream)
-                host.print_('')
-                import pdb
-                dbg = pdb.Pdb(stdout=host.stdout.stream)
-                dbg.set_trace()
-
-            result = self.call(host, prog + argv, stdin=stdin, env=env)
-
-            actual_ret, actual_out, actual_err = result
-            actual_files = self._read_files(host, tmpdir)
-        finally:
-            host.chdir(orig_wd)
-            if tmpdir:
-                host.rmtree(tmpdir)
-
-        if universal_newlines:
-            actual_out = convert_newlines(actual_out)
-        if universal_newlines:
-            actual_err = convert_newlines(actual_err)
-
-        if ret is not None:
-            self.assertEqual(ret, actual_ret)
-        if out is not None:
-            self.assertMultiLineEqual(out, actual_out)
-        if rout is not None:
-            self.assertRegexpMatches(actual_out, rout)
-        if err is not None:
-            self.assertMultiLineEqual(err, actual_err)
-        if rerr is not None:
-            self.assertRegexpMatches(actual_err, rerr)
-        if exp_files:
-            self.assert_files(exp_files, actual_files, files_to_ignore)
-
-        return actual_ret, actual_out, actual_err, actual_files
diff --git a/third_party/typ/typ/tests/__init__.py b/third_party/typ/typ/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/third_party/typ/typ/tests/__init__.py
+++ /dev/null
diff --git a/third_party/typ/typ/tests/arg_parser_test.py b/third_party/typ/typ/tests/arg_parser_test.py
deleted file mode 100644
index 3d443f6..0000000
--- a/third_party/typ/typ/tests/arg_parser_test.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import optparse
-import unittest
-
-from typ import ArgumentParser
-
-
-class ArgumentParserTest(unittest.TestCase):
-
-    def test_optparse_options(self):
-        parser = optparse.OptionParser()
-        ArgumentParser.add_option_group(parser, 'foo',
-                                        discovery=True,
-                                        running=True,
-                                        reporting=True,
-                                        skip='[-d]')
-        options, _ = parser.parse_args(['-j', '1'])
-        self.assertEqual(options.jobs, 1)
-
-    def test_argv_from_args(self):
-
-        def check(argv, expected=None):
-            parser = ArgumentParser()
-            args = parser.parse_args(argv)
-            actual_argv = parser.argv_from_args(args)
-            expected = expected or argv
-            self.assertEqual(expected, actual_argv)
-
-        check(['--version'])
-        check(['--coverage', '--coverage-omit', 'foo'])
-        check(['--jobs', '3'])
-        check(['-vv'], ['--verbose', '--verbose'])
-
-    def test_argv_from_args_foreign_argument(self):
-        parser = ArgumentParser()
-        parser.add_argument('--some-foreign-argument', default=False,
-                            action='store_true')
-        args = parser.parse_args(['--some-foreign-argument', '--verbose'])
-        self.assertEqual(['--verbose'], ArgumentParser().argv_from_args(args))
-
-    def test_valid_shard_options(self):
-        parser = ArgumentParser()
-
-        parser.parse_args(['--total-shards', '1'])
-        self.assertEqual(parser.exit_status, None)
-
-        parser.parse_args(['--total-shards', '5', '--shard-index', '4'])
-        self.assertEqual(parser.exit_status, None)
-
-        parser.parse_args(['--total-shards', '5', '--shard-index', '0'])
-        self.assertEqual(parser.exit_status, None)
-
-
-    def test_invalid_shard_options(self):
-        parser = ArgumentParser()
-
-        parser.parse_args(['--total-shards', '0'])
-        self.assertEqual(parser.exit_status, 2)
-
-        parser.parse_args(['--total-shards', '-1'])
-        self.assertEqual(parser.exit_status, 2)
-
-        parser.parse_args(['--total-shards', '5', '--shard-index', '-1'])
-        self.assertEqual(parser.exit_status, 2)
-
-        parser.parse_args(['--total-shards', '5', '--shard-index', '5'])
-        self.assertEqual(parser.exit_status, 2)
-
-        parser.parse_args(['--total-shards', '5', '--shard-index', '6'])
-        self.assertEqual(parser.exit_status, 2)
diff --git a/third_party/typ/typ/tests/host_test.py b/third_party/typ/typ/tests/host_test.py
deleted file mode 100644
index 5100a2a2..0000000
--- a/third_party/typ/typ/tests/host_test.py
+++ /dev/null
@@ -1,216 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import logging
-import pickle
-import sys
-import unittest
-
-from typ.host import Host
-
-
-class TestHost(unittest.TestCase):
-
-    def host(self):
-        return Host()
-
-    def test_capture_output(self):
-        try:
-            logging.basicConfig()
-            h = self.host()
-            h.capture_output()
-            h.print_('on stdout')
-            h.print_('on stderr', stream=h.stderr)
-            logging.critical('critical log failure')
-            out, err = h.restore_output()
-            self.assertEqual(out, 'on stdout\n')
-            self.assertEqual(err, 'on stderr\ncritical log failure\n')
-        finally:
-            h.logger.handlers = []
-
-        # TODO: Add tests for divert=False or eliminate the flag?
-
-    def test_abspath_and_realpath(self):
-        h = self.host()
-        self.assertNotEqual(h.abspath(h.getcwd()), None)
-        self.assertNotEqual(h.realpath(h.getcwd()), None)
-
-    def test_chdir(self):
-        h = self.host()
-        orig_cwd = h.getcwd()
-        h.chdir('.')
-        self.assertEqual(orig_cwd, h.getcwd())
-        h.chdir('..')
-        self.assertNotEqual(orig_cwd, h.getcwd())
-
-    def test_files(self):
-        h = self.host()
-        orig_cwd = h.getcwd()
-        try:
-            now = h.time()
-
-            # TODO: MacOS does goofy things with temp dirs by default, so
-            # we can't compare for equality. Figure out how to get the normpath
-            # from mkdtemp
-            dirpath = h.mkdtemp(suffix='host_test')
-            self.assertTrue(h.isdir(dirpath))
-            h.chdir(dirpath)
-            self.assertIn(dirpath, h.getcwd())
-
-            h.maybe_mkdir('bar')
-            self.assertTrue(h.exists(dirpath, 'bar'))
-            self.assertTrue(h.isdir(dirpath, 'bar'))
-            self.assertFalse(h.isfile(dirpath, 'bar'))
-
-            bar_path = h.join(dirpath, 'bar')
-            self.assertEqual(dirpath, h.dirname(bar_path))
-
-            h.write_text_file('bar/foo.txt', 'foo')
-            self.assertTrue(h.exists('bar', 'foo.txt'))
-            self.assertEqual(h.read_text_file('bar/foo.txt'), 'foo')
-            self.assertTrue(h.exists(dirpath, 'bar', 'foo.txt'))
-            self.assertTrue(h.isfile(dirpath, 'bar', 'foo.txt'))
-            self.assertFalse(h.isdir(dirpath, 'bar', 'foo.txt'))
-
-            h.write_binary_file('binfile', b'bin contents')
-            self.assertEqual(h.read_binary_file('binfile'),
-                             b'bin contents')
-
-            self.assertEqual(sorted(h.files_under(dirpath)),
-                             ['bar' + h.sep + 'foo.txt', 'binfile'])
-
-            mtime = h.mtime(dirpath, 'bar', 'foo.txt')
-            self.assertGreaterEqual(now, mtime - 0.1)
-            h.remove(dirpath, 'bar', 'foo.txt')
-            self.assertFalse(h.exists(dirpath, 'bar', 'foo.txt'))
-            self.assertFalse(h.isfile(dirpath, 'bar', 'foo.txt'))
-
-            h.chdir(orig_cwd)
-            h.rmtree(dirpath)
-            self.assertFalse(h.exists(dirpath))
-            self.assertFalse(h.isdir(dirpath))
-        finally:
-            h.chdir(orig_cwd)
-
-    def test_terminal_width(self):
-        h = self.host()
-        self.assertGreaterEqual(h.terminal_width(), 0)
-
-    def test_for_mp_and_pickling(self):
-        h = self.host()
-        mp_host = h.for_mp()
-        s = pickle.dumps(mp_host)
-        pickle.loads(s)
-
-    def test_cpu_count(self):
-        h = self.host()
-        self.assertGreaterEqual(h.cpu_count(), 1)
-
-    def test_getenv(self):
-        h = self.host()
-        self.assertNotEqual(h.getenv('PATH', ''), None)
-
-    def test_getpid(self):
-        h = self.host()
-        self.assertNotEqual(h.getpid(), 0)
-
-    def test_basename(self):
-        h = self.host()
-        self.assertEqual(h.basename('foo.txt'), 'foo.txt')
-        self.assertEqual(h.basename('foo/bar.txt'), 'bar.txt')
-
-    def test_mktempfile(self, delete=False): # pylint: disable=unused-argument
-        h = self.host()
-        f = h.mktempfile()
-        f.close()
-        self.assertNotEqual(f.name, None)
-
-    def test_splitext(self):
-        h = self.host()
-        self.assertEqual(h.splitext('foo'), ('foo', ''))
-        self.assertEqual(h.splitext('foo.txt'), ('foo', '.txt'))
-        self.assertEqual(h.splitext('foo/bar'), ('foo/bar', ''))
-        self.assertEqual(h.splitext('foo/bar.txt'), ('foo/bar', '.txt'))
-
-    def test_print(self):
-        h = self.host()
-
-        class FakeStream(object):
-
-            def __init__(self):
-                self.contents = None
-                self.flush_called = False
-
-            def write(self, m):
-                self.contents = m
-
-            def flush(self):
-                self.flush_called = True
-
-        s = FakeStream()
-        h.print_('hello', stream=s)
-        self.assertEqual(s.contents, 'hello\n')
-        self.assertTrue(s.flush_called)
-
-        s = FakeStream()
-        h.stdout = s
-        h.print_('hello')
-        self.assertEqual(s.contents, 'hello\n')
-
-        s = FakeStream()
-        h.stdout = s
-        h.print_('hello', '')
-        self.assertEqual(s.contents, 'hello')
-
-    def test_call(self):
-        h = self.host()
-        ret, out, err = h.call(
-            [h.python_interpreter,
-             '-c', 'import sys; sys.stdout.write(sys.stdin.read())'],
-            stdin='foo', env={})
-        self.assertEqual(ret, 0)
-        self.assertEqual(out, 'foo')
-        self.assertEqual(err, '')
-
-        ret, out, err = h.call(
-            [h.python_interpreter,
-             '-c', 'import sys; sys.stderr.write("err\\n")'])
-        self.assertEqual(ret, 0)
-        self.assertEqual(out, '')
-        self.assertIn(err, ('err\n', 'err\r\n'))
-
-    def test_call_inline(self):
-        h = self.host()
-        h.stdout = None
-        h.stderr = None
-        ret = h.call_inline([h.python_interpreter,
-                             '-c', 'import sys; sys.exit(0)'])
-        self.assertEqual(ret, 0)
-
-    def test_add_to_path(self):
-        orig_sys_path = sys.path[:]
-        try:
-            h = self.host()
-            h.add_to_path(sys.path[-1])
-            self.assertEqual(sys.path, orig_sys_path)
-
-            dirpath = h.mkdtemp()
-            h.add_to_path(dirpath)
-            self.assertNotEqual(sys.path, orig_sys_path)
-        finally:
-            sys.path = orig_sys_path
-
-    def test_platform(self):
-        h = self.host()
-        self.assertNotEqual(h.platform, None)
diff --git a/third_party/typ/typ/tests/json_results_test.py b/third_party/typ/typ/tests/json_results_test.py
deleted file mode 100644
index 76446f9..0000000
--- a/third_party/typ/typ/tests/json_results_test.py
+++ /dev/null
@@ -1,113 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-
-from typ import json_results
-
-
-class TestMakeUploadRequest(unittest.TestCase):
-    maxDiff = 4096
-
-    def test_basic_upload(self):
-        results = json_results.ResultSet()
-        full_results = json_results.make_full_results([], 0, [], results)
-        url, content_type, data = json_results.make_upload_request(
-            'localhost', 'fake_builder_name', 'fake_master', 'fake_test_type',
-            full_results)
-
-        self.assertEqual(
-            content_type,
-            'multipart/form-data; '
-            'boundary=-J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-')
-
-        self.assertEqual(url, 'https://localhost/testfile/upload')
-        self.assertMultiLineEqual(
-            data,
-            ('---J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-\r\n'
-             'Content-Disposition: form-data; name="builder"\r\n'
-             '\r\n'
-             'fake_builder_name\r\n'
-             '---J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-\r\n'
-             'Content-Disposition: form-data; name="master"\r\n'
-             '\r\n'
-             'fake_master\r\n'
-             '---J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-\r\n'
-             'Content-Disposition: form-data; name="testtype"\r\n'
-             '\r\n'
-             'fake_test_type\r\n'
-             '---J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-\r\n'
-             'Content-Disposition: form-data; name="file"; '
-             'filename="full_results.json"\r\n'
-             'Content-Type: application/json\r\n'
-             '\r\n'
-             '{"version": 3, "interrupted": false, "path_delimiter": ".", '
-             '"seconds_since_epoch": 0, '
-             '"num_failures_by_type": {"FAIL": 0, "PASS": 0, "SKIP": 0}, '
-             '"tests": {}}\r\n'
-             '---J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y---\r\n'))
-
-
-class TestMakeFullResults(unittest.TestCase):
-    maxDiff = 2048
-
-    def test_basic(self):
-        test_names = ['foo_test.FooTest.test_fail',
-                      'foo_test.FooTest.test_pass',
-                      'foo_test.FooTest.test_skip']
-
-        result_set = json_results.ResultSet()
-        result_set.add(
-            json_results.Result('foo_test.FooTest.test_fail',
-                                json_results.ResultType.Failure, 0, 0.1, 0,
-                                unexpected=True))
-        result_set.add(json_results.Result('foo_test.FooTest.test_pass',
-                                           json_results.ResultType.Pass,
-                                           0, 0.2, 0))
-        result_set.add(json_results.Result('foo_test.FooTest.test_skip',
-                                           json_results.ResultType.Skip,
-                                           0, 0.3, 0, unexpected=False))
-
-        full_results = json_results.make_full_results(
-            ['foo=bar'], 0, test_names, result_set)
-        expected_full_results = {
-            'foo': 'bar',
-            'interrupted': False,
-            'num_failures_by_type': {
-                'FAIL': 1,
-                'PASS': 1,
-                'SKIP': 1},
-            'path_delimiter': '.',
-            'seconds_since_epoch': 0,
-            'tests': {
-                'foo_test': {
-                    'FooTest': {
-                        'test_fail': {
-                            'expected': 'PASS',
-                            'actual': 'FAIL',
-                            'times': [0.1],
-                            'is_unexpected': True,
-                        },
-                        'test_pass': {
-                            'expected': 'PASS',
-                            'actual': 'PASS',
-                            'times': [0.2],
-                        },
-                        'test_skip': {
-                            'expected': 'SKIP',
-                            'actual': 'SKIP',
-                            'times': [0.3],
-                        }}}},
-            'version': 3}
-        self.assertEqual(full_results, expected_full_results)
diff --git a/third_party/typ/typ/tests/main_test.py b/third_party/typ/typ/tests/main_test.py
deleted file mode 100644
index 2d90b16..0000000
--- a/third_party/typ/typ/tests/main_test.py
+++ /dev/null
@@ -1,829 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import io
-import json
-import os
-import sys
-import textwrap
-
-from typ import main
-from typ import test_case
-from typ import Host
-from typ import VERSION
-from typ.fakes import test_result_server_fake
-
-
-is_python3 = bool(sys.version_info.major == 3)
-
-if is_python3:  # pragma: python3
-    # pylint: disable=redefined-builtin,invalid-name
-    unicode = str
-
-d = textwrap.dedent
-
-
-PASS_TEST_PY = """
-import unittest
-class PassingTest(unittest.TestCase):
-    def test_pass(self):
-        pass
-"""
-
-
-PASS_TEST_FILES = {'pass_test.py': PASS_TEST_PY}
-
-
-FAIL_TEST_PY = """
-import unittest
-class FailingTest(unittest.TestCase):
-    def test_fail(self):
-        self.fail()
-"""
-
-
-FAIL_TEST_FILES = {'fail_test.py': FAIL_TEST_PY}
-
-
-OUTPUT_TEST_PY = """
-import sys
-import unittest
-
-class PassTest(unittest.TestCase):
-  def test_out(self):
-    sys.stdout.write("hello on stdout\\n")
-    sys.stdout.flush()
-
-  def test_err(self):
-    sys.stderr.write("hello on stderr\\n")
-
-class FailTest(unittest.TestCase):
- def test_out_err_fail(self):
-    sys.stdout.write("hello on stdout\\n")
-    sys.stdout.flush()
-    sys.stderr.write("hello on stderr\\n")
-    self.fail()
-"""
-
-
-OUTPUT_TEST_FILES = {'output_test.py': OUTPUT_TEST_PY}
-
-
-SF_TEST_PY = """
-import sys
-import unittest
-
-class SkipMethods(unittest.TestCase):
-    @unittest.skip('reason')
-    def test_reason(self):
-        self.fail()
-
-    @unittest.skipIf(True, 'reason')
-    def test_skip_if_true(self):
-        self.fail()
-
-    @unittest.skipIf(False, 'reason')
-    def test_skip_if_false(self):
-        self.fail()
-
-
-class SkipSetup(unittest.TestCase):
-    def setUp(self):
-        self.skipTest('setup failed')
-
-    def test_notrun(self):
-        self.fail()
-
-
-@unittest.skip('skip class')
-class SkipClass(unittest.TestCase):
-    def test_method(self):
-        self.fail()
-
-class SetupClass(unittest.TestCase):
-    @classmethod
-    def setUpClass(cls):
-        sys.stdout.write('in setupClass\\n')
-        sys.stdout.flush()
-        assert False, 'setupClass failed'
-
-    def test_method1(self):
-        pass
-
-    def test_method2(self):
-        pass
-
-class ExpectedFailures(unittest.TestCase):
-    @unittest.expectedFailure
-    def test_fail(self):
-        self.fail()
-
-    @unittest.expectedFailure
-    def test_pass(self):
-        pass
-"""
-
-
-SF_TEST_FILES = {'sf_test.py': SF_TEST_PY}
-
-
-LOAD_TEST_PY = """
-import unittest
-
-
-class BaseTest(unittest.TestCase):
-    pass
-
-
-def method_fail(self):
-    self.fail()
-
-
-def method_pass(self):
-    pass
-
-
-def load_tests(_, _2, _3):
-    setattr(BaseTest, "test_fail", method_fail)
-    setattr(BaseTest, "test_pass", method_pass)
-    suite = unittest.TestSuite()
-    suite.addTest(BaseTest("test_fail"))
-    suite.addTest(BaseTest("test_pass"))
-    return suite
-"""
-
-LOAD_TEST_FILES = {'load_test.py': LOAD_TEST_PY}
-
-
-
-path_to_main = os.path.join(
-    os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
-    'runner.py')
-
-
-class TestCli(test_case.MainTestCase):
-    prog = [sys.executable, path_to_main]
-    files_to_ignore = ['*.pyc']
-
-    def test_bad_arg(self):
-        self.check(['--bad-arg'], ret=2, out='',
-                   rerr='.*: error: unrecognized arguments: --bad-arg\n')
-        self.check(['-help'], ret=2, out='',
-                   rerr=(".*: error: argument -h/--help: "
-                         "ignored explicit argument 'elp'\n"))
-
-    def test_bad_metadata(self):
-        self.check(['--metadata', 'foo'], ret=2, err='',
-                   out='Error: malformed --metadata "foo"\n')
-
-    def test_basic(self):
-        self.check([], files=PASS_TEST_FILES,
-                   ret=0,
-                   out=('[1/1] pass_test.PassingTest.test_pass passed\n'
-                        '1 test passed, 0 skipped, 0 failures.\n'), err='')
-
-    def test_coverage(self):
-        try:
-            import coverage  # pylint: disable=W0612
-            files = {
-                'pass_test.py': PASS_TEST_PY,
-                'fail_test.py': FAIL_TEST_PY,
-            }
-            self.check(['-c', 'pass_test'], files=files, ret=0, err='',
-                       out=d("""\
-                             [1/1] pass_test.PassingTest.test_pass passed
-                             1 test passed, 0 skipped, 0 failures.
-
-                             Name           Stmts   Miss  Cover
-                             ----------------------------------
-                             fail_test.py       4      4     0%
-                             pass_test.py       4      0   100%
-                             ----------------------------------
-                             TOTAL              8      4    50%
-                             """))
-        except ImportError:  # pragma: no cover
-            # We can never cover this line, since running coverage means
-            # that import will succeed.
-            self.check(['-c'], files=PASS_TEST_FILES, ret=1,
-                       out='Error: coverage is not installed\n', err='')
-
-    def test_debugger(self):
-        if sys.version_info.major == 3:  # pragma: python3
-            return
-        else:  # pragma: python2
-            _, out, _, _ = self.check(['-d'], stdin='quit()\n',
-                                      files=PASS_TEST_FILES, ret=0, err='')
-            self.assertIn('(Pdb) ', out)
-
-    def test_dryrun(self):
-        self.check(['-n'], files=PASS_TEST_FILES, ret=0, err='',
-                   out=d("""\
-                         [1/1] pass_test.PassingTest.test_pass passed
-                         1 test passed, 0 skipped, 0 failures.
-                         """))
-
-    def test_error(self):
-        files = {'err_test.py': d("""\
-                                  import unittest
-                                  class ErrTest(unittest.TestCase):
-                                      def test_err(self):
-                                          foo = bar
-                                  """)}
-        _, out, _, _ = self.check([''], files=files, ret=1, err='')
-        self.assertIn('[1/1] err_test.ErrTest.test_err failed unexpectedly',
-                      out)
-        self.assertIn('0 tests passed, 0 skipped, 1 failure', out)
-
-    def test_fail(self):
-        _, out, _, _ = self.check([], files=FAIL_TEST_FILES, ret=1, err='')
-        self.assertIn('fail_test.FailingTest.test_fail failed unexpectedly',
-                      out)
-
-    def test_fail_then_pass(self):
-        files = {'fail_then_pass_test.py': d("""\
-            import unittest
-            count = 0
-            class FPTest(unittest.TestCase):
-                def test_count(self):
-                    global count
-                    count += 1
-                    if count == 1:
-                        self.fail()
-            """)}
-        _, out, _, files = self.check(['--retry-limit', '3',
-                                       '--write-full-results-to',
-                                       'full_results.json'],
-                                      files=files, ret=0, err='')
-        self.assertIn('Retrying failed tests (attempt #1 of 3)', out)
-        self.assertNotIn('Retrying failed tests (attempt #2 of 3)', out)
-        self.assertIn('1 test passed, 0 skipped, 0 failures.\n', out)
-        results = json.loads(files['full_results.json'])
-        self.assertEqual(
-            results['tests'][
-                'fail_then_pass_test']['FPTest']['test_count']['actual'],
-            'FAIL PASS')
-
-    def test_fail_then_skip(self):
-        files = {'fail_then_skip_test.py': d("""\
-            import unittest
-            count = 0
-            class FPTest(unittest.TestCase):
-                def test_count(self):
-                    global count
-                    count += 1
-                    if count == 1:
-                        self.fail()
-                    elif count == 2:
-                        self.skipTest('')
-            """)}
-        _, out, _, files = self.check(['--retry-limit', '3',
-                                       '--write-full-results-to',
-                                       'full_results.json'],
-                                      files=files, ret=0, err='')
-        self.assertIn('Retrying failed tests (attempt #1 of 3)', out)
-        self.assertNotIn('Retrying failed tests (attempt #2 of 3)', out)
-        self.assertIn('0 tests passed, 1 skipped, 0 failures.\n', out)
-        results = json.loads(files['full_results.json'])
-        self.assertEqual(
-            results['tests'][
-                'fail_then_skip_test']['FPTest']['test_count']['actual'],
-            'FAIL SKIP')
-
-    def test_failures_are_not_elided(self):
-        _, out, _, _ = self.check(['--terminal-width=20'],
-                                  files=FAIL_TEST_FILES, ret=1, err='')
-        self.assertIn('[1/1] fail_test.FailingTest.test_fail failed '
-                      'unexpectedly:\n', out)
-
-    def test_file_list(self):
-        files = PASS_TEST_FILES
-        self.check(['-f', '-'], files=files, stdin='pass_test\n', ret=0)
-        self.check(['-f', '-'], files=files, stdin='pass_test.PassingTest\n',
-                   ret=0)
-        self.check(['-f', '-'], files=files,
-                   stdin='pass_test.PassingTest.test_pass\n',
-                   ret=0)
-        files = {'pass_test.py': PASS_TEST_PY,
-                 'test_list.txt': 'pass_test.PassingTest.test_pass\n'}
-        self.check(['-f', 'test_list.txt'], files=files, ret=0)
-
-    def test_find(self):
-        files = PASS_TEST_FILES
-        self.check(['-l'], files=files, ret=0,
-                   out='pass_test.PassingTest.test_pass\n')
-        self.check(['-l', 'pass_test'], files=files, ret=0, err='',
-                   out='pass_test.PassingTest.test_pass\n')
-        self.check(['-l', 'pass_test.py'], files=files, ret=0, err='',
-                   out='pass_test.PassingTest.test_pass\n')
-        self.check(['-l', './pass_test.py'], files=files, ret=0, err='',
-                   out='pass_test.PassingTest.test_pass\n')
-        self.check(['-l', '.'], files=files, ret=0, err='',
-                   out='pass_test.PassingTest.test_pass\n')
-        self.check(['-l', 'pass_test.PassingTest.test_pass'], files=files,
-                   ret=0, err='',
-                   out='pass_test.PassingTest.test_pass\n')
-        self.check(['-l', '.'], files=files, ret=0, err='',
-                   out='pass_test.PassingTest.test_pass\n')
-
-    def test_find_from_subdirs(self):
-        files = {
-            'foo/__init__.py': '',
-            'foo/pass_test.py': PASS_TEST_PY,
-            'bar/__init__.py': '',
-            'bar/tmp': '',
-
-        }
-        self.check(['-l', '../foo/pass_test.py'], files=files, cwd='bar',
-                   ret=0, err='',
-                   out='foo.pass_test.PassingTest.test_pass\n')
-        self.check(['-l', 'foo'], files=files, cwd='bar',
-                   ret=0, err='',
-                   out='foo.pass_test.PassingTest.test_pass\n')
-        self.check(['-l', '--path', '../foo', 'pass_test'],
-                   files=files, cwd='bar', ret=0, err='',
-                   out='pass_test.PassingTest.test_pass\n')
-
-    def test_multiple_top_level_dirs(self):
-        files = {
-            'foo/bar/__init__.py': '',
-            'foo/bar/pass_test.py': PASS_TEST_PY,
-            'baz/quux/__init__.py': '',
-            'baz/quux/second_test.py': PASS_TEST_PY,
-        }
-        self.check(['-l', 'foo/bar', 'baz/quux'], files=files,
-                   ret=0, err='',
-                   out=(
-                       'bar.pass_test.PassingTest.test_pass\n'
-                       'quux.second_test.PassingTest.test_pass\n'
-                       ))
-        self.check(['-l', 'foo/bar/pass_test.py', 'baz/quux'], files=files,
-                   ret=0, err='',
-                   out=(
-                       'bar.pass_test.PassingTest.test_pass\n'
-                       'quux.second_test.PassingTest.test_pass\n'
-                       ))
-        self.check(['-l', '--top-level-dirs', 'foo', '--top-level-dirs', 'baz'],
-                   files=files,
-                   ret=0, err='',
-                   out=(
-                       'bar.pass_test.PassingTest.test_pass\n'
-                       'quux.second_test.PassingTest.test_pass\n'
-                       ))
-
-    def test_single_top_level_dir(self):
-        files = {
-            'foo/bar/__init__.py': '',
-            'foo/bar/pass_test.py': PASS_TEST_PY,
-            'baz/quux/__init__.py': '',
-            'baz/quux/second_test.py': PASS_TEST_PY,
-        }
-        self.check(['-l', '--top-level-dir', 'foo'],
-                   files=files,
-                   ret=0, err='',
-                   out=(
-                       'bar.pass_test.PassingTest.test_pass\n'
-                       ))
-
-    def test_can_not_have_both_top_level_flags(self):
-        files = {
-            'foo/bar/__init__.py': '',
-            'foo/bar/pass_test.py': PASS_TEST_PY,
-            'baz/quux/__init__.py': '',
-            'baz/quux/second_test.py': PASS_TEST_PY,
-        }
-        self.check(
-            ['-l', '--top-level-dir', 'foo', '--top-level-dirs', 'bar'],
-            files=files,
-            ret=1, out='',
-            err='Cannot specify both --top-level-dir and --top-level-dirs\n')
-
-    def test_help(self):
-        self.check(['--help'], ret=0, rout='.*', err='')
-
-    def test_import_failure_missing_file(self):
-        _, out, _, _ = self.check(['-l', 'foo'], ret=1, err='')
-        self.assertIn('Failed to load "foo" in find_tests', out)
-        self.assertIn('No module named foo', out)
-
-    def test_import_failure_missing_package(self):
-        files = {'foo.py': d("""\
-                             import unittest
-                             import package_that_does_not_exist
-
-                             class ImportFailureTest(unittest.TestCase):
-                                def test_case(self):
-                                    pass
-                             """)}
-        _, out, _, _ = self.check(['-l', 'foo.py'], files=files, ret=1, err='')
-        self.assertIn('Failed to load "foo.py" in find_tests', out)
-        self.assertIn('No module named package_that_does_not_exist', out)
-
-    def test_import_failure_no_tests(self):
-        files = {'foo.py': 'import unittest'}
-        self.check(['-l', 'foo'], files=files, ret=0, err='',
-                   out='\n')
-
-    def test_import_failure_syntax_error(self):
-        files = {'syn_test.py': d("""\
-                             import unittest
-
-                             class SyntaxErrorTest(unittest.TestCase):
-                                 def test_syntax_error_in_test(self):
-                                     syntax error
-                             """)}
-        _, out, _, _ = self.check([], files=files, ret=1, err='')
-        self.assertIn('Failed to import test module: syn_test', out)
-        self.assertIn('SyntaxError: invalid syntax', out)
-
-    def test_interrupt(self):
-        files = {'interrupt_test.py': d("""\
-                                        import unittest
-                                        class Foo(unittest.TestCase):
-                                           def test_interrupt(self):
-                                               raise KeyboardInterrupt()
-                                        """)}
-        self.check(['-j', '1'], files=files, ret=130, out='',
-                   err='interrupted, exiting\n')
-
-    def test_isolate(self):
-        self.check(['--isolate', '*test_pass*'], files=PASS_TEST_FILES, ret=0,
-                   out=('[1/1] pass_test.PassingTest.test_pass passed\n'
-                        '1 test passed, 0 skipped, 0 failures.\n'), err='')
-
-    def test_load_tests_failure(self):
-        files = {'foo_test.py': d("""\
-                                  import unittest
-
-                                  def load_tests(_, _2, _3):
-                                      raise ValueError('this should fail')
-                                  """)}
-        _, out, _, _ = self.check([], files=files, ret=1, err='')
-        self.assertIn('this should fail', out)
-
-    def test_load_tests_single_worker(self):
-        files = LOAD_TEST_FILES
-        _, out, _, _ = self.check(['-j', '1', '-v'], files=files, ret=1,
-                                  err='')
-        self.assertIn('[1/2] load_test.BaseTest.test_fail failed', out)
-        self.assertIn('[2/2] load_test.BaseTest.test_pass passed', out)
-        self.assertIn('1 test passed, 0 skipped, 1 failure.\n', out)
-
-    def test_load_tests_multiple_workers(self):
-        _, out, _, _ = self.check([], files=LOAD_TEST_FILES, ret=1, err='')
-
-        # The output for this test is nondeterministic since we may run
-        # two tests in parallel. So, we just test that some of the substrings
-        # we care about are present.
-        self.assertIn('test_pass passed', out)
-        self.assertIn('test_fail failed', out)
-        self.assertIn('1 test passed, 0 skipped, 1 failure.\n', out)
-
-    def test_missing_builder_name(self):
-        self.check(['--test-results-server', 'localhost'], ret=2,
-                   out=('Error: --builder-name must be specified '
-                        'along with --test-result-server\n'
-                        'Error: --master-name must be specified '
-                        'along with --test-result-server\n'
-                        'Error: --test-type must be specified '
-                        'along with --test-result-server\n'), err='')
-
-    def test_ninja_status_env(self):
-        self.check(['-v', 'output_test.PassTest.test_out'],
-                   files=OUTPUT_TEST_FILES, aenv={'NINJA_STATUS': 'ns: '},
-                   out=d("""\
-                         ns: output_test.PassTest.test_out passed
-                         1 test passed, 0 skipped, 0 failures.
-                         """), err='')
-
-    def test_output_for_failures(self):
-        _, out, _, _ = self.check(['output_test.FailTest'],
-                                  files=OUTPUT_TEST_FILES,
-                                  ret=1, err='')
-        self.assertIn('[1/1] output_test.FailTest.test_out_err_fail '
-                      'failed unexpectedly:\n'
-                      '  hello on stdout\n'
-                      '  hello on stderr\n', out)
-
-    def test_quiet(self):
-        self.check(['-q'], files=PASS_TEST_FILES, ret=0, err='', out='')
-
-    def test_retry_limit(self):
-        _, out, _, _ = self.check(['--retry-limit', '2'],
-                                  files=FAIL_TEST_FILES, ret=1, err='')
-        self.assertIn('Retrying failed tests', out)
-        lines = out.splitlines()
-        self.assertEqual(len([l for l in lines
-                              if 'test_fail failed unexpectedly:' in l]),
-                         3)
-
-    def test_skip(self):
-        _, out, _, _ = self.check(['--skip', '*test_fail*'],
-                                  files=FAIL_TEST_FILES, ret=0)
-        self.assertIn('0 tests passed, 1 skipped, 0 failures.', out)
-
-        files = {'fail_test.py': FAIL_TEST_PY,
-                 'pass_test.py': PASS_TEST_PY}
-        self.check(['-j', '1', '--skip', '*test_fail*'], files=files, ret=0,
-                   out=('[1/2] fail_test.FailingTest.test_fail was skipped\n'
-                        '[2/2] pass_test.PassingTest.test_pass passed\n'
-                        '1 test passed, 1 skipped, 0 failures.\n'), err='')
-
-        # This tests that we print test_started updates for skipped tests
-        # properly. It also tests how overwriting works.
-        _, out, _, _ = self.check(['-j', '1', '--overwrite', '--skip',
-                                   '*test_fail*'], files=files, ret=0,
-                                  err='', universal_newlines=False)
-
-        # We test this string separately and call out.strip() to
-        # avoid the trailing \r\n we get on windows, while keeping
-        # the \r's elsewhere in the string.
-        self.assertMultiLineEqual(
-            out.strip(),
-            ('[0/2] fail_test.FailingTest.test_fail\r'
-             '                                     \r'
-             '[1/2] fail_test.FailingTest.test_fail was skipped\r'
-             '                                                 \r'
-             '[1/2] pass_test.PassingTest.test_pass\r'
-             '                                     \r'
-             '[2/2] pass_test.PassingTest.test_pass passed\r'
-             '                                            \r'
-             '1 test passed, 1 skipped, 0 failures.'))
-
-    def test_skips_and_failures(self):
-        _, out, _, _ = self.check(['-j', '1', '-v', '-v'], files=SF_TEST_FILES,
-                                  ret=1, err='')
-
-        # We do a bunch of assertIn()'s to work around the non-portable
-        # tracebacks.
-        self.assertIn(('[1/9] sf_test.ExpectedFailures.test_fail failed:\n'
-                       '  Traceback '), out)
-        self.assertIn(('[2/9] sf_test.ExpectedFailures.test_pass '
-                       'passed unexpectedly'), out)
-        self.assertIn(('[3/9] sf_test.SetupClass.test_method1 '
-                       'failed unexpectedly:\n'
-                       '  in setupClass\n'), out)
-        self.assertIn(('[4/9] sf_test.SetupClass.test_method2 '
-                       'failed unexpectedly:\n'
-                       '  in setupClass\n'), out)
-        self.assertIn(('[5/9] sf_test.SkipClass.test_method was skipped:\n'
-                       '  skip class\n'), out)
-        self.assertIn(('[6/9] sf_test.SkipMethods.test_reason was skipped:\n'
-                       '  reason\n'), out)
-        self.assertIn(('[7/9] sf_test.SkipMethods.test_skip_if_false '
-                       'failed unexpectedly:\n'
-                       '  Traceback'), out)
-        self.assertIn(('[8/9] sf_test.SkipMethods.test_skip_if_true '
-                       'was skipped:\n'
-                       '  reason\n'
-                       '[9/9] sf_test.SkipSetup.test_notrun was skipped:\n'
-                       '  setup failed\n'
-                       '1 test passed, 4 skipped, 4 failures.\n'), out)
-
-    def test_skip_and_all(self):
-        # --all should override --skip
-        _, out, _, _ = self.check(['--skip', '*test_pass'],
-                                  files=PASS_TEST_FILES, ret=0, err='')
-        self.assertIn('0 tests passed, 1 skipped, 0 failures.', out)
-
-        _, out, _, _ = self.check(['--all', '--skip', '*test_pass'],
-                                  files=PASS_TEST_FILES, ret=0, err='')
-        self.assertIn('1 test passed, 0 skipped, 0 failures.', out)
-
-    def test_skip_decorators_and_all(self):
-        _, out, _, _ = self.check(['--all', '-j', '1', '-v', '-v'],
-                                  files=SF_TEST_FILES, ret=1, err='')
-        self.assertIn('sf_test.SkipClass.test_method failed', out)
-        self.assertIn('sf_test.SkipMethods.test_reason failed', out)
-        self.assertIn('sf_test.SkipMethods.test_skip_if_true failed', out)
-        self.assertIn('sf_test.SkipMethods.test_skip_if_false failed', out)
-
-        # --all does not override explicit calls to skipTest(), only
-        # the decorators.
-        self.assertIn('sf_test.SkipSetup.test_notrun was skipped', out)
-
-    def test_sharding(self):
-
-        def run(shard_index, total_shards, tests):
-            files = {'shard_test.py': textwrap.dedent(
-                """\
-                import unittest
-                class ShardTest(unittest.TestCase):
-                    def test_01(self):
-                        pass
-
-                    def test_02(self):
-                        pass
-
-                    def test_03(self):
-                        pass
-
-                    def test_04(self):
-                        pass
-
-                    def test_05(self):
-                        pass
-                """)}
-            _, out, _, _ = self.check(
-                ['--shard-index', str(shard_index),
-                 '--total-shards', str(total_shards),
-                 '--jobs', '1'],
-                files=files)
-
-            exp_out = ''
-            total_tests = len(tests)
-            for i, test in enumerate(tests):
-                exp_out += ('[%d/%d] shard_test.ShardTest.test_%s passed\n' %
-                            (i + 1, total_tests, test))
-            exp_out += '%d test%s passed, 0 skipped, 0 failures.\n' % (
-                total_tests, "" if total_tests == 1 else "s")
-            self.assertEqual(out, exp_out)
-
-        run(0, 1, ['01', '02', '03', '04', '05'])
-        run(0, 2, ['01', '03', '05'])
-        run(1, 2, ['02', '04'])
-        run(0, 6, ['01'])
-
-    def test_subdir(self):
-        files = {
-            'foo/__init__.py': '',
-            'foo/bar/__init__.py': '',
-            'foo/bar/pass_test.py': PASS_TEST_PY
-        }
-        self.check(['foo/bar'], files=files, ret=0, err='',
-                   out=d("""\
-                         [1/1] foo.bar.pass_test.PassingTest.test_pass passed
-                         1 test passed, 0 skipped, 0 failures.
-                         """))
-
-    def test_timing(self):
-        self.check(['-t'], files=PASS_TEST_FILES, ret=0, err='',
-                   rout=(r'\[1/1\] pass_test.PassingTest.test_pass passed '
-                         r'\d+.\d+s\n'
-                         r'1 test passed in \d+.\d+s, 0 skipped, 0 failures.'))
-
-    def test_test_results_server(self):
-        server = test_result_server_fake.start()
-        self.assertNotEqual(server, None, 'could not start fake server')
-
-        try:
-            self.check(['--test-results-server',
-                        'http://%s:%d' % server.server_address,
-                        '--master-name', 'fake_master',
-                        '--builder-name', 'fake_builder',
-                        '--test-type', 'typ_tests',
-                        '--metadata', 'foo=bar'],
-                       files=PASS_TEST_FILES, ret=0, err='',
-                       out=('[1/1] pass_test.PassingTest.test_pass passed\n'
-                            '1 test passed, 0 skipped, 0 failures.\n'))
-
-        finally:
-            posts = server.stop()
-
-        self.assertEqual(len(posts), 1)
-        payload = posts[0][2].decode('utf8')
-        self.assertIn('"test_pass": {"actual": "PASS"',
-                      payload)
-        self.assertTrue(payload.endswith('--\r\n'))
-        self.assertNotEqual(server.log.getvalue(), '')
-
-    def test_test_results_server_error(self):
-        server = test_result_server_fake.start(code=500)
-        self.assertNotEqual(server, None, 'could not start fake server')
-
-        try:
-            self.check(['--test-results-server',
-                        'http://%s:%d' % server.server_address,
-                        '--master-name', 'fake_master',
-                        '--builder-name', 'fake_builder',
-                        '--test-type', 'typ_tests',
-                        '--metadata', 'foo=bar'],
-                       files=PASS_TEST_FILES, ret=1, err='',
-                       out=('[1/1] pass_test.PassingTest.test_pass passed\n'
-                            '1 test passed, 0 skipped, 0 failures.\n'
-                            'Uploading the JSON results raised '
-                            '"HTTP Error 500: Internal Server Error"\n'))
-
-        finally:
-            _ = server.stop()
-
-    def test_test_results_server_not_running(self):
-        self.check(['--test-results-server', 'http://localhost:99999',
-                    '--master-name', 'fake_master',
-                    '--builder-name', 'fake_builder',
-                    '--test-type', 'typ_tests',
-                    '--metadata', 'foo=bar'],
-                   files=PASS_TEST_FILES, ret=1, err='',
-                   rout=(r'\[1/1\] pass_test.PassingTest.test_pass passed\n'
-                         '1 test passed, 0 skipped, 0 failures.\n'
-                         'Uploading the JSON results raised .*\n'))
-
-    def test_verbose_2(self):
-        self.check(['-vv', '-j', '1', 'output_test.PassTest'],
-                   files=OUTPUT_TEST_FILES, ret=0,
-                   out=d("""\
-                         [1/2] output_test.PassTest.test_err passed:
-                           hello on stderr
-                         [2/2] output_test.PassTest.test_out passed:
-                           hello on stdout
-                         2 tests passed, 0 skipped, 0 failures.
-                         """), err='')
-
-    def test_verbose_3(self):
-        self.check(['-vvv', '-j', '1', 'output_test.PassTest'],
-                   files=OUTPUT_TEST_FILES, ret=0,
-                   out=d("""\
-                         [0/2] output_test.PassTest.test_err queued
-                         [1/2] output_test.PassTest.test_err passed:
-                           hello on stderr
-                         [1/2] output_test.PassTest.test_out queued
-                         [2/2] output_test.PassTest.test_out passed:
-                           hello on stdout
-                         2 tests passed, 0 skipped, 0 failures.
-                         """), err='')
-
-    def test_version(self):
-        self.check('--version', ret=0, out=(VERSION + '\n'))
-
-    def test_write_full_results_to(self):
-        _, _, _, files = self.check(['--write-full-results-to',
-                                     'results.json'], files=PASS_TEST_FILES)
-        self.assertIn('results.json', files)
-        results = json.loads(files['results.json'])
-        self.assertEqual(results['interrupted'], False)
-        self.assertEqual(results['path_delimiter'], '.')
-
-        # The time it takes to run the test varies, so we test that
-        # we got a single entry greater than zero, but then delete it from
-        # the result so we can do an exact match on the rest of the trie.
-        result = results['tests']['pass_test']['PassingTest']['test_pass']
-        self.assertEqual(len(result['times']), 1)
-        self.assertGreater(result['times'][0], 0)
-        result.pop('times')
-        self.assertEqual(results['tests'],
-                         {u'pass_test': {
-                             u'PassingTest': {
-                                 u'test_pass': {
-                                     u'actual': u'PASS',
-                                     u'expected': u'PASS',
-                                 }
-                             }
-                         }})
-
-    def test_write_trace_to(self):
-        _, _, _, files = self.check(['--write-trace-to', 'trace.json'],
-                                    files=PASS_TEST_FILES)
-        self.assertIn('trace.json', files)
-        trace_obj = json.loads(files['trace.json'])
-        self.assertEqual(trace_obj['otherData'], {})
-        self.assertEqual(len(trace_obj['traceEvents']), 5)
-        event = trace_obj['traceEvents'][0]
-        self.assertEqual(event['name'], 'pass_test.PassingTest.test_pass')
-        self.assertEqual(event['ph'], 'X')
-        self.assertEqual(event['tid'], 1)
-        self.assertEqual(event['args']['expected'], ['Pass'])
-        self.assertEqual(event['args']['actual'], 'Pass')
-
-
-class TestMain(TestCli):
-    prog = []
-
-    def make_host(self):
-        return Host()
-
-    def call(self, host, argv, stdin, env):
-        stdin = unicode(stdin)
-        host.stdin = io.StringIO(stdin)
-        if env:
-            host.getenv = env.get
-        host.capture_output()
-        orig_sys_path = sys.path[:]
-        orig_sys_modules = list(sys.modules.keys())
-
-        try:
-            ret = main(argv + ['-j', '1'], host)
-        finally:
-            out, err = host.restore_output()
-            modules_to_unload = []
-            for k in sys.modules:
-                if k not in orig_sys_modules:
-                    modules_to_unload.append(k)
-            for k in modules_to_unload:
-                del sys.modules[k]
-            sys.path = orig_sys_path
-
-        return ret, out, err
-
-    def test_debugger(self):
-        # TODO: this test seems to hang under coverage.
-        pass
diff --git a/third_party/typ/typ/tests/pool_test.py b/third_party/typ/typ/tests/pool_test.py
deleted file mode 100644
index 319c3961..0000000
--- a/third_party/typ/typ/tests/pool_test.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import sys
-import unittest
-
-from typ import test_case
-from typ.host import Host
-from typ.pool import make_pool, _MessageType, _ProcessPool, _loop
-
-
-def _pre(host, worker_num, context):  # pylint: disable=W0613
-    context['pre'] = True
-    return context
-
-
-def _post(context):
-    context['post'] = True
-    return context
-
-
-def _echo(context, msg):
-    return '%s/%s/%s' % (context['pre'], context['post'], msg)
-
-
-def _error(context, msg):  # pylint: disable=W0613
-    raise Exception('_error() raised Exception')
-
-
-def _interrupt(context, msg):  # pylint: disable=W0613
-    raise KeyboardInterrupt()
-
-
-def _stub(*args):  # pylint: disable=W0613
-    return None
-
-
-class TestPool(test_case.TestCase):
-
-    def run_basic_test(self, jobs):
-        host = Host()
-        context = {'pre': False, 'post': False}
-        pool = make_pool(host, jobs, _echo, context, _pre, _post)
-        pool.send('hello')
-        pool.send('world')
-        msg1 = pool.get()
-        msg2 = pool.get()
-        pool.close()
-        final_contexts = pool.join()
-        self.assertEqual(set([msg1, msg2]),
-                         set(['True/False/hello',
-                              'True/False/world']))
-        expected_context = {'pre': True, 'post': True}
-        expected_final_contexts = [expected_context for _ in range(jobs)]
-        self.assertEqual(final_contexts, expected_final_contexts)
-
-    def run_through_loop(self, callback=None, pool=None):
-        callback = callback or _stub
-        if pool:
-            host = pool.host
-        else:
-            host = Host()
-            pool = _ProcessPool(host, 0, _stub, None, _stub, _stub)
-            pool.send('hello')
-
-        worker_num = 1
-        _loop(pool.requests, pool.responses, host, worker_num, callback,
-              None, _stub, _stub, should_loop=False)
-        return pool
-
-    def test_async_close(self):
-        host = Host()
-        pool = make_pool(host, 1, _echo, None, _stub, _stub)
-        pool.join()
-
-    def test_basic_one_job(self):
-        self.run_basic_test(1)
-
-    def test_basic_two_jobs(self):
-        self.run_basic_test(2)
-
-    def test_join_discards_messages(self):
-        host = Host()
-        context = {'pre': False, 'post': False}
-        pool = make_pool(host, 2, _echo, context, _pre, _post)
-        pool.send('hello')
-        pool.close()
-        pool.join()
-        self.assertEqual(len(pool.discarded_responses), 1)
-
-    @unittest.skipIf(sys.version_info.major == 3, 'fails under python3')
-    def test_join_gets_an_error(self):
-        host = Host()
-        pool = make_pool(host, 2, _error, None, _stub, _stub)
-        pool.send('hello')
-        pool.close()
-        try:
-            pool.join()
-        except Exception as e:
-            self.assertIn('_error() raised Exception', str(e))
-
-    def test_join_gets_an_interrupt(self):
-        host = Host()
-        pool = make_pool(host, 2, _interrupt, None, _stub, _stub)
-        pool.send('hello')
-        pool.close()
-        self.assertRaises(KeyboardInterrupt, pool.join)
-
-    def test_loop(self):
-        pool = self.run_through_loop()
-        resp = pool.get()
-        self.assertEqual(resp, None)
-        pool.requests.put((_MessageType.Close, None))
-        pool.close()
-        self.run_through_loop(pool=pool)
-        pool.join()
-
-    def test_loop_fails_to_respond(self):
-        # This tests what happens if _loop() tries to send a response
-        # on a closed queue; we can't simulate this directly through the
-        # api in a single thread.
-        pool = self.run_through_loop()
-        pool.requests.put((_MessageType.Request, None))
-        pool.requests.put((_MessageType.Close, None))
-        self.run_through_loop(pool=pool)
-        pool.join()
-
-    @unittest.skipIf(sys.version_info.major == 3, 'fails under python3')
-    def test_loop_get_raises_error(self):
-        pool = self.run_through_loop(_error)
-        self.assertRaises(Exception, pool.get)
-        pool.requests.put((_MessageType.Close, None))
-        pool.close()
-        pool.join()
-
-    def test_loop_get_raises_interrupt(self):
-        pool = self.run_through_loop(_interrupt)
-        self.assertRaises(KeyboardInterrupt, pool.get)
-        pool.requests.put((_MessageType.Close, None))
-        pool.close()
-        pool.join()
-
-    def test_pickling_errors(self):
-        def unpicklable_fn():  # pragma: no cover
-            pass
-
-        host = Host()
-        jobs = 2
-        self.assertRaises(Exception, make_pool,
-                          host, jobs, _stub, unpicklable_fn, None, None)
-        self.assertRaises(Exception, make_pool,
-                          host, jobs, _stub, None, unpicklable_fn, None)
-        self.assertRaises(Exception, make_pool,
-                          host, jobs, _stub, None, None, unpicklable_fn)
-
-    def test_no_close(self):
-        host = Host()
-        context = {'pre': False, 'post': False}
-        pool = make_pool(host, 2, _echo, context, _pre, _post)
-        final_contexts = pool.join()
-        self.assertEqual(final_contexts, [])
diff --git a/third_party/typ/typ/tests/printer_test.py b/third_party/typ/typ/tests/printer_test.py
deleted file mode 100644
index b2310bc0..0000000
--- a/third_party/typ/typ/tests/printer_test.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-
-from typ.printer import Printer
-
-
-class TestPrinter(unittest.TestCase):
-
-    def setUp(self):
-        # 'Invalid name' pylint: disable=C0103
-        self.out = []
-
-    def print_(self, msg, end='\n'):
-        self.out.append(msg + end)
-
-    def test_basic(self):
-        pr = Printer(self.print_, False, 80)
-        pr.update('foo')
-        pr.flush()
-        self.assertEqual(self.out, ['foo', '\n'])
-
-    def test_elide(self):
-        pr = Printer(self.print_, False, 8)
-        pr.update('hello world')
-        pr.flush()
-        self.assertEqual(self.out, ['h...d', '\n'])
-
-    def test_overwrite(self):
-        pr = Printer(self.print_, True, 80)
-        pr.update('hello world')
-        pr.update('goodbye world')
-        pr.flush()
-        self.assertEqual(self.out,
-                         ['hello world',
-                          '\r           \r',
-                          'goodbye world',
-                          '\n'])
-
-    def test_last_line_flushed_when_not_overwriting(self):
-        pr = Printer(self.print_, False, 80)
-        pr.update('foo\nbar')
-        pr.update('baz')
-        pr.flush()
-        self.assertEqual(self.out,
-                         ['foo\nbar',
-                          '\n',
-                          'baz',
-                          '\n'])
diff --git a/third_party/typ/typ/tests/runner_test.py b/third_party/typ/typ/tests/runner_test.py
deleted file mode 100644
index a5013b2..0000000
--- a/third_party/typ/typ/tests/runner_test.py
+++ /dev/null
@@ -1,224 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import sys
-import tempfile
-import unittest
-
-from textwrap import dedent as d
-
-
-from typ import Host, Runner, TestCase, TestSet, TestInput
-from typ import WinMultiprocessing
-
-
-def _setup_process(child, context):  # pylint: disable=W0613
-    return context
-
-
-def _teardown_process(child, context):  # pylint: disable=W0613
-    return context
-
-def _teardown_throws(child, context):  # pylint: disable=W0613
-    raise Exception("exception in teardown")
-
-
-class RunnerTests(TestCase):
-    def test_context(self):
-        r = Runner()
-        r.args.tests = ['typ.tests.runner_test.ContextTests']
-        r.context = {'foo': 'bar'}
-        r.setup_fn = _setup_process
-        r.teardown_fn = _teardown_process
-        r.win_multiprocessing = WinMultiprocessing.importable
-        ret, _, _ = r.run()
-        self.assertEqual(ret, 0)
-
-    @unittest.skipIf(sys.version_info.major == 3, 'fails under python3')
-    def test_exception_in_teardown(self):
-        r = Runner()
-        r.args.tests = ['typ.tests.runner_test.ContextTests']
-        r.context = {'foo': 'bar'}
-        r.setup_fn = _setup_process
-        r.teardown_fn = _teardown_throws
-        r.win_multiprocessing = WinMultiprocessing.importable
-        ret, _, _ = r.run()
-        self.assertEqual(ret, 0)
-        self.assertEqual(r.final_responses[0][2].message,
-                         'exception in teardown')
-
-    def test_bad_default(self):
-        r = Runner()
-        ret = r.main([], foo='bar')
-        self.assertEqual(ret, 2)
-
-    def test_good_default(self):
-        r = Runner()
-        ret = r.main([], tests=['typ.tests.runner_test.ContextTests'])
-        self.assertEqual(ret, 0)
-
-
-class TestSetTests(TestCase):
-    # This class exists to test the failures that can come up if you
-    # create your own test sets and bypass find_tests(); failures that
-    # would normally be caught there can occur later during test execution.
-
-    def test_missing_name(self):
-        test_set = TestSet()
-        test_set.parallel_tests = [TestInput('nonexistent test')]
-        r = Runner()
-        r.args.jobs = 1
-        ret, _, _ = r.run(test_set)
-        self.assertEqual(ret, 1)
-
-    def test_failing_load_test(self):
-        h = Host()
-        orig_wd = h.getcwd()
-        tmpdir = None
-        try:
-            tmpdir = h.mkdtemp()
-            h.chdir(tmpdir)
-            h.write_text_file('load_test.py', d("""\
-                import unittest
-                def load_tests(_, _2, _3):
-                    assert False
-                """))
-            test_set = TestSet()
-            test_set.parallel_tests = [TestInput('load_test.BaseTest.test_x')]
-            r = Runner()
-            r.args.jobs = 1
-            ret, _, trace = r.run(test_set)
-            self.assertEqual(ret, 1)
-            self.assertIn('Failed to load "load_test.BaseTest.test_x" in '
-                          'run_one_test',
-                          trace['traceEvents'][0]['args']['err'])
-        finally:
-            h.chdir(orig_wd)
-            if tmpdir:
-                h.rmtree(tmpdir)
-
-
-class TestWinMultiprocessing(TestCase):
-    def make_host(self):
-        return Host()
-
-    def call(self, argv, platform=None, win_multiprocessing=None, **kwargs):
-        h = self.make_host()
-        orig_wd = h.getcwd()
-        tmpdir = None
-        try:
-            tmpdir = h.mkdtemp()
-            h.chdir(tmpdir)
-            h.capture_output()
-            if platform is not None:
-                h.platform = platform
-            r = Runner(h)
-            if win_multiprocessing is not None:
-                r.win_multiprocessing = win_multiprocessing
-            ret = r.main(argv, **kwargs)
-        finally:
-            out, err = h.restore_output()
-            h.chdir(orig_wd)
-            if tmpdir:
-                h.rmtree(tmpdir)
-
-        return ret, out, err
-
-    def test_bad_value(self):
-        self.assertRaises(ValueError, self.call, [], win_multiprocessing='foo')
-
-    def test_ignore(self):
-        h = self.make_host()
-        if h.platform == 'win32':  # pragma: win32
-            self.assertRaises(ValueError, self.call, [],
-                              win_multiprocessing=WinMultiprocessing.ignore)
-        else:
-            result = self.call([],
-                               win_multiprocessing=WinMultiprocessing.ignore)
-            ret, out, err = result
-            self.assertEqual(ret, 0)
-            self.assertEqual(out, '0 tests passed, 0 skipped, 0 failures.\n')
-            self.assertEqual(err, '')
-
-    def test_real_unimportable_main(self):
-        h = self.make_host()
-        tmpdir = None
-        orig_wd = h.getcwd()
-        out = err = None
-        out_str = err_str = ''
-        try:
-            tmpdir = h.mkdtemp()
-            h.chdir(tmpdir)
-            out = tempfile.NamedTemporaryFile(delete=False)
-            err = tempfile.NamedTemporaryFile(delete=False)
-            path_above_typ = h.realpath(h.dirname(__file__), '..', '..')
-            env = h.env.copy()
-            if 'PYTHONPATH' in env:  # pragma: untested
-                env['PYTHONPATH'] = '%s%s%s' % (env['PYTHONPATH'],
-                                                h.pathsep,
-                                                path_above_typ)
-            else:  # pragma: untested.
-                env['PYTHONPATH'] = path_above_typ
-
-            h.write_text_file('test', d("""
-                import sys
-                import typ
-                importable = typ.WinMultiprocessing.importable
-                sys.exit(typ.main(win_multiprocessing=importable))
-                """))
-            h.stdout = out
-            h.stderr = err
-            ret = h.call_inline([h.python_interpreter, h.join(tmpdir, 'test')],
-                                env=env)
-        finally:
-            h.chdir(orig_wd)
-            if tmpdir:
-                h.rmtree(tmpdir)
-            if out:
-                out.close()
-                out = open(out.name)
-                out_str = out.read()
-                out.close()
-                h.remove(out.name)
-            if err:
-                err.close()
-                err = open(err.name)
-                err_str = err.read()
-                err.close()
-                h.remove(err.name)
-
-        self.assertEqual(ret, 1)
-        self.assertEqual(out_str, '')
-        self.assertIn('ValueError: The __main__ module ',
-                      err_str)
-
-    def test_single_job(self):
-        ret, out, err = self.call(['-j', '1'], platform='win32')
-        self.assertEqual(ret, 0)
-        self.assertEqual('0 tests passed, 0 skipped, 0 failures.\n', out )
-        self.assertEqual(err, '')
-
-    def test_spawn(self):
-        ret, out, err = self.call([])
-        self.assertEqual(ret, 0)
-        self.assertEqual('0 tests passed, 0 skipped, 0 failures.\n', out)
-        self.assertEqual(err, '')
-
-
-class ContextTests(TestCase):
-    def test_context(self):
-        # This test is mostly intended to be called by
-        # RunnerTests.test_context, above. It is not interesting on its own.
-        if self.context:
-            self.assertEquals(self.context['foo'], 'bar')
diff --git a/third_party/typ/typ/tests/stats_test.py b/third_party/typ/typ/tests/stats_test.py
deleted file mode 100644
index 3154768f..0000000
--- a/third_party/typ/typ/tests/stats_test.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-
-from typ.stats import Stats
-
-
-class TestStats(unittest.TestCase):
-
-    def test_basic(self):
-        s = Stats('foo', lambda: 0, 32)
-        self.assertEqual(s.format(), 'foo')
-
-    def test_edges(self):
-        s = Stats('[%s/%f/%t/%r/%p]', lambda: 0, 32)
-        self.assertEqual(s.format(), '[0/0/0/0/-]')
-        s.started = 3
-        s.total = 5
-        s.finished = 1
-        self.assertEqual(s.format(), '[3/1/5/2/ 60.0]')
-
-        s.started = 5
-        s.finished = 5
-        self.assertEqual(s.format(), '[5/5/5/0/100.0]')
-
-    def test_elapsed_time(self):
-        times = [0.0, 0.4]
-        s = Stats('[%e]', lambda: times.pop(0), 32)
-        self.assertEqual(s.format(), '[0.400]')
-
-        s = Stats('[%e]', lambda: 0, 32)
-        self.assertEqual(s.format(), '[0.000]')
-
-    def test_current_rate(self):
-        times = [0.0, 0.1, 0.2]
-        s = Stats('[%c]', lambda: times.pop(0), 1)
-        self.assertEquals(s.format(), '[-]')
-        s.add_time()
-        s.add_time()
-        self.assertEquals(s.format(), '[ 10.0]')
-
-    def test_overall_rate(self):
-        times = [0, 0, 5]
-        s = Stats('[%o]', lambda: times.pop(0), 32)
-        self.assertEqual(s.format(), '[-]')
-        s.started = 3
-        s.finished = 1
-        s.total = 5
-        self.assertEqual(s.format(), '[  0.2]')
-
-    def test_escaped_percent(self):
-        s = Stats('%%', lambda: 0, 32)
-        self.assertEqual(s.format(), '%')
-
-    def test_unrecognized_escape(self):
-        s = Stats('%x', lambda: 0, 32)
-        self.assertEqual(s.format(), '%x')
-
-    def test_remaining(self):
-        s = Stats('%u', lambda: 0, 32)
-        s.total = 2
-        self.assertEqual(s.format(), '2')
diff --git a/third_party/typ/typ/tests/test_case_test.py b/third_party/typ/typ/tests/test_case_test.py
deleted file mode 100644
index 4d22bd9..0000000
--- a/third_party/typ/typ/tests/test_case_test.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2014 Dirk Pranke. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from typ import test_case
-
-
-class TestFuncs(test_case.MainTestCase):
-
-    def test_convert_newlines(self):
-        cn = test_case.convert_newlines
-        self.assertEqual(cn('foo'), 'foo')
-        self.assertEqual(cn('foo\nbar\nbaz'), 'foo\nbar\nbaz')
-        self.assertEqual(cn('foo\rbar\nbaz\r'), 'foo\nbar\nbaz\n')
-        self.assertEqual(cn('foo\r\nbar\r\nbaz\r\nmeh\n'),
-                         'foo\nbar\nbaz\nmeh\n')
-
-
-class TestMainTestCase(test_case.MainTestCase):
-
-    def test_basic(self):
-        h = self.make_host()
-        files = {
-            'test.py': """
-import os
-import sys
-sys.stdout.write("in: %s\\n" % sys.stdin.read())
-sys.stdout.write("out: %s\\n" % os.environ['TEST_VAR'])
-sys.stderr.write("err\\n")
-with open("../results", "w") as fp:
-  fp.write(open("../input", "r").read() + " written")
-""",
-            'input': 'results',
-            'subdir/x': 'y',
-        }
-        exp_files = files.copy()
-        exp_files['results'] = 'results written'
-        self.check(prog=[h.python_interpreter, '../test.py'],
-                   stdin='hello on stdin',
-                   env={'TEST_VAR': 'foo'},
-                   cwd='subdir',
-                   files=files,
-                   ret=0, out='in: hello on stdin\nout: foo\n',
-                   err='err\n', exp_files=exp_files)
diff --git a/third_party/typ/typ/version.py b/third_party/typ/typ/version.py
deleted file mode 100644
index 437f236..0000000
--- a/third_party/typ/typ/version.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-VERSION = '0.10.0'
diff --git a/tools/metrics/BUILD.gn b/tools/metrics/BUILD.gn
index 5900f4b1..84417f33 100644
--- a/tools/metrics/BUILD.gn
+++ b/tools/metrics/BUILD.gn
@@ -71,7 +71,7 @@
     "//testing/scripts/common.py",
     "//testing/xvfb.py",
     "//testing/test_env.py",
-    "//third_party/typ/",
+    "//third_party/catapult/third_party/typ/",
 
     # Scripts we depend on. Their unit tests are also included.
     "//tools/json_comment_eater/json_comment_eater.py",
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 8399310..3e2f74d 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -22129,6 +22129,22 @@
   <int value="3" label="active, was active"/>
 </enum>
 
+<enum name="GpuTerminationStatus">
+  <summary>
+    Return status re-encoded values from GetTerminationStatus as defined in
+    base/process/kill.h enum TerminationStatus.
+  </summary>
+  <int value="0" label="Normal">NORMAL_TERMINATION</int>
+  <int value="1" label="Abnormal">ABNORMAL_TERMINATION</int>
+  <int value="2" label="Killed">PROCESS_WAS_KILLED</int>
+  <int value="3" label="Crashed">PROCESS_CRASHED</int>
+  <int value="4" label="Still Running">STILL_RUNNING</int>
+  <int value="5" label="Killed by OOM">PROCESS_WAS_KILLED_BY_OOM</int>
+  <int value="6" label="OOM protected">OOM_PROTECTED</int>
+  <int value="7" label="Launch Failed">LAUNCH_FAILED</int>
+  <int value="8" label="OOM">OOM</int>
+</enum>
+
 <enum name="GpuTextureResultR16_L16">
   <summary>
     Keeps track of how many users have R16_EXT or/and LUMINANCE_F16, and also
@@ -26656,7 +26672,6 @@
   <int value="-886912558" label="ChromeHomePromo:enabled"/>
   <int value="-885601782" label="enable-contextual-search"/>
   <int value="-884864731" label="WebPaymentsSingleAppUiSkip:enabled"/>
-  <int value="-881854123" label="enable-heap-profiling"/>
   <int value="-881447505" label="ash-disable-shelf-model-synchronization"/>
   <int value="-881054479" label="WebAssemblyStreaming:disabled"/>
   <int value="-879055117" label="ClipboardContentSetting:enabled"/>
@@ -43908,6 +43923,9 @@
 </enum>
 
 <enum name="TerminationStatus">
+  <obsolete>
+    Deprecated April 2018. Replaced by GpuTerminationStatus.
+  </obsolete>
   <summary>
     Return status values from GetTerminationStatus as defined in
     base/process/kill.h enum TerminationStatus. The last couple enums are
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 8f0ded7..1e3c846 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -29558,6 +29558,16 @@
 </histogram>
 
 <histogram name="GPU.GPUProcessTerminationStatus" enum="TerminationStatus">
+  <obsolete>
+    Deprecated April 2018. Replaced by GPU.GPUProcessTerminationStatus2.
+  </obsolete>
+  <owner>vmiura@chromium.org</owner>
+  <summary>
+    Counts for each time the GPU Process Host detects the process dies.
+  </summary>
+</histogram>
+
+<histogram name="GPU.GPUProcessTerminationStatus2" enum="GpuTerminationStatus">
   <owner>vmiura@chromium.org</owner>
   <summary>
     Counts for each time the GPU Process Host detects the process dies.
@@ -58436,9 +58446,40 @@
   </summary>
 </histogram>
 
+<histogram name="OfflinePages.ConsistencyCheck.Legacy.DeletedHeadlessFileCount"
+    units="files">
+  <owner>romax@chromium.org</owner>
+  <summary>
+    Number of files which are deleted during legacy dir clearing since they have
+    no associated DB entry and live in private directory.
+  </summary>
+</histogram>
+
+<histogram name="OfflinePages.ConsistencyCheck.Persistent.ExpiredEntryCount"
+    units="entries">
+  <owner>romax@chromium.org</owner>
+  <summary>
+    Number of DB entries (in persistent namespaces) that have been missing their
+    files for longer than 365 days, and deleted during maintenance task.
+  </summary>
+</histogram>
+
+<histogram name="OfflinePages.ConsistencyCheck.Persistent.MissingFileCount"
+    units="files">
+  <owner>romax@chromium.org</owner>
+  <summary>
+    Number of files that are found missing during maintenance task, which is
+    also the number of DB entries that are updated with valid file missing time.
+  </summary>
+</histogram>
+
 <histogram
     name="OfflinePages.ConsistencyCheck.Persistent.PagesMissingArchiveFileCount"
     units="pages">
+  <obsolete>
+    Deprecated 04/2018, since saving public offline pages to external download
+    directory needs a different consistency check strategy.
+  </obsolete>
   <owner>romax@chromium.org</owner>
   <summary>
     Number of persistent offline pages without archive file when checking
@@ -58449,6 +58490,10 @@
 <histogram
     name="OfflinePages.ConsistencyCheck.Persistent.PagesMissingDbEntryCount"
     units="pages">
+  <obsolete>
+    Deprecated 04/2018, since saving public offline pages to external download
+    directory needs a different consistency check strategy.
+  </obsolete>
   <owner>romax@chromium.org</owner>
   <summary>
     Number of archives without database entry when checking persistent page
@@ -58456,6 +58501,15 @@
   </summary>
 </histogram>
 
+<histogram name="OfflinePages.ConsistencyCheck.Persistent.ReappearedFileCount"
+    units="files">
+  <owner>romax@chromium.org</owner>
+  <summary>
+    Number of files that were marked as missing reappeared in the file system,
+    which is also the number of DB entries that removes file missing time.
+  </summary>
+</histogram>
+
 <histogram name="OfflinePages.ConsistencyCheck.Persistent.Result"
     enum="OfflinePagesSyncOperationResult">
   <owner>romax@chromium.org</owner>
@@ -109700,7 +109754,11 @@
 
 <histogram_suffixes name="ExtensionWebUiPageType" separator=".">
   <suffix name="MD" label="The Material Design chrome://extensions page."/>
-  <suffix name="Uber" label="The Uber chrome://extensions page."/>
+  <suffix name="Uber" label="The Uber chrome://extensions page.">
+    <obsolete>
+      Deprecated and removed from code as of 04/2018.
+    </obsolete>
+  </suffix>
   <affected-histogram name="Extensions.WebUi.DocumentLoadedInMainFrameTime"/>
   <affected-histogram name="Extensions.WebUi.LoadCompletedInMainFrame"/>
 </histogram_suffixes>
diff --git a/tools/metrics/metrics_python_tests.py b/tools/metrics/metrics_python_tests.py
index d619265..6acc509e 100755
--- a/tools/metrics/metrics_python_tests.py
+++ b/tools/metrics/metrics_python_tests.py
@@ -8,7 +8,7 @@
 
 THIS_DIR = os.path.abspath(os.path.dirname(__file__))
 SRC_DIR = os.path.dirname(os.path.dirname(THIS_DIR))
-TYP_DIR = os.path.join(SRC_DIR, 'third_party', 'typ')
+TYP_DIR = os.path.join(SRC_DIR, 'third_party', 'catapult', 'third_party', 'typ')
 
 if not TYP_DIR in sys.path:
     sys.path.insert(0, TYP_DIR)
diff --git a/tools/perf/benchmarks/memory.py b/tools/perf/benchmarks/memory.py
index 5a1e2a84..7870c80 100644
--- a/tools/perf/benchmarks/memory.py
+++ b/tools/perf/benchmarks/memory.py
@@ -89,14 +89,6 @@
     return page_sets.TrivialSitesStorySet(wait_in_seconds=0,
                                           measure_memory=True)
 
-  def SetExtraBrowserOptions(self, options):
-    super(MemoryBenchmarkTrivialSitesDesktop, self).SetExtraBrowserOptions(
-          options)
-    # Heap profiling is disabled because of crbug.com/757847.
-    #options.AppendExtraBrowserArgs([
-    #  '--enable-heap-profiling=native',
-    #])
-
   @classmethod
   def Name(cls):
     return 'memory.desktop'
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index 0b86d552c..4e672089 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -127,14 +127,6 @@
   def Name(cls):
     return 'system_health.memory_desktop'
 
-  def SetExtraBrowserOptions(self, options):
-    super(DesktopMemorySystemHealth, self).SetExtraBrowserOptions(
-          options)
-    # Heap profiling is disabled because of crbug.com/757847.
-    #options.AppendExtraBrowserArgs([
-    #  '--enable-heap-profiling=native',
-    #])
-
 
 @benchmark.Owner(emails=['perezju@chromium.org'])
 class MobileMemorySystemHealth(_MemorySystemHealthBenchmark):
diff --git a/tools/perf/contrib/heap_profiling/heap_profiling.py b/tools/perf/contrib/heap_profiling/heap_profiling.py
index c60f4c5..8c95ac8b 100644
--- a/tools/perf/contrib/heap_profiling/heap_profiling.py
+++ b/tools/perf/contrib/heap_profiling/heap_profiling.py
@@ -63,9 +63,12 @@
     super(_HeapProfilingBenchmark, self).SetExtraBrowserOptions(options)
     args = []
     if self.PROFILING_MODE == 'pseudo':
-      args += ['--enable-heap-profiling']
+      args += [
+          '--memlog=all', '--memlog-stack-mode=pseudo', '--memlog-sampling']
     elif self.PROFILING_MODE == 'native':
-      args += ['--enable-heap-profiling=native']
+      args += [
+          '--memlog=all', '--memlog-stack-mode=native-with-thread-names',
+          '--memlog-sampling']
     options.AppendExtraBrowserArgs(args)
 
 
diff --git a/tools/perf/contrib/memory_extras/memory_extras.py b/tools/perf/contrib/memory_extras/memory_extras.py
index f46092f..42f44bf 100644
--- a/tools/perf/contrib/memory_extras/memory_extras.py
+++ b/tools/perf/contrib/memory_extras/memory_extras.py
@@ -82,7 +82,9 @@
   def SetExtraBrowserOptions(self, options):
     super(LongRunningMemoryBenchmarkSitesDesktop, self).SetExtraBrowserOptions(
         options)
-    options.AppendExtraBrowserArgs(['--enable-heap-profiling=native'])
+    options.AppendExtraBrowserArgs([
+        '--memlog=all', '--memlog-sampling',
+        '--memlog-stack-mode=native-with-thread-names'])
     # Disable taking screenshot on failing pages.
     options.take_screenshot_for_failed_page = False
 
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc
index a93b33bb..16076e2a 100644
--- a/ui/android/view_android.cc
+++ b/ui/android/view_android.cc
@@ -87,14 +87,9 @@
 ViewAndroid::ViewAndroid() : ViewAndroid(LayoutType::NORMAL) {}
 
 ViewAndroid::~ViewAndroid() {
+  RemoveAllChildren();
   observer_list_.Clear();
   RemoveFromParent();
-
-  for (std::list<ViewAndroid*>::iterator it = children_.begin();
-       it != children_.end(); it++) {
-    DCHECK_EQ((*it)->parent_, this);
-    (*it)->parent_ = nullptr;
-  }
 }
 
 void ViewAndroid::SetDelegate(const JavaRef<jobject>& delegate) {
@@ -256,6 +251,18 @@
   return gfx::PointF(x + loc_x, y + loc_y);
 }
 
+void ViewAndroid::RemoveAllChildren() {
+  bool has_window = GetWindowAndroid();
+  auto it = children_.begin();
+  while (it != children_.end()) {
+    if (has_window)
+      (*it)->OnDetachedFromWindow();
+    (*it)->parent_ = nullptr;
+    // erase returns a new iterator for the element following the ereased one.
+    it = children_.erase(it);
+  }
+}
+
 void ViewAndroid::RemoveChild(ViewAndroid* child) {
   DCHECK(child);
   DCHECK_EQ(child->parent_, this);
diff --git a/ui/android/view_android.h b/ui/android/view_android.h
index 18c8ca7..92ecadc 100644
--- a/ui/android/view_android.h
+++ b/ui/android/view_android.h
@@ -197,6 +197,7 @@
   bool OnGestureEvent(const GestureEventAndroid& event);
 
   void RemoveChild(ViewAndroid* child);
+  void RemoveAllChildren();
 
   void OnAttachedToWindow();
   void OnDetachedFromWindow();
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn
index 2f74c3a9..14aa332 100644
--- a/ui/aura/BUILD.gn
+++ b/ui/aura/BUILD.gn
@@ -360,6 +360,7 @@
 test("aura_unittests") {
   sources = [
     "../compositor_extra/shadow_unittest.cc",
+    "//ui/aura_extra/window_occlusion_impl_unittest_win.cc",
     "gestures/gesture_recognizer_unittest.cc",
     "hit_test_data_provider_aura_unittest.cc",
     "mus/drag_drop_controller_mus_unittest.cc",
@@ -392,6 +393,7 @@
     "//services/ui/public/cpp",
     "//skia",
     "//testing/gtest",
+    "//ui/aura_extra",
     "//ui/base:test_support",
     "//ui/compositor:test_support",
     "//ui/compositor_extra",
diff --git a/ui/aura_extra/BUILD.gn b/ui/aura_extra/BUILD.gn
index dae41d2..f66afd1 100644
--- a/ui/aura_extra/BUILD.gn
+++ b/ui/aura_extra/BUILD.gn
@@ -9,6 +9,10 @@
     "aura_extra_export.h",
     "image_window_delegate.cc",
     "image_window_delegate.h",
+    "window_occlusion_impl_win.cc",
+    "window_occlusion_impl_win.h",
+    "window_occlusion_win.cc",
+    "window_occlusion_win.h",
   ]
 
   defines = [ "AURA_EXTRA_IMPLEMENTATION" ]
diff --git a/ui/aura_extra/window_occlusion_impl_unittest_win.cc b/ui/aura_extra/window_occlusion_impl_unittest_win.cc
new file mode 100644
index 0000000..44e8efeb
--- /dev/null
+++ b/ui/aura_extra/window_occlusion_impl_unittest_win.cc
@@ -0,0 +1,457 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_extra/window_occlusion_impl_win.h"
+
+#include "base/win/scoped_gdi_object.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/window_tree_host_platform.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace aura_extra {
+
+// A single set of arguments that are passed to WindowEvaluator::Evaluate().
+// Used to mock calls to WindowEvaluator::Evaluate().
+struct EvaluatorArgs {
+  bool is_relevant;
+  gfx::Rect window_rect;
+  HWND hwnd;
+};
+
+// Iterates over a provided set of mock windows and their properties.
+class MockNativeWindowIterator : public NativeWindowIterator {
+ public:
+  MockNativeWindowIterator(
+      const std::vector<EvaluatorArgs>& evaluator_args_list)
+      : args_list_(evaluator_args_list) {}
+
+  void Iterate(WindowEvaluator* evaluator) override {
+    for (EvaluatorArgs args : args_list_) {
+      if (!evaluator->EvaluateWindow(args.is_relevant, args.window_rect,
+                                     args.hwnd))
+        return;
+    }
+  }
+
+ private:
+  std::vector<EvaluatorArgs> args_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockNativeWindowIterator);
+};
+
+// Test implementation of WindowBoundsDelegate using a flat_map of aura::Window
+// to gfx::Rect.
+class MockWindowBoundsDelegateImpl : public WindowBoundsDelegate {
+ public:
+  MockWindowBoundsDelegateImpl() = default;
+
+  // WindowBoundsDelegate implementation:
+  gfx::Rect GetBoundsInPixels(aura::WindowTreeHost* window) override {
+    return root_window_bounds_[window];
+  }
+
+  void AddWindowWithBounds(aura::WindowTreeHost* window,
+                           const gfx::Rect& window_bounds_in_pixels) {
+    root_window_bounds_[window] = window_bounds_in_pixels;
+  }
+
+ private:
+  base::flat_map<aura::WindowTreeHost*, gfx::Rect> root_window_bounds_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockWindowBoundsDelegateImpl);
+};
+
+// The int argument here is an offset in pixels for tests that need to offset
+// windows. This allows for variable offsets in the parameterized tests.
+using OffsetAndBoundsPair = std::pair<int, gfx::Rect>;
+
+class WindowOcclusionWinTest
+    : public aura::test::AuraTestBase,
+      public ::testing::WithParamInterface<OffsetAndBoundsPair> {
+ public:
+  WindowOcclusionWinTest() {}
+
+  void TearDown() override {
+    Clear();
+    aura::test::AuraTestBase::TearDown();
+  }
+
+  aura::WindowTreeHost* AddRootAuraWindowWithBounds(const gfx::Rect& bounds) {
+    std::unique_ptr<aura::WindowTreeHost> window_tree_host(
+        aura::WindowTreeHost::Create(bounds));
+    window_tree_host->window()->Show();
+
+    EvaluatorArgs args{true, bounds, window_tree_host->GetAcceleratedWidget()};
+    evaluator_args_list_.push_back(args);
+
+    mock_bounds_delegate_->AddWindowWithBounds(window_tree_host.get(), bounds);
+
+    aura::WindowTreeHost* host = window_tree_host.get();
+    window_tree_hosts_.push_back(std::move(window_tree_host));
+    return host;
+  }
+
+  void AddMockNativeWindowWithBounds(gfx::Rect bounds) {
+    EvaluatorArgs args{true, bounds, 0};
+    evaluator_args_list_.push_back(args);
+  }
+
+  base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState>
+  ComputeOcclusion() {
+    std::unique_ptr<NativeWindowIterator> iterator =
+        std::make_unique<MockNativeWindowIterator>(evaluator_args_list_);
+    std::vector<aura::WindowTreeHost*> window_tree_hosts;
+
+    for (auto& host : window_tree_hosts_)
+      window_tree_hosts.push_back(host.get());
+
+    return ComputeNativeWindowOcclusionStatusImpl(
+        window_tree_hosts, std::move(iterator),
+        std::unique_ptr<WindowBoundsDelegate>(mock_bounds_delegate_.release()));
+  }
+
+  void Clear() {
+    evaluator_args_list_.clear();
+    window_tree_hosts_.clear();
+  }
+
+ private:
+  std::vector<EvaluatorArgs> evaluator_args_list_;
+
+  std::vector<std::unique_ptr<aura::WindowTreeHost>> window_tree_hosts_;
+  std::unique_ptr<MockWindowBoundsDelegateImpl> mock_bounds_delegate_ =
+      std::make_unique<MockWindowBoundsDelegateImpl>();
+
+  DISALLOW_COPY_AND_ASSIGN(WindowOcclusionWinTest);
+};
+
+// An aura window completely covered by a native window should be occluded.
+TEST_P(WindowOcclusionWinTest, SimpleOccluded) {
+  OffsetAndBoundsPair param = GetParam();
+  AddMockNativeWindowWithBounds(param.second);
+  aura::WindowTreeHost* window = AddRootAuraWindowWithBounds(param.second);
+
+  base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState> result =
+      ComputeOcclusion();
+
+  EXPECT_EQ(result.size(), 1U);
+  ASSERT_TRUE(base::ContainsKey(result, window));
+  EXPECT_EQ(result[window], aura::Window::OcclusionState::OCCLUDED);
+}
+
+// An aura window not occluded at all by a native window should be visible.
+TEST_P(WindowOcclusionWinTest, SimpleVisible) {
+  OffsetAndBoundsPair param = GetParam();
+  aura::WindowTreeHost* window = AddRootAuraWindowWithBounds(param.second);
+  AddMockNativeWindowWithBounds(param.second);
+
+  base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState> result =
+      ComputeOcclusion();
+
+  EXPECT_EQ(result.size(), 1U);
+  ASSERT_TRUE(base::ContainsKey(result, window));
+  EXPECT_EQ(result[window], aura::Window::OcclusionState::VISIBLE);
+  Clear();
+}
+
+// An aura window occluded by an aura window should be occluded.
+TEST_P(WindowOcclusionWinTest, OccludedByAuraWindow) {
+  OffsetAndBoundsPair param = GetParam();
+  aura::WindowTreeHost* window1 = AddRootAuraWindowWithBounds(param.second);
+  aura::WindowTreeHost* window2 = AddRootAuraWindowWithBounds(param.second);
+
+  std::vector<aura::WindowTreeHost*> windows({window1, window2});
+
+  base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState> result =
+      ComputeOcclusion();
+
+  EXPECT_EQ(result.size(), 2U);
+
+  ASSERT_TRUE(base::ContainsKey(result, window1));
+  EXPECT_EQ(result[window1], aura::Window::OcclusionState::VISIBLE);
+
+  ASSERT_TRUE(base::ContainsKey(result, window2));
+  EXPECT_EQ(result[window2], aura::Window::OcclusionState::OCCLUDED);
+}
+
+// An aura window occluded by two native windows should be occluded.
+TEST_P(WindowOcclusionWinTest, OccludedByMultipleWindows) {
+  OffsetAndBoundsPair param = GetParam();
+
+  gfx::Rect left_half = param.second;
+  left_half.Offset(-left_half.width() / 2, 0);
+
+  gfx::Rect right_half = param.second;
+  right_half.Offset(right_half.width() / 2, 0);
+
+  AddMockNativeWindowWithBounds(left_half);
+  AddMockNativeWindowWithBounds(right_half);
+  aura::WindowTreeHost* window = AddRootAuraWindowWithBounds(param.second);
+
+  base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState> result =
+      ComputeOcclusion();
+
+  EXPECT_EQ(result.size(), 1U);
+  ASSERT_TRUE(base::ContainsKey(result, window));
+  EXPECT_EQ(result[window], aura::Window::OcclusionState::OCCLUDED);
+}
+
+// An aura window partially occluded by an aura window should be visible.
+TEST_P(WindowOcclusionWinTest, PartiallyOverlappedAuraWindows) {
+  OffsetAndBoundsPair param = GetParam();
+  aura::WindowTreeHost* window1 = AddRootAuraWindowWithBounds(param.second);
+
+  gfx::Rect offset_bounds = param.second;
+  offset_bounds.Offset(param.first, param.first);
+  aura::WindowTreeHost* window2 = AddRootAuraWindowWithBounds(offset_bounds);
+
+  base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState> result =
+      ComputeOcclusion();
+
+  EXPECT_EQ(result.size(), 2U);
+
+  ASSERT_TRUE(base::ContainsKey(result, window1));
+  EXPECT_EQ(result[window1], aura::Window::OcclusionState::VISIBLE);
+
+  ASSERT_TRUE(base::ContainsKey(result, window2));
+  EXPECT_EQ(result[window2], aura::Window::OcclusionState::VISIBLE);
+}
+
+// An aura window partially occluded by a native window should be visible.
+TEST_P(WindowOcclusionWinTest, PartiallyOverlappedWindows) {
+  OffsetAndBoundsPair param = GetParam();
+  aura::WindowTreeHost* window = AddRootAuraWindowWithBounds(param.second);
+
+  gfx::Rect offset_bounds = param.second;
+  offset_bounds.Offset(param.first, param.first);
+  AddMockNativeWindowWithBounds(offset_bounds);
+
+  base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState> result =
+      ComputeOcclusion();
+
+  EXPECT_EQ(result.size(), 1U);
+
+  ASSERT_TRUE(base::ContainsKey(result, window));
+  EXPECT_EQ(result[window], aura::Window::OcclusionState::VISIBLE);
+}
+
+// If for some reason the bounds of an aura::Window are empty, this signals some
+// sort of failure in the call to GetWindowRect() This tests that in this case
+// the window is marked as aura::Window::OcclusionState::VISIBLE to avoid
+// falsely marking it as occluded.
+TEST_P(WindowOcclusionWinTest, EmptyWindowIsVisible) {
+  aura::WindowTreeHost* window =
+      AddRootAuraWindowWithBounds(gfx::Rect(0, 0, 0, 0));
+
+  base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState> result =
+      ComputeOcclusion();
+
+  EXPECT_EQ(result.size(), 1U);
+
+  ASSERT_TRUE(base::ContainsKey(result, window));
+  EXPECT_EQ(result[window], aura::Window::OcclusionState::VISIBLE);
+}
+
+INSTANTIATE_TEST_CASE_P(/* no prefix */
+                        ,
+                        WindowOcclusionWinTest,
+                        ::testing::Values(
+                            OffsetAndBoundsPair(5, gfx::Rect(0, 0, 100, 100)),
+                            OffsetAndBoundsPair(10, gfx::Rect(0, 0, 100, 200)),
+                            OffsetAndBoundsPair(15, gfx::Rect(0, 0, 200, 100)),
+                            OffsetAndBoundsPair(20, gfx::Rect(0, 0, 200, 200)),
+                            OffsetAndBoundsPair(25, gfx::Rect(0, 50, 100, 100)),
+                            OffsetAndBoundsPair(50, gfx::Rect(0, 50, 100, 200)),
+                            OffsetAndBoundsPair(75, gfx::Rect(0, 50, 200, 100)),
+                            OffsetAndBoundsPair(100,
+                                                gfx::Rect(0, 50, 200, 200)),
+                            OffsetAndBoundsPair(125,
+                                                gfx::Rect(100, 0, 100, 100)),
+                            OffsetAndBoundsPair(150,
+                                                gfx::Rect(100, 0, 100, 200)),
+                            OffsetAndBoundsPair(200,
+                                                gfx::Rect(100, 0, 200, 100)),
+                            OffsetAndBoundsPair(250,
+                                                gfx::Rect(100, 0, 200, 200)),
+                            OffsetAndBoundsPair(300,
+                                                gfx::Rect(100, 50, 100, 100)),
+                            OffsetAndBoundsPair(400,
+                                                gfx::Rect(100, 50, 100, 200)),
+                            OffsetAndBoundsPair(500,
+                                                gfx::Rect(100, 50, 200, 100)),
+                            OffsetAndBoundsPair(750,
+                                                gfx::Rect(100, 50, 200, 200))));
+
+class WindowFitnessFunctionTest : public testing::Test {
+ public:
+  HWND CreateNativeWindow(gfx::Rect bounds) {
+    HWND hwnd = CreateWindow(L"STATIC", L"TestWindow", WS_OVERLAPPED,
+                             bounds.x(), bounds.y(), bounds.width(),
+                             bounds.height(), (HWND)NULL, NULL, NULL, NULL);
+
+    return hwnd;
+  }
+
+  // Adds the windows style |style| to |hwnd|.
+  void AddStyle(HWND hwnd, int style_type, DWORD style) {
+    SetWindowLong(hwnd, style_type, GetWindowLong(hwnd, style_type) | style);
+  }
+
+  void RemoveStyle(HWND hwnd, int style_type, DWORD style) {
+    SetWindowLong(hwnd, style_type, GetWindowLong(hwnd, style_type) & ~style);
+  }
+};
+
+TEST_F(WindowFitnessFunctionTest, FitnessTest) {
+  HWND hwnd = CreateNativeWindow(gfx::Rect(0, 0, 100, 100));
+  gfx::Rect rect;
+
+  // The window doesn't have the WS_VISIBLE style yet, so it should not pass.
+  EXPECT_FALSE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  AddStyle(hwnd, GWL_STYLE, WS_VISIBLE);
+  EXPECT_TRUE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  AddStyle(hwnd, GWL_STYLE, WS_MINIMIZE);
+  EXPECT_FALSE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  RemoveStyle(hwnd, GWL_STYLE, WS_MINIMIZE);
+  EXPECT_TRUE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  AddStyle(hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT);
+  EXPECT_FALSE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  RemoveStyle(hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT);
+  EXPECT_TRUE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  AddStyle(hwnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
+  EXPECT_FALSE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  RemoveStyle(hwnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
+  EXPECT_TRUE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  AddStyle(hwnd, GWL_EXSTYLE, WS_EX_LAYERED);
+  SetLayeredWindowAttributes(hwnd, RGB(10, 10, 10), NULL, LWA_COLORKEY);
+  EXPECT_FALSE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  RemoveStyle(hwnd, GWL_EXSTYLE, WS_EX_LAYERED);
+  EXPECT_TRUE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  AddStyle(hwnd, GWL_EXSTYLE, WS_EX_LAYERED);
+  SetLayeredWindowAttributes(hwnd, NULL, 0, LWA_ALPHA);
+  EXPECT_FALSE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  RemoveStyle(hwnd, GWL_EXSTYLE, WS_EX_LAYERED);
+  EXPECT_TRUE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  AddStyle(hwnd, GWL_EXSTYLE, WS_EX_LAYERED);
+  SetLayeredWindowAttributes(hwnd, NULL, 255, LWA_ALPHA);
+  EXPECT_FALSE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  RemoveStyle(hwnd, GWL_EXSTYLE, WS_EX_LAYERED);
+  EXPECT_TRUE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  // Any complex region should fail, as we only consider simple rectangular
+  // windows. In this case, we make the region a triangle.
+  POINT point1;
+  point1.x = 0;
+  point1.y = 0;
+  POINT point2;
+  point2.x = 50;
+  point2.y = 0;
+  POINT point3;
+  point3.x = 0;
+  point3.y = 50;
+  POINT points[] = {point1, point2, point3};
+  base::win::ScopedRegion complex_region(CreatePolygonRgn(points, 3, WINDING));
+  SetWindowRgn(hwnd, complex_region.get(), TRUE);
+  EXPECT_FALSE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+
+  // A rectangular region should pass.
+  base::win::ScopedRegion rectangular_region(CreateRectRgn(200, 200, 200, 200));
+  SetWindowRgn(hwnd, rectangular_region.get(), TRUE);
+  EXPECT_TRUE(IsWindowVisibleAndFullyOpaque(hwnd, &rect));
+}
+
+class MockWindowEvaluator : public WindowEvaluator {
+ public:
+  // At the end of the test, the window_stack must be empty, otherwise not all
+  // the windows were seen.
+  ~MockWindowEvaluator() { EXPECT_TRUE(window_stack.empty()); }
+
+  // Tests that EnumWindows goes front to back by creating a stack of aura
+  // windows and popping the top window off the stack as its HWND is seen in
+  // this callback. If the stack isn't empty at the end, EnumWindows did not see
+  // all the windows, or did not see them in the correct order.
+  bool EvaluateWindow(bool is_relevant,
+                      const gfx::Rect& window_rect_in_pixels,
+                      HWND hwnd) override {
+    if (window_stack.empty())
+      return FALSE;
+
+    HWND top_window_hwnd =
+        window_stack.top()->GetHost()->GetAcceleratedWidget();
+
+    if (hwnd == top_window_hwnd)
+      window_stack.pop();
+
+    return TRUE;
+  }
+
+  void AddToStack(aura::Window* window) { window_stack.push(window); }
+
+ private:
+  base::stack<aura::Window*> window_stack;
+};
+
+// Tests the functionality of EnumWindows. Specifically:
+//  1) EnumWindows enumerates all windows on the desktop.
+//  2) EnumWindows enumerates from front to back in the Z-order.
+// This needs to be tested because 2) is undocumented behavior. However, this
+// behavior has been observed in the community and tested to be true.
+// ComputeNativeWindowOcclusionStatus() relies on this assumption.
+class EnumWindowsTest : public aura::test::AuraTestBase {
+ public:
+  EnumWindowsTest() {}
+
+  void TearDown() override {
+    window_tree_hosts_.clear();
+    aura::test::AuraTestBase::TearDown();
+  }
+
+  void CreateAuraWindowWithBounds(const gfx::Rect& bounds) {
+    std::unique_ptr<aura::WindowTreeHost> host(
+        aura::WindowTreeHost::Create(bounds));
+    host->window()->Show();
+    evaluator_.AddToStack(host->window());
+    window_tree_hosts_.push_back(std::move(host));
+  }
+
+  void TestIterator() {
+    // The iterator will validate that the OS returns the full set of windows in
+    // the expected order, as encoded by |window_stack| in |evaluator_|
+    WindowsDesktopWindowIterator iterator;
+    iterator.Iterate(&evaluator_);
+  }
+
+ private:
+  std::vector<std::unique_ptr<aura::WindowTreeHost>> window_tree_hosts_;
+
+  MockWindowEvaluator evaluator_;
+
+  DISALLOW_COPY_AND_ASSIGN(EnumWindowsTest);
+};
+
+TEST_F(EnumWindowsTest, EnumWindowsGoesFrontToBack) {
+  CreateAuraWindowWithBounds(gfx::Rect(0, 0, 100, 100));
+  CreateAuraWindowWithBounds(gfx::Rect(50, 50, 500, 500));
+  CreateAuraWindowWithBounds(gfx::Rect(20, 20, 300, 50));
+  CreateAuraWindowWithBounds(gfx::Rect(200, 200, 10, 10));
+  CreateAuraWindowWithBounds(gfx::Rect(0, 0, 100, 100));
+
+  TestIterator();
+}
+
+}  // namespace aura_extra
diff --git a/ui/aura_extra/window_occlusion_impl_win.cc b/ui/aura_extra/window_occlusion_impl_win.cc
new file mode 100644
index 0000000..271578a
--- /dev/null
+++ b/ui/aura_extra/window_occlusion_impl_win.cc
@@ -0,0 +1,234 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_extra/window_occlusion_impl_win.h"
+
+#include "base/win/scoped_gdi_object.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace aura_extra {
+
+namespace {
+
+// Determines the occlusion status of each aura::Window in |windows_of_interest|
+// passed to the constructor. Evaluates a window by subtracting its bounds from
+// every window beneath it in the z-order.
+class WindowEvaluatorImpl : public WindowEvaluator {
+ public:
+  // |windows_of_interest| are the aura::WindowTreeHost's  whose occlusion
+  // status are being calculated. |bounds_delegate| is used to obtain the bounds
+  // in pixels of each root aura::Window in |windows_of_interest|.
+  WindowEvaluatorImpl(
+      const std::vector<aura::WindowTreeHost*>& windows_of_interest,
+      std::unique_ptr<WindowBoundsDelegate> bounds_delegate);
+  ~WindowEvaluatorImpl();
+
+  // WindowEvaluator.
+  bool EvaluateWindow(bool is_relevant,
+                      const gfx::Rect& window_rect_in_pixels,
+                      HWND hwnd) override;
+
+  // Returns whether there was at least one visible root aura::Window passed to
+  // ComputeNativeWindowOcclusionStatus().
+  bool HasAtLeastOneVisibleWindow() const {
+    return !unoccluded_regions_.empty();
+  }
+
+  // Called once the occlusion computation is done. Returns |occlusion_states_|
+  base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState>
+  TakeResult();
+
+ private:
+  using WindowRegionPair = std::pair<aura::WindowTreeHost*, SkRegion>;
+
+  // Stores intermediate values for the unoccluded regions of an aura::Window in
+  // pixels. Once an aura::Window::OcclusionState is determined for a root
+  // aura::Window, that aura::Window is removed from |unoccluded_regions_| and
+  // added to |occlusion_states_| with the computed
+  // aura::Window::OcclusionState.
+  std::vector<WindowRegionPair> unoccluded_regions_;
+
+  // Stores the final aura::Window::OcclusionState for each root
+  // aura::WindowTreeHost that is passed to
+  // ComputeNativeWindowOcclusionStatus().
+  base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState>
+      occlusion_states_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowEvaluatorImpl);
+};
+
+WindowEvaluatorImpl::WindowEvaluatorImpl(
+    const std::vector<aura::WindowTreeHost*>& windows_of_interest,
+    std::unique_ptr<WindowBoundsDelegate> bounds_delegate) {
+  for (aura::WindowTreeHost* window : windows_of_interest) {
+    // If the window isn't visible at this time, it is
+    // aura::Window::OcclusionState::HIDDEN.
+    if (!window->window()->IsVisible() ||
+        IsIconic(window->GetAcceleratedWidget())) {
+      occlusion_states_[window] = aura::Window::OcclusionState::HIDDEN;
+      continue;
+    }
+
+    gfx::Rect window_rect_in_pixels =
+        bounds_delegate->GetBoundsInPixels(window);
+
+    SkRegion window_region(SkIRect::MakeXYWH(
+        window_rect_in_pixels.x(), window_rect_in_pixels.y(),
+        window_rect_in_pixels.width(), window_rect_in_pixels.height()));
+
+    unoccluded_regions_.emplace_back(window, window_region);
+  }
+}
+
+WindowEvaluatorImpl::~WindowEvaluatorImpl() = default;
+
+bool WindowEvaluatorImpl::EvaluateWindow(bool is_relevant,
+                                         const gfx::Rect& window_rect_in_pixels,
+                                         HWND hwnd) {
+  // Loop through |unoccluded_regions_| and determine how |hwnd| affects each
+  // root window with respect to occlusion.
+  for (WindowRegionPair& root_window_pair : unoccluded_regions_) {
+    HWND window_hwnd = root_window_pair.first->GetAcceleratedWidget();
+
+    // The EnumWindows callbacks have reached this window in the Z-order
+    // (EnumWindows goes from front to back). This window must be visible
+    // because we did not discover that it was completely occluded earlier.
+    if (hwnd == window_hwnd) {
+      occlusion_states_[root_window_pair.first] =
+          aura::Window::OcclusionState::VISIBLE;
+      // Set the unoccluded region for this window to empty as a signal that the
+      // occlusion computation is complete.
+      root_window_pair.second.setEmpty();
+      continue;
+    }
+
+    // |hwnd| is not taken into account for occlusion computations, move on.
+    if (!is_relevant)
+      continue;
+
+    // Current occlusion state for this window cannot be determined yet. The
+    // EnumWindows callbacks are currently above this window in the Z-order.
+    // Subtract the other windows bounding rectangle from this window's
+    // unoccluded region if the two regions intersect.
+    SkRegion window_region(SkIRect::MakeXYWH(
+        window_rect_in_pixels.x(), window_rect_in_pixels.y(),
+        window_rect_in_pixels.width(), window_rect_in_pixels.height()));
+
+    if (root_window_pair.second.intersects(window_region)) {
+      root_window_pair.second.op(window_region, SkRegion::kDifference_Op);
+
+      if (root_window_pair.second.isEmpty()) {
+        occlusion_states_[root_window_pair.first] =
+            aura::Window::OcclusionState::OCCLUDED;
+      }
+    }
+  }
+
+  // Occlusion computation is done for windows with an empty region in
+  // |unoccluded_regions_|. If the window is visible, the region is set to empty
+  // explicitly. If it is occluded, the region is implicitly empty.
+  base::EraseIf(unoccluded_regions_, [](const WindowRegionPair& element) {
+    return element.second.isEmpty();
+  });
+
+  // If |unoccluded_regions_| is empty, the occlusion calculation is complete.
+  // So, we return false to signal to EnumWindows to stop enumerating.
+  // Otherwise, we want EnumWindows to continue, and return true.
+  return !unoccluded_regions_.empty();
+}
+
+base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState>
+WindowEvaluatorImpl::TakeResult() {
+  return std::move(occlusion_states_);
+}
+
+}  // namespace
+
+WindowsDesktopWindowIterator::WindowsDesktopWindowIterator() = default;
+
+void WindowsDesktopWindowIterator::Iterate(WindowEvaluator* evaluator) {
+  evaluator_ = evaluator;
+  EnumWindows(&EnumWindowsOcclusionCallback, reinterpret_cast<LPARAM>(this));
+}
+
+BOOL WindowsDesktopWindowIterator::RunEvaluator(HWND hwnd) {
+  gfx::Rect window_rect;
+  bool is_relevant = IsWindowVisibleAndFullyOpaque(hwnd, &window_rect);
+  return evaluator_->EvaluateWindow(is_relevant, window_rect, hwnd);
+}
+
+// static
+BOOL CALLBACK
+WindowsDesktopWindowIterator::EnumWindowsOcclusionCallback(HWND hwnd,
+                                                           LPARAM lParam) {
+  WindowsDesktopWindowIterator* iterator =
+      reinterpret_cast<WindowsDesktopWindowIterator*>(lParam);
+  return iterator->RunEvaluator(hwnd);
+}
+
+base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState>
+ComputeNativeWindowOcclusionStatusImpl(
+    const std::vector<aura::WindowTreeHost*>& windows,
+    std::unique_ptr<NativeWindowIterator> iterator,
+    std::unique_ptr<WindowBoundsDelegate> bounds_delegate) {
+  WindowEvaluatorImpl window_evaluator(windows, std::move(bounds_delegate));
+
+  // Only compute occlusion if there was at least one window that is visible.
+  if (window_evaluator.HasAtLeastOneVisibleWindow())
+    iterator->Iterate(&window_evaluator);
+
+  return window_evaluator.TakeResult();
+}
+
+bool IsWindowVisibleAndFullyOpaque(HWND hwnd, gfx::Rect* rect_in_pixels) {
+  // Filter out invalid hwnds.
+  if (!IsWindow(hwnd))
+    return false;
+
+  // Filter out windows that are not “visible”.
+  if (!IsWindowVisible(hwnd))
+    return false;
+
+  // Filter out minimized windows.
+  if (IsIconic(hwnd))
+    return false;
+
+  LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE);
+
+  // Filter out “transparent” windows, windows where the mouse clicks fall
+  // through them.
+  if (ex_styles & WS_EX_TRANSPARENT)
+    return false;
+
+  // Filter out “tool windows”, which are floating windows that do not appear on
+  // the taskbar or ALT-TAB. Floating windows can have larger window rectangles
+  // than what is visible to the user, so by filtering them out we will avoid
+  // incorrectly marking native windows as occluded.
+  if (ex_styles & WS_EX_TOOLWINDOW)
+    return false;
+
+  // Filter out layered windows.
+  if (ex_styles & WS_EX_LAYERED)
+    return false;
+
+  // Filter out windows that do not have a simple rectangular region.
+  base::win::ScopedRegion region(CreateRectRgn(0, 0, 0, 0));
+  if (GetWindowRgn(hwnd, region.get()) == COMPLEXREGION)
+    return false;
+
+  RECT window_rect;
+  // Filter out windows that take up zero area. The call to GetWindowRect is one
+  // of the most expensive parts of this function, so it is last.
+  if (!GetWindowRect(hwnd, &window_rect))
+    return false;
+  if (IsRectEmpty(&window_rect))
+    return false;
+
+  rect_in_pixels->SetByBounds(window_rect.left, window_rect.top,
+                              window_rect.right, window_rect.bottom);
+  return true;
+}
+
+}  // namespace aura_extra
diff --git a/ui/aura_extra/window_occlusion_impl_win.h b/ui/aura_extra/window_occlusion_impl_win.h
new file mode 100644
index 0000000..2f0aa13f
--- /dev/null
+++ b/ui/aura_extra/window_occlusion_impl_win.h
@@ -0,0 +1,100 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_EXTRA_WINDOW_OCCLUSION_IMPL_WIN_H_
+#define UI_AURA_EXTRA_WINDOW_OCCLUSION_IMPL_WIN_H_
+
+#include <windows.h>
+#include <winuser.h>
+
+#include "base/containers/flat_map.h"
+#include "base/macros.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/aura_extra/aura_extra_export.h"
+
+namespace aura_extra {
+
+// Delegate to get the native window bounds in pixels for a root aura::Window.
+class WindowBoundsDelegate {
+ public:
+  WindowBoundsDelegate() {}
+  virtual ~WindowBoundsDelegate() {}
+
+  // Gets the bounds in pixels for |window|.
+  virtual gfx::Rect GetBoundsInPixels(aura::WindowTreeHost* window) = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowBoundsDelegate);
+};
+
+// Stores internal state during occlusion computation by
+// ComputeNativeWindowOcclusionStatus().
+class AURA_EXTRA_EXPORT WindowEvaluator {
+ public:
+  WindowEvaluator() {}
+  // Called by NativeWindowIterator::Iterate and processes the metadata for a
+  // single window. It is assumed that this is called in reverse z-order
+  // (topmost window first, bottom window last). |is_relevant| describes if the
+  // window is relevant to this calculation (it is visible and fully opaque),
+  // |window_rect_in_pixels| is the bounds of the window in pixels, and |hwnd|
+  // is the HWND of the window. Returns false if no more windows need to be
+  // evaluated (this happens when all the desired occlusion states have been
+  // determined), true otherwise.
+  virtual bool EvaluateWindow(bool is_relevant,
+                              const gfx::Rect& window_rect_in_pixels,
+                              HWND hwnd) = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowEvaluator);
+};
+
+// Interface to enumerate through all the native windows. Overriden in tests to
+// avoid having to rely on the OS to enumerate native windows using
+// EnumWindows().
+class NativeWindowIterator {
+ public:
+  virtual ~NativeWindowIterator() {}
+
+  // Enumerates through a collection of windows and applies |evaluator| to each
+  // window. Enumeration is done from topmost to bottommost in the z-order, and
+  // will stop once the evaluator returns false.
+  virtual void Iterate(WindowEvaluator* evaluator) = 0;
+};
+
+class AURA_EXTRA_EXPORT WindowsDesktopWindowIterator
+    : public NativeWindowIterator {
+ public:
+  WindowsDesktopWindowIterator();
+
+  // NativeWindowIterator:
+  void Iterate(WindowEvaluator* evaluator) override;
+
+ private:
+  // Runs |evaluator_| for |hwnd|. Returns TRUE if the evaluator should be run
+  // again, FALSE otherwise.
+  BOOL RunEvaluator(HWND hwnd);
+
+  static BOOL CALLBACK EnumWindowsOcclusionCallback(HWND hwnd, LPARAM lParam);
+
+  WindowEvaluator* evaluator_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowsDesktopWindowIterator);
+};
+
+// Returns true if we are interested in |hwnd| for purposes of occlusion
+// calculation. We are interested in |hwnd| if it is a window that is visible,
+// opaque, and a simple rectangle. If we are interested in |hwnd|, stores the
+// window rectangle in |rect|
+bool AURA_EXTRA_EXPORT IsWindowVisibleAndFullyOpaque(HWND hwnd,
+                                                     gfx::Rect* rect_in_pixels);
+
+// Implementation of ComputeNativeWindowOcclusionStatus().
+base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState>
+    AURA_EXTRA_EXPORT ComputeNativeWindowOcclusionStatusImpl(
+        const std::vector<aura::WindowTreeHost*>& windows,
+        std::unique_ptr<NativeWindowIterator> iterator,
+        std::unique_ptr<WindowBoundsDelegate> bounds_delegate);
+
+}  // namespace aura_extra
+
+#endif  // UI_AURA_EXTRA_WINDOW_OCCLUSION_IMPL_WIN_H_
diff --git a/ui/aura_extra/window_occlusion_win.cc b/ui/aura_extra/window_occlusion_win.cc
new file mode 100644
index 0000000..9a8c4be7
--- /dev/null
+++ b/ui/aura_extra/window_occlusion_win.cc
@@ -0,0 +1,48 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_extra/window_occlusion_win.h"
+
+#include "ui/aura_extra/window_occlusion_impl_win.h"
+
+namespace aura_extra {
+
+namespace {
+
+// Default implementation of WindowBoundsDelegate using GetWindowRect().
+class WindowBoundsDelegateImpl : public WindowBoundsDelegate {
+ public:
+  WindowBoundsDelegateImpl();
+  ~WindowBoundsDelegateImpl() override {}
+
+  // WindowBoundsDelegate:
+  gfx::Rect GetBoundsInPixels(aura::WindowTreeHost* window) override;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowBoundsDelegateImpl);
+};
+
+WindowBoundsDelegateImpl::WindowBoundsDelegateImpl() = default;
+
+gfx::Rect WindowBoundsDelegateImpl::GetBoundsInPixels(
+    aura::WindowTreeHost* window) {
+  HWND hwnd = window->GetAcceleratedWidget();
+  RECT window_rect_in_pixels;
+
+  bool success = GetWindowRect(hwnd, &window_rect_in_pixels);
+  DCHECK(success);
+
+  return gfx::Rect(window_rect_in_pixels);
+}
+
+}  // namespace
+
+base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState>
+ComputeNativeWindowOcclusionStatus(
+    const std::vector<aura::WindowTreeHost*>& windows) {
+  return ComputeNativeWindowOcclusionStatusImpl(
+      windows, std::make_unique<WindowsDesktopWindowIterator>(),
+      std::make_unique<WindowBoundsDelegateImpl>());
+}
+
+}  // namespace aura_extra
diff --git a/ui/aura_extra/window_occlusion_win.h b/ui/aura_extra/window_occlusion_win.h
new file mode 100644
index 0000000..9e0096907
--- /dev/null
+++ b/ui/aura_extra/window_occlusion_win.h
@@ -0,0 +1,26 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_EXTRA_WINDOW_OCCLUSION_WIN_H_
+#define UI_AURA_EXTRA_WINDOW_OCCLUSION_WIN_H_
+
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/aura_extra/aura_extra_export.h"
+
+namespace aura_extra {
+
+// Computes the native window occlusion status for each aura::WindowTreeHost in
+// |windows|.
+AURA_EXTRA_EXPORT
+base::flat_map<aura::WindowTreeHost*, aura::Window::OcclusionState>
+ComputeNativeWindowOcclusionStatus(
+    const std::vector<aura::WindowTreeHost*>& windows);
+
+}  // namespace aura_extra
+
+#endif  // UI_AURA_EXTRA_WINDOW_OCCLUSION_WIN_H
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index b209b39..64d19b6 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -210,7 +210,6 @@
     "l10n/l10n_util_collator.h",
     "l10n/l10n_util_mac.h",
     "l10n/l10n_util_mac.mm",
-    "l10n/l10n_util_posix.cc",
     "l10n/l10n_util_win.cc",
     "l10n/l10n_util_win.h",
     "l10n/time_format.cc",
@@ -325,6 +324,10 @@
     "work_area_watcher_observer.h",
   ]
 
+  if (is_posix) {
+    sources += [ "l10n/l10n_util_posix.cc" ]
+  }
+
   if (!is_ios) {
     sources += [
       "accelerators/accelerator.cc",
@@ -394,6 +397,7 @@
   if (is_fuchsia) {
     sources += [
       "idle/idle_fuchsia.cc",
+      "l10n/l10n_util_posix.cc",
       "resource/resource_bundle_fuchsia.cc",
     ]
   }
diff --git a/ui/display/display_switches.cc b/ui/display/display_switches.cc
index 880fba6..72da86a 100644
--- a/ui/display/display_switches.cc
+++ b/ui/display/display_switches.cc
@@ -76,13 +76,7 @@
 // TODO(malaykeshav): Remove this in M68 when the feature has been in stable for
 // atleast one milestone.
 constexpr base::Feature kEnableDisplayZoomSetting{
-  "EnableDisplayZoomSetting",
-#if defined(OS_CHROMEOS)
-      base::FEATURE_ENABLED_BY_DEFAULT
-#else
-      base::FEATURE_DISABLED_BY_DEFAULT
-#endif
-};
+    "EnableDisplayZoomSetting", base::FEATURE_DISABLED_BY_DEFAULT};
 
 bool IsDisplayZoomSettingEnabled() {
   return base::FeatureList::IsEnabled(kEnableDisplayZoomSetting);
diff --git a/ui/display/manager/display_layout_store.h b/ui/display/manager/display_layout_store.h
index 878e4cd..5c68352 100644
--- a/ui/display/manager/display_layout_store.h
+++ b/ui/display/manager/display_layout_store.h
@@ -22,10 +22,15 @@
   DisplayLayoutStore();
   ~DisplayLayoutStore();
 
-  // Set true to force mirror mode.
-  void set_forced_mirror_mode(bool forced) { forced_mirror_mode_ = forced; }
+  // Set true to force mirror mode. This should only be used when tablet mode is
+  // turned on/off.
+  void set_forced_mirror_mode_for_tablet(bool forced) {
+    forced_mirror_mode_for_tablet_ = forced;
+  }
 
-  bool forced_mirror_mode() const { return forced_mirror_mode_; }
+  bool forced_mirror_mode_for_tablet() const {
+    return forced_mirror_mode_for_tablet_;
+  }
 
   void SetDefaultDisplayPlacement(const DisplayPlacement& placement);
 
@@ -50,7 +55,7 @@
   // The default display placement.
   DisplayPlacement default_display_placement_;
 
-  bool forced_mirror_mode_ = false;
+  bool forced_mirror_mode_for_tablet_ = false;
 
   // Display layout per list of devices.
   std::map<DisplayIdList, std::unique_ptr<DisplayLayout>> layouts_;
diff --git a/ui/display/manager/display_manager.cc b/ui/display/manager/display_manager.cc
index 5301ee42..f1cccf22 100644
--- a/ui/display/manager/display_manager.cc
+++ b/ui/display/manager/display_manager.cc
@@ -1283,7 +1283,7 @@
 
 bool DisplayManager::ShouldSetMirrorModeOn(const DisplayIdList& new_id_list) {
   DCHECK(new_id_list.size() > 1);
-  if (layout_store_->forced_mirror_mode())
+  if (layout_store_->forced_mirror_mode_for_tablet())
     return true;
 
   if (disable_restoring_mirror_mode_for_test_)
@@ -1406,7 +1406,10 @@
 bool DisplayManager::IsSoftwareMirroringEnforced() const {
   // There is no source display for hardware mirroring, so enforce software
   // mirroring if the mixed mirror mode parameters are specified.
-  return !!mixed_mirror_mode_params_;
+  // Enforce software mirroring if tablet mode is enabled as well because
+  // the tablet's rotation should be offset in external display.
+  return !!mixed_mirror_mode_params_ ||
+         layout_store_->forced_mirror_mode_for_tablet();
 }
 
 void DisplayManager::SetTouchCalibrationData(
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index dee370bf..42e62a1 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -159,7 +159,6 @@
     "win/keyboard_hook_win.cc",
     "win/system_event_state_lookup.cc",
     "win/system_event_state_lookup.h",
-    "x/keyboard_hook_posix.cc",
   ]
 
   defines = [ "EVENTS_IMPLEMENTATION" ]
@@ -179,7 +178,10 @@
   ]
 
   if (use_x11) {
-    sources += [ "x/events_x.cc" ]
+    sources += [
+      "x/events_x.cc",
+      "x/keyboard_hook_posix.cc",
+    ]
     configs += [ "//build/config/linux:x11" ]
     deps += [
       "//ui/events/devices",
diff --git a/ui/file_manager/file_manager/background/js/media_import_handler.js b/ui/file_manager/file_manager/background/js/media_import_handler.js
index c2655e5..5aa28d5 100644
--- a/ui/file_manager/file_manager/background/js/media_import_handler.js
+++ b/ui/file_manager/file_manager/background/js/media_import_handler.js
@@ -242,7 +242,7 @@
     tracker) {
 
   importer.TaskQueue.BaseTask.call(this, taskId);
-  /** @private {string} */
+  /** @protected {string} */
   this.taskId_ = taskId;
 
   /** @private {!importer.Destination} */
diff --git a/ui/file_manager/file_manager/background/js/task_queue.js b/ui/file_manager/file_manager/background/js/task_queue.js
index 0170b28..1f1adea 100644
--- a/ui/file_manager/file_manager/background/js/task_queue.js
+++ b/ui/file_manager/file_manager/background/js/task_queue.js
@@ -178,7 +178,7 @@
  * @param {string} taskId
  */
 importer.TaskQueue.BaseTask = function(taskId) {
-  /** @private {string} */
+  /** @protected {string} */
   this.taskId_ = taskId;
   /** @private {!Array<!importer.TaskQueue.Task.Observer>} */
   this.observers_ = [];
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index 7a2865d..9bc1e8fe 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -324,7 +324,6 @@
  * returns it.
  * @param {string} query Query for the element.
  * @param {function(new: T, ...)} type Type used to decorate.
- * @private
  * @template T
  * @return {!T} Decorated element.
  */
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index b687fd73..0e6da8e 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -1680,6 +1680,11 @@
       url(../images/files/ui/2x/person_add.png) 2x);
 }
 
+#action-bar {
+  display: flex;
+  flex: none;
+}
+
 .detail-name > * {
   align-items: center;
   display: flex;
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 acac23f3..0d4eb71 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -268,10 +268,11 @@
 
   if (!this.ignoreCurrentDirectoryDeletion_) {
     // If the change is deletion of currentDir, move up to its parent directory.
-    directoryEntry.getDirectory(directoryEntry.fullPath, {create: false},
-        function() {},
+    directoryEntry.getDirectory(
+        directoryEntry.fullPath, {create: false}, function() {},
         function() {
-          var volumeInfo = this.volumeManager_.getVolumeInfo(directoryEntry);
+          var volumeInfo =
+              this.volumeManager_.getVolumeInfo(assert(directoryEntry));
           if (volumeInfo) {
             volumeInfo.resolveDisplayRoot().then(function(displayRoot) {
               this.changeDirectoryEntry(displayRoot);
@@ -1156,8 +1157,8 @@
   // When the volume where we are is unmounted, fallback to the default volume's
   // root. If current directory path is empty, stop the fallback
   // since the current directory is initializing now.
-  if (this.getCurrentDirEntry() &&
-      !this.volumeManager_.getVolumeInfo(this.getCurrentDirEntry())) {
+  var entry = this.getCurrentDirEntry();
+  if (entry && !this.volumeManager_.getVolumeInfo(entry)) {
     this.volumeManager_.getDefaultDisplayRoot(function(displayRoot) {
       this.changeDirectoryEntry(displayRoot);
     }.bind(this));
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index 95c9035..0a55cc2 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -548,7 +548,7 @@
     if (!root)
       root = directoryModel.getCurrentDirEntry();
 
-    var volumeInfo = fileManager.volumeManager.getVolumeInfo(root);
+    var volumeInfo = fileManager.volumeManager.getVolumeInfo(assert(root));
     if (volumeInfo) {
       fileManager.ui.confirmDialog.show(
           loadTimeData.getString('FORMATTING_WARNING'),
@@ -1051,8 +1051,9 @@
         event.target instanceof DirectoryItem) {
       var isRemovableRoot = false;
       var entry = CommandUtil.getCommandEntry(event.target);
+      var volumeInfo = null;
       if (entry) {
-        var volumeInfo = fileManager.volumeManager.getVolumeInfo(entry);
+        volumeInfo = fileManager.volumeManager.getVolumeInfo(entry);
         // Checks whether the target is actually external drive or just a folder
         // inside the drive.
         if (volumeInfo &&
@@ -1761,6 +1762,25 @@
 });
 
 /**
+ * Focus the first button visible on action bar (at the top).
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['focus-action-bar'] = /** @type {Command} */ ({
+  /**
+   * @param {!Event} event Command event.
+   * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
+   */
+  execute: function(event, fileManager) {
+    fileManager.ui.actionbar.querySelector('button:not([hidden])').focus();
+  },
+  /**
+   * @param {!Event} event Command event.
+   * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
+   */
+  canExecute: CommandUtil.canExecuteAlways
+});
+
+/**
  * Handle back button.
  * @type {Command}
  */
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index 7e9f05d..1e1d1a34 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -516,7 +516,6 @@
  *
  * @param {function(boolean, Array<!Entry>)=} opt_callback Called when the
  *     default task is executed, or the error is occurred.
- * @private
  */
 FileTasks.prototype.executeDefault = function(opt_callback) {
   FileTasks.recordViewingFileTypeUMA_(this.entries_);
@@ -652,7 +651,6 @@
  * Executes a single task.
  *
  * @param {string} taskId Task identifier.
- * @private
  */
 FileTasks.prototype.execute = function(taskId) {
   FileTasks.recordViewingFileTypeUMA_(this.entries_);
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
index 087a7795..aa5b5ff 100644
--- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
+++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
@@ -244,7 +244,7 @@
   var entry = /** @type {Entry} */ (this.dataModel_.item(this.cursor_));
 
   // Check volume type for optimizing the parameters.
-  var volumeInfo = this.volumeManager_.getVolumeInfo(entry);
+  var volumeInfo = this.volumeManager_.getVolumeInfo(assert(entry));
   this.currentVolumeType_ = volumeInfo ? volumeInfo.volumeType : null;
 
   // If tasks are running full or all items are scanned, do nothing.
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
index 098a64e..9f8a7b28 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
@@ -200,7 +200,7 @@
 
   this.shortcutList_ = [];
   for (var i = 0; i < this.shortcutListModel_.length; i++) {
-    var shortcutEntry = /** @type {Entry} */ (this.shortcutListModel_.item(i));
+    var shortcutEntry = /** @type {!Entry} */ (this.shortcutListModel_.item(i));
     var volumeInfo = this.volumeManager_.getVolumeInfo(shortcutEntry);
     this.shortcutList_.push(entryToModelItem(shortcutEntry));
   }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners.js b/ui/file_manager/file_manager/foreground/js/ui/banners.js
index f21eef6..408c7f5 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners.js
@@ -554,7 +554,7 @@
   if (!this.directoryModel_.getCurrentDirEntry())
     return;
 
-  var currentDirEntry = this.directoryModel_.getCurrentDirEntry();
+  var currentDirEntry = assert(this.directoryModel_.getCurrentDirEntry());
   var currentVolume = currentDirEntry &&
       this.volumeManager_.getVolumeInfo(currentDirEntry);
   var eventVolume = this.volumeManager_.getVolumeInfo(event.entry);
@@ -592,10 +592,9 @@
     return;
 
   chrome.fileManagerPrivate.getSizeStats(
-      volume.volumeId,
-      function(sizeStats) {
+      volume.volumeId, function(sizeStats) {
         var currentVolume = this.volumeManager_.getVolumeInfo(
-            this.directoryModel_.getCurrentDirEntry());
+            assert(this.directoryModel_.getCurrentDirEntry()));
         if (volume !== currentVolume) {
           // This happens when the current directory is moved during requesting
           // the file system size. Just ignore it.
diff --git a/ui/file_manager/file_manager/foreground/js/ui/error_dialog.js b/ui/file_manager/file_manager/foreground/js/ui/error_dialog.js
index 63515a6f..6a70b68 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/error_dialog.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/error_dialog.js
@@ -17,7 +17,7 @@
 
 /**
  * One-time initialization of DOM.
- * @private
+ * @protected
  */
 ErrorDialog.prototype.initDom_ = function() {
   cr.ui.dialogs.BaseDialog.prototype.initDom_.call(this);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
index eb67a386..af808be 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -117,7 +117,6 @@
 /**
  * Sets list thumbnail loader.
  * @param {ListThumbnailLoader} listThumbnailLoader A list thumbnail loader.
- * @private
  */
 FileGrid.prototype.setListThumbnailLoader = function(listThumbnailLoader) {
   if (this.listThumbnailLoader_) {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
index b445455..abd6cd53 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -121,7 +121,6 @@
   /**
    * The container element of the dialog.
    * @type {!HTMLElement}
-   * @private
    */
   this.dialogContainer =
       queryRequiredElement('.dialog-container', this.element);
@@ -148,6 +147,14 @@
   this.toolbar = queryRequiredElement('.dialog-header', this.element);
 
   /**
+   * The actionbar which contains buttons to perform actions on selected
+   * file(s).
+   * @type {!HTMLElement}
+   * @const
+   */
+  this.actionbar = queryRequiredElement('#action-bar', this.toolbar);
+
+  /**
    * The navigation list.
    * @type {!HTMLElement}
    * @const
@@ -189,7 +196,7 @@
 
   /**
    * Ripple effect of sort button.
-   * @private {!FilesToggleRipple}
+   * @type {!FilesToggleRipple}
    * @const
    */
   this.sortButtonToggleRipple =
@@ -542,7 +549,7 @@
     }
   };
 
-  customSplitter.decorate(splitterElement);
+  /** @type Object */ (customSplitter).decorate(splitterElement);
   splitterElement.resizeNextElement = !!opt_resizeNextElement;
 };
 
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index 0ec9ea30..d69727d 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -482,7 +482,7 @@
     var currentSelection = [];
     var bottom = y + (opt_height || 0);
     for (var i = 0; i < this.selectionModel_.length; i++) {
-      var itemMetrics = this.getHeightsForIndex_(i);
+      var itemMetrics = this.getHeightsForIndex(i);
       if (itemMetrics.top < bottom && itemMetrics.top + itemMetrics.height >= y)
         currentSelection.push(i);
     }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js b/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
index 7cc90e7..3576bea 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
@@ -139,6 +139,7 @@
   // Overriding the default role 'list' to 'listbox' for better
   // accessibility on ChromeOS.
   li.setAttribute('role', 'option');
+  li.setAttribute('aria-describedby', 'more-actions-info');
 
   Object.defineProperty(li, 'selected', {
     /**
diff --git a/ui/file_manager/file_manager/foreground/js/ui/files_alert_dialog.js b/ui/file_manager/file_manager/foreground/js/ui/files_alert_dialog.js
index 3c1d404..b1e7cde 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/files_alert_dialog.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/files_alert_dialog.js
@@ -15,7 +15,7 @@
 FilesAlertDialog.prototype.__proto__ = cr.ui.dialogs.AlertDialog.prototype;
 
 /**
- * @private
+ * @protected
  * @override
  */
 FilesAlertDialog.prototype.initDom_ = function() {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/files_confirm_dialog.js b/ui/file_manager/file_manager/foreground/js/ui/files_confirm_dialog.js
index 85e03460..3be04f8 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/files_confirm_dialog.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/files_confirm_dialog.js
@@ -15,7 +15,7 @@
 FilesConfirmDialog.prototype.__proto__ = cr.ui.dialogs.ConfirmDialog.prototype;
 
 /**
- * @private
+ * @protected
  * @override
  */
 FilesConfirmDialog.prototype.initDom_ = function() {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js b/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js
index 3f94e0a..e6dcf93 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js
@@ -133,7 +133,7 @@
 
 /**
  * One-time initialization of DOM.
- * @private
+ * @protected
  */
 ShareDialog.prototype.initDom_ = function() {
   FileManagerDialogBase.prototype.initDom_.call(this);
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 52aa70bc..df35133b 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -172,6 +172,7 @@
                i18n-values="label:INSTALL_NEW_EXTENSION_LABEL">
       <command id="open-gear-menu" shortcut="e|Alt f|Alt">
       <command id="browser-back" shortcut="BrowserBack">
+      <command id="focus-action-bar" shortcut="a|Alt">
     </commands>
 
     <cr-menu id="file-context-menu" class="chrome-menu files-menu"
@@ -300,99 +301,101 @@
       </div>
       <div id="files-selected-label"></div>
       <div class="spacer"></div>
-      <button id="tasks" class="combobutton menu-button" menu="#tasks-menu"
-              tabindex="10" hidden
-              i18n-values="aria-label:TASKS_BUTTON_LABEL">
-      </button>
-      <button id="share-menu-button" class="icon-button menu-button" tabindex="11" hidden
-              menu="#share-menu"
-              i18n-values="aria-label:SHARE_BUTTON_TOOLTIP"
-              aria-activedescendant="share-menu"
-              has-tooltip>
-        <files-toggle-ripple></files-toggle-ripple>
-        <div class="icon"></div>
-      </button>
-      <button id="delete-button" class="icon-button menu-button" tabindex="12" hidden
-              i18n-values="aria-label:DELETE_BUTTON_LABEL"
-              visibleif="full-page"
-              has-tooltip>
-        <files-ripple></files-ripple>
-        <div class="icon"></div>
-      </button>
-      <button id="search-button" class="icon-button menu-button" tabindex="13"
-              i18n-values="aria-label:SEARCH_TEXT_LABEL"
-              has-tooltip>
-        <files-toggle-ripple></files-toggle-ripple>
-        <div class="icon"></div>
-      </button>
-      <div id="search-box">
-        <paper-input-container no-label-float>
-          <input is="iron-input" type="search" tabindex="14" slot="input"
-                 i18n-values="aria-label:SEARCH_TEXT_LABEL;placeholder:SEARCH_TEXT_LABEL"
-                 hidden>
-          <span class="clear" slot="suffix"></span>
-        </paper-input-container>
-      </div>
-      <button id="refresh-button" class="icon-button menu-button" tabindex="15" hidden
-              i18n-values="aria-label:REFRESH_BUTTON_LABEL"
-              command="#refresh" has-tooltip>
-        <files-ripple></files-ripple>
-        <div class="icon"></div>
-      </button>
-      <div id="cloud-import-combo-button"
-           class="cloud-import-combo-button"
-           hidden>
-        <div class="buttons">
-          <button id="cloud-import-button"
-                  class="icon-button menu-button"
-                  tabindex="16"
-                  i18n-values="aria-label:CLOUD_IMPORT_COMMAND"
-                  has-tooltip>
-            <iron-icon icon="files:cloud-queue"></iron-icon>
-          </button>
-          <button id="cloud-import-details-button"
-                  class="icon-button menu-button"
-                  tabindex="16"
-                  i18n-values="aria-label:CLOUD_IMPORT_SHOW_DETAILS"
-                  has-tooltip>
-            <iron-icon icon="files:arrow-drop-down"></iron-icon>
-          </button>
-        </div>
-        <div class="ripples">
-          <paper-ripple></paper-ripple>
+      <div id="action-bar">
+        <button id="tasks" class="combobutton menu-button" menu="#tasks-menu"
+                tabindex="10" hidden
+                i18n-values="aria-label:TASKS_BUTTON_LABEL">
+        </button>
+        <button id="share-menu-button" class="icon-button menu-button" tabindex="11" hidden
+                menu="#share-menu"
+                i18n-values="aria-label:SHARE_BUTTON_TOOLTIP"
+                aria-activedescendant="share-menu"
+                has-tooltip>
           <files-toggle-ripple></files-toggle-ripple>
+          <div class="icon"></div>
+        </button>
+        <button id="delete-button" class="icon-button menu-button" tabindex="12" hidden
+                i18n-values="aria-label:DELETE_BUTTON_LABEL"
+                visibleif="full-page"
+                has-tooltip>
+          <files-ripple></files-ripple>
+          <div class="icon"></div>
+        </button>
+        <button id="search-button" class="icon-button menu-button" tabindex="13"
+                i18n-values="aria-label:SEARCH_TEXT_LABEL"
+                has-tooltip>
+          <files-toggle-ripple></files-toggle-ripple>
+          <div class="icon"></div>
+        </button>
+        <div id="search-box">
+          <paper-input-container no-label-float>
+            <input is="iron-input" type="search" tabindex="14" slot="input"
+                   i18n-values="aria-label:SEARCH_TEXT_LABEL;placeholder:SEARCH_TEXT_LABEL"
+                   hidden>
+            <span class="clear" slot="suffix"></span>
+          </paper-input-container>
         </div>
+        <button id="refresh-button" class="icon-button menu-button" tabindex="15" hidden
+                i18n-values="aria-label:REFRESH_BUTTON_LABEL"
+                command="#refresh" has-tooltip>
+          <files-ripple></files-ripple>
+          <div class="icon"></div>
+        </button>
+        <div id="cloud-import-combo-button"
+             class="cloud-import-combo-button"
+             hidden>
+          <div class="buttons">
+            <button id="cloud-import-button"
+                    class="icon-button menu-button"
+                    tabindex="16"
+                    i18n-values="aria-label:CLOUD_IMPORT_COMMAND"
+                    has-tooltip>
+              <iron-icon icon="files:cloud-queue"></iron-icon>
+            </button>
+            <button id="cloud-import-details-button"
+                    class="icon-button menu-button"
+                    tabindex="16"
+                    i18n-values="aria-label:CLOUD_IMPORT_SHOW_DETAILS"
+                    has-tooltip>
+              <iron-icon icon="files:arrow-drop-down"></iron-icon>
+            </button>
+          </div>
+          <div class="ripples">
+            <paper-ripple></paper-ripple>
+            <files-toggle-ripple></files-toggle-ripple>
+          </div>
+        </div>
+        <button id="view-button" class="icon-button menu-button" tabindex="17"
+                i18n-values="aria-label:CHANGE_TO_THUMBNAILVIEW_BUTTON_LABEL"
+                has-tooltip>
+          <files-ripple></files-ripple>
+          <div class="icon"></div>
+        </button>
+        <button id="sort-button" class="icon-button menu-button" tabindex="18"
+                menu="#sort-menu"
+                i18n-values="aria-label:SORT_BUTTON_TOOLTIP"
+                aria-activedescendant="sort-menu"
+                has-tooltip>
+          <files-toggle-ripple></files-toggle-ripple>
+          <div class="icon"></div>
+        </button>
+        <button id="gear-button" class="icon-button menu-button" tabindex="19"
+                menu="#gear-menu"
+                i18n-values="aria-label:GEAR_BUTTON_TOOLTIP"
+                aria-activedescendant="gear-menu"
+                has-tooltip>
+          <files-toggle-ripple></files-toggle-ripple>
+          <div class="icon"></div>
+        </button>
+        <button id="selection-menu-button" class="icon-button menu-button" tabindex="19"
+                menu="#file-context-menu"
+                i18n-values="aria-label:SELECTION_MENU_BUTTON_TOOLTIP"
+                aria-activedescendant="file-context-menu"
+                has-tooltip hidden>
+          <files-toggle-ripple></files-toggle-ripple>
+          <div class="icon"></div>
+        </button>
       </div>
-      <button id="view-button" class="icon-button menu-button" tabindex="17"
-              i18n-values="aria-label:CHANGE_TO_THUMBNAILVIEW_BUTTON_LABEL"
-              has-tooltip>
-        <files-ripple></files-ripple>
-        <div class="icon"></div>
-      </button>
-      <button id="sort-button" class="icon-button menu-button" tabindex="18"
-              menu="#sort-menu"
-              i18n-values="aria-label:SORT_BUTTON_TOOLTIP"
-              aria-activedescendant="sort-menu"
-              has-tooltip>
-        <files-toggle-ripple></files-toggle-ripple>
-        <div class="icon"></div>
-      </button>
-      <button id="gear-button" class="icon-button menu-button" tabindex="19"
-              menu="#gear-menu"
-              i18n-values="aria-label:GEAR_BUTTON_TOOLTIP"
-              aria-activedescendant="gear-menu"
-              has-tooltip>
-        <files-toggle-ripple></files-toggle-ripple>
-        <div class="icon"></div>
-      </button>
-      <button id="selection-menu-button" class="icon-button menu-button" tabindex="19"
-              menu="#file-context-menu"
-              i18n-values="aria-label:SELECTION_MENU_BUTTON_TOOLTIP"
-              aria-activedescendant="file-context-menu"
-              has-tooltip hidden>
-        <files-toggle-ripple></files-toggle-ripple>
-        <div class="icon"></div>
-      </button>
     </div>
 
     <div id="cloud-import-details" class="hidden" hidden>
@@ -459,6 +462,7 @@
                 Welcome to the new epic photo importer!
               </div>
               <div id="list-container">
+                <div id="more-actions-info" i18n-content="SEE_MENU_FOR_ACTIONS" hidden></div>
                 <div id="empty-folder" hidden>
                   <div class="image"></div>
                   <span id="empty-folder-label" class="label" i18n-content="EMPTY_FOLDER"></span>
diff --git a/ui/file_manager/gallery/js/background.js b/ui/file_manager/gallery/js/background.js
index c4ddb512..d5b9ac2 100644
--- a/ui/file_manager/gallery/js/background.js
+++ b/ui/file_manager/gallery/js/background.js
@@ -29,8 +29,8 @@
  * Gallery app window wrapper.
  * @type {!SingletonAppWindowWrapper}
  */
-var gallery = new SingletonAppWindowWrapper('gallery.html',
-    windowCreateOptions);
+var galleryWrapper =
+    new SingletonAppWindowWrapper('gallery.html', windowCreateOptions);
 
 /**
  * Opens gallery window.
@@ -39,41 +39,46 @@
  */
 function openGalleryWindow(urls) {
   return new Promise(function(fulfill, reject) {
-    util.URLsToEntries(urls).then(function(result) {
-      fulfill(util.entriesToURLs(result.entries));
-    }).catch(reject);
-  }).then(function(urls) {
-    if (urls.length === 0)
-      return Promise.reject('No file to open.');
+           util.URLsToEntries(urls)
+               .then(function(result) {
+                 fulfill(util.entriesToURLs(result.entries));
+               })
+               .catch(reject);
+         })
+      .then(function(urls) {
+        if (urls.length === 0)
+          return Promise.reject('No file to open.');
 
-    // Opens a window.
-    return new Promise(function(fulfill, reject) {
-      gallery.launch(
-          {urls: urls},
-          false,
-          fulfill.bind(null, gallery));
-    }).then(function(gallery) {
-      var galleryDocument = gallery.rawAppWindow.contentWindow.document;
-      if (galleryDocument.readyState == 'complete')
-        return gallery;
+        // Opens a window.
+        return new Promise(function(fulfill, reject) {
+                 galleryWrapper.launch(
+                     {urls: urls}, false, fulfill.bind(null, galleryWrapper));
+               })
+            .then(function(galleryWrapper) {
+              var galleryWrapperDocument =
+                  galleryWrapper.rawAppWindow.contentWindow.document;
+              if (galleryWrapperDocument.readyState == 'complete')
+                return galleryWrapper;
 
-      return new Promise(function(fulfill, reject) {
-        galleryDocument.addEventListener(
-            'DOMContentLoaded', fulfill.bind(null, gallery));
+              return new Promise(function(fulfill, reject) {
+                galleryWrapperDocument.addEventListener(
+                    'DOMContentLoaded', fulfill.bind(null, galleryWrapper));
+              });
+            });
+      })
+      .then(function(galleryWrapper) {
+        // If the window is minimized, we need to restore it first.
+        if (galleryWrapper.rawAppWindow.isMinimized())
+          galleryWrapper.rawAppWindow.restore();
+
+        galleryWrapper.rawAppWindow.show();
+
+        return galleryWrapper.rawAppWindow.contentWindow.appID;
+      })
+      .catch(function(error) {
+        console.error('Launch failed' + error.stack || error);
+        return Promise.reject(error);
       });
-    });
-  }).then(function(gallery) {
-    // If the window is minimized, we need to restore it first.
-    if (gallery.rawAppWindow.isMinimized())
-      gallery.rawAppWindow.restore();
-
-    gallery.rawAppWindow.show();
-
-    return gallery.rawAppWindow.contentWindow.appID;
-  }).catch(function(error) {
-    console.error('Launch failed' + error.stack || error);
-    return Promise.reject(error);
-  });
 }
 
 background.setLaunchHandler(openGalleryWindow);
diff --git a/ui/file_manager/gallery/js/entry_list_watcher.js b/ui/file_manager/gallery/js/entry_list_watcher.js
index 453a29d..35fda26b 100644
--- a/ui/file_manager/gallery/js/entry_list_watcher.js
+++ b/ui/file_manager/gallery/js/entry_list_watcher.js
@@ -37,7 +37,6 @@
 /**
  * Obtains entry from ArrayDataModel's item.
  * @param {*} item Item in ArrayDataModel.
- * @protected
  * @return {!FileEntry}
  */
 EntryListWatcher.prototype.getEntry = function(item) {
diff --git a/ui/file_manager/gallery/js/image_editor/image_editor_mode.js b/ui/file_manager/gallery/js/image_editor/image_editor_mode.js
index 64b02d62a..b7914ac7 100644
--- a/ui/file_manager/gallery/js/image_editor/image_editor_mode.js
+++ b/ui/file_manager/gallery/js/image_editor/image_editor_mode.js
@@ -40,13 +40,11 @@
 
   /**
    * @type {Viewport}
-   * @private
    */
   this.viewport_ = null;
 
   /**
    * @type {HTMLElement}
-   * @private
    */
   this.button_ = null;
 
@@ -58,7 +56,6 @@
 
   /**
    * @type {boolean}
-   * @private
    */
   this.updated_ = false;
 
@@ -67,7 +64,7 @@
    * @private
    */
   this.imageView_ = null;
-};
+}
 
 ImageEditorMode.prototype = {
   __proto__: ImageBuffer.Overlay.prototype
diff --git a/ui/file_manager/gallery/js/image_editor/image_view.js b/ui/file_manager/gallery/js/image_editor/image_view.js
index a75282d7..6333f02 100644
--- a/ui/file_manager/gallery/js/image_editor/image_view.js
+++ b/ui/file_manager/gallery/js/image_editor/image_view.js
@@ -666,7 +666,6 @@
  *     transformation.
  * @param {ImageView.Effect=} opt_effect The effect to apply.
  * @param {number=} opt_duration Transition duration.
- * @private
  */
 ImageView.prototype.setTransform_ = function(
     element, viewport, opt_effect, opt_duration) {
diff --git a/ui/file_manager/integration_tests/audio_player/background.js b/ui/file_manager/integration_tests/audio_player/background.js
index 2638afc..973a752 100644
--- a/ui/file_manager/integration_tests/audio_player/background.js
+++ b/ui/file_manager/integration_tests/audio_player/background.js
@@ -56,24 +56,29 @@
  */
 var testcase = {};
 
-// Ensure the test cases are loaded.
+/**
+ * When the FileManagerBrowserTest harness loads this test extension, request
+ * configuration and other details from that harness, including the test case
+ * name to run. Use the configuration/details to setup the test ennvironment,
+ * then run the test case using chrome.test.RunTests.
+ */
 window.addEventListener('load', function() {
   var steps = [
-    // Check for the guest mode.
+    // Request the guest mode state.
     function() {
       chrome.test.sendMessage(
           JSON.stringify({name: 'isInGuestMode'}), steps.shift());
     },
-    // Obtain the test case name.
-    function(result) {
-      if (JSON.parse(result) != chrome.extension.inIncognitoContext)
+    // Request the root entry paths.
+    function(mode) {
+      if (JSON.parse(mode) != chrome.extension.inIncognitoContext)
         return;
       chrome.test.sendMessage(
           JSON.stringify({name: 'getRootPaths'}), steps.shift());
     },
-    // Obtain the root entry paths.
-    function(result) {
-      var roots = JSON.parse(result);
+    // Request the test case name.
+    function(paths) {
+      var roots = JSON.parse(paths);
       RootPath.DOWNLOADS = roots.downloads;
       RootPath.DRIVE = roots.drive;
       chrome.test.sendMessage(
@@ -81,16 +86,23 @@
     },
     // Run the test case.
     function(testCaseName) {
-      var targetTest = testcase[testCaseName];
-      if (!targetTest) {
-        chrome.test.fail(testCaseName + ' is not found.');
+      // Get the test function from testcase namespace testCaseName.
+      var test = testcase[testCaseName];
+      // Verify test is an unnamed (aka 'anonymous') Function.
+      if (!test instanceof Function || test.name) {
+        chrome.test.fail('[' + testCaseName + '] not found.');
         return;
       }
-      // Specify the name of test to the test system.
-      targetTest.generatedName = testCaseName;
-      chrome.test.runTests([function() {
-        return testPromiseAndApps(targetTest(), [remoteCallAudioPlayer]);
-      }]);
+      // Define the test case and its name for chrome.test logging.
+      test.generatedName = testCaseName;
+      var testCaseSymbol = Symbol(testCaseName);
+      var testCase = {
+        [testCaseSymbol] :() => {
+          return testPromiseAndApps(test(), [remoteCallAudioPlayer]);
+        },
+      };
+      // Run the test.
+      chrome.test.runTests([testCase[testCaseSymbol]]);
     }
   ];
   steps.shift()();
diff --git a/ui/file_manager/integration_tests/file_manager/background.js b/ui/file_manager/integration_tests/file_manager/background.js
index 0d1837a..ed671c1 100644
--- a/ui/file_manager/integration_tests/file_manager/background.js
+++ b/ui/file_manager/integration_tests/file_manager/background.js
@@ -374,24 +374,29 @@
  */
 var testcase = {};
 
-// Ensure the test cases are loaded.
+/**
+ * When the FileManagerBrowserTest harness loads this test extension, request
+ * configuration and other details from that harness, including the test case
+ * name to run. Use the configuration/details to setup the test ennvironment,
+ * then run the test case using chrome.test.RunTests.
+ */
 window.addEventListener('load', function() {
   var steps = [
-    // Check for the guest mode.
+    // Request the guest mode state.
     function() {
       chrome.test.sendMessage(
           JSON.stringify({name: 'isInGuestMode'}), steps.shift());
     },
-    // Obtain the test case name.
-    function(result) {
-      if (JSON.parse(result) != chrome.extension.inIncognitoContext)
+    // Request the root entry paths.
+    function(mode) {
+      if (JSON.parse(mode) != chrome.extension.inIncognitoContext)
         return;
       chrome.test.sendMessage(
           JSON.stringify({name: 'getRootPaths'}), steps.shift());
     },
-    // Obtain the root entry paths.
-    function(result) {
-      var roots = JSON.parse(result);
+    // Request the test case name.
+    function(paths) {
+      var roots = JSON.parse(paths);
       RootPath.DOWNLOADS = roots.downloads;
       RootPath.DRIVE = roots.drive;
       chrome.test.sendMessage(
@@ -399,14 +404,23 @@
     },
     // Run the test case.
     function(testCaseName) {
-      var targetTest = testcase[testCaseName];
-      if (!targetTest) {
-        chrome.test.fail(testCaseName + ' is not found.');
+      // Get the test function from testcase namespace testCaseName.
+      var test = testcase[testCaseName];
+      // Verify test is an unnamed (aka 'anonymous') Function.
+      if (!test instanceof Function || test.name) {
+        chrome.test.fail('[' + testCaseName + '] not found.');
         return;
       }
-      // Specify the name of test to the test system.
-      targetTest.generatedName = testCaseName;
-      chrome.test.runTests([targetTest]);
+      // Define the test case and its name for chrome.test logging.
+      test.generatedName = testCaseName;
+      var testCaseSymbol = Symbol(testCaseName);
+      var testCase = {
+        [testCaseSymbol] :() => {
+          return test();
+        },
+      };
+      // Run the test.
+      chrome.test.runTests([testCase[testCaseSymbol]]);
     }
   ];
   steps.shift()();
diff --git a/ui/file_manager/integration_tests/file_manager/providers.js b/ui/file_manager/integration_tests/file_manager/providers.js
index 04b8c26f..d61eb15 100644
--- a/ui/file_manager/integration_tests/file_manager/providers.js
+++ b/ui/file_manager/integration_tests/file_manager/providers.js
@@ -175,27 +175,34 @@
   ]);
 }
 
-function requestMount() {
-  requestMountInternal(false /* multipleMounts */, 'manifest.json');
-}
+/**
+ * Tests mounting a single mount point in the button menu.
+ */
+testcase.requestMount = function() {
+  const multipleMounts = false;
+  requestMountInternal(multipleMounts, 'manifest.json');
+};
 
-function requestMountMultipleMounts() {
-  requestMountInternal(
-      true /* multipleMounts */, 'manifest_multiple_mounts.json');
-}
+/**
+ * Tests mounting multiple mount points in the button menu.
+ */
+testcase.requestMountMultipleMounts = function() {
+  const multipleMounts = true;
+  requestMountInternal(multipleMounts, 'manifest_multiple_mounts.json');
+};
 
-function requestMountSourceDevice() {
+/**
+ * Tests mounting a device not present in the button menu.
+ */
+testcase.requestMountSourceDevice = function() {
   requestMountNotInMenuInternal('manifest_source_device.json');
-}
+};
 
-function requestMountSourceFile() {
+/**
+ * Tests mounting a file not present in the button menu.
+ */
+testcase.requestMountSourceFile = function() {
   requestMountNotInMenuInternal('manifest_source_file.json');
-}
-
-// Exports test functions.
-testcase.requestMount = requestMount;
-testcase.requestMountMultipleMounts = requestMountMultipleMounts;
-testcase.requestMountSourceDevice = requestMountSourceDevice;
-testcase.requestMountSourceFile = requestMountSourceFile;
+};
 
 })();
diff --git a/ui/file_manager/integration_tests/file_manager/transfer.js b/ui/file_manager/integration_tests/file_manager/transfer.js
index 8806cf1..bc5f1668 100644
--- a/ui/file_manager/integration_tests/file_manager/transfer.js
+++ b/ui/file_manager/integration_tests/file_manager/transfer.js
@@ -96,68 +96,82 @@
   ]);
 }
 
-/**
- * Tests copy from drive's root to local's downloads.
- */
-testcase.transferFromDriveToDownloads = copyBetweenVolumes.bind(
-    null,
-    ENTRIES.hello,
-    'drive',
-    BASIC_DRIVE_ENTRY_SET,
-    'downloads',
-    BASIC_LOCAL_ENTRY_SET);
+// TODO(noel): transfer implies move to some. Change these test names to say
+// "copy" rather than "transfer" because all these tests copy something from
+// a volume to another volume.
 
 /**
- * Tests copy from local's downloads to drive's root.
+ * Tests copying from Drive to Downloads.
  */
-testcase.transferFromDownloadsToDrive = copyBetweenVolumes.bind(
-    null,
-    ENTRIES.hello,
-    'downloads',
-    BASIC_LOCAL_ENTRY_SET,
-    'drive',
-    BASIC_DRIVE_ENTRY_SET);
+testcase.transferFromDriveToDownloads = function() {
+  copyBetweenVolumes(
+      ENTRIES.hello,
+      'drive',
+      BASIC_DRIVE_ENTRY_SET,
+      'downloads',
+      BASIC_LOCAL_ENTRY_SET);
+};
 
 /**
- * Tests copy from drive's shared_with_me to local's downloads.
+ * Tests copying from Downloads to Drive.
  */
-testcase.transferFromSharedToDownloads = copyBetweenVolumes.bind(
-    null,
-    ENTRIES.testSharedDocument,
-    'drive_shared_with_me',
-    SHARED_WITH_ME_ENTRY_SET,
-    'downloads',
-    BASIC_LOCAL_ENTRY_SET);
+testcase.transferFromDownloadsToDrive = function() {
+  copyBetweenVolumes(
+      ENTRIES.hello,
+      'downloads',
+      BASIC_LOCAL_ENTRY_SET,
+      'drive',
+      BASIC_DRIVE_ENTRY_SET);
+};
 
 /**
- * Tests copy from drive's shared_with_me to drive's root.
+ * Tests copying from Drive shared with me to Downloads.
+ * TODO(noel) naming: ...fromDriveSharedToDownloads?
  */
-testcase.transferFromSharedToDrive = copyBetweenVolumes.bind(
-    null,
-    ENTRIES.testSharedDocument,
-    'drive_shared_with_me',
-    SHARED_WITH_ME_ENTRY_SET,
-    'drive',
-    BASIC_DRIVE_ENTRY_SET);
+testcase.transferFromSharedToDownloads = function() {
+  copyBetweenVolumes(
+      ENTRIES.testSharedDocument,
+      'drive_shared_with_me',
+      SHARED_WITH_ME_ENTRY_SET,
+      'downloads',
+      BASIC_LOCAL_ENTRY_SET);
+};
 
 /**
- * Tests copy from drive's offline to local's downloads.
+ * Tests copying from Drive shared with me to Drive.
+ * TODO(noel) naming: ...fromDriveSharedToDrive?
  */
-testcase.transferFromOfflineToDownloads = copyBetweenVolumes.bind(
-    null,
-    ENTRIES.testDocument,
-    'drive_offline',
-    OFFLINE_ENTRY_SET,
-    'downloads',
-    BASIC_LOCAL_ENTRY_SET);
+testcase.transferFromSharedToDrive = function() {
+  copyBetweenVolumes(
+      ENTRIES.testSharedDocument,
+      'drive_shared_with_me',
+      SHARED_WITH_ME_ENTRY_SET,
+      'drive',
+      BASIC_DRIVE_ENTRY_SET);
+};
 
 /**
- * Tests copy from drive's offline to drive's root.
+ * Tests copying from Drive offline to Downloads.
+ * TODO(noel) naming: ...fromDriveOfflineToDownloads?
  */
-testcase.transferFromOfflineToDrive = copyBetweenVolumes.bind(
-    null,
-    ENTRIES.testDocument,
-    'drive_offline',
-    OFFLINE_ENTRY_SET,
-    'drive',
-    BASIC_DRIVE_ENTRY_SET);
+testcase.transferFromOfflineToDownloads = function() {
+  copyBetweenVolumes(
+      ENTRIES.testDocument,
+      'drive_offline',
+      OFFLINE_ENTRY_SET,
+      'downloads',
+      BASIC_LOCAL_ENTRY_SET);
+};
+
+/**
+ * Tests copying from Drive offline to Drive.
+ * TODO(noel): naming: ...fromDriveOfflinetoDrive?
+ */
+testcase.transferFromOfflineToDrive = function() {
+  copyBetweenVolumes(
+      ENTRIES.testDocument,
+      'drive_offline',
+      OFFLINE_ENTRY_SET,
+      'drive',
+      BASIC_DRIVE_ENTRY_SET);
+};
diff --git a/ui/file_manager/integration_tests/gallery/background.js b/ui/file_manager/integration_tests/gallery/background.js
index ffaba3de..41def38 100644
--- a/ui/file_manager/integration_tests/gallery/background.js
+++ b/ui/file_manager/integration_tests/gallery/background.js
@@ -58,24 +58,29 @@
  */
 var testcase = {};
 
-// Ensure the test cases are loaded.
+/**
+ * When the FileManagerBrowserTest harness loads this test extension, request
+ * configuration and other details from that harness, including the test case
+ * name to run. Use the configuration/details to setup the test ennvironment,
+ * then run the test case using chrome.test.RunTests.
+ */
 window.addEventListener('load', function() {
   var steps = [
-    // Check for the guest mode.
+    // Request the guest mode state.
     function() {
       chrome.test.sendMessage(
           JSON.stringify({name: 'isInGuestMode'}), steps.shift());
     },
-    // Obtain the test case name.
-    function(result) {
-      if (JSON.parse(result) != chrome.extension.inIncognitoContext)
+    // Request the root entry paths.
+    function(mode) {
+      if (JSON.parse(mode) != chrome.extension.inIncognitoContext)
         return;
       chrome.test.sendMessage(
           JSON.stringify({name: 'getRootPaths'}), steps.shift());
     },
-    // Obtain the root entry paths.
-    function(result) {
-      var roots = JSON.parse(result);
+    // Request the test case name.
+    function(paths) {
+      var roots = JSON.parse(paths);
       RootPath.DOWNLOADS = roots.downloads;
       RootPath.DRIVE = roots.drive;
       chrome.test.sendMessage(
@@ -83,16 +88,23 @@
     },
     // Run the test case.
     function(testCaseName) {
-      var targetTest = testcase[testCaseName];
-      if (!targetTest) {
-        chrome.test.fail(testCaseName + ' is not found.');
+      // Get the test function from testcase namespace testCaseName.
+      var test = testcase[testCaseName];
+      // Verify test is an unnamed (aka 'anonymous') Function.
+      if (!test instanceof Function || test.name) {
+        chrome.test.fail('[' + testCaseName + '] not found.');
         return;
       }
-      // Specify the name of test to the test system.
-      targetTest.generatedName = testCaseName;
-      chrome.test.runTests([function() {
-        return testPromiseAndApps(targetTest(), [gallery]);
-      }]);
+      // Define the test case and its name for chrome.test logging.
+      test.generatedName = testCaseName;
+      var testCaseSymbol = Symbol(testCaseName);
+      var testCase = {
+        [testCaseSymbol] :() => {
+          return testPromiseAndApps(test(), [gallery]);
+        },
+      };
+      // Run the test.
+      chrome.test.runTests([testCase[testCaseSymbol]]);
     }
   ];
   steps.shift()();
diff --git a/ui/file_manager/integration_tests/video_player/background.js b/ui/file_manager/integration_tests/video_player/background.js
index 2ff6007c..76f9f04d 100644
--- a/ui/file_manager/integration_tests/video_player/background.js
+++ b/ui/file_manager/integration_tests/video_player/background.js
@@ -72,31 +72,36 @@
     chrome.test.assertFalse('disabled' in videoPlayer.attributes);
     return args;
   });
-};
+}
 
 /**
  * Namespace for test cases.
  */
 var testcase = {};
 
-// Ensure the test cases are loaded.
+/**
+ * When the FileManagerBrowserTest harness loads this test extension, request
+ * configuration and other details from that harness, including the test case
+ * name to run. Use the configuration/details to setup the test ennvironment,
+ * then run the test case using chrome.test.RunTests.
+ */
 window.addEventListener('load', function() {
   var steps = [
-    // Check for the guest mode.
+    // Request the guest mode state.
     function() {
       chrome.test.sendMessage(
           JSON.stringify({name: 'isInGuestMode'}), steps.shift());
     },
-    // Obtain the test case name.
-    function(result) {
-      if (JSON.parse(result) != chrome.extension.inIncognitoContext)
+    // Request the root entry paths.
+    function(mode) {
+      if (JSON.parse(mode) != chrome.extension.inIncognitoContext)
         return;
       chrome.test.sendMessage(
           JSON.stringify({name: 'getRootPaths'}), steps.shift());
     },
-    // Obtain the root entry paths.
-    function(result) {
-      var roots = JSON.parse(result);
+    // Request the test case name.
+    function(paths) {
+      var roots = JSON.parse(paths);
       RootPath.DOWNLOADS = roots.downloads;
       RootPath.DRIVE = roots.drive;
       chrome.test.sendMessage(
@@ -104,16 +109,23 @@
     },
     // Run the test case.
     function(testCaseName) {
-      var targetTest = testcase[testCaseName];
-      if (!targetTest) {
-        chrome.test.fail(testCaseName + ' is not found.');
+      // Get the test function from testcase namespace testCaseName.
+      var test = testcase[testCaseName];
+      // Verify test is an unnamed (aka 'anonymous') Function.
+      if (!test instanceof Function || test.name) {
+        chrome.test.fail('[' + testCaseName + '] not found.');
         return;
       }
-      // Specify the name of test to the test system.
-      targetTest.generatedName = testCaseName;
-      chrome.test.runTests([function() {
-        return testPromiseAndApps(targetTest(), [remoteCallVideoPlayer]);
-      }]);
+      // Define the test case and its name for chrome.test logging.
+      test.generatedName = testCaseName;
+      var testCaseSymbol = Symbol(testCaseName);
+      var testCase = {
+        [testCaseSymbol] :() => {
+          return testPromiseAndApps(test(), [remoteCallVideoPlayer]);
+        },
+      };
+      // Run the test.
+      chrome.test.runTests([testCase[testCaseSymbol]]);
     }
   ];
   steps.shift()();
diff --git a/ui/gfx/color_transform_unittest.cc b/ui/gfx/color_transform_unittest.cc
index aa5a3de..4230f62 100644
--- a/ui/gfx/color_transform_unittest.cc
+++ b/ui/gfx/color_transform_unittest.cc
@@ -284,7 +284,7 @@
 }
 
 TEST(SimpleColorSpace, ICCProfileOnlyColorSpin) {
-  const float kEpsilon = 2.5f / 255.f;
+  const float kEpsilon = 3.0f / 255.f;
   ICCProfile icc_profile = ICCProfileForTestingNoAnalyticTrFn();
   ColorSpace icc_space = icc_profile.GetColorSpace();
   ColorSpace colorspin =
diff --git a/ui/gfx/paint_vector_icon.cc b/ui/gfx/paint_vector_icon.cc
index d2968ffe..b60aab1 100644
--- a/ui/gfx/paint_vector_icon.cc
+++ b/ui/gfx/paint_vector_icon.cc
@@ -4,6 +4,7 @@
 
 #include "ui/gfx/paint_vector_icon.h"
 
+#include <algorithm>
 #include <map>
 #include <tuple>
 
@@ -27,6 +28,30 @@
 
 namespace {
 
+// Retrieves the specified CANVAS_DIMENSIONS size from a PathElement.
+int GetCanvasDimensions(const PathElement* path) {
+  if (!path)
+    return kReferenceSizeDip;
+  return path[0].command == CANVAS_DIMENSIONS ? path[1].arg : kReferenceSizeDip;
+}
+
+// Retrieves the appropriate icon representation to draw when the pixel size
+// requested is |icon_size_px|. VectorIconReps may only be downscaled, not
+// upscaled (with the exception of the largest VectorIconRep), so the return
+// result will be the smallest VectorIconRep greater or equal to |icon_size_px|.
+const VectorIconRep* GetRepForPxSize(const VectorIcon& icon, int icon_size_px) {
+  if (icon.is_empty())
+    return nullptr;
+
+  // Since |VectorIcon::reps| is sorted in descending order by size, search in
+  // reverse order for an icon that is equal to or greater than |icon_size_px|.
+  for (int i = icon.reps_size - 1; i >= 0; --i) {
+    if (GetCanvasDimensions(icon.reps[i].path) >= icon_size_px)
+      return &icon.reps[i];
+  }
+  return &icon.reps[0];
+}
+
 struct CompareIconDescription {
   bool operator()(const IconDescription& a, const IconDescription& b) const {
     const VectorIcon* a_icon = &a.icon;
@@ -534,11 +559,6 @@
       badge_icon(badge_icon) {
   if (dip_size == 0)
     this->dip_size = GetDefaultSizeOfVectorIcon(icon);
-
-  // If an icon has a .1x.icon version, it should only be rendered at the size
-  // specified in that definition.
-  if (icon.rep_1x)
-    DCHECK_EQ(this->dip_size, GetDefaultSizeOfVectorIcon(icon));
 }
 
 IconDescription::~IconDescription() {}
@@ -559,12 +579,10 @@
                      SkColor color,
                      const base::TimeDelta& elapsed_time) {
   DCHECK(!icon.is_empty());
-  if (icon.rep)
-    DCHECK(icon.rep->path_size > 0);
-  if (icon.rep_1x)
-    DCHECK(icon.rep_1x->path_size > 0);
-  const VectorIconRep* rep =
-      (canvas->image_scale() == 1.f && icon.rep_1x) ? icon.rep_1x : icon.rep;
+  for (size_t i = 0; i < icon.reps_size; ++i)
+    DCHECK(icon.reps[i].path_size > 0);
+  const int px_size = gfx::ToCeiledInt(canvas->image_scale() * dip_size);
+  const VectorIconRep* rep = GetRepForPxSize(icon, px_size);
   PaintPath(canvas, rep->path, rep->path_size, dip_size, color, elapsed_time);
 }
 
@@ -602,15 +620,15 @@
 }
 
 int GetDefaultSizeOfVectorIcon(const VectorIcon& icon) {
-  const PathElement* one_x_path =
-      icon.rep_1x ? icon.rep_1x->path : icon.rep->path;
-  return one_x_path[0].command == CANVAS_DIMENSIONS ? one_x_path[1].arg
-                                                    : kReferenceSizeDip;
+  if (icon.is_empty())
+    return -1;
+  const PathElement* default_icon_path = icon.reps[icon.reps_size - 1].path;
+  return GetCanvasDimensions(default_icon_path);
 }
 
 base::TimeDelta GetDurationOfAnimation(const VectorIcon& icon) {
   base::TimeDelta last_motion;
-  for (PathParser parser(icon.rep->path, icon.rep->path_size);
+  for (PathParser parser(icon.reps[0].path, icon.reps[0].path_size);
        parser.HasCommandsRemaining(); parser.Advance()) {
     if (parser.CurrentCommand() != TRANSITION_END)
       continue;
diff --git a/ui/gfx/paint_vector_icon.h b/ui/gfx/paint_vector_icon.h
index b953dce1..2c6871b 100644
--- a/ui/gfx/paint_vector_icon.h
+++ b/ui/gfx/paint_vector_icon.h
@@ -86,7 +86,8 @@
                                                 SkColor color);
 #endif
 
-// Calculates the size that will be default for |icon|, in dip.
+// Calculates the size that will be default for |icon|, in dip. This will be the
+// smallest icon size |icon| contains.
 GFX_EXPORT int GetDefaultSizeOfVectorIcon(const gfx::VectorIcon& icon);
 
 // Calculates and returns the elapsed time at which all animations/transitions
diff --git a/ui/gfx/paint_vector_icon_unittest.cc b/ui/gfx/paint_vector_icon_unittest.cc
index 1188c35e..b472dff7 100644
--- a/ui/gfx/paint_vector_icon_unittest.cc
+++ b/ui/gfx/paint_vector_icon_unittest.cc
@@ -19,6 +19,10 @@
 
 namespace {
 
+SkColor GetColorAtTopLeft(const Canvas& canvas) {
+  return canvas.GetBitmap().getColor(0, 0);
+}
+
 class MockCanvas : public SkCanvas {
  public:
   MockCanvas(int width, int height) : SkCanvas(width, height) {}
@@ -46,8 +50,8 @@
       MOVE_TO, 4, 5, LINE_TO, 10, 11, CLOSE,
       // This move should use (4, 5) as the start point rather than (10, 11).
       R_MOVE_TO, 20, 21, R_LINE_TO, 50, 51};
-  const VectorIconRep icon_rep = {elements, arraysize(elements)};
-  const VectorIcon icon = {&icon_rep};
+  const VectorIconRep rep_list[] = {{elements, arraysize(elements)}};
+  const VectorIcon icon = {rep_list, 1u};
 
   PaintVectorIcon(&canvas, icon, 100, SK_ColorMAGENTA);
   sk_sp<cc::PaintRecord> record = recorder.finishRecordingAsPicture();
@@ -87,8 +91,8 @@
                                   R_H_LINE_TO,
                                   -20,
                                   CLOSE};
-  const VectorIconRep icon_rep = {elements, arraysize(elements)};
-  const VectorIcon icon = {&icon_rep};
+  const VectorIconRep rep_list[] = {{elements, arraysize(elements)}};
+  const VectorIcon icon = {rep_list, 1u};
   PaintVectorIcon(&canvas, icon, canvas_size, color);
 
   // Count the number of pixels in the canvas.
@@ -107,6 +111,173 @@
   EXPECT_EQ(100, colored_pixel_count);
 }
 
+TEST(VectorIconTest, CorrectSizePainted) {
+  // Create a set of 5 icons reps, sized {48, 32, 24, 20, 16} for the test icon.
+  // Color each of them differently so they can be differentiated (the parts of
+  // an icon painted with PATH_COLOR_ARGB will not be overwritten by the color
+  // provided to it at creation time).
+  // SK_ColorRED.
+  const PathElement elements48[] = {CANVAS_DIMENSIONS,
+                                    48,
+                                    PATH_COLOR_ARGB,
+                                    0xFF,
+                                    0xFF,
+                                    0x00,
+                                    0x00,
+                                    MOVE_TO,
+                                    0,
+                                    0,
+                                    H_LINE_TO,
+                                    48,
+                                    V_LINE_TO,
+                                    48,
+                                    H_LINE_TO,
+                                    0,
+                                    V_LINE_TO,
+                                    0,
+                                    CLOSE};
+  // SK_ColorGREEN.
+  const PathElement elements32[] = {CANVAS_DIMENSIONS,
+                                    32,
+                                    PATH_COLOR_ARGB,
+                                    0xFF,
+                                    0x00,
+                                    0xFF,
+                                    0x00,
+                                    MOVE_TO,
+                                    0,
+                                    0,
+                                    H_LINE_TO,
+                                    32,
+                                    V_LINE_TO,
+                                    32,
+                                    H_LINE_TO,
+                                    0,
+                                    V_LINE_TO,
+                                    0,
+                                    CLOSE};
+  // SK_ColorBLUE.
+  const PathElement elements24[] = {CANVAS_DIMENSIONS,
+                                    24,
+                                    PATH_COLOR_ARGB,
+                                    0xFF,
+                                    0x00,
+                                    0x00,
+                                    0xFF,
+                                    MOVE_TO,
+                                    0,
+                                    0,
+                                    H_LINE_TO,
+                                    24,
+                                    V_LINE_TO,
+                                    24,
+                                    H_LINE_TO,
+                                    0,
+                                    V_LINE_TO,
+                                    0,
+                                    CLOSE};
+  // SK_ColorYELLOW.
+  const PathElement elements20[] = {CANVAS_DIMENSIONS,
+                                    20,
+                                    PATH_COLOR_ARGB,
+                                    0xFF,
+                                    0xFF,
+                                    0xFF,
+                                    0x00,
+                                    MOVE_TO,
+                                    0,
+                                    0,
+                                    H_LINE_TO,
+                                    20,
+                                    V_LINE_TO,
+                                    20,
+                                    H_LINE_TO,
+                                    0,
+                                    V_LINE_TO,
+                                    0,
+                                    CLOSE};
+  // SK_ColorCYAN.
+  const PathElement elements16[] = {CANVAS_DIMENSIONS,
+                                    16,
+                                    PATH_COLOR_ARGB,
+                                    0xFF,
+                                    0x00,
+                                    0xFF,
+                                    0xFF,
+                                    MOVE_TO,
+                                    0,
+                                    0,
+                                    H_LINE_TO,
+                                    16,
+                                    V_LINE_TO,
+                                    16,
+                                    H_LINE_TO,
+                                    0,
+                                    V_LINE_TO,
+                                    0,
+                                    CLOSE};
+  // VectorIconReps are always sorted in descending order of size.
+  const VectorIconRep rep_list[] = {{elements48, arraysize(elements48)},
+                                    {elements32, arraysize(elements32)},
+                                    {elements24, arraysize(elements24)},
+                                    {elements20, arraysize(elements20)},
+                                    {elements16, arraysize(elements16)}};
+  const VectorIcon icon = {rep_list, 5u};
+
+  // Test exact sizes paint the correctly sized icon, including the largest and
+  // smallest icon.
+  Canvas canvas_100(gfx::Size(100, 100), 1.0, true);
+  PaintVectorIcon(&canvas_100, icon, 48, SK_ColorBLACK);
+  EXPECT_EQ(SK_ColorRED, GetColorAtTopLeft(canvas_100));
+  PaintVectorIcon(&canvas_100, icon, 32, SK_ColorBLACK);
+  EXPECT_EQ(SK_ColorGREEN, GetColorAtTopLeft(canvas_100));
+  PaintVectorIcon(&canvas_100, icon, 16, SK_ColorBLACK);
+  EXPECT_EQ(SK_ColorCYAN, GetColorAtTopLeft(canvas_100));
+
+  // Only the largest icon may be upscaled to a size larger than what it was
+  // designed for.
+  PaintVectorIcon(&canvas_100, icon, 50, SK_ColorBLACK);
+  EXPECT_EQ(SK_ColorRED, GetColorAtTopLeft(canvas_100));
+
+  // All other icons may never be upscaled.
+  PaintVectorIcon(&canvas_100, icon, 27, SK_ColorBLACK);
+  EXPECT_EQ(SK_ColorGREEN, GetColorAtTopLeft(canvas_100));
+  PaintVectorIcon(&canvas_100, icon, 8, SK_ColorBLACK);
+  EXPECT_EQ(SK_ColorCYAN, GetColorAtTopLeft(canvas_100));
+
+  // Test icons at a scale factor < 100%, still with an exact size, paint the
+  // correctly sized icon.
+  Canvas canvas_75(gfx::Size(100, 100), 0.75, true);
+  PaintVectorIcon(&canvas_75, icon, 32, SK_ColorBLACK);  // 32 * 0.75 = 24.
+  EXPECT_EQ(SK_ColorBLUE, GetColorAtTopLeft(canvas_75));
+
+  // Test icons at a scale factor > 100%, still with an exact size, paint the
+  // correctly sized icon.
+  Canvas canvas_125(gfx::Size(100, 100), 1.25, true);
+  PaintVectorIcon(&canvas_125, icon, 16, SK_ColorBLACK);  // 16 * 1.25 = 20.
+  EXPECT_EQ(SK_ColorYELLOW, GetColorAtTopLeft(canvas_125));
+
+  // Inexact sizes at scale factors < 100%.
+  PaintVectorIcon(&canvas_75, icon, 12, SK_ColorBLACK);  // 12 * 0.75 = 9.
+  EXPECT_EQ(SK_ColorCYAN, GetColorAtTopLeft(canvas_75));
+  PaintVectorIcon(&canvas_75, icon, 28, SK_ColorBLACK);  // 28 * 0.75 = 21.
+  EXPECT_EQ(SK_ColorBLUE, GetColorAtTopLeft(canvas_75));
+
+  // Inexact sizes at scale factors > 100%.
+  PaintVectorIcon(&canvas_125, icon, 12, SK_ColorBLACK);  // 12 * 1.25 = 15.
+  EXPECT_EQ(SK_ColorCYAN, GetColorAtTopLeft(canvas_125));
+  PaintVectorIcon(&canvas_125, icon, 28, SK_ColorBLACK);  // 28 * 1.25 = 35.
+  EXPECT_EQ(SK_ColorRED, GetColorAtTopLeft(canvas_125));
+
+  // Painting without a requested size will default to the smallest icon rep.
+  PaintVectorIcon(&canvas_100, icon, SK_ColorBLACK);
+  EXPECT_EQ(SK_ColorCYAN, GetColorAtTopLeft(canvas_100));
+  // But doing this in another scale factor should assume the smallest icon rep
+  // size, then scale it up by the DSF.
+  PaintVectorIcon(&canvas_125, icon, SK_ColorBLACK);  // 16 * 1.25 = 20.
+  EXPECT_EQ(SK_ColorYELLOW, GetColorAtTopLeft(canvas_125));
+}
+
 }  // namespace
 
 }  // namespace gfx
diff --git a/ui/gfx/vector_icon_types.h b/ui/gfx/vector_icon_types.h
index e03aa126..195de85a 100644
--- a/ui/gfx/vector_icon_types.h
+++ b/ui/gfx/vector_icon_types.h
@@ -95,10 +95,10 @@
 struct VectorIcon {
   VectorIcon() = default;
 
-  bool is_empty() const { return !rep; }
+  bool is_empty() const { return !reps; }
 
-  const VectorIconRep* rep = nullptr;
-  const VectorIconRep* rep_1x = nullptr;
+  const VectorIconRep* const reps = nullptr;
+  size_t reps_size = 0u;
 
   // A human-readable name, useful for debugging, derived from the name of the
   // icon file. This can also be used as an identifier, but vector icon targets
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc
index cfca601..5a76f78 100644
--- a/ui/gl/gl_surface_glx.cc
+++ b/ui/gl/gl_surface_glx.cc
@@ -419,7 +419,7 @@
     return false;
   }
 
-  int major, minor;
+  int major = 0, minor = 0;
   if (!glXQueryVersion(gfx::GetXDisplay(), &major, &minor)) {
     LOG(ERROR) << "glxQueryVersion failed";
     return false;
diff --git a/ui/surface/BUILD.gn b/ui/surface/BUILD.gn
index 6f171275..2790a3d 100644
--- a/ui/surface/BUILD.gn
+++ b/ui/surface/BUILD.gn
@@ -10,7 +10,6 @@
     "surface_export.h",
     "transport_dib.cc",
     "transport_dib.h",
-    "transport_dib_posix.cc",
     "transport_dib_win.cc",
   ]
 
@@ -26,4 +25,8 @@
     "//ui/gfx/geometry",
     "//ui/gl",
   ]
+
+  if (is_posix) {
+    sources += [ "transport_dib_posix.cc" ]
+  }
 }
diff --git a/ui/views/accessibility/native_view_accessibility_base.cc b/ui/views/accessibility/native_view_accessibility_base.cc
index e895c9d..c3ae609 100644
--- a/ui/views/accessibility/native_view_accessibility_base.cc
+++ b/ui/views/accessibility/native_view_accessibility_base.cc
@@ -291,8 +291,9 @@
 }
 
 void NativeViewAccessibilityBase::OnAutofillHidden() {
-  DCHECK(fake_focus_view_id_ == GetUniqueId().Get())
-      << "Cannot clear fake focus on an object that did not have fake focus.";
+  DCHECK(fake_focus_view_id_) << "No autofill fake focus set.";
+  DCHECK_EQ(fake_focus_view_id_, GetUniqueId().Get())
+      << "Cannot clear autofill fake focus on an object that did not have it.";
   fake_focus_view_id_ = 0;
   ui::AXPlatformNode::OnAutofillHidden();
 }
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index fd0748f..5021792 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -134,7 +134,7 @@
   ImageButton* close_button = nullptr;
   if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
     close_button = CreateVectorImageButton(listener);
-    SetImageFromVectorIcon(close_button, vector_icons::kClose16Icon);
+    SetImageFromVectorIcon(close_button, vector_icons::kCloseRoundedIcon);
   } else {
     ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
     close_button = new ImageButton(listener);
diff --git a/ui/views/controls/button/image_button_factory_unittest.cc b/ui/views/controls/button/image_button_factory_unittest.cc
index 52728ff3..6a2e776d 100644
--- a/ui/views/controls/button/image_button_factory_unittest.cc
+++ b/ui/views/controls/button/image_button_factory_unittest.cc
@@ -26,14 +26,14 @@
 
 TEST_F(ImageButtonFactoryTest, SetImageFromVectorIcon) {
   ImageButton* button = CreateVectorImageButton(nullptr);
-  SetImageFromVectorIcon(button, vector_icons::kClose16Icon, SK_ColorRED);
+  SetImageFromVectorIcon(button, vector_icons::kCloseRoundedIcon, SK_ColorRED);
   EXPECT_FALSE(button->GetImage(Button::STATE_NORMAL).isNull());
   EXPECT_FALSE(button->GetImage(Button::STATE_DISABLED).isNull());
   EXPECT_EQ(color_utils::DeriveDefaultIconColor(SK_ColorRED),
             button->GetInkDropBaseColor());
 
   // Default to GoogleGrey900.
-  SetImageFromVectorIcon(button, vector_icons::kClose16Icon);
+  SetImageFromVectorIcon(button, vector_icons::kCloseRoundedIcon);
   EXPECT_EQ(color_utils::DeriveDefaultIconColor(gfx::kGoogleGrey900),
             button->GetInkDropBaseColor());
   delete button;
diff --git a/ui/views/focus/focus_manager.cc b/ui/views/focus/focus_manager.cc
index 7129685..97d9260d 100644
--- a/ui/views/focus/focus_manager.cc
+++ b/ui/views/focus/focus_manager.cc
@@ -345,6 +345,9 @@
 
   for (FocusChangeListener& observer : focus_change_listeners_)
     observer.OnDidChangeFocus(old_focused_view, focused_view_);
+
+  if (delegate_)
+    delegate_->OnDidChangeFocus(old_focused_view, focused_view_);
 }
 
 void FocusManager::ClearFocus() {
diff --git a/ui/views/focus/focus_manager_delegate.h b/ui/views/focus/focus_manager_delegate.h
index a4d9186..c57571b 100644
--- a/ui/views/focus/focus_manager_delegate.h
+++ b/ui/views/focus/focus_manager_delegate.h
@@ -13,6 +13,8 @@
 
 namespace views {
 
+class View;
+
 // Delegate interface for views::FocusManager.
 class VIEWS_EXPORT FocusManagerDelegate {
  public:
@@ -25,6 +27,9 @@
   // target, and so on.
   // Returns true if an accelerator was activated.
   virtual bool ProcessAccelerator(const ui::Accelerator& accelerator) = 0;
+
+  // Called after focus state has changed.
+  virtual void OnDidChangeFocus(View* focused_before, View* focused_now) = 0;
 };
 
 }  // namespace views
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc
index 3e88b8d..739e5e5 100644
--- a/ui/views/window/dialog_delegate.cc
+++ b/ui/views/window/dialog_delegate.cc
@@ -42,11 +42,6 @@
   creation_time_ = base::TimeTicks::Now();
 }
 
-DialogDelegate::~DialogDelegate() {
-  UMA_HISTOGRAM_LONG_TIMES("Dialog.DialogDelegate.Duration",
-                           base::TimeTicks::Now() - creation_time_);
-}
-
 // static
 Widget* DialogDelegate::CreateDialogWidget(WidgetDelegate* delegate,
                                            gfx::NativeWindow context,
@@ -249,6 +244,11 @@
     observer.OnDialogModelChanged();
 }
 
+DialogDelegate::~DialogDelegate() {
+  UMA_HISTOGRAM_LONG_TIMES("Dialog.DialogDelegate.Duration",
+                           base::TimeTicks::Now() - creation_time_);
+}
+
 ax::mojom::Role DialogDelegate::GetAccessibleWindowRole() const {
   return ax::mojom::Role::kDialog;
 }
diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h
index 69add25..83019bb 100644
--- a/ui/views/window/dialog_delegate.h
+++ b/ui/views/window/dialog_delegate.h
@@ -35,7 +35,6 @@
                                     public WidgetDelegate {
  public:
   DialogDelegate();
-  ~DialogDelegate() override;
 
   // Creates a widget at a default location.
   static Widget* CreateDialogWidget(WidgetDelegate* delegate,
@@ -129,6 +128,8 @@
   void DialogModelChanged();
 
  protected:
+  ~DialogDelegate() override;
+
   // Overridden from WidgetDelegate:
   ax::mojom::Role GetAccessibleWindowRole() const override;
 
diff --git a/ui/webui/resources/js/cr/ui/dialogs.js b/ui/webui/resources/js/cr/ui/dialogs.js
index 96693e0..089e0b6 100644
--- a/ui/webui/resources/js/cr/ui/dialogs.js
+++ b/ui/webui/resources/js/cr/ui/dialogs.js
@@ -35,7 +35,7 @@
    */
   BaseDialog.ANIMATE_STABLE_DURATION = 500;
 
-  /** @private */
+  /** @protected */
   BaseDialog.prototype.initDom_ = function() {
     var doc = this.document_;
     this.container_ = doc.createElement('div');
@@ -94,7 +94,7 @@
   /** @private {Function|undefined} */
   BaseDialog.prototype.onCancel_ = null;
 
-  /** @private */
+  /** @protected */
   BaseDialog.prototype.onContainerKeyDown_ = function(event) {
     // Handle Escape.
     if (event.keyCode == 27 && !this.cancelButton_.disabled) {
diff --git a/ui/webui/resources/js/cr/ui/list.js b/ui/webui/resources/js/cr/ui/list.js
index 6cf92762..f370f0f 100644
--- a/ui/webui/resources/js/cr/ui/list.js
+++ b/ui/webui/resources/js/cr/ui/list.js
@@ -873,9 +873,8 @@
      * possibility that the lead item may be a different height.
      * @param {number} index The index to find the top height of.
      * @return {{top: number, height: number}} The heights for the given index.
-     * @private
      */
-    getHeightsForIndex_: function(index) {
+    getHeightsForIndex: function(index) {
       var itemHeight = this.getItemHeightByIndex_(index);
       var top = this.getItemTop(index);
       return {top: top, height: itemHeight};
@@ -901,7 +900,7 @@
       // If offset exceeds the height of list.
       var lastHeight = 0;
       if (this.dataModel.length) {
-        var h = this.getHeightsForIndex_(this.dataModel.length - 1);
+        var h = this.getHeightsForIndex(this.dataModel.length - 1);
         lastHeight = h.top + h.height;
       }
       if (lastHeight < offset)
@@ -914,7 +913,7 @@
 
       // Searchs the correct index.
       do {
-        var heights = this.getHeightsForIndex_(estimatedIndex);
+        var heights = this.getHeightsForIndex(estimatedIndex);
         var top = heights.top;
         var height = heights.height;
 
diff --git a/ui/webui/resources/js/cr/ui/splitter.js b/ui/webui/resources/js/cr/ui/splitter.js
index b655f5b..4c97d691 100644
--- a/ui/webui/resources/js/cr/ui/splitter.js
+++ b/ui/webui/resources/js/cr/ui/splitter.js
@@ -229,7 +229,6 @@
     /**
      * Handles start of the splitter dragging. Saves current width of the
      * element being resized.
-     * @protected
      */
     handleSplitterDragStart: function() {
       // Use the computed width style as the base so that we can ignore what
@@ -247,7 +246,6 @@
     /**
      * Handles splitter moves. Updates width of the element being resized.
      * @param {number} deltaX The change of splitter horizontal position.
-     * @protected
      */
     handleSplitterDragMove: function(deltaX) {
       var targetElement = this.getResizeTarget_();
@@ -259,7 +257,6 @@
     /**
      * Handles end of the splitter dragging. This fires a 'resize' event if the
      * size changed.
-     * @protected
      */
     handleSplitterDragEnd: function() {
       // Check if the size changed.