diff --git a/DEPS b/DEPS
index 23d6943..3f6ac0b 100644
--- a/DEPS
+++ b/DEPS
@@ -129,11 +129,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': '0e9401dafeb34b3459b528e78b6a9c47fe996089',
+  'skia_revision': 'd0995493f8f3d1d4d882c6b5b5dbc327072dd41b',
   # 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': '1eaccad69d406ebb986c67009383c8d4ce8167bb',
+  'v8_revision': 'c4cbeac0c0dcce8ac9351199474eb58917de2df7',
   # 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.
@@ -141,15 +141,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'f2bf49e20849a2b95e0e962a3779e3258307e857',
+  'angle_revision': '3e8a8d5b8567d08855d500c85bcf7cdcc4653f9a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '603a1b53f72ed4f99dfd47eeedffd6879545b027',
+  'swiftshader_revision': 'b55772e6e7ddfebcb9cebf78ddcbe686d9cacf28',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'fbecffccd534a7431fd7a0d0577196b34576ac7f',
+  'pdfium_revision': '459ad7fe015ed4858ed881fcf81dca3eaadc91f3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -192,7 +192,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '869dc82afef9e537154f8666c7b78acbba5e3366',
+  'catapult_revision': '2f1832aff38dc3475514b0364f5d27117f6cc8a5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -801,7 +801,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7192683560fe8a34d3277c3543b93482cc7f7648',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'ec6b379371e10acb0e7472473406331052b17449',
       'condition': 'checkout_linux',
   },
 
@@ -1367,7 +1367,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/${{platform}}',
-          'version': 'git_revision:1c5d71e846840d56aa37758548789d987a0515bc',
+          'version': 'git_revision:eefd466493dd3cffb9ee22810c3e48466a3e67fb',
         },
       ],
       'dep_type': 'cipd',
@@ -1380,7 +1380,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@847dfe2143dcd2240e1bd279c06592bf96aef572',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@00c5601ee11abb2cf141125c38eb31e907308aa2',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc
index a2bcdeb..e4478620 100644
--- a/android_webview/browser/aw_contents.cc
+++ b/android_webview/browser/aw_contents.cc
@@ -1286,9 +1286,6 @@
       return static_cast<jint>(RendererPriority::LOW);
     case content::ChildProcessImportance::IMPORTANT:
       return static_cast<jint>(RendererPriority::HIGH);
-    case content::ChildProcessImportance::COUNT:
-      NOTREACHED();
-      return 0;
   }
   NOTREACHED();
   return 0;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 7e4acc4..3e77d59 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -518,12 +518,14 @@
     "session/teleport_warning_dialog.h",
     "shelf/app_list_button.cc",
     "shelf/app_list_button.h",
-    "shelf/app_list_shelf_item_delegate.cc",
-    "shelf/app_list_shelf_item_delegate.h",
+    "shelf/app_list_button_controller.cc",
+    "shelf/app_list_button_controller.h",
     "shelf/assistant_overlay.cc",
     "shelf/assistant_overlay.h",
     "shelf/back_button.cc",
     "shelf/back_button.h",
+    "shelf/home_button_delegate.cc",
+    "shelf/home_button_delegate.h",
     "shelf/ink_drop_button_listener.h",
     "shelf/login_shelf_view.cc",
     "shelf/login_shelf_view.h",
@@ -1626,6 +1628,7 @@
     "highlighter/highlighter_controller_unittest.cc",
     "highlighter/highlighter_gesture_util_unittest.cc",
     "home_screen/home_launcher_gesture_handler_unittest.cc",
+    "home_screen/home_screen_controller_unittest.cc",
     "ime/ime_controller_unittest.cc",
     "ime/ime_focus_handler_unittest.cc",
     "keyboard/arc/arc_input_method_surface_manager_unittest.cc",
@@ -1690,7 +1693,6 @@
     "screen_util_unittest.cc",
     "session/session_controller_unittest.cc",
     "shelf/app_list_button_unittest.cc",
-    "shelf/app_list_shelf_item_delegate_unittest.cc",
     "shelf/back_button_unittest.cc",
     "shelf/login_shelf_view_unittest.cc",
     "shelf/shelf_application_menu_model_unittest.cc",
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index e47e4fe1..e3abe52 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -37,6 +37,7 @@
 #include "ash/root_window_controller.h"
 #include "ash/rotator/window_rotation.h"
 #include "ash/session/session_controller.h"
+#include "ash/shelf/home_button_delegate.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
@@ -515,7 +516,7 @@
   if (accelerator.key_code() == ui::VKEY_LWIN)
     base::RecordAction(UserMetricsAction("Accel_Search_LWin"));
 
-  Shell::Get()->app_list_controller()->OnAppListButtonPressed(
+  HomeButtonDelegate::PerformHomeButtonAction(
       display::Screen::GetScreen()
           ->GetDisplayNearestWindow(Shell::GetRootWindowForNewWindows())
           .id(),
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index ae50a24..ea2b11e 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -31,8 +31,8 @@
 #include "ash/shell.h"
 #include "ash/voice_interaction/voice_interaction_controller.h"
 #include "ash/wallpaper/wallpaper_controller.h"
+#include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/overview/overview_controller.h"
-#include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "base/logging.h"
@@ -50,6 +50,10 @@
 
 namespace {
 
+bool IsHomeScreenAvailable() {
+  return Shell::Get()->home_screen_controller()->IsHomeScreenAvailable();
+}
+
 bool IsTabletMode() {
   return Shell::Get()
       ->tablet_mode_controller()
@@ -62,27 +66,6 @@
     Shell::Get()->assistant_controller()->ui_controller()->CloseUi(exit_point);
 }
 
-// Minimize all windows that aren't the app list in reverse order to preserve
-// the mru ordering.
-// Returns false if no window is minimized.
-bool MinimizeAllWindows() {
-  bool handled = false;
-  aura::Window* app_list_container =
-      Shell::Get()->GetPrimaryRootWindow()->GetChildById(
-          kShellWindowId_AppListTabletModeContainer);
-  aura::Window::Windows windows =
-      Shell::Get()->mru_window_tracker()->BuildWindowForCycleList();
-  std::reverse(windows.begin(), windows.end());
-  for (auto* window : windows) {
-    if (!app_list_container->Contains(window) &&
-        !wm::GetWindowState(window)->IsMinimized()) {
-      wm::GetWindowState(window)->Minimize();
-      handled = true;
-    }
-  }
-  return handled;
-}
-
 }  // namespace
 
 AppListControllerImpl::AppListControllerImpl()
@@ -411,7 +394,7 @@
 
 void AppListControllerImpl::OnActiveUserPrefServiceChanged(
     PrefService* /* pref_service */) {
-  if (!IsTabletMode()) {
+  if (!IsHomeScreenAvailable()) {
     DismissAppList();
     return;
   }
@@ -498,7 +481,7 @@
     int y_position_in_screen,
     float background_opacity) {
   // Avoid changing app list opacity and position when homecher is enabled.
-  if (IsTabletMode())
+  if (IsHomeScreenAvailable())
     return;
   presenter_.UpdateYPositionAndOpacity(y_position_in_screen,
                                        background_opacity);
@@ -507,7 +490,7 @@
 void AppListControllerImpl::EndDragFromShelf(
     app_list::AppListViewState app_list_state) {
   // Avoid dragging app list when homecher is enabled.
-  if (IsTabletMode())
+  if (IsHomeScreenAvailable())
     return;
   presenter_.EndDragFromShelf(app_list_state);
 }
@@ -560,7 +543,7 @@
 }
 
 void AppListControllerImpl::OnOverviewModeStarting() {
-  if (!IsTabletMode()) {
+  if (!IsHomeScreenAvailable()) {
     DismissAppList();
     return;
   }
@@ -577,7 +560,7 @@
 
 void AppListControllerImpl::OnOverviewModeEnding(
     OverviewSession* overview_session) {
-  if (!IsTabletMode())
+  if (!IsHomeScreenAvailable())
     return;
 
   // Animate the launcher if overview mode is sliding out. Let
@@ -592,7 +575,7 @@
 
 void AppListControllerImpl::OnOverviewModeEndingAnimationComplete(
     bool canceled) {
-  if (!IsTabletMode() || canceled)
+  if (!IsHomeScreenAvailable() || canceled)
     return;
 
   presenter_.ScheduleOverviewModeAnimation(/*start=*/false,
@@ -653,6 +636,7 @@
   // expected if it's enabled and we're still in tablet mode.
   // https://crbug.com/900956.
   const bool should_be_shown = IsTabletMode();
+  DCHECK_EQ(should_be_shown, IsHomeScreenAvailable());
   if (should_be_shown == GetTargetVisibility())
     return;
 
@@ -693,7 +677,7 @@
 
       // Reset model state.
       presenter_.ShowEmbeddedAssistantUI(false);
-      if (IsTabletMode()) {
+      if (IsHomeScreenAvailable()) {
         presenter_.GetView()->app_list_main_view()->ResetForShow();
         presenter_.GetView()->SetState(
             app_list::AppListViewState::FULLSCREEN_ALL_APPS);
@@ -752,33 +736,10 @@
     int64_t display_id,
     app_list::AppListShowSource show_source,
     base::TimeTicks event_time_stamp) {
-  if (!IsTabletMode())
+  if (!IsHomeScreenAvailable())
     return ToggleAppList(display_id, show_source, event_time_stamp);
 
-  bool handled =
-      Shell::Get()
-          ->home_screen_controller()
-          ->home_launcher_gesture_handler()
-          ->ShowHomeLauncher(
-              Shell::Get()->display_manager()->GetDisplayForId(display_id));
-
-  if (!handled) {
-    if (Shell::Get()->overview_controller()->IsSelecting()) {
-      // End overview mode.
-      Shell::Get()->overview_controller()->ToggleOverview(
-          OverviewSession::EnterExitOverviewType::kWindowsMinimized);
-      handled = true;
-    }
-    if (Shell::Get()->split_view_controller()->IsSplitViewModeActive()) {
-      // End split view mode.
-      Shell::Get()->split_view_controller()->EndSplitView(
-          SplitViewController::EndReason::kHomeLauncherPressed);
-      handled = true;
-    }
-  }
-
-  if (!handled)
-    handled = MinimizeAllWindows();
+  bool handled = Shell::Get()->home_screen_controller()->GoHome(display_id);
 
   // Perform the "back" action for the app list.
   if (!handled)
@@ -794,9 +755,9 @@
 void AppListControllerImpl::UpdateExpandArrowVisibility() {
   bool should_show = false;
 
-  // Hide the expand arrow view when tablet mode is enabled and there is no
-  // activatable window.
-  if (IsTabletMode()) {
+  // Hide the expand arrow view when the home screen is available and there is
+  // no activatable window.
+  if (IsHomeScreenAvailable()) {
     should_show = !ash::Shell::Get()
                        ->mru_window_tracker()
                        ->BuildWindowForCycleList()
@@ -834,7 +795,7 @@
     return;
   }
 
-  if (!IsTabletMode())
+  if (!IsHomeScreenAvailable())
     DismissAppList();
 
   ash::Shell::Get()->assistant_controller()->ui_controller()->ShowUi(
@@ -1151,7 +1112,8 @@
 }
 
 int64_t AppListControllerImpl::GetDisplayIdToShowAppListOn() {
-  if (IsTabletMode() && !Shell::Get()->display_manager()->IsInUnifiedMode()) {
+  if (IsHomeScreenAvailable() &&
+      !Shell::Get()->display_manager()->IsInUnifiedMode()) {
     return display::Display::HasInternalDisplay()
                ? display::Display::InternalDisplayId()
                : display::Screen::GetScreen()->GetPrimaryDisplay().id();
@@ -1163,7 +1125,7 @@
 }
 
 void AppListControllerImpl::ResetHomeLauncherIfShown() {
-  if (!IsTabletMode() || !presenter_.IsVisible())
+  if (!IsHomeScreenAvailable() || !presenter_.IsVisible())
     return;
 
   auto* const keyboard_controller = keyboard::KeyboardController::Get();
@@ -1177,7 +1139,7 @@
 
 void AppListControllerImpl::UpdateLauncherContainer() {
   bool launcher_should_show_behind_apps =
-      IsTabletMode() &&
+      IsHomeScreenAvailable() &&
       model_->state() != ash::AppListState::kStateEmbeddedAssistant;
 
   aura::Window* window = presenter_.GetWindow();
diff --git a/ash/app_list/app_list_controller_impl_unittest.cc b/ash/app_list/app_list_controller_impl_unittest.cc
index 4c62417..2fb3d5d 100644
--- a/ash/app_list/app_list_controller_impl_unittest.cc
+++ b/ash/app_list/app_list_controller_impl_unittest.cc
@@ -9,8 +9,10 @@
 #include "ash/app_list/views/app_list_view.h"
 #include "ash/app_list/views/contents_view.h"
 #include "ash/app_list/views/expand_arrow_view.h"
+#include "ash/app_list/views/search_box_view.h"
 #include "ash/home_screen/home_launcher_gesture_handler.h"
 #include "ash/home_screen/home_screen_controller.h"
+#include "ash/keyboard/ash_keyboard_controller.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
@@ -34,17 +36,32 @@
       ->IsTabletModeWindowManagerEnabled();
 }
 
+app_list::AppListView* GetAppListView() {
+  return Shell::Get()->app_list_controller()->presenter()->GetView();
+}
+
 bool GetExpandArrowViewVisibility() {
-  return Shell::Get()
-      ->app_list_controller()
-      ->presenter()
-      ->GetView()
+  return GetAppListView()
       ->app_list_main_view()
       ->contents_view()
       ->expand_arrow_view()
       ->visible();
 }
 
+app_list::SearchBoxView* GetSearchBoxView() {
+  return GetAppListView()
+      ->app_list_main_view()
+      ->contents_view()
+      ->GetSearchBoxView();
+}
+
+aura::Window* GetVirtualKeyboardWindow() {
+  return Shell::Get()
+      ->ash_keyboard_controller()
+      ->keyboard_controller()
+      ->GetKeyboardWindow();
+}
+
 }  // namespace
 
 class AppListControllerImplTest : public AshTestBase {
@@ -94,6 +111,52 @@
   EXPECT_FALSE(GetExpandArrowViewVisibility());
 }
 
+// In clamshell mode, when the AppListView's bottom is on the display edge
+// and app list state is HALF, the rounded corners should be hidden
+// (https://crbug.com/942084).
+TEST_F(AppListControllerImplTest, HideRoundingCorners) {
+  Shell::Get()->ash_keyboard_controller()->SetEnableFlag(
+      keyboard::mojom::KeyboardEnableFlag::kShelfEnabled);
+
+  // Show the app list view and click on the search box with mouse. So the
+  // VirtualKeyboard is shown.
+  Shell::Get()->app_list_controller()->presenter()->Show(
+      display::Screen::GetScreen()->GetPrimaryDisplay().id(),
+      base::TimeTicks::Now());
+  GetSearchBoxView()->SetSearchBoxActive(true, ui::ET_MOUSE_PRESSED);
+
+  // Wait until the virtual keyboard shows on the screen.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(GetVirtualKeyboardWindow()->IsVisible());
+
+  // Test the following things:
+  // (1) AppListView is at the top of the screen.
+  // (2) AppListView's state is HALF.
+  // (3) AppListBackgroundShield is translated to hide the rounded corners.
+  aura::Window* native_window =
+      GetAppListView()->get_fullscreen_widget_for_test()->GetNativeView();
+  gfx::Rect app_list_screen_bounds = native_window->GetBoundsInScreen();
+  EXPECT_EQ(0, app_list_screen_bounds.y());
+  EXPECT_EQ(app_list::AppListViewState::HALF,
+            GetAppListView()->app_list_state());
+  gfx::Transform expected_transform;
+  expected_transform.Translate(0, -app_list::kAppListBackgroundRadius);
+  EXPECT_EQ(
+      expected_transform,
+      GetAppListView()->GetAppListBackgroundShieldForTest()->GetTransform());
+
+  // Set the search box inactive and wait until the virtual keyboard is hidden.
+  GetSearchBoxView()->SetSearchBoxActive(false, ui::ET_MOUSE_PRESSED);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(nullptr, GetVirtualKeyboardWindow());
+
+  // Test that the rounded corners should show again.
+  expected_transform = gfx::Transform();
+  EXPECT_EQ(
+      expected_transform,
+      GetAppListView()->GetAppListBackgroundShieldForTest()->GetTransform());
+}
+
 class AppListControllerImplMetricsTest : public AshTestBase {
  public:
   AppListControllerImplMetricsTest() = default;
diff --git a/ash/app_list/app_list_unittest.cc b/ash/app_list/app_list_unittest.cc
index d4b26a7..ed49122 100644
--- a/ash/app_list/app_list_unittest.cc
+++ b/ash/app_list/app_list_unittest.cc
@@ -42,7 +42,7 @@
   EXPECT_FALSE(controller->GetTargetVisibility());
   EXPECT_FALSE(presenter->GetTargetVisibility());
   EXPECT_EQ(0u, app_list_container->children().size());
-  EXPECT_FALSE(app_list_button->is_showing_app_list());
+  EXPECT_FALSE(app_list_button->IsShowingAppList());
   generator.set_current_screen_location(
       app_list_button->GetBoundsInScreen().CenterPoint());
   generator.ClickLeftButton();
@@ -52,7 +52,7 @@
   // Flush the mojo message from Chrome to Ash reporting the visibility change.
   EXPECT_TRUE(controller->GetTargetVisibility());
   EXPECT_EQ(1u, app_list_container->children().size());
-  EXPECT_TRUE(app_list_button->is_showing_app_list());
+  EXPECT_TRUE(app_list_button->IsShowingAppList());
 
   // Click the button again to dismiss the app list; it will animate to close.
   generator.ClickLeftButton();
@@ -62,7 +62,7 @@
   // Flush the mojo message from Chrome to Ash reporting the visibility change.
   EXPECT_FALSE(controller->GetTargetVisibility());
   EXPECT_EQ(1u, app_list_container->children().size());
-  EXPECT_FALSE(app_list_button->is_showing_app_list());
+  EXPECT_FALSE(app_list_button->IsShowingAppList());
 }
 
 }  // namespace ash
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc
index e2df65f..555aae5 100644
--- a/ash/app_list/views/app_list_item_view.cc
+++ b/ash/app_list/views/app_list_item_view.cc
@@ -475,8 +475,8 @@
       base::BindOnce(&AppListItemView::OnMenuClosed,
                      weak_ptr_factory_.GetWeakPtr()));
   context_menu_->Build(std::move(menu));
-  context_menu_->Run(anchor_rect, views::MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT,
-                     run_types);
+  context_menu_->Run(
+      anchor_rect, views::MenuAnchorPosition::kBubbleTouchableRight, run_types);
   apps_grid_view_->SetSelectedView(this);
 }
 
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 787ef01..c2e1d35 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -690,6 +690,7 @@
       ->set_arrow_key_traversal_enabled_for_widget(true);
 
   widget_observer_ = std::make_unique<FullscreenWidgetObserver>(this);
+  fullscreen_widget_->GetNativeView()->AddObserver(this);
 }
 
 void AppListView::HandleClickOrTap(ui::LocatedEvent* event) {
@@ -1588,6 +1589,32 @@
   return state_animation_metrics_reporter_.get();
 }
 
+void AppListView::OnWindowDestroying(aura::Window* window) {
+  DCHECK_EQ(fullscreen_widget_->GetNativeView(), window);
+  window->RemoveObserver(this);
+}
+
+void AppListView::OnWindowBoundsChanged(aura::Window* window,
+                                        const gfx::Rect& old_bounds,
+                                        const gfx::Rect& new_bounds,
+                                        ui::PropertyChangeReason reason) {
+  DCHECK_EQ(fullscreen_widget_->GetNativeView(), window);
+
+  // When the virtual keyboard shows, the AppListView is moved upward to avoid
+  // the overlapping area with the virtual keyboard. As a result, its bottom
+  // side may be on the display edge. Stop showing the rounded corners under
+  // this circumstance.
+  const bool hide_rounded_corners =
+      app_list_state_ == AppListViewState::HALF && new_bounds.y() == 0;
+
+  gfx::Transform transform;
+  if (hide_rounded_corners)
+    transform.Translate(0, -kAppListBackgroundRadius);
+
+  app_list_background_shield_->SetTransform(transform);
+  app_list_background_shield_->SchedulePaint();
+}
+
 void AppListView::UpdateChildViewsYPositionAndOpacity() {
   if (app_list_state_ == AppListViewState::CLOSED)
     return;
@@ -1656,6 +1683,7 @@
     const int work_area_offset = GetDisplayNearestView().work_area().y();
     OffsetYPositionOfAppList(shown ? work_area_offset : -work_area_offset);
   }
+  app_list_main_view_->contents_view()->NotifySearchBoxBoundsUpdated();
 }
 
 bool AppListView::CloseKeyboardIfVisible() {
diff --git a/ash/app_list/views/app_list_view.h b/ash/app_list/views/app_list_view.h
index 8af06e0..7871e125 100644
--- a/ash/app_list/views/app_list_view.h
+++ b/ash/app_list/views/app_list_view.h
@@ -15,6 +15,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "ui/aura/window_observer.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
@@ -53,7 +54,8 @@
 // and hosts a AppsGridView and passes AppListModel to it for display.
 // TODO(newcomer|weidongg): Organize the cc file to match the order of
 // definitions in this header.
-class APP_LIST_EXPORT AppListView : public views::WidgetDelegateView {
+class APP_LIST_EXPORT AppListView : public views::WidgetDelegateView,
+                                    public aura::WindowObserver {
  public:
   class TestApi {
    public:
@@ -238,6 +240,13 @@
   // Returns a animation metrics reportre for state transition.
   ui::AnimationMetricsReporter* GetStateTransitionMetricsReporter();
 
+  // WindowObserver overrides:
+  void OnWindowDestroying(aura::Window* window) override;
+  void OnWindowBoundsChanged(aura::Window* window,
+                             const gfx::Rect& old_bounds,
+                             const gfx::Rect& new_bounds,
+                             ui::PropertyChangeReason reason) override;
+
   views::Widget* get_fullscreen_widget_for_test() const {
     return fullscreen_widget_;
   }
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index 055042dd..bc00870 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -1594,10 +1594,6 @@
 }
 
 void AppsGridView::HandleKeyboardAppMovement(ui::KeyboardCode key_code) {
-  // TODO(newcomer): Support app movement via key in folders.
-  if (folder_delegate_)
-    return;
-
   DCHECK(selected_view_);
   const GridIndex target_index = GetTargetGridIndexForKeyboardMove(key_code);
 
@@ -2630,8 +2626,11 @@
                                    ((key_code == backward) ? -1 : 1);
 
     // A forward move on the last item in |view_model_| should result in page
-    // creation
+    // creation.
     if (target_model_index == view_model_.view_size()) {
+      // If the move is within a folder, do not allow page creation.
+      if (folder_delegate_)
+        return source_index;
       // If |source_index| is the last item in the grid on a page by itself,
       // moving right to a new page should be a no-op.
       if (view_structure_.items_on_page(source_index.page) == 1)
@@ -2642,7 +2641,8 @@
     target_index = GetIndexOfView(
         static_cast<const AppListItemView*>(GetItemViewAt(std::min(
             std::max(0, target_model_index), view_model_.view_size() - 1))));
-    if (key_code == backward && target_index.page < source_index.page &&
+    if (!folder_delegate_ && key_code == backward &&
+        target_index.page < source_index.page &&
         !view_structure_.IsFullPage(target_index.page)) {
       // Apps swap positions if the target page is the same as the
       // destination page, or the target page is full. If the page is not
@@ -2669,22 +2669,32 @@
   } else if (target_row > (GetItemsNumOfPage(target_page) - 1) / cols_) {
     // The app will move to the first row of the next page.
     ++target_page;
-    if (target_page >= view_structure_.total_pages()) {
-      // If |source_index| page only has one item, moving down to a new page
-      // should be a no-op.
-      if (view_structure_.items_on_page(source_index.page) == 1)
+    if (folder_delegate_) {
+      if (target_page >= pagination_model_.total_pages())
         return source_index;
-      return GridIndex(target_page, 0);
+    } else {
+      if (target_page >= view_structure_.total_pages()) {
+        // If |source_index| page only has one item, moving down to a new page
+        // should be a no-op.
+        if (view_structure_.items_on_page(source_index.page) == 1)
+          return source_index;
+        return GridIndex(target_page, 0);
+      }
     }
     target_row = 0;
   }
 
+  // The ideal slot shares a column with |source_index|.
+  const int ideal_slot = target_row * cols_ + source_index.slot % cols_;
+  if (folder_delegate_) {
+    return GridIndex(target_page,
+                     std::min(GetItemsNumOfPage(target_page) - 1, ideal_slot));
+  }
+
   // If the app is being moved to a new page there is 1 extra slot available.
   const int last_slot_in_target_page =
       view_structure_.items_on_page(target_page) -
       (source_index.page != target_page ? 0 : 1);
-  // The ideal slot shares a column with |source_index|.
-  const int ideal_slot = target_row * cols_ + source_index.slot % cols_;
   return GridIndex(target_page, std::min(last_slot_in_target_page, ideal_slot));
 }
 
@@ -2699,9 +2709,10 @@
   const GridIndex original_selected_view_index =
       GetIndexOfView(original_selected_view);
   // Moving an AppListItemView is either a swap within the origin page, a swap
-  // to a full page, or a dump to a page with room.
+  // to a full page, or a dump to a page with room. A move within a folder is
+  // always a swap because there are no gaps.
   const bool swap_items =
-      view_structure_.IsFullPage(target_index.page) ||
+      folder_delegate_ || view_structure_.IsFullPage(target_index.page) ||
       target_index.page == original_selected_view_index.page;
 
   AppListItemView* target_view = GetViewAtIndex(target_index);
@@ -2709,22 +2720,28 @@
   // the initial move. Clearing the overflow when |target_index| is on a full
   // page results in the last item being pushed to the next page.
   MoveItemInModel(selected_view_, target_index, !swap_items /*clear_overflow*/);
-  view_structure_.SaveToMetadata();
+  if (!folder_delegate_)
+    view_structure_.SaveToMetadata();
 
   if (swap_items) {
     DCHECK(target_view);
     MoveItemInModel(target_view, original_selected_view_index);
-    view_structure_.SaveToMetadata();
+    if (!folder_delegate_)
+      view_structure_.SaveToMetadata();
   }
 
-  // Update |pagination_model_| because the move could have resulted in a
-  // page getting collapsed or created.
-  if (view_structure_.total_pages() != pagination_model_.total_pages())
-    pagination_model_.SetTotalPages(view_structure_.total_pages());
-
-  pagination_model_.SelectPage(
-      std::min(view_structure_.total_pages() - 1, target_index.page),
-      false /*animate*/);
+  int target_page = target_index.page;
+  if (!folder_delegate_) {
+    // Update |pagination_model_| because the move could have resulted in a
+    // page getting collapsed or created.
+    if (view_structure_.total_pages() != pagination_model_.total_pages()) {
+      pagination_model_.SetTotalPages(view_structure_.total_pages());
+    }
+    // |target_page| may change due to a page collapsing.
+    target_page =
+        std::min(pagination_model_.total_pages() - 1, target_index.page);
+  }
+  pagination_model_.SelectPage(target_page, false /*animate*/);
   SetSelectedView(original_selected_view);
   Layout();
 
diff --git a/ash/app_list/views/contents_view.cc b/ash/app_list/views/contents_view.cc
index 43996ec..24274559 100644
--- a/ash/app_list/views/contents_view.cc
+++ b/ash/app_list/views/contents_view.cc
@@ -365,9 +365,7 @@
   gfx::Transform transform;
   transform.Scale(scale, scale);
   search_box->GetWidget()->GetNativeView()->SetTransform(transform);
-
-  for (auto& observer : search_box_observers_)
-    observer.OnSearchBoxBoundsUpdated();
+  NotifySearchBoxBoundsUpdated();
 }
 
 void ContentsView::UpdateExpandArrowOpacity(double progress,
@@ -641,6 +639,11 @@
   expand_arrow_view_->SetVisible(show);
 }
 
+void ContentsView::NotifySearchBoxBoundsUpdated() {
+  for (auto& observer : search_box_observers_)
+    observer.OnSearchBoxBoundsUpdated();
+}
+
 void ContentsView::AddSearchBoxUpdateObserver(
     SearchBoxUpdateObserver* observer) {
   search_box_observers_.AddObserver(observer);
diff --git a/ash/app_list/views/contents_view.h b/ash/app_list/views/contents_view.h
index 84b0071..29fcb8d8 100644
--- a/ash/app_list/views/contents_view.h
+++ b/ash/app_list/views/contents_view.h
@@ -194,6 +194,8 @@
   // and tablet mode is enabled.
   void SetExpandArrowViewVisibility(bool show);
 
+  void NotifySearchBoxBoundsUpdated();
+
   void AddSearchBoxUpdateObserver(SearchBoxUpdateObserver* observer);
   void RemoveSearchBoxUpdateObserver(SearchBoxUpdateObserver* observer);
 
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index ff58c634..393a3dd 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -151,12 +151,14 @@
   if (!keyboard::KeyboardController::HasInstance())
     return;
   auto* const keyboard_controller = keyboard::KeyboardController::Get();
+  bool should_show_keyboard =
+      is_search_box_active() && search_box()->HasFocus();
   if (!keyboard_controller->IsEnabled() ||
-      is_search_box_active() == keyboard_controller->IsKeyboardVisible()) {
+      should_show_keyboard == keyboard_controller->IsKeyboardVisible()) {
     return;
   }
 
-  if (is_search_box_active()) {
+  if (should_show_keyboard) {
     keyboard_controller->ShowKeyboard(false);
     return;
   }
diff --git a/ash/app_list/views/search_result_tile_item_view.cc b/ash/app_list/views/search_result_tile_item_view.cc
index 41a7779..aff95a0 100644
--- a/ash/app_list/views/search_result_tile_item_view.cc
+++ b/ash/app_list/views/search_result_tile_item_view.cc
@@ -369,11 +369,11 @@
       base::BindOnce(&SearchResultTileItemView::OnMenuClosed,
                      weak_ptr_factory_.GetWeakPtr()));
   context_menu_->Build(std::move(menu));
-  context_menu_->Run(anchor_rect, views::MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT,
-                     views::MenuRunner::HAS_MNEMONICS |
-                         views::MenuRunner::USE_TOUCHABLE_LAYOUT |
-                         views::MenuRunner::CONTEXT_MENU |
-                         views::MenuRunner::FIXED_ANCHOR);
+  context_menu_->Run(
+      anchor_rect, views::MenuAnchorPosition::kBubbleTouchableRight,
+      views::MenuRunner::HAS_MNEMONICS |
+          views::MenuRunner::USE_TOUCHABLE_LAYOUT |
+          views::MenuRunner::CONTEXT_MENU | views::MenuRunner::FIXED_ANCHOR);
   source->RequestFocus();
 }
 
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc
index 0f46a138..b2dddca9 100644
--- a/ash/app_list/views/search_result_view.cc
+++ b/ash/app_list/views/search_result_view.cc
@@ -526,7 +526,8 @@
       std::string(), this, source_type, this,
       AppListMenuModelAdapter::SEARCH_RESULT, base::OnceClosure());
   context_menu_->Build(std::move(menu));
-  context_menu_->Run(gfx::Rect(point, gfx::Size()), views::MENU_ANCHOR_TOPLEFT,
+  context_menu_->Run(gfx::Rect(point, gfx::Size()),
+                     views::MenuAnchorPosition::kTopLeft,
                      views::MenuRunner::HAS_MNEMONICS);
   source->RequestFocus();
 }
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index b34a9a8..f43eca23 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -906,7 +906,7 @@
 
       <!-- Status tray screen share strings. -->
       <message name="IDS_ASH_STATUS_TRAY_SCREEN_SHARE_TITLE" desc="The title for screen sharing notification">
-        You are sharing your screen
+        You're sharing your screen
       </message>
       <message name="IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP" desc="label used for screen sharing stop button">
         Stop
diff --git a/ash/frame/non_client_frame_view_ash.cc b/ash/frame/non_client_frame_view_ash.cc
index a436c98..82615ec 100644
--- a/ash/frame/non_client_frame_view_ash.cc
+++ b/ash/frame/non_client_frame_view_ash.cc
@@ -503,7 +503,7 @@
       views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU);
   menu_runner_->RunMenuAt(GetWidget(), nullptr,
                           gfx::Rect(point, gfx::Size(0, 0)),
-                          views::MENU_ANCHOR_TOPLEFT, source_type);
+                          views::MenuAnchorPosition::kTopLeft, source_type);
 }
 
 bool NonClientFrameViewAsh::IsCommandIdChecked(int command_id) const {
diff --git a/ash/home_screen/home_screen_controller.cc b/ash/home_screen/home_screen_controller.cc
index 2292fad..1b89b1c 100644
--- a/ash/home_screen/home_screen_controller.cc
+++ b/ash/home_screen/home_screen_controller.cc
@@ -6,16 +6,42 @@
 
 #include "ash/home_screen/home_launcher_gesture_handler.h"
 #include "ash/home_screen/home_screen_delegate.h"
+#include "ash/public/cpp/shell_window_ids.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/wallpaper/wallpaper_controller.h"
+#include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/overview/overview_controller.h"
+#include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/window_state.h"
 #include "base/logging.h"
 #include "ui/aura/window.h"
+#include "ui/display/manager/display_manager.h"
 
 namespace ash {
+namespace {
+
+// Minimizes all windows that aren't in the home screen container. Done in
+// reverse order to preserve the mru ordering.
+// Returns true if any windows are minimized.
+bool MinimizeAllWindows() {
+  bool handled = false;
+  aura::Window* container = Shell::Get()->GetPrimaryRootWindow()->GetChildById(
+      kShellWindowId_AppListTabletModeContainer);
+  aura::Window::Windows windows =
+      Shell::Get()->mru_window_tracker()->BuildWindowForCycleList();
+  for (auto it = windows.rbegin(); it != windows.rend(); it++) {
+    if (!container->Contains(*it) && !wm::GetWindowState(*it)->IsMinimized()) {
+      wm::GetWindowState(*it)->Minimize();
+      handled = true;
+    }
+  }
+  return handled;
+}
+
+}  // namespace
 
 HomeScreenController::HomeScreenController()
     : home_launcher_gesture_handler_(
@@ -45,6 +71,34 @@
     Shelf::ForWindow(window)->MaybeUpdateShelfBackground();
 }
 
+bool HomeScreenController::GoHome(int64_t display_id) {
+  DCHECK(IsHomeScreenAvailable());
+
+  if (home_launcher_gesture_handler_->ShowHomeLauncher(
+          Shell::Get()->display_manager()->GetDisplayForId(display_id))) {
+    return true;
+  }
+
+  if (Shell::Get()->overview_controller()->IsSelecting()) {
+    // End overview mode.
+    Shell::Get()->overview_controller()->ToggleOverview(
+        OverviewSession::EnterExitOverviewType::kWindowsMinimized);
+    return true;
+  }
+
+  if (Shell::Get()->split_view_controller()->IsSplitViewModeActive()) {
+    // End split view mode.
+    Shell::Get()->split_view_controller()->EndSplitView(
+        SplitViewController::EndReason::kHomeLauncherPressed);
+    return true;
+  }
+
+  if (MinimizeAllWindows())
+    return true;
+
+  return false;
+}
+
 void HomeScreenController::SetDelegate(HomeScreenDelegate* delegate) {
   delegate_ = delegate;
 }
diff --git a/ash/home_screen/home_screen_controller.h b/ash/home_screen/home_screen_controller.h
index 2969e0d..6def248 100644
--- a/ash/home_screen/home_screen_controller.h
+++ b/ash/home_screen/home_screen_controller.h
@@ -33,6 +33,11 @@
   // Shows the home screen.
   void Show();
 
+  // Takes the user to the home screen, either by ending Overview Mode/Split
+  // View Mode or by minimizing the other windows. Returns false if there was
+  // nothing to do because the given display was already "home".
+  bool GoHome(int64_t display_id);
+
   // Sets the delegate for home screen animations.
   void SetDelegate(HomeScreenDelegate* delegate);
 
diff --git a/ash/shelf/app_list_shelf_item_delegate_unittest.cc b/ash/home_screen/home_screen_controller_unittest.cc
similarity index 60%
rename from ash/shelf/app_list_shelf_item_delegate_unittest.cc
rename to ash/home_screen/home_screen_controller_unittest.cc
index 96d55ee..4d0227e 100644
--- a/ash/shelf/app_list_shelf_item_delegate_unittest.cc
+++ b/ash/home_screen/home_screen_controller_unittest.cc
@@ -2,28 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/shelf/app_list_shelf_item_delegate.h"
+#include "ash/home_screen/home_screen_controller.h"
 
 #include <memory>
-#include <utility>
 
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
-#include "base/bind.h"
 #include "base/macros.h"
 
 namespace ash {
 namespace {
 
-class AppListShelfItemDelegateTest : public AshTestBase {
+class HomeScreenControllerTest : public AshTestBase {
  public:
-  AppListShelfItemDelegateTest()
-      : delegate_(std::make_unique<AppListShelfItemDelegate>()) {}
-  ~AppListShelfItemDelegateTest() override = default;
+  HomeScreenControllerTest() = default;
+  ~HomeScreenControllerTest() override = default;
 
   std::unique_ptr<aura::Window> CreateTestWindow() {
     return AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
@@ -34,26 +30,22 @@
                                          aura::client::WINDOW_TYPE_POPUP);
   }
 
-  AppListShelfItemDelegate* delegate() { return delegate_.get(); }
+  HomeScreenController* home_screen_controller() {
+    return Shell::Get()->home_screen_controller();
+  }
 
  private:
-  std::unique_ptr<AppListShelfItemDelegate> delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppListShelfItemDelegateTest);
+  DISALLOW_COPY_AND_ASSIGN(HomeScreenControllerTest);
 };
 
-TEST_F(AppListShelfItemDelegateTest, OnlyMinimizeCycleListWindows) {
+TEST_F(HomeScreenControllerTest, OnlyMinimizeCycleListWindows) {
   std::unique_ptr<aura::Window> w1(CreateTestWindow());
   std::unique_ptr<aura::Window> w2(CreatePopupTestWindow());
 
   Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
   std::unique_ptr<ui::Event> test_event = std::make_unique<ui::KeyEvent>(
       ui::EventType::ET_MOUSE_PRESSED, ui::VKEY_UNKNOWN, ui::EF_NONE);
-  delegate()->ItemSelected(
-      std::move(test_event), GetPrimaryDisplay().id(),
-      ShelfLaunchSource::LAUNCH_FROM_SHELF,
-      base::BindOnce(
-          [](ash::ShelfAction, base::Optional<ash::MenuItemList>) {}));
+  home_screen_controller()->GoHome(GetPrimaryDisplay().id());
   ASSERT_TRUE(wm::GetWindowState(w1.get())->IsMinimized());
   ASSERT_FALSE(wm::GetWindowState(w2.get())->IsMinimized());
 }
diff --git a/ash/public/cpp/shelf_model.cc b/ash/public/cpp/shelf_model.cc
index e16ac99..9fee37d 100644
--- a/ash/public/cpp/shelf_model.cc
+++ b/ash/public/cpp/shelf_model.cc
@@ -42,6 +42,7 @@
 
 }  // namespace
 
+// TODO(michaelpg): Rename App List item to Home Button.
 const char kAppListId[] = "jlfapfmkapbjlfbpjedlinehodkccjee";
 const char kBackButtonId[] = "icmmkgojeloilfifneofeejijgdhjknf";
 
diff --git a/ash/public/cpp/shelf_types.h b/ash/public/cpp/shelf_types.h
index d21997bd..438d880 100644
--- a/ash/public/cpp/shelf_types.h
+++ b/ash/public/cpp/shelf_types.h
@@ -116,6 +116,7 @@
   TYPE_PINNED_APP,
 
   // Toggles visiblity of the app list.
+  // TODO(michaelpg): Rename App List item to Home Button.
   TYPE_APP_LIST,
 
   // The browser shortcut button, the browser may be running or not.
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 9262ba8..2fd50b41 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -654,7 +654,7 @@
                  base::TimeTicks::Now()));
   menu_runner_->RunMenuAt(wallpaper_widget_controller()->GetWidget(), nullptr,
                           gfx::Rect(location_in_screen, gfx::Size()),
-                          views::MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT,
+                          views::MenuAnchorPosition::kBubbleTouchableRight,
                           source_type);
 }
 
diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc
index 28af351..2997874 100644
--- a/ash/shelf/app_list_button.cc
+++ b/ash/shelf/app_list_button.cc
@@ -4,190 +4,59 @@
 
 #include "ash/shelf/app_list_button.h"
 
-#include <algorithm>
-#include <memory>
-#include <utility>
+#include <math.h>  // std::ceil
 
-#include "ash/app_list/app_list_controller_impl.h"
-#include "ash/assistant/assistant_controller.h"
-#include "ash/assistant/assistant_ui_controller.h"
-#include "ash/assistant/model/assistant_ui_model.h"
-#include "ash/home_screen/home_screen_controller.h"
 #include "ash/public/cpp/shelf_types.h"
-#include "ash/session/session_controller.h"
-#include "ash/shelf/assistant_overlay.h"
-#include "ash/shelf/ink_drop_button_listener.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_constants.h"
-#include "ash/shelf/shelf_view.h"
-#include "ash/shell.h"
-#include "ash/shell_state.h"
-#include "ash/system/tray/tray_popup_utils.h"
-#include "ash/voice_interaction/voice_interaction_controller.h"
-#include "ash/wm/tablet_mode/tablet_mode_controller.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "base/metrics/user_metrics_action.h"
-#include "base/timer/timer.h"
-#include "chromeos/constants/chromeos_switches.h"
+#include "base/logging.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
-#include "components/account_id/account_id.h"
-#include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/display/screen.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/scoped_canvas.h"
 #include "ui/views/animation/flood_fill_ink_drop_ripple.h"
 #include "ui/views/animation/ink_drop_impl.h"
-#include "ui/views/animation/ink_drop_mask.h"
-#include "ui/views/painter.h"
-#include "ui/views/widget/widget.h"
 
 namespace ash {
 namespace {
 
-constexpr int kVoiceInteractionAnimationDelayMs = 200;
-constexpr int kVoiceInteractionAnimationHideDelayMs = 500;
 constexpr uint8_t kVoiceInteractionRunningAlpha = 255;     // 100% alpha
 constexpr uint8_t kVoiceInteractionNotRunningAlpha = 138;  // 54% alpha
 
-bool IsHomeScreenAvailable() {
-  return Shell::Get()->home_screen_controller()->IsHomeScreenAvailable();
-}
-
 }  // namespace
 
 // static
 const char AppListButton::kViewClassName[] = "ash/AppListButton";
 
 AppListButton::AppListButton(ShelfView* shelf_view, Shelf* shelf)
-    : ShelfControlButton(shelf_view), shelf_(shelf) {
-  DCHECK(shelf_);
-  Shell::Get()->app_list_controller()->AddObserver(this);
-  Shell::Get()->session_controller()->AddObserver(this);
-  Shell::Get()->tablet_mode_controller()->AddObserver(this);
-
-  Shell::Get()->voice_interaction_controller()->AddLocalObserver(this);
+    : ShelfControlButton(shelf_view), controller_(this, shelf) {
+  DCHECK(shelf_view);
+  DCHECK(shelf);
   SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE));
   set_notify_action(Button::NOTIFY_ON_PRESS);
   set_has_ink_drop_action_on_click(false);
-
-  // Initialize voice interaction overlay and sync the flags if active user
-  // session has already started. This could happen when an external monitor
-  // is plugged in.
-  if (Shell::Get()->session_controller()->IsActiveUserSessionStarted() &&
-      chromeos::switches::IsAssistantEnabled()) {
-    InitializeVoiceInteractionOverlay();
-  }
 }
 
-AppListButton::~AppListButton() {
-  // AppListController and TabletModeController are destroyed early when Shell
-  // is being destroyed, they may not exist.
-  if (Shell::Get()->app_list_controller())
-    Shell::Get()->app_list_controller()->RemoveObserver(this);
-  if (Shell::Get()->tablet_mode_controller())
-    Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
-  Shell::Get()->session_controller()->RemoveObserver(this);
-  Shell::Get()->voice_interaction_controller()->RemoveLocalObserver(this);
-}
-
-void AppListButton::OnAppListShown() {
-  // Do not show a highlight if the home screen is available, since the home
-  // screen view is always open in the background.
-  if (!IsHomeScreenAvailable())
-    AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr);
-  is_showing_app_list_ = true;
-  shelf_->UpdateAutoHideState();
-}
-
-void AppListButton::OnAppListDismissed() {
-  AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr);
-  is_showing_app_list_ = false;
-  shelf_->UpdateAutoHideState();
-}
+AppListButton::~AppListButton() = default;
 
 void AppListButton::OnGestureEvent(ui::GestureEvent* event) {
-  // Handle gesture events that are on the app list circle.
-  switch (event->type()) {
-    case ui::ET_GESTURE_TAP:
-    case ui::ET_GESTURE_TAP_CANCEL:
-      if (UseVoiceInteractionStyle()) {
-        assistant_overlay_->EndAnimation();
-        assistant_animation_delay_timer_->Stop();
-      }
-      if (!Shell::Get()->app_list_controller()->IsVisible() ||
-          IsHomeScreenAvailable()) {
-        AnimateInkDrop(views::InkDropState::ACTION_TRIGGERED, event);
-      }
-
-      Button::OnGestureEvent(event);
-      return;
-    case ui::ET_GESTURE_TAP_DOWN:
-      // If |!ShouldEnterPushedState|, Button::OnGestureEvent will not set
-      // the event to be handled. This will cause the |ET_GESTURE_TAP| or
-      // |ET_GESTURE_TAP_CANCEL| not to be sent to |app_list_button|, therefore
-      // leaving the assistant overlay ripple stays visible.
-      if (!ShouldEnterPushedState(*event))
-        return;
-
-      if (UseVoiceInteractionStyle()) {
-        assistant_animation_delay_timer_->Start(
-            FROM_HERE,
-            base::TimeDelta::FromMilliseconds(
-                kVoiceInteractionAnimationDelayMs),
-            base::Bind(&AppListButton::StartVoiceInteractionAnimation,
-                       base::Unretained(this)));
-      }
-      if (!Shell::Get()->app_list_controller()->IsVisible() ||
-          IsHomeScreenAvailable()) {
-        AnimateInkDrop(views::InkDropState::ACTION_PENDING, event);
-      }
-
-      Button::OnGestureEvent(event);
-      // If assistant overlay animation starts, we need to make sure the event
-      // is handled in order to end the animation in |ET_GESTURE_TAP| or
-      // |ET_GESTURE_TAP_CANCEL|.
-      DCHECK(event->handled());
-      return;
-    case ui::ET_GESTURE_LONG_PRESS:
-      if (UseVoiceInteractionStyle()) {
-        base::RecordAction(base::UserMetricsAction(
-            "VoiceInteraction.Started.AppListButtonLongPress"));
-        assistant_overlay_->BurstAnimation();
-        event->SetHandled();
-        Shell::Get()->shell_state()->SetRootWindowForNewWindows(
-            GetWidget()->GetNativeWindow()->GetRootWindow());
-        Shell::Get()->assistant_controller()->ui_controller()->ShowUi(
-            AssistantEntryPoint::kLongPressLauncher);
-      } else {
-        Button::OnGestureEvent(event);
-      }
-      return;
-    case ui::ET_GESTURE_LONG_TAP:
-      if (UseVoiceInteractionStyle()) {
-        // Also consume the long tap event. This happens after the user long
-        // presses and lifts the finger. We already handled the long press
-        // ignore the long tap to avoid bringing up the context menu again.
-        AnimateInkDrop(views::InkDropState::HIDDEN, event);
-        event->SetHandled();
-      } else {
-        Button::OnGestureEvent(event);
-      }
-      return;
-    default:
-      Button::OnGestureEvent(event);
-      return;
-  }
+  if (!controller_.MaybeHandleGestureEvent(event, shelf_view()))
+    Button::OnGestureEvent(event);
 }
 
 const char* AppListButton::GetClassName() const {
   return kViewClassName;
 }
 
+void AppListButton::OnVoiceInteractionAvailabilityChanged() {
+  SchedulePaint();
+}
+
+bool AppListButton::IsShowingAppList() const {
+  return controller_.is_showing_app_list();
+}
+
 void AppListButton::PaintButtonContents(gfx::Canvas* canvas) {
   gfx::PointF circle_center(GetCenterPoint());
 
@@ -196,7 +65,7 @@
   // factors.
   float ring_outer_radius_dp = 7.f;
   float ring_thickness_dp = 1.5f;
-  if (UseVoiceInteractionStyle()) {
+  if (controller_.IsVoiceInteractionAvailable()) {
     ring_outer_radius_dp = 8.f;
     ring_thickness_dp = 1.f;
   }
@@ -209,14 +78,9 @@
     fg_flags.setStyle(cc::PaintFlags::kStroke_Style);
     fg_flags.setColor(kShelfIconColor);
 
-    if (UseVoiceInteractionStyle()) {
-      mojom::VoiceInteractionState state =
-          Shell::Get()
-              ->voice_interaction_controller()
-              ->voice_interaction_state()
-              .value_or(mojom::VoiceInteractionState::STOPPED);
+    if (controller_.IsVoiceInteractionAvailable()) {
       // active: 100% alpha, inactive: 54% alpha
-      fg_flags.setAlpha(state == mojom::VoiceInteractionState::RUNNING
+      fg_flags.setAlpha(controller_.IsVoiceInteractionRunning()
                             ? kVoiceInteractionRunningAlpha
                             : kVoiceInteractionNotRunningAlpha);
     }
@@ -227,7 +91,7 @@
     // Make sure the center of the circle lands on pixel centers.
     canvas->DrawCircle(circle_center, radius, fg_flags);
 
-    if (UseVoiceInteractionStyle()) {
+    if (controller_.IsVoiceInteractionAvailable()) {
       fg_flags.setAlpha(255);
       const float kCircleRadiusDp = 5.f;
       fg_flags.setStyle(cc::PaintFlags::kFill_Style);
@@ -237,108 +101,4 @@
   }
 }
 
-void AppListButton::OnAppListVisibilityChanged(bool shown, int64_t display_id) {
-  if (display::Screen::GetScreen()
-          ->GetDisplayNearestWindow(GetWidget()->GetNativeWindow())
-          .id() != display_id) {
-    return;
-  }
-  if (shown)
-    OnAppListShown();
-  else
-    OnAppListDismissed();
-}
-
-void AppListButton::OnVoiceInteractionStatusChanged(
-    mojom::VoiceInteractionState state) {
-  SchedulePaint();
-
-  if (!assistant_overlay_)
-    return;
-
-  switch (state) {
-    case mojom::VoiceInteractionState::STOPPED:
-      UMA_HISTOGRAM_TIMES(
-          "VoiceInteraction.OpenDuration",
-          base::TimeTicks::Now() - voice_interaction_start_timestamp_);
-      break;
-    case mojom::VoiceInteractionState::NOT_READY:
-      // If we are showing the bursting or waiting animation, no need to do
-      // anything. Otherwise show the waiting animation now.
-      // NOTE: No waiting animation for native assistant.
-      if (!chromeos::switches::IsAssistantEnabled() &&
-          !assistant_overlay_->IsBursting() &&
-          !assistant_overlay_->IsWaiting()) {
-        assistant_overlay_->WaitingAnimation();
-      }
-      break;
-    case mojom::VoiceInteractionState::RUNNING:
-      // we start hiding the animation if it is running.
-      if (assistant_overlay_->IsBursting() || assistant_overlay_->IsWaiting()) {
-        assistant_animation_hide_delay_timer_->Start(
-            FROM_HERE,
-            base::TimeDelta::FromMilliseconds(
-                kVoiceInteractionAnimationHideDelayMs),
-            base::Bind(&AssistantOverlay::HideAnimation,
-                       base::Unretained(assistant_overlay_)));
-      }
-
-      voice_interaction_start_timestamp_ = base::TimeTicks::Now();
-      break;
-  }
-}
-
-void AppListButton::OnVoiceInteractionSettingsEnabled(bool enabled) {
-  SchedulePaint();
-}
-
-void AppListButton::OnVoiceInteractionConsentStatusUpdated(
-    mojom::ConsentStatus consent_status) {
-  SchedulePaint();
-}
-
-void AppListButton::OnActiveUserSessionChanged(const AccountId& account_id) {
-  SchedulePaint();
-  // Initialize voice interaction overlay when primary user session becomes
-  // active.
-  if (Shell::Get()->session_controller()->IsUserPrimary() &&
-      !assistant_overlay_ && chromeos::switches::IsAssistantEnabled()) {
-    InitializeVoiceInteractionOverlay();
-  }
-}
-
-void AppListButton::OnTabletModeStarted() {
-  AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr);
-}
-
-void AppListButton::StartVoiceInteractionAnimation() {
-  assistant_overlay_->StartAnimation(false);
-}
-
-bool AppListButton::UseVoiceInteractionStyle() {
-  VoiceInteractionController* controller =
-      Shell::Get()->voice_interaction_controller();
-  bool settings_enabled = controller->settings_enabled().value_or(false);
-
-  const bool consent_given = controller->consent_status() ==
-                             mojom::ConsentStatus::kActivityControlAccepted;
-
-  bool is_feature_allowed =
-      controller->allowed_state() == mojom::AssistantAllowedState::ALLOWED;
-  if (assistant_overlay_ && is_feature_allowed &&
-      (settings_enabled || !consent_given)) {
-    return true;
-  }
-  return false;
-}
-
-void AppListButton::InitializeVoiceInteractionOverlay() {
-  assistant_overlay_ = new AssistantOverlay(this);
-  AddChildView(assistant_overlay_);
-  assistant_overlay_->SetVisible(false);
-  assistant_animation_delay_timer_ = std::make_unique<base::OneShotTimer>();
-  assistant_animation_hide_delay_timer_ =
-      std::make_unique<base::OneShotTimer>();
-}
-
 }  // namespace ash
diff --git a/ash/shelf/app_list_button.h b/ash/shelf/app_list_button.h
index c698120..86c6bfc 100644
--- a/ash/shelf/app_list_button.h
+++ b/ash/shelf/app_list_button.h
@@ -7,87 +7,48 @@
 
 #include <memory>
 
-#include "ash/app_list/app_list_controller_observer.h"
 #include "ash/ash_export.h"
-#include "ash/public/cpp/assistant/default_voice_interaction_observer.h"
-#include "ash/public/interfaces/voice_interaction_controller.mojom.h"
-#include "ash/session/session_observer.h"
+#include "ash/shelf/app_list_button_controller.h"
 #include "ash/shelf/shelf_control_button.h"
-#include "ash/wm/tablet_mode/tablet_mode_observer.h"
 #include "base/macros.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-namespace base {
-class OneShotTimer;
-}  // namespace base
 
 namespace ash {
 
-class AssistantOverlay;
 class Shelf;
 class ShelfView;
 
-// Button used for the AppList icon on the shelf.
-class ASH_EXPORT AppListButton : public ShelfControlButton,
-                                 public AppListControllerObserver,
-                                 public SessionObserver,
-                                 public TabletModeObserver,
-                                 public DefaultVoiceInteractionObserver {
+// Button used for the AppList icon on the shelf. It opens the app list (in
+// clamshell mode) or home screen (in tablet mode). Because the clamshell-mode
+// app list appears like a dismissable overlay, the button is highlighted while
+// the app list is open in clamshell mode.
+//
+// If Assistant is enabled, the button is filled in; long-pressing it will
+// launch Assistant.
+class ASH_EXPORT AppListButton : public ShelfControlButton {
  public:
   static const char kViewClassName[];
 
   AppListButton(ShelfView* shelf_view, Shelf* shelf);
   ~AppListButton() override;
 
-  void OnAppListShown();
-  void OnAppListDismissed();
-
-  bool is_showing_app_list() const { return is_showing_app_list_; }
-
   // views::Button:
   void OnGestureEvent(ui::GestureEvent* event) override;
   const char* GetClassName() const override;
 
+  // Called when the availability of a long-press gesture may have changed, e.g.
+  // when Assistant becomes enabled.
+  void OnVoiceInteractionAvailabilityChanged();
+
+  // True if the app list is shown for the display containing this button.
+  bool IsShowingAppList() const;
+
  protected:
   // views::Button:
   void PaintButtonContents(gfx::Canvas* canvas) override;
 
  private:
-  // AppListControllerObserver:
-  void OnAppListVisibilityChanged(bool shown, int64_t display_id) override;
-
-  // mojom::VoiceInteractionObserver:
-  void OnVoiceInteractionStatusChanged(
-      mojom::VoiceInteractionState state) override;
-  void OnVoiceInteractionSettingsEnabled(bool enabled) override;
-  void OnVoiceInteractionConsentStatusUpdated(
-      mojom::ConsentStatus consent_status) override;
-
-  // SessionObserver:
-  void OnActiveUserSessionChanged(const AccountId& account_id) override;
-
-  // TabletModeObserver:
-  void OnTabletModeStarted() override;
-
-  void StartVoiceInteractionAnimation();
-
-  // Whether the voice interaction style should be used.
-  bool UseVoiceInteractionStyle();
-
-  // Initialize the voice interaction overlay.
-  void InitializeVoiceInteractionOverlay();
-
-  // True if the app list is currently showing for this display.
-  // This is useful because other app_list_visible functions aren't per-display.
-  bool is_showing_app_list_ = false;
-
-  Shelf* shelf_;
-
-  // Owned by the view hierarchy. Null if the voice interaction is not enabled.
-  AssistantOverlay* assistant_overlay_ = nullptr;
-  std::unique_ptr<base::OneShotTimer> assistant_animation_delay_timer_;
-  std::unique_ptr<base::OneShotTimer> assistant_animation_hide_delay_timer_;
-  base::TimeTicks voice_interaction_start_timestamp_;
+  // The controller used to determine the button's behavior.
+  AppListButtonController controller_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListButton);
 };
diff --git a/ash/shelf/app_list_button_controller.cc b/ash/shelf/app_list_button_controller.cc
new file mode 100644
index 0000000..bc1b6327
--- /dev/null
+++ b/ash/shelf/app_list_button_controller.cc
@@ -0,0 +1,271 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/shelf/app_list_button_controller.h"
+
+#include "ash/app_list/app_list_controller_impl.h"
+#include "ash/assistant/assistant_controller.h"
+#include "ash/home_screen/home_screen_controller.h"
+#include "ash/session/session_controller.h"
+#include "ash/shelf/app_list_button.h"
+#include "ash/shelf/assistant_overlay.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_view.h"
+#include "ash/shell.h"
+#include "ash/shell_state.h"
+#include "ash/voice_interaction/voice_interaction_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+#include "base/timer/timer.h"
+#include "chromeos/constants/chromeos_switches.h"
+#include "components/account_id/account_id.h"
+#include "ui/display/screen.h"
+#include "ui/views/animation/ink_drop_state.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+namespace {
+
+constexpr int kVoiceInteractionAnimationDelayMs = 200;
+constexpr int kVoiceInteractionAnimationHideDelayMs = 500;
+
+// Returns true if the button should appear activatable.
+bool CanActivate() {
+  return !Shell::Get()->app_list_controller()->IsVisible() ||
+         Shell::Get()->home_screen_controller()->IsHomeScreenAvailable();
+}
+
+}  // namespace
+
+AppListButtonController::AppListButtonController(AppListButton* button,
+                                                 Shelf* shelf)
+    : button_(button), shelf_(shelf) {
+  DCHECK(button_);
+  DCHECK(shelf_);
+  Shell* shell = Shell::Get();
+  shell->app_list_controller()->AddObserver(this);
+  shell->session_controller()->AddObserver(this);
+  shell->tablet_mode_controller()->AddObserver(this);
+  shell->voice_interaction_controller()->AddLocalObserver(this);
+
+  // Initialize voice interaction overlay and sync the flags if active user
+  // session has already started. This could happen when an external monitor
+  // is plugged in.
+  if (shell->session_controller()->IsActiveUserSessionStarted() &&
+      chromeos::switches::IsAssistantEnabled()) {
+    InitializeVoiceInteractionOverlay();
+  }
+}
+
+AppListButtonController::~AppListButtonController() {
+  Shell* shell = Shell::Get();
+
+  // AppListController and TabletModeController are destroyed early when Shell
+  // is being destroyed, so they may not exist.
+  if (shell->app_list_controller())
+    shell->app_list_controller()->RemoveObserver(this);
+  if (shell->tablet_mode_controller())
+    shell->tablet_mode_controller()->RemoveObserver(this);
+  shell->session_controller()->RemoveObserver(this);
+  shell->voice_interaction_controller()->RemoveLocalObserver(this);
+}
+
+bool AppListButtonController::MaybeHandleGestureEvent(ui::GestureEvent* event,
+                                                      ShelfView* shelf_view) {
+  switch (event->type()) {
+    case ui::ET_GESTURE_TAP:
+    case ui::ET_GESTURE_TAP_CANCEL:
+      if (IsVoiceInteractionAvailable()) {
+        assistant_overlay_->EndAnimation();
+        assistant_animation_delay_timer_->Stop();
+      }
+
+      if (CanActivate())
+        button_->AnimateInkDrop(views::InkDropState::ACTION_TRIGGERED, event);
+
+      // After animating the ripple, let the button handle the event.
+      return false;
+    case ui::ET_GESTURE_TAP_DOWN:
+      // If |!ShouldEnterPushedState|, Button::OnGestureEvent will not set the
+      // |ET_GESTURE_TAP_DOWN| event to be handled. This will cause the
+      // |ET_GESTURE_TAP| or |ET_GESTURE_TAP_CANCEL| not to be sent to
+      // |button_|, therefore leaving the assistant overlay ripple visible.
+      if (!shelf_view->ShouldEventActivateButton(button_, *event))
+        return true;
+
+      if (IsVoiceInteractionAvailable()) {
+        assistant_animation_delay_timer_->Start(
+            FROM_HERE,
+            base::TimeDelta::FromMilliseconds(
+                kVoiceInteractionAnimationDelayMs),
+            base::BindOnce(
+                &AppListButtonController::StartVoiceInteractionAnimation,
+                base::Unretained(this)));
+      }
+
+      if (CanActivate())
+        button_->AnimateInkDrop(views::InkDropState::ACTION_PENDING, event);
+
+      return false;
+    case ui::ET_GESTURE_LONG_PRESS:
+      // Only consume the long press event if voice interaction is available.
+      if (!IsVoiceInteractionAvailable())
+        return false;
+
+      base::RecordAction(base::UserMetricsAction(
+          "VoiceInteraction.Started.AppListButtonLongPress"));
+      assistant_overlay_->BurstAnimation();
+      event->SetHandled();
+      Shell::Get()->shell_state()->SetRootWindowForNewWindows(
+          button_->GetWidget()->GetNativeWindow()->GetRootWindow());
+      Shell::Get()->assistant_controller()->ui_controller()->ShowUi(
+          AssistantEntryPoint::kLongPressLauncher);
+      return true;
+    case ui::ET_GESTURE_LONG_TAP:
+      // Only consume the long tap event if voice interaction is available.
+      if (!IsVoiceInteractionAvailable())
+        return false;
+
+      // This event happens after the user long presses and lifts the finger.
+      button_->AnimateInkDrop(views::InkDropState::HIDDEN, event);
+
+      // We already handled the long press; consume the long tap to avoid
+      // bringing up the context menu again.
+      event->SetHandled();
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool AppListButtonController::IsVoiceInteractionAvailable() {
+  VoiceInteractionController* controller =
+      Shell::Get()->voice_interaction_controller();
+  bool settings_enabled = controller->settings_enabled().value_or(false);
+  bool consent_given = controller->consent_status() ==
+                       mojom::ConsentStatus::kActivityControlAccepted;
+  bool feature_allowed =
+      controller->allowed_state() == mojom::AssistantAllowedState::ALLOWED;
+
+  return assistant_overlay_ && feature_allowed &&
+         (settings_enabled || !consent_given);
+}
+
+bool AppListButtonController::IsVoiceInteractionRunning() {
+  return Shell::Get()
+             ->voice_interaction_controller()
+             ->voice_interaction_state()
+             .value_or(mojom::VoiceInteractionState::STOPPED) ==
+         mojom::VoiceInteractionState::RUNNING;
+}
+
+void AppListButtonController::OnAppListVisibilityChanged(bool shown,
+                                                         int64_t display_id) {
+  if (display::Screen::GetScreen()
+          ->GetDisplayNearestWindow(button_->GetWidget()->GetNativeWindow())
+          .id() != display_id) {
+    return;
+  }
+  if (shown)
+    OnAppListShown();
+  else
+    OnAppListDismissed();
+}
+
+void AppListButtonController::OnActiveUserSessionChanged(
+    const AccountId& account_id) {
+  button_->OnVoiceInteractionAvailabilityChanged();
+  // Initialize voice interaction overlay when primary user session becomes
+  // active.
+  if (Shell::Get()->session_controller()->IsUserPrimary() &&
+      !assistant_overlay_ && chromeos::switches::IsAssistantEnabled()) {
+    InitializeVoiceInteractionOverlay();
+  }
+}
+
+void AppListButtonController::OnTabletModeStarted() {
+  button_->AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr);
+}
+
+void AppListButtonController::OnVoiceInteractionStatusChanged(
+    mojom::VoiceInteractionState state) {
+  button_->OnVoiceInteractionAvailabilityChanged();
+
+  if (!assistant_overlay_)
+    return;
+
+  switch (state) {
+    case mojom::VoiceInteractionState::STOPPED:
+      UMA_HISTOGRAM_TIMES(
+          "VoiceInteraction.OpenDuration",
+          base::TimeTicks::Now() - voice_interaction_start_timestamp_);
+      break;
+    case mojom::VoiceInteractionState::NOT_READY:
+      // If we are showing the bursting or waiting animation, no need to do
+      // anything. Otherwise show the waiting animation now.
+      // NOTE: No waiting animation for native assistant.
+      if (!chromeos::switches::IsAssistantEnabled() &&
+          !assistant_overlay_->IsBursting() &&
+          !assistant_overlay_->IsWaiting()) {
+        assistant_overlay_->WaitingAnimation();
+      }
+      break;
+    case mojom::VoiceInteractionState::RUNNING:
+      // we start hiding the animation if it is running.
+      if (assistant_overlay_->IsBursting() || assistant_overlay_->IsWaiting()) {
+        assistant_animation_hide_delay_timer_->Start(
+            FROM_HERE,
+            base::TimeDelta::FromMilliseconds(
+                kVoiceInteractionAnimationHideDelayMs),
+            base::BindOnce(&AssistantOverlay::HideAnimation,
+                           base::Unretained(assistant_overlay_)));
+      }
+
+      voice_interaction_start_timestamp_ = base::TimeTicks::Now();
+      break;
+  }
+}
+
+void AppListButtonController::OnVoiceInteractionSettingsEnabled(bool enabled) {
+  button_->OnVoiceInteractionAvailabilityChanged();
+}
+
+void AppListButtonController::OnVoiceInteractionConsentStatusUpdated(
+    mojom::ConsentStatus consent_status) {
+  button_->OnVoiceInteractionAvailabilityChanged();
+}
+
+void AppListButtonController::StartVoiceInteractionAnimation() {
+  assistant_overlay_->StartAnimation(false);
+}
+
+void AppListButtonController::OnAppListShown() {
+  // Do not show a highlight if the home screen is available, since the home
+  // screen view is always open in the background.
+  if (!Shell::Get()->home_screen_controller()->IsHomeScreenAvailable())
+    button_->AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr);
+  is_showing_app_list_ = true;
+  shelf_->UpdateAutoHideState();
+}
+
+void AppListButtonController::OnAppListDismissed() {
+  button_->AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr);
+  is_showing_app_list_ = false;
+  shelf_->UpdateAutoHideState();
+}
+
+void AppListButtonController::InitializeVoiceInteractionOverlay() {
+  assistant_overlay_ = new AssistantOverlay(button_);
+  button_->AddChildView(assistant_overlay_);
+  assistant_overlay_->SetVisible(false);
+  assistant_animation_delay_timer_ = std::make_unique<base::OneShotTimer>();
+  assistant_animation_hide_delay_timer_ =
+      std::make_unique<base::OneShotTimer>();
+}
+
+}  // namespace ash
diff --git a/ash/shelf/app_list_button_controller.h b/ash/shelf/app_list_button_controller.h
new file mode 100644
index 0000000..7203fada
--- /dev/null
+++ b/ash/shelf/app_list_button_controller.h
@@ -0,0 +1,106 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SHELF_APP_LIST_BUTTON_CONTROLLER_H_
+#define ASH_SHELF_APP_LIST_BUTTON_CONTROLLER_H_
+
+#include <memory>
+
+#include "ash/app_list/app_list_controller_observer.h"
+#include "ash/public/cpp/assistant/default_voice_interaction_observer.h"
+#include "ash/public/interfaces/voice_interaction_controller.mojom.h"
+#include "ash/session/session_observer.h"
+#include "ash/wm/tablet_mode/tablet_mode_observer.h"
+#include "base/macros.h"
+
+namespace base {
+class OneShotTimer;
+}  // namespace base
+
+namespace ui {
+class GestureEvent;
+}  // namespace ui
+
+namespace ash {
+
+class AssistantOverlay;
+class AppListButton;
+class Shelf;
+class ShelfView;
+
+// Controls behavior of the AppListButton, including a possible long-press
+// action (for Assistant).
+// Behavior is tested indirectly in AppListButtonTest and ShelfViewInkDropTest.
+class AppListButtonController : public AppListControllerObserver,
+                                public SessionObserver,
+                                public TabletModeObserver,
+                                public DefaultVoiceInteractionObserver {
+ public:
+  AppListButtonController(AppListButton* button, Shelf* shelf);
+  ~AppListButtonController() override;
+
+  // Maybe handles a gesture event based on the event and whether voice
+  // interaction is available.
+  // |shelf_view| is used to determine whether it is safe to animate the ripple.
+  //
+  // Returns true if the event is consumed; otherwise, AppListButton should pass
+  // the event along to Button to consume.
+  bool MaybeHandleGestureEvent(ui::GestureEvent* event, ShelfView* shelf_view);
+
+  // Whether voice interaction is available via long-press.
+  bool IsVoiceInteractionAvailable();
+
+  // Whether voice interaction is currently running.
+  bool IsVoiceInteractionRunning();
+
+  bool is_showing_app_list() const { return is_showing_app_list_; }
+
+ private:
+  // AppListControllerObserver:
+  void OnAppListVisibilityChanged(bool shown, int64_t display_id) override;
+
+  // SessionObserver:
+  void OnActiveUserSessionChanged(const AccountId& account_id) override;
+
+  // TabletModeObserver:
+  void OnTabletModeStarted() override;
+
+  // mojom::VoiceInteractionObserver:
+  void OnVoiceInteractionStatusChanged(
+      mojom::VoiceInteractionState state) override;
+  void OnVoiceInteractionSettingsEnabled(bool enabled) override;
+  void OnVoiceInteractionConsentStatusUpdated(
+      mojom::ConsentStatus consent_status) override;
+
+  void OnAppListShown();
+  void OnAppListDismissed();
+
+  void StartVoiceInteractionAnimation();
+
+  // Initialize the voice interaction overlay.
+  void InitializeVoiceInteractionOverlay();
+
+  // True if the app list is currently showing for the button's display.
+  // This is useful because other app_list_visible functions aren't per-display.
+  bool is_showing_app_list_ = false;
+
+  // The button that owns this controller.
+  AppListButton* const button_;
+
+  // The shelf the button resides in.
+  Shelf* const shelf_;
+
+  // Owned by the button's view hierarchy. Null if voice interaction is not
+  // enabled.
+  AssistantOverlay* assistant_overlay_ = nullptr;
+  std::unique_ptr<base::OneShotTimer> assistant_animation_delay_timer_;
+  std::unique_ptr<base::OneShotTimer> assistant_animation_hide_delay_timer_;
+  base::TimeTicks voice_interaction_start_timestamp_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppListButtonController);
+};
+
+}  // namespace ash
+
+#endif  // ASH_SHELF_APP_LIST_BUTTON_CONTROLLER_H_
diff --git a/ash/shelf/app_list_shelf_item_delegate.cc b/ash/shelf/app_list_shelf_item_delegate.cc
deleted file mode 100644
index a84e4640..0000000
--- a/ash/shelf/app_list_shelf_item_delegate.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/shelf/app_list_shelf_item_delegate.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "ash/app_list/app_list_controller_impl.h"
-#include "ash/public/cpp/shelf_model.h"
-#include "ash/shell.h"
-
-namespace ash {
-
-AppListShelfItemDelegate::AppListShelfItemDelegate()
-    : ShelfItemDelegate(ShelfID(kAppListId)) {}
-
-AppListShelfItemDelegate::~AppListShelfItemDelegate() = default;
-
-void AppListShelfItemDelegate::ItemSelected(std::unique_ptr<ui::Event> event,
-                                            int64_t display_id,
-                                            ShelfLaunchSource source,
-                                            ItemSelectedCallback callback) {
-  std::move(callback).Run(
-      Shell::Get()->app_list_controller()->OnAppListButtonPressed(
-          display_id,
-          event->IsShiftDown() ? app_list::kShelfButtonFullscreen
-                               : app_list::kShelfButton,
-          event->time_stamp()),
-      base::nullopt);
-}
-
-void AppListShelfItemDelegate::ExecuteCommand(bool from_context_menu,
-                                              int64_t command_id,
-                                              int32_t event_flags,
-                                              int64_t display_id) {
-  // This delegate does not show custom context or application menu items.
-  NOTIMPLEMENTED();
-}
-
-void AppListShelfItemDelegate::Close() {}
-
-}  // namespace ash
diff --git a/ash/shelf/app_list_shelf_item_delegate.h b/ash/shelf/app_list_shelf_item_delegate.h
deleted file mode 100644
index fe6883b..0000000
--- a/ash/shelf/app_list_shelf_item_delegate.h
+++ /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.
-
-#ifndef ASH_SHELF_APP_LIST_SHELF_ITEM_DELEGATE_H_
-#define ASH_SHELF_APP_LIST_SHELF_ITEM_DELEGATE_H_
-
-#include <memory>
-
-#include "ash/ash_export.h"
-#include "ash/public/cpp/shelf_item_delegate.h"
-#include "base/macros.h"
-
-namespace ash {
-
-// ShelfItemDelegate for TYPE_APP_LIST.
-class ASH_EXPORT AppListShelfItemDelegate : public ShelfItemDelegate {
- public:
-  AppListShelfItemDelegate();
-  ~AppListShelfItemDelegate() override;
-
-  // ShelfItemDelegate:
-  void ItemSelected(std::unique_ptr<ui::Event> event,
-                    int64_t display_id,
-                    ShelfLaunchSource source,
-                    ItemSelectedCallback callback) override;
-  void ExecuteCommand(bool from_context_menu,
-                      int64_t command_id,
-                      int32_t event_flags,
-                      int64_t display_id) override;
-  void Close() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AppListShelfItemDelegate);
-};
-
-}  // namespace ash
-
-#endif  // ASH_SHELF_APP_LIST_SHELF_ITEM_DELEGATE_H_
diff --git a/ash/shelf/home_button_delegate.cc b/ash/shelf/home_button_delegate.cc
new file mode 100644
index 0000000..e7c7f7ae
--- /dev/null
+++ b/ash/shelf/home_button_delegate.cc
@@ -0,0 +1,61 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/shelf/home_button_delegate.h"
+
+#include <utility>
+
+#include "ash/app_list/app_list_controller_impl.h"
+#include "ash/home_screen/home_screen_controller.h"
+#include "ash/kiosk_next/kiosk_next_shell_controller.h"
+#include "ash/public/cpp/shelf_model.h"
+#include "ash/shell.h"
+#include "base/logging.h"
+
+namespace ash {
+
+HomeButtonDelegate::HomeButtonDelegate()
+    : ShelfItemDelegate(ShelfID(kAppListId)) {}
+
+HomeButtonDelegate::~HomeButtonDelegate() = default;
+
+// static
+ShelfAction HomeButtonDelegate::PerformHomeButtonAction(
+    int64_t display_id,
+    app_list::AppListShowSource show_source,
+    base::TimeTicks event_time_stamp) {
+  ShelfAction shelf_action = ash::SHELF_ACTION_NONE;
+  if (Shell::Get()->kiosk_next_shell_controller()->IsEnabled()) {
+    Shell::Get()->home_screen_controller()->GoHome(display_id);
+    shelf_action = ash::SHELF_ACTION_APP_LIST_SHOWN;
+  } else {
+    shelf_action = Shell::Get()->app_list_controller()->OnAppListButtonPressed(
+        display_id, show_source, event_time_stamp);
+  }
+  return shelf_action;
+}
+
+void HomeButtonDelegate::ItemSelected(std::unique_ptr<ui::Event> event,
+                                      int64_t display_id,
+                                      ShelfLaunchSource source,
+                                      ItemSelectedCallback callback) {
+  ShelfAction shelf_action = PerformHomeButtonAction(
+      display_id,
+      event->IsShiftDown() ? app_list::kShelfButtonFullscreen
+                           : app_list::kShelfButton,
+      event->time_stamp());
+  std::move(callback).Run(shelf_action, base::nullopt);
+}
+
+void HomeButtonDelegate::ExecuteCommand(bool from_context_menu,
+                                        int64_t command_id,
+                                        int32_t event_flags,
+                                        int64_t display_id) {
+  // This delegate does not show custom context or application menu items.
+  NOTIMPLEMENTED();
+}
+
+void HomeButtonDelegate::Close() {}
+
+}  // namespace ash
diff --git a/ash/shelf/home_button_delegate.h b/ash/shelf/home_button_delegate.h
new file mode 100644
index 0000000..a06bc7c
--- /dev/null
+++ b/ash/shelf/home_button_delegate.h
@@ -0,0 +1,53 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SHELF_HOME_BUTTON_DELEGATE_H_
+#define ASH_SHELF_HOME_BUTTON_DELEGATE_H_
+
+#include <memory>
+
+#include "ash/app_list/app_list_metrics.h"
+#include "ash/ash_export.h"
+#include "ash/public/cpp/shelf_item_delegate.h"
+#include "ash/public/cpp/shelf_types.h"
+#include "base/macros.h"
+
+namespace ash {
+
+// ShelfItemDelegate for the Home button, aka the app list button.
+// TODO(michaelpg): Rename references to app list button to home button.
+class ASH_EXPORT HomeButtonDelegate : public ShelfItemDelegate {
+ public:
+  HomeButtonDelegate();
+  ~HomeButtonDelegate() override;
+
+  // Responds to the home button being activated or the equivalent accelerator
+  // being pressed.
+  // |display_id| is the display of the button, indicating where the Home screen
+  // should be shown.
+  // |show_source| is the type of user action that triggered this.
+  // |event_time_stamp| is timestamp of the triggering event.
+  static ShelfAction PerformHomeButtonAction(
+      int64_t display_id,
+      app_list::AppListShowSource show_source,
+      base::TimeTicks event_time_stamp);
+
+  // ShelfItemDelegate:
+  void ItemSelected(std::unique_ptr<ui::Event> event,
+                    int64_t display_id,
+                    ShelfLaunchSource source,
+                    ItemSelectedCallback callback) override;
+  void ExecuteCommand(bool from_context_menu,
+                      int64_t command_id,
+                      int32_t event_flags,
+                      int64_t display_id) override;
+  void Close() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HomeButtonDelegate);
+};
+
+}  // namespace ash
+
+#endif  // ASH_SHELF_HOME_BUTTON_DELEGATE_H_
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc
index 47ddc43d..16ce6f78 100644
--- a/ash/shelf/login_shelf_view.cc
+++ b/ash/shelf/login_shelf_view.cc
@@ -336,7 +336,8 @@
     origin.set_y(point.y() - source->height());
     menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(), this,
                             gfx::Rect(origin, gfx::Size()),
-                            views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_NONE);
+                            views::MenuAnchorPosition::kTopLeft,
+                            ui::MENU_SOURCE_NONE);
   }
 
   // ui::SimpleMenuModel:
diff --git a/ash/shelf/shelf_controller.cc b/ash/shelf/shelf_controller.cc
index 28d3915..8b4360b 100644
--- a/ash/shelf/shelf_controller.cc
+++ b/ash/shelf/shelf_controller.cc
@@ -9,10 +9,11 @@
 
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/remote_shelf_item_delegate.h"
+#include "ash/public/cpp/shelf_item_delegate.h"
 #include "ash/public/cpp/shelf_prefs.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
-#include "ash/shelf/app_list_shelf_item_delegate.h"
+#include "ash/shelf/home_button_delegate.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shelf/shelf_widget.h"
@@ -121,9 +122,9 @@
   back_item.title = l10n_util::GetStringUTF16(IDS_ASH_SHELF_BACK_BUTTON_TITLE);
   model_.Set(0, back_item);
 
-  // Set the delegate and title string for the app list item.
+  // Set the delegate and title string for the home button.
   model_.SetShelfItemDelegate(ShelfID(kAppListId),
-                              std::make_unique<AppListShelfItemDelegate>());
+                              std::make_unique<HomeButtonDelegate>());
   DCHECK_EQ(1, model_.ItemIndexByID(ShelfID(kAppListId)));
   ShelfItem launcher_item = model_.items()[1];
   launcher_item.title =
@@ -131,9 +132,11 @@
   model_.Set(1, launcher_item);
 
   model_.AddObserver(this);
+
   Shell::Get()->session_controller()->AddObserver(this);
   Shell::Get()->tablet_mode_controller()->AddObserver(this);
   Shell::Get()->window_tree_host_manager()->AddObserver(this);
+
   if (is_notification_indicator_enabled_)
     message_center_observer_.Add(message_center::MessageCenter::Get());
 }
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 87be8b8..54768094 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -483,7 +483,7 @@
   const AppListButton* app_list_button = GetAppListButton();
   if (app_list_button &&
       app_list_button->GetMirroredBounds().Contains(cursor_location)) {
-    return app_list_button->is_showing_app_list();
+    return app_list_button->IsShowingAppList();
   }
   return !visible_shelf_item_bounds_union_.Contains(cursor_location);
 }
@@ -492,7 +492,7 @@
   // If this is the app list button, only show the tooltip if the app list is
   // not already showing.
   if (view == GetAppListButton())
-    return !GetAppListButton()->is_showing_app_list();
+    return !GetAppListButton()->IsShowingAppList();
   if (view == overflow_button_)
     return true;
   // Don't show a tooltip for a view that's currently being dragged.
@@ -2336,8 +2336,8 @@
   shelf_menu_model_adapter_->Run(
       GetMenuAnchorRect(*source, click_point, context_menu),
       shelf_->IsHorizontalAlignment()
-          ? views::MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE
-          : views::MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT,
+          ? views::MenuAnchorPosition::kBubbleTouchableAbove
+          : views::MenuAnchorPosition::kBubbleTouchableLeft,
       run_types);
 }
 
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index a2c5ec7..8922a45 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -1445,7 +1445,7 @@
   const AppListButton* app_list_button = shelf_view_->GetAppListButton();
 
   // Make sure we're not showing the app list.
-  EXPECT_FALSE(app_list_button->is_showing_app_list())
+  EXPECT_FALSE(app_list_button->IsShowingAppList())
       << "We should not be showing the app list";
 
   // The tooltip shouldn't hide if the mouse is on normal buttons.
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 687e132..415e670 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -433,7 +433,7 @@
 }
 
 bool ShelfWidget::IsShowingAppList() const {
-  return GetAppListButton() && GetAppListButton()->is_showing_app_list();
+  return GetAppListButton() && GetAppListButton()->IsShowingAppList();
 }
 
 bool ShelfWidget::IsShowingMenu() const {
diff --git a/ash/shell/window_type_launcher.cc b/ash/shell/window_type_launcher.cc
index 113735b9..7198f6e 100644
--- a/ash/shell/window_type_launcher.cc
+++ b/ash/shell/window_type_launcher.cc
@@ -340,7 +340,7 @@
   menu_runner_.reset(new MenuRunner(
       root, MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
   menu_runner_->RunMenuAt(GetWidget(), NULL, gfx::Rect(point, gfx::Size()),
-                          views::MENU_ANCHOR_TOPLEFT, source_type);
+                          views::MenuAnchorPosition::kTopLeft, source_type);
 }
 
 }  // namespace shell
diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc
index 41c9b2b..a68fd576 100644
--- a/ash/shell_unittest.cc
+++ b/ash/shell_unittest.cc
@@ -429,7 +429,8 @@
   std::unique_ptr<views::MenuRunner> menu_runner(
       new views::MenuRunner(menu_model.get(), views::MenuRunner::CONTEXT_MENU));
 
-  menu_runner->RunMenuAt(widget, NULL, gfx::Rect(), views::MENU_ANCHOR_TOPLEFT,
+  menu_runner->RunMenuAt(widget, NULL, gfx::Rect(),
+                         views::MenuAnchorPosition::kTopLeft,
                          ui::MENU_SOURCE_MOUSE);
   LockScreenAndVerifyMenuClosed();
 }
diff --git a/ash/system/network/tray_network_state_observer.cc b/ash/system/network/tray_network_state_observer.cc
index f0763d3..bf4b19b 100644
--- a/ash/system/network/tray_network_state_observer.cc
+++ b/ash/system/network/tray_network_state_observer.cc
@@ -25,6 +25,12 @@
       chromeos::NetworkTypePattern::WiFi());
 }
 
+bool IsMobileEnabled() {
+  return NetworkHandler::Get()->network_state_handler()->IsTechnologyEnabled(
+      chromeos::NetworkTypePattern::Cellular() |
+      chromeos::NetworkTypePattern::Tether());
+}
+
 }  // namespace
 
 namespace ash {
@@ -78,11 +84,17 @@
 }
 
 void TrayNetworkStateObserver::SignalUpdate(bool notify_a11y) {
-  bool old_state = wifi_enabled_;
+  bool old_wifi_state = wifi_enabled_;
   wifi_enabled_ = IsWifiEnabled();
 
-  // Update immediately when wifi network changed from enabled->disabled.
-  if (old_state && !wifi_enabled_) {
+  bool old_mobile_state = mobile_enabled_;
+  mobile_enabled_ = IsMobileEnabled();
+
+  // Update immediately when Wi-Fi and/or Mobile have been turned on or off.
+  // This ensures that the UI for settings and quick settings stays in sync; see
+  // https://crbug.com/917325.
+  if (old_wifi_state != wifi_enabled_ || old_mobile_state != mobile_enabled_) {
+    timer_.Stop();
     SendNetworkStateChanged(notify_a11y);
     return;
   }
diff --git a/ash/system/network/tray_network_state_observer.h b/ash/system/network/tray_network_state_observer.h
index 2e91a3d..bbead095 100644
--- a/ash/system/network/tray_network_state_observer.h
+++ b/ash/system/network/tray_network_state_observer.h
@@ -52,9 +52,12 @@
   // Timer used to limit the frequency of NetworkStateChanged updates.
   base::OneShotTimer timer_;
 
-  // The previous state of the wifi network, used to immediately send
-  // NetworkStateChanged update when wifi changed from enabled->disabled.
+  // The cached states of whether Wi-Fi and Mobile are enabled. The tray
+  // includes expanding network lists of these types, so these cached values
+  // are used to determine when to prioritize updating the tray when they
+  // change.
   bool wifi_enabled_ = false;
+  bool mobile_enabled_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(TrayNetworkStateObserver);
 };
diff --git a/base/profiler/native_stack_sampler_win.cc b/base/profiler/native_stack_sampler_win.cc
index 4eda475..7487ad86 100644
--- a/base/profiler/native_stack_sampler_win.cc
+++ b/base/profiler/native_stack_sampler_win.cc
@@ -264,9 +264,11 @@
                          ProfileBuilder* profile_builder) override;
 
  private:
-  // Suspends the thread with |thread_handle|, copies its stack, register
-  // context, and current metadata and resumes the thread. Returns true on
-  // success.
+  // Suspends the thread with |thread_handle|, copies its stack base address,
+  // stack, and register context, and records the current metadata, then resumes
+  // the thread.  Returns true on success, and returns the copied state via the
+  // |base_address|, |stack_buffer|, |profile_builder|, and |thread_context|
+  // params.
   static bool CopyStack(HANDLE thread_handle,
                         const void* base_address,
                         StackBuffer* stack_buffer,
@@ -313,8 +315,7 @@
                "NativeStackSamplerWin::RecordStackFrames");
   DCHECK(stack_buffer);
 
-  CONTEXT thread_context = {0};
-  thread_context.ContextFlags = CONTEXT_FULL;
+  CONTEXT thread_context;
   bool success = CopyStack(thread_handle_.Get(), thread_stack_base_address_,
                            stack_buffer, profile_builder, &thread_context);
   if (!success)
@@ -342,6 +343,10 @@
                                       CONTEXT* thread_context) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
                "SuspendThread");
+
+  *thread_context = {0};
+  thread_context->ContextFlags = CONTEXT_FULL;
+
   {
     ScopedSuspendThread suspend_thread(thread_handle);
 
diff --git a/build/android/gyp/java_cpp_enum.py b/build/android/gyp/java_cpp_enum.py
index 2d493f7..bacc8e3 100755
--- a/build/android/gyp/java_cpp_enum.py
+++ b/build/android/gyp/java_cpp_enum.py
@@ -385,7 +385,8 @@
           comments_line_wrapper.wrap(enum_comments)))
       enum_entries_string.append('   */')
     enum_entries_string.append(enum_template.substitute(values))
-    enum_names.append(enum_definition.class_name + '.' + enum_name)
+    if enum_name != "NUM_ENTRIES":
+      enum_names.append(enum_definition.class_name + '.' + enum_name)
   enum_entries_string = '\n'.join(enum_entries_string)
 
   enum_names_indent = ' ' * 4
diff --git a/build/android/stacktrace/crashpad_stackwalker.py b/build/android/stacktrace/crashpad_stackwalker.py
index dc3fd89..a538105 100755
--- a/build/android/stacktrace/crashpad_stackwalker.py
+++ b/build/android/stacktrace/crashpad_stackwalker.py
@@ -92,7 +92,7 @@
                                       r'"(?P<library_name>lib[^. ]+.so)"')
   in_module = False
   for line in stdout.splitlines():
-    line = line.rstrip('\n')
+    line = line.lstrip().rstrip('\n')
     if line == 'MDRawModule':
       in_module = True
       continue
@@ -149,23 +149,23 @@
   if not crashpad_file:
     logging.error('Could not locate a crashpad dump')
     return 1
-  else:
-    dump_dir = tempfile.mkdtemp()
-    symbols_dir = None
-    try:
-      device.PullFile(
-          device_path=posixpath.join(device_crashpad_path, crashpad_file),
-          host_path=dump_dir)
-      dump_full_path = os.path.join(dump_dir, crashpad_file)
-      library_names = _ExtractLibraryNamesFromDump(args.build_path,
-                                                   dump_full_path)
-      symbols_dir = _CreateSymbolsDir(args.build_path, library_names)
-      stackwalk_cmd = [stackwalk_path, dump_full_path, symbols_dir]
-      subprocess.call(stackwalk_cmd)
-    finally:
-      shutil.rmtree(dump_dir, ignore_errors=True)
-      if symbols_dir:
-        shutil.rmtree(symbols_dir, ignore_errors=True)
+
+  dump_dir = tempfile.mkdtemp()
+  symbols_dir = None
+  try:
+    device.PullFile(
+        device_path=posixpath.join(device_crashpad_path, crashpad_file),
+        host_path=dump_dir)
+    dump_full_path = os.path.join(dump_dir, crashpad_file)
+    library_names = _ExtractLibraryNamesFromDump(args.build_path,
+                                                 dump_full_path)
+    symbols_dir = _CreateSymbolsDir(args.build_path, library_names)
+    stackwalk_cmd = [stackwalk_path, dump_full_path, symbols_dir]
+    subprocess.call(stackwalk_cmd)
+  finally:
+    shutil.rmtree(dump_dir, ignore_errors=True)
+    if symbols_dir:
+      shutil.rmtree(symbols_dir, ignore_errors=True)
   return 0
 
 
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 83a07e1..a86f3b2 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-eaac7b7f5bb54fa74873c9d37796702e49e98987
\ No newline at end of file
+0aba3e826b3187b0bd1bfdbf06fbaff168801edd
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 7641efa..b6be569 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-4186125ff0046e4fe61888e0ecb60eae34e42327
\ No newline at end of file
+b058131a0406f496bda02c45ea22c75cf12f7d4d
\ No newline at end of file
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 331491a4..e559854 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -954,6 +954,7 @@
             "//third_party/gvr-android-sdk:controller_test_api_java",
             "//third_party/gvr-android-sdk:gvr_common_java",
             ":chrome_test_util_java",
+            "//components/module_installer/android:module_installer_java",
             "//components/module_installer/android:module_installer_test_java",
           ]
 
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index e3621c8..b22fce0 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -10,6 +10,7 @@
     "java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtils.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java",
+    "java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinder.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetMediator.java",
@@ -43,6 +44,7 @@
     "//chrome/android:chrome_strings_grd",
     "//chrome/android:ui_locale_string_resources",
     "//chrome/app:java_strings_grd",
+    "//components/embedder_support/android:web_contents_delegate_java",
     "//components/feature_engagement:feature_engagement_java",
     "//components/policy/android:policy_java",
     "//content/public/android:content_java_resources",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java
index 11cf153e..55a0d5d 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java
@@ -6,6 +6,7 @@
 
 import android.content.Context;
 
+import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeController;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
@@ -33,6 +34,7 @@
     private final ActivityLifecycleDispatcher mLifecycleDispatcher;
     private final TabListCoordinator mTabGridCoordinator;
     private final GridTabSwitcherMediator mMediator;
+    private final MultiThumbnailCardProvider mMultiThumbnailCardProvider;
 
     public GridTabSwitcherCoordinator(Context context,
             ActivityLifecycleDispatcher lifecycleDispatcher, ToolbarManager toolbarManager,
@@ -40,8 +42,22 @@
             CompositorViewHolder compositorViewHolder, ChromeFullscreenManager fullscreenManager) {
         PropertyModel containerViewModel = new PropertyModel(TabListContainerProperties.ALL_KEYS);
 
+        mMultiThumbnailCardProvider =
+                new MultiThumbnailCardProvider(context, tabContentManager, tabModelSelector);
+
+        TabListMediator.TitleProvider titleProvider = tab -> {
+            int numRelatedTabs = tabModelSelector.getTabModelFilterProvider()
+                                         .getCurrentTabModelFilter()
+                                         .getRelatedTabList(tab.getId())
+                                         .size();
+            if (numRelatedTabs == 1) return tab.getTitle();
+            return context.getResources().getQuantityString(
+                    R.plurals.bottom_tab_grid_title_placeholder, numRelatedTabs, numRelatedTabs);
+        };
+
         mTabGridCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context,
-                tabModelSelector, tabContentManager, compositorViewHolder, true, COMPONENT_NAME);
+                tabModelSelector, mMultiThumbnailCardProvider, titleProvider, compositorViewHolder,
+                true, COMPONENT_NAME);
 
         mContainerViewChangeProcessor = PropertyModelChangeProcessor.create(containerViewModel,
                 mTabGridCoordinator.getContainerView(), TabGridContainerViewBinder::bind);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
new file mode 100644
index 0000000..1f3d1d44
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
@@ -0,0 +1,224 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.Callback;
+import org.chromium.base.PathUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.task.AsyncTask;
+import org.chromium.base.task.PostTask;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A {@link TabListMediator.ThumbnailProvider} that will create a single Bitmap Thumbnail for all
+ * the related tabs for the given tabs.
+ */
+public class MultiThumbnailCardProvider implements TabListMediator.ThumbnailProvider {
+    private final TabContentManager mTabContentManager;
+    private final TabModelSelector mTabModelSelector;
+
+    private final float mPadding;
+    private final float mRadius;
+    private final Paint mEmptyThumbnailPaint;
+    private final Paint mThumbnailFramePaint;
+    private final Paint mTextPaint;
+    private final int mSize;
+    private final List<RectF> mRects = new ArrayList<>(4);
+
+    private class MultiThumbnailFetchingTask extends AsyncTask<Void> {
+        private final Tab mInitialTab;
+        private final Callback<Bitmap> mFinalCallback;
+        private final List<Tab> mTabs = new ArrayList<>(4);
+        private final AtomicInteger mThumbnailsToFetch = new AtomicInteger();
+
+        private Canvas mCanvas;
+        private Bitmap mMultiThumbnailBitmap;
+        private String mText;
+
+        MultiThumbnailFetchingTask(Tab initialTab, Callback<Bitmap> finalCallback) {
+            mFinalCallback = finalCallback;
+            mInitialTab = initialTab;
+        }
+
+        private void initializeAndStartFetching(Tab tab) {
+            // Initialize mMultiThumbnailBitmap.
+            int width = mSize;
+            int height = mSize;
+            mMultiThumbnailBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            mCanvas = new Canvas(mMultiThumbnailBitmap);
+            mCanvas.drawColor(Color.TRANSPARENT);
+
+            // Initialize Tabs.
+            List<Tab> relatedTabList = new ArrayList<>();
+            relatedTabList.addAll(mTabModelSelector.getTabModelFilterProvider()
+                                          .getCurrentTabModelFilter()
+                                          .getRelatedTabList(tab.getId()));
+            if (relatedTabList.size() <= 4) {
+                mThumbnailsToFetch.set(relatedTabList.size());
+
+                mTabs.add(tab);
+                relatedTabList.remove(tab);
+
+                for (int i = 0; i < 3; i++) {
+                    mTabs.add(i < relatedTabList.size() ? relatedTabList.get(i) : null);
+                }
+            } else {
+                mText = "+" + (relatedTabList.size() - 3);
+                mThumbnailsToFetch.set(3);
+
+                mTabs.add(tab);
+                relatedTabList.remove(tab);
+
+                mTabs.add(relatedTabList.get(0));
+                mTabs.add(relatedTabList.get(1));
+                mTabs.add(null);
+            }
+
+            // Fetch and draw all.
+            for (int i = 0; i < 4; i++) {
+                if (mTabs.get(i) != null) {
+                    if (hasThumbnailFileForTab(mTabs.get(i).getId())) {
+                        final int index = i;
+                        mTabContentManager.getTabThumbnailWithCallback(mTabs.get(i), result -> {
+                            drawBitmapOnCanvasWithFrame(result, index, mEmptyThumbnailPaint);
+                            if (mThumbnailsToFetch.decrementAndGet() == 0) {
+                                PostTask.postTask(UiThreadTaskTraits.USER_VISIBLE,
+                                        () -> mFinalCallback.onResult(mMultiThumbnailBitmap));
+                            }
+                        });
+                    } else {
+                        if (mThumbnailsToFetch.decrementAndGet() == 0) {
+                            PostTask.postTask(UiThreadTaskTraits.USER_VISIBLE,
+                                    () -> mFinalCallback.onResult(mMultiThumbnailBitmap));
+                        }
+                    }
+                } else {
+                    drawBitmapOnCanvasWithFrame(null, i, mEmptyThumbnailPaint);
+                    if (mText != null && i == 3) {
+                        // Draw the text exactly centered on the thumbnail rect.
+                        mCanvas.drawText(mText, (mRects.get(i).left + mRects.get(i).right) / 2,
+                                (mRects.get(i).top + mRects.get(i).bottom) / 2
+                                        - ((mTextPaint.descent() + mTextPaint.ascent()) / 2),
+                                mTextPaint);
+                    }
+                }
+            }
+        }
+
+        private void drawBitmapOnCanvasWithFrame(
+                Bitmap result, int index, Paint emptyThumbnailPaint) {
+            // Draw the rounded rect. If Bitmap is not null, this is used for XferMode.
+            mCanvas.drawRoundRect(mRects.get(index), mRadius, mRadius, emptyThumbnailPaint);
+
+            if (result == null) return;
+
+            result = Bitmap.createScaledBitmap(result, (int) mRects.get(index).width(),
+                    (int) mRects.get(index).height(), true);
+
+            emptyThumbnailPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+            mCanvas.drawBitmap(result, new Rect(0, 0, result.getWidth(), result.getHeight()),
+                    mRects.get(index), emptyThumbnailPaint);
+            result.recycle();
+
+            emptyThumbnailPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
+
+            mCanvas.drawRoundRect(mRects.get(index), mRadius, mRadius, mThumbnailFramePaint);
+        }
+
+        @Override
+        protected Void doInBackground() {
+            initializeAndStartFetching(mInitialTab);
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(Void aVoid) {}
+    }
+
+    MultiThumbnailCardProvider(Context context, TabContentManager tabContentManager,
+            TabModelSelector tabModelSelector) {
+        mTabContentManager = tabContentManager;
+        mTabModelSelector = tabModelSelector;
+        mPadding = context.getResources().getDimension(R.dimen.tab_list_card_padding);
+        mRadius = context.getResources().getDimension(R.dimen.tab_list_mini_card_radius);
+        mSize = (int) context.getResources().getDimension(
+                R.dimen.tab_grid_thumbnail_card_default_size);
+
+        // Initialize Paints to use.
+        mEmptyThumbnailPaint = new Paint();
+        mEmptyThumbnailPaint.setStyle(Paint.Style.FILL);
+        mEmptyThumbnailPaint.setColor(
+                ApiCompatibilityUtils.getColor(context.getResources(), R.color.modern_grey_100));
+        mEmptyThumbnailPaint.setAntiAlias(true);
+
+        mThumbnailFramePaint = new Paint();
+        mThumbnailFramePaint.setStyle(Paint.Style.STROKE);
+        mThumbnailFramePaint.setStrokeWidth(
+                context.getResources().getDimension(R.dimen.tab_list_mini_card_frame_size));
+        mThumbnailFramePaint.setColor(
+                ApiCompatibilityUtils.getColor(context.getResources(), R.color.modern_grey_300));
+        mThumbnailFramePaint.setAntiAlias(true);
+
+        mTextPaint = new Paint();
+        mTextPaint.setTextSize(
+                context.getResources().getDimension(R.dimen.compositor_tab_title_text_size));
+        mTextPaint.setFakeBoldText(true);
+        mTextPaint.setAntiAlias(true);
+        mTextPaint.setTextAlign(Paint.Align.CENTER);
+
+        // Initialize Rects.
+        mRects.add(
+                new RectF(mPadding, mPadding, mSize / 2 - mPadding / 2, mSize / 2 - mPadding / 2));
+        mRects.add(new RectF(
+                mSize / 2 + mPadding / 2, mPadding, mSize - mPadding, mSize / 2 - mPadding / 2));
+        mRects.add(new RectF(
+                mPadding, mSize / 2 + mPadding / 2, mSize / 2 - mPadding / 2, mSize - mPadding));
+        mRects.add(new RectF(mSize / 2 + mPadding / 2, mSize / 2 + mPadding / 2, mSize - mPadding,
+                mSize - mPadding));
+    }
+
+    @Override
+    public void getTabThumbnailWithCallback(Tab tab, Callback<Bitmap> finalCallback) {
+        if (mTabModelSelector.getTabModelFilterProvider()
+                        .getCurrentTabModelFilter()
+                        .getRelatedTabList(tab.getId())
+                        .size()
+                == 1) {
+            mTabContentManager.getTabThumbnailWithCallback(tab, finalCallback);
+            return;
+        }
+
+        new MultiThumbnailFetchingTask(tab, finalCallback)
+                .executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+    }
+
+    private static boolean hasThumbnailFileForTab(int tabId) {
+        ThreadUtils.assertOnBackgroundThread();
+
+        // The thumbnail file path for a tab with id, ID is "cache_directory_path/ID".
+        File file = new File(PathUtils.getThumbnailCacheDirectory() + "/" + tabId);
+        return file.exists();
+    }
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/SilenceLintErrors.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/SilenceLintErrors.java
index 126c0cab..8db01bc 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/SilenceLintErrors.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/SilenceLintErrors.java
@@ -26,6 +26,8 @@
                     R.string.iph_tab_groups_tap_to_see_another_tab_accessibility_text,
                     R.string.accessibility_bottom_tab_strip_expand_tab_sheet,
                     R.layout.bottom_tab_strip_toolbar, R.drawable.tabstrip_selected,
+                    R.dimen.tab_list_card_padding, R.dimen.tab_list_mini_card_text_size,
+                    R.dimen.tab_list_mini_card_frame_size, R.dimen.tab_list_mini_card_radius,
                     R.drawable.tabstrip_favicon_background};
 
     private SilenceLintErrors() {}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java
index 0c84d6b..4eca89d 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java
@@ -44,8 +44,8 @@
         mToolbarPropertyModel = new PropertyModel(TabGridSheetProperties.ALL_KEYS);
 
         mTabGridCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context,
-                tabModelSelector, tabContentManager, bottomSheetController.getBottomSheet(), false,
-                COMPONENT_NAME);
+                tabModelSelector, tabContentManager::getTabThumbnailWithCallback, null,
+                bottomSheetController.getBottomSheet(), false, COMPONENT_NAME);
 
         mMediator = new TabGridSheetMediator(mContext, bottomSheetController,
                 this::resetWithListOfTabs, mToolbarPropertyModel, tabModelSelector,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
index 6e6e44d3..f3c58a3 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
@@ -59,7 +59,7 @@
         TabContentManager tabContentManager = activity.getTabContentManager();
 
         mTabStripCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.STRIP,
-                mContext, tabModelSelector, tabContentManager,
+                mContext, tabModelSelector, null, null,
                 mTabStripToolbarCoordinator.getTabListContainerView(), true, COMPONENT_NAME);
 
         mTabGridSheetCoordinator =
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
index fc83adeb..f1a69485 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
@@ -14,7 +14,6 @@
 import android.view.ViewGroup;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.lifecycle.Destroyable;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
@@ -55,7 +54,8 @@
      * @param context The context to use for accessing {@link android.content.res.Resources}.
      * @param tabModelSelector {@link TabModelSelector} that will provide and receive signals about
      *                              the tabs concerned.
-     * @param tabContentManager {@link TabContentManager} to provide screenshot related details.
+     * @param thumbnailProvider Provider to provide screenshot related details.
+     * @param titleProvider Provider for a given tab's title.
      * @param parentView {@link ViewGroup} The root view of the UI.
      * @param attachToParent Whether the UI should attach to root view.
      * @param componentName A unique string uses to identify different components for UMA recording.
@@ -63,7 +63,8 @@
      *                      through actions.xml file.
      */
     TabListCoordinator(@TabListMode int mode, Context context, TabModelSelector tabModelSelector,
-            TabContentManager tabContentManager, @NonNull ViewGroup parentView,
+            TabListMediator.ThumbnailProvider thumbnailProvider,
+            TabListMediator.TitleProvider titleProvider, @NonNull ViewGroup parentView,
             boolean attachToParent, String componentName) {
         TabListModel tabListModel = new TabListModel();
         mMode = mode;
@@ -106,11 +107,11 @@
 
         mRecyclerView.setHasFixedSize(true);
 
-        TabListFaviconProvider mTabListFaviconProvider =
+        TabListFaviconProvider tabListFaviconProvider =
                 new TabListFaviconProvider(context, Profile.getLastUsedProfile());
 
-        mMediator = new TabListMediator(tabListModel, tabModelSelector, tabContentManager,
-                mTabListFaviconProvider, componentName);
+        mMediator = new TabListMediator(tabListModel, tabModelSelector, thumbnailProvider,
+                titleProvider, tabListFaviconProvider, componentName);
     }
 
     /**
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
index d859691c..eefed2fb 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -11,7 +11,6 @@
 import org.chromium.base.Callback;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.native_page.NativePageFactory;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
@@ -43,6 +42,11 @@
     }
 
     /**
+     * An interface to get the title to be used for a tab.
+     */
+    public interface TitleProvider { String getTitle(Tab tab); }
+
+    /**
      * The object to set to TabProperties.THUMBNAIL_FETCHER for the TabGridViewBinder to obtain
      * the thumbnail asynchronously.
      */
@@ -62,7 +66,8 @@
     private final TabListFaviconProvider mTabListFaviconProvider;
     private final TabListModel mModel;
     private final TabModelSelector mTabModelSelector;
-    private final TabContentManager mTabContentManager;
+    private final ThumbnailProvider mThumbnailProvider;
+    private final TitleProvider mTitleProvider;
     private final String mComponentName;
 
     private final TabActionListener mTabSelectedListener = new TabActionListener() {
@@ -130,7 +135,7 @@
         public void onTitleUpdated(Tab updatedTab) {
             int index = mModel.indexFromId(updatedTab.getId());
             if (index == TabModel.INVALID_TAB_INDEX) return;
-            mModel.get(index).set(TabProperties.TITLE, updatedTab.getTitle());
+            mModel.get(index).set(TabProperties.TITLE, mTitleProvider.getTitle(updatedTab));
         }
 
         @Override
@@ -156,18 +161,20 @@
      * @param model The Model to keep state about a list of {@link Tab}s.
      * @param tabModelSelector {@link TabModelSelector} that will provide and receive signals about
      *                                                 the tabs concerned.
-     * @param tabContentManager {@link TabContentManager} to provide screenshot related details.
+     * @param thumbnailProvider {@link ThumbnailProvider} to provide screenshot related details.
+     * @param titleProvider {@link TitleProvider} for a given tab's title to show.
+     * @param tabListFaviconProvider Provider for all favicon related drawables.
      * @param componentName This is a unique string to identify different components.
      */
-
     public TabListMediator(TabListModel model, TabModelSelector tabModelSelector,
-            TabContentManager tabContentManager, TabListFaviconProvider tabListFaviconProvider,
-            String componentName) {
+            @Nullable ThumbnailProvider thumbnailProvider, @Nullable TitleProvider titleProvider,
+            TabListFaviconProvider tabListFaviconProvider, String componentName) {
         mTabModelSelector = tabModelSelector;
-        mTabContentManager = tabContentManager;
+        mThumbnailProvider = thumbnailProvider;
         mModel = model;
         mTabListFaviconProvider = tabListFaviconProvider;
         mComponentName = componentName;
+        mTitleProvider = titleProvider != null ? titleProvider : Tab::getTitle;
 
         mTabModelObserver = new EmptyTabModelObserver() {
             @Override
@@ -247,7 +254,7 @@
         PropertyModel tabInfo =
                 new PropertyModel.Builder(TabProperties.ALL_KEYS_TAB_GRID)
                         .with(TabProperties.TAB_ID, tab.getId())
-                        .with(TabProperties.TITLE, tab.getTitle())
+                        .with(TabProperties.TITLE, mTitleProvider.getTitle(tab))
                         .with(TabProperties.FAVICON,
                                 mTabListFaviconProvider.getDefaultFaviconDrawable())
                         .with(TabProperties.IS_SELECTED, isSelected)
@@ -269,9 +276,10 @@
         mTabListFaviconProvider.getFaviconForUrlAsync(
                 tab.getUrl(), tab.isIncognito(), faviconCallback);
 
-        ThumbnailFetcher callback =
-                new ThumbnailFetcher(mTabContentManager::getTabThumbnailWithCallback, tab);
-        tabInfo.set(TabProperties.THUMBNAIL_FETCHER, callback);
+        if (mThumbnailProvider != null) {
+            ThumbnailFetcher callback = new ThumbnailFetcher(mThumbnailProvider, tab);
+            tabInfo.set(TabProperties.THUMBNAIL_FETCHER, callback);
+        }
         tab.addObserver(mTabObserver);
     }
 }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
index 255f1a7..64514288 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -122,8 +122,9 @@
                 .getFaviconForUrlAsync(anyString(), anyBoolean(), mCallbackCaptor.capture());
 
         mModel = new TabListModel();
-        mMediator = new TabListMediator(mModel, mTabModelSelector, mTabContentManager,
-                mTabListFaviconProvider, getClass().getSimpleName());
+        mMediator = new TabListMediator(mModel, mTabModelSelector,
+                mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider,
+                getClass().getSimpleName());
     }
 
     @After
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java
index 4cae074..6e97197 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java
@@ -4,13 +4,11 @@
 
 package org.chromium.chrome.browser.vr;
 
-import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.modules.ModuleInstallUi;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.components.module_installer.Module;
 import org.chromium.components.module_installer.OnModuleInstallFinishedListener;
 
 import java.util.ArrayList;
@@ -87,15 +85,6 @@
         for (VrModeObserver observer : sVrModeObservers) observer.onExitVr();
     }
 
-    @VisibleForTesting
-    public static void setAlwaysUseFallbackDelegate(boolean useFallbackDelegate) {
-        // TODO(crbug.com/944216): Remove this method and call Module.setForceUninstalled("vr")
-        // directly once we change the restriction checking code to use the Daydream API directly so
-        // that a delegate provider doesn't get created during pre-test setup.
-        sDelegateProvider = null;
-        Module.setForceUninstalled("vr");
-    }
-
     /* package */ static void installModule(OnModuleInstallFinishedListener onFinishedListener) {
         VrModule.install((success) -> {
             if (success) {
diff --git a/chrome/android/java/res/drawable/selected_tab_background.xml b/chrome/android/java/res/drawable/selected_tab_background.xml
index 6dd969f..23af4b4 100644
--- a/chrome/android/java/res/drawable/selected_tab_background.xml
+++ b/chrome/android/java/res/drawable/selected_tab_background.xml
@@ -6,6 +6,6 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
     <stroke
         android:width="2dp"
-        android:color="@color/modern_grey_700" />
+        android:color="@color/modern_blue_600" />
     <corners android:radius="@dimen/default_card_corner_radius" />
 </shape>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/tab_grid_card_item.xml b/chrome/android/java/res/layout/tab_grid_card_item.xml
index 04faf36..d8dc9d27 100644
--- a/chrome/android/java/res/layout/tab_grid_card_item.xml
+++ b/chrome/android/java/res/layout/tab_grid_card_item.xml
@@ -6,7 +6,7 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="216dp">
+    android:layout_height="wrap_content">
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -35,10 +35,12 @@
             <org.chromium.ui.widget.RoundedCornerImageView
                 android:id="@+id/tab_thumbnail"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent"
+                android:layout_height="wrap_content"
+                android:minHeight="@dimen/tab_grid_thumbnail_card_default_size"
                 android:layout_below="@id/tab_title"
                 android:gravity="center_horizontal"
-                android:scaleType="centerCrop"
+                android:adjustViewBounds="true"
+                android:scaleType="fitCenter"
                 android:importantForAccessibility="no"
                 android:src="@color/thumbnail_placeholder_on_primary_bg"
                 app:cornerRadiusBottomStart="@dimen/default_card_corner_radius"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index e421560..52ee5b4 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -596,6 +596,11 @@
 
     <!-- Tab List dimensions -->
     <dimen name="tab_grid_favicon_size">32dp</dimen>
-    <dimen name="tab_list_selected_inset">6dp</dimen>
+    <dimen name="tab_list_selected_inset">7dp</dimen>
+    <dimen name="tab_list_card_padding">8dp</dimen>
+    <dimen name="tab_list_mini_card_radius">4dp</dimen>
+    <dimen name="tab_list_mini_card_frame_size">1dp</dimen>
+    <dimen name="tab_list_mini_card_text_size">12sp</dimen>
+    <dimen name="tab_grid_thumbnail_card_default_size">152dp</dimen>
 
 </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTask.java
index 167f67a..86eb1ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTask.java
@@ -54,7 +54,7 @@
 
     @Override
     protected boolean onStopTaskBeforeNativeLoaded(Context context, TaskParameters taskParameters) {
-        assert taskParameters.getTaskId() == TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID;
+        assert taskParameters.getTaskId() == TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID;
 
         // Native didn't complete loading, but it was supposed to.
         // Presume we need to reschedule.
@@ -63,10 +63,12 @@
 
     @Override
     protected boolean onStopTaskWithNative(Context context, TaskParameters taskParameters) {
-        assert taskParameters.getTaskId() == TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID;
+        assert taskParameters.getTaskId() == TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID;
 
-        // Don't reschedule again.
-        return false;
+        // The method is called when the task was interrupted due to some reason.
+        // It is not called when the task finishes successfully. Reschedule so
+        // we can attempt it again.
+        return true;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
index 35f45b51..c17abd5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -72,6 +72,21 @@
     @VisibleForTesting
     static final String EXTRA_MARKET_REFERRER = "market_referrer";
 
+    @IntDef({WebApkLaunchDecision.LAUNCHED, WebApkLaunchDecision.LAUNCH_FAILED,
+            WebApkLaunchDecision.ALREADY_IN_WEBAPK,
+            WebApkLaunchDecision.WEBAPK_NOT_SOLE_INTENT_HANDLER})
+    public @interface WebApkLaunchDecision {
+        int LAUNCHED = 0;
+        int LAUNCH_FAILED = 1;
+
+        // User is either in target WebAPK or in CCT launched by the target WebAPK.
+        int ALREADY_IN_WEBAPK = 2;
+
+        // The WebAPK either cannot handle intent or there are multiple non-browser apps which
+        // can handle the intent.
+        int WEBAPK_NOT_SOLE_INTENT_HANDLER = 3;
+    }
+
     // These values are persisted in histograms. Please do not renumber. Append only.
     @IntDef({AiaIntent.FALLBACK_USED, AiaIntent.SERP, AiaIntent.OTHER})
     @Retention(RetentionPolicy.SOURCE)
@@ -400,15 +415,7 @@
             return OverrideUrlLoadingResult.NO_OVERRIDE;
         }
 
-        // Sanitize the Intent, ensuring web pages can not bypass browser
-        // security (only access to BROWSABLE activities).
-        intent.addCategory(Intent.CATEGORY_BROWSABLE);
-        intent.setComponent(null);
-        Intent selector = intent.getSelector();
-        if (selector != null) {
-            selector.addCategory(Intent.CATEGORY_BROWSABLE);
-            selector.setComponent(null);
-        }
+        sanitizeQueryIntentActivitiesIntent(intent);
 
         List<ResolveInfo> resolvingInfos = mDelegate.queryIntentActivities(intent);
         if (resolvingInfos == null) return OverrideUrlLoadingResult.NO_OVERRIDE;
@@ -419,6 +426,32 @@
         // from the Market.
         if (!canResolveActivity) {
             if (hasBrowserFallbackUrl) {
+                // Launch WebAPK if it can handle the URL.
+                if (!TextUtils.isEmpty(intent.getPackage())
+                        || (intent.getSelector() != null
+                                && !TextUtils.isEmpty(intent.getSelector().getPackage()))) {
+                    try {
+                        intent = Intent.parseUri(browserFallbackUrl, Intent.URI_INTENT_SCHEME);
+                    } catch (Exception e) {
+                        if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Could not parse fallback url");
+                        return OverrideUrlLoadingResult.NO_OVERRIDE;
+                    }
+                    sanitizeQueryIntentActivitiesIntent(intent);
+                    resolvingInfos = mDelegate.queryIntentActivities(intent);
+                    switch (launchWebApkIfSoleIntentHandler(params, resolvingInfos, intent)) {
+                        case WebApkLaunchDecision.ALREADY_IN_WEBAPK:
+                            if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Already in WebAPK");
+                            return OverrideUrlLoadingResult.NO_OVERRIDE;
+                        case WebApkLaunchDecision.LAUNCH_FAILED:
+                            if (DEBUG) Log.i(TAG, "NO_OVERRIDE: WebAPK launch failed");
+                            return OverrideUrlLoadingResult.NO_OVERRIDE;
+                        case WebApkLaunchDecision.LAUNCHED:
+                            if (DEBUG) Log.i(TAG, "OVERRIDE_WITH_EXTERNAL_INTENT: Launched WebAPK");
+                            return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT;
+                        case WebApkLaunchDecision.WEBAPK_NOT_SOLE_INTENT_HANDLER:
+                            break;
+                    }
+                }
                 return clobberCurrentTabWithFallbackUrl(browserFallbackUrl, params);
             }
 
@@ -602,31 +635,18 @@
             IntentWithGesturesHandler.getInstance().onNewIntentWithGesture(intent);
         }
 
-        // If the only specialized intent handler is a WebAPK, set the intent's package to
-        // launch the WebAPK without showing the intent picker.
-        String targetWebApkPackageName = mDelegate.findFirstWebApkPackageName(resolvingInfos);
-
-        // We can't rely on this falling through to startActivityIfNeeded and behaving
-        // correctly for WebAPKs. This is because the target of the intent is the WebApk's main
-        // activity but that's just a bouncer which will redirect to WebApkActivity in chrome.
-        // To avoid bouncing indefinitely, don't override the navigation if we are currently
-        // showing the WebApk |params.webApkPackageName()| that we will redirect to.
-        if (targetWebApkPackageName != null
-                && targetWebApkPackageName.equals(params.nativeClientPackageName())) {
-            if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Navigation in WebApk");
-            return OverrideUrlLoadingResult.NO_OVERRIDE;
-        }
-
-        if (targetWebApkPackageName != null
-                && mDelegate.countSpecializedHandlers(resolvingInfos) == 1) {
-            intent.setPackage(targetWebApkPackageName);
-        }
-
-        // http://crbug.com/831806 : Stay in the CCT if the CCT is opened by WebAPK and the url
-        // is within the WebAPK scope.
-        if (shouldStayInWebappCCT(params, resolvingInfos)) {
-            if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Navigation in CCT within scope of parent webapp.");
-            return OverrideUrlLoadingResult.NO_OVERRIDE;
+        switch (launchWebApkIfSoleIntentHandler(params, resolvingInfos, intent)) {
+            case WebApkLaunchDecision.ALREADY_IN_WEBAPK:
+                if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Already in WebAPK");
+                return OverrideUrlLoadingResult.NO_OVERRIDE;
+            case WebApkLaunchDecision.LAUNCH_FAILED:
+                if (DEBUG) Log.i(TAG, "NO_OVERRIDE: WebAPK launch failed");
+                return OverrideUrlLoadingResult.NO_OVERRIDE;
+            case WebApkLaunchDecision.LAUNCHED:
+                if (DEBUG) Log.i(TAG, "OVERRIDE_WITH_EXTERNAL_INTENT: Launched WebAPK");
+                return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT;
+            case WebApkLaunchDecision.WEBAPK_NOT_SOLE_INTENT_HANDLER:
+                break;
         }
 
         try {
@@ -645,6 +665,20 @@
     }
 
     /**
+     * Sanitize intent to be passed to {@link ExternalNavigationDelegate#queryIntentActivities()}
+     * ensuring that web pages cannot bypass browser security.
+     */
+    private void sanitizeQueryIntentActivitiesIntent(Intent intent) {
+        intent.addCategory(Intent.CATEGORY_BROWSABLE);
+        intent.setComponent(null);
+        Intent selector = intent.getSelector();
+        if (selector != null) {
+            selector.addCategory(Intent.CATEGORY_BROWSABLE);
+            selector.setComponent(null);
+        }
+    }
+
+    /**
      * @return OVERRIDE_WITH_EXTERNAL_INTENT when we successfully started market activity,
      *         NO_OVERRIDE otherwise.
      */
@@ -775,10 +809,10 @@
         return null;
     }
 
-    // Returns whether a navigation in a CustomTabActivity opened from a WebAPK/TWA should stay
+    // Returns whether a navigation in a CustomTabActivity opened from a WebAPK should stay
     // within the CustomTabActivity. Returns false if the navigation does not occur within a
     // CustomTabActivity or the CustomTabActivity was not opened from a WebAPK/TWA.
-    private boolean shouldStayInWebappCCT(
+    private boolean shouldStayInWebApkCCT(
             ExternalNavigationParams params, List<ResolveInfo> handlers) {
         Tab tab = params.getTab();
         if (tab == null || !tab.isCurrentlyACustomTab() || tab.getActivity() == null) {
@@ -806,6 +840,43 @@
     }
 
     /**
+     * Launches WebAPK if the WebAPK is the sole non-browser handler for the given intent.
+     * Returns whether a WebAPK was launched and if it was not launched returns why.
+     */
+    private @WebApkLaunchDecision int launchWebApkIfSoleIntentHandler(
+            ExternalNavigationParams params, List<ResolveInfo> resolvingInfos, Intent intent) {
+        if (shouldStayInWebApkCCT(params, resolvingInfos)) {
+            return WebApkLaunchDecision.ALREADY_IN_WEBAPK;
+        }
+
+        String targetWebApkPackageName = mDelegate.findFirstWebApkPackageName(resolvingInfos);
+
+        // We can't rely on this falling through to startActivityIfNeeded and behaving
+        // correctly for WebAPKs. This is because the target of the intent is the WebApk's main
+        // activity but that's just a bouncer which will redirect to WebApkActivity in chrome.
+        // To avoid bouncing indefinitely, don't override the navigation if we are currently
+        // showing the WebApk |params.webApkPackageName()| that we will redirect to.
+        if (targetWebApkPackageName != null
+                && targetWebApkPackageName.equals(params.nativeClientPackageName())) {
+            return WebApkLaunchDecision.ALREADY_IN_WEBAPK;
+        }
+
+        if (targetWebApkPackageName == null
+                || mDelegate.countSpecializedHandlers(resolvingInfos) != 1) {
+            return WebApkLaunchDecision.WEBAPK_NOT_SOLE_INTENT_HANDLER;
+        }
+
+        intent.setPackage(targetWebApkPackageName);
+        try {
+            if (mDelegate.startActivityIfNeeded(intent, false)) {
+                return WebApkLaunchDecision.LAUNCHED;
+            }
+        } catch (ActivityNotFoundException e) {
+        }
+        return WebApkLaunchDecision.LAUNCH_FAILED;
+    }
+
+    /**
      * Returns whether or not there's an activity available to handle the intent.
      */
     private boolean deviceCanHandleIntent(Intent intent) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
index e4e83d5d3..cf7c8f6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -836,6 +836,37 @@
 
     @Test
     @SmallTest
+    public void testFallbackUrl_FallbackToWebApk() {
+        // IMDB app isn't installed.
+        mDelegate.setCanResolveActivityForExternalSchemes(false);
+
+        mDelegate.add(new IntentActivity(IMDB_WEBPAGE_FOR_TOM_HANKS, WEBAPK_PACKAGE_NAME)
+                              .withIsWebApk(true));
+        checkUrl(INTENT_URL_WITH_FALLBACK_URL)
+                .withReferrer(SEARCH_RESULT_URL_FOR_TOM_HANKS)
+                .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT, START_WEBAPK);
+    }
+
+    @Test
+    @SmallTest
+    public void testFallbackUrl_DontFallbackToWebApkMultipleHandlers() {
+        // IMDB app isn't installed.
+        mDelegate.setCanResolveActivityForExternalSchemes(false);
+
+        mDelegate.add(new IntentActivity(IMDB_WEBPAGE_FOR_TOM_HANKS, WEBAPK_PACKAGE_NAME)
+                              .withIsWebApk(true));
+        mDelegate.add(new IntentActivity(IMDB_WEBPAGE_FOR_TOM_HANKS, TEXT_APP_1_PACKAGE_NAME));
+        checkUrl(INTENT_URL_WITH_FALLBACK_URL)
+                .withReferrer(SEARCH_RESULT_URL_FOR_TOM_HANKS)
+                .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
+        Assert.assertNull(mDelegate.startActivityIntent);
+        Assert.assertEquals(IMDB_WEBPAGE_FOR_TOM_HANKS, mDelegate.getNewUrlAfterClobbering());
+        Assert.assertEquals(
+                SEARCH_RESULT_URL_FOR_TOM_HANKS, mDelegate.getReferrerUrlForClobbering());
+    }
+
+    @Test
+    @SmallTest
     public void testFallbackUrl_IntentResolutionFails() {
         // IMDB app isn't installed.
         mDelegate.setCanResolveActivityForExternalSchemes(false);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTestRuleUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTestRuleUtils.java
index 85bf41e..e8c47c14 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTestRuleUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrTestRuleUtils.java
@@ -19,13 +19,13 @@
 import org.chromium.chrome.browser.vr.TestVrShellDelegate;
 import org.chromium.chrome.browser.vr.VrFeedbackStatus;
 import org.chromium.chrome.browser.vr.VrIntentDelegate;
-import org.chromium.chrome.browser.vr.VrModuleProvider;
 import org.chromium.chrome.browser.vr.rules.ChromeTabbedActivityVrTestRule;
 import org.chromium.chrome.browser.vr.rules.CustomTabActivityVrTestRule;
 import org.chromium.chrome.browser.vr.rules.VrActivityRestrictionRule;
 import org.chromium.chrome.browser.vr.rules.VrModuleNotInstalled;
 import org.chromium.chrome.browser.vr.rules.VrTestRule;
 import org.chromium.chrome.browser.vr.rules.WebappActivityVrTestRule;
+import org.chromium.components.module_installer.Module;
 
 import java.util.ArrayList;
 import java.util.concurrent.Callable;
@@ -61,7 +61,7 @@
             final VrTestRule rule, final ChromeLaunchMethod launcher) throws Throwable {
         // Should be called before any other VR methods get called.
         if (desc.getAnnotation(VrModuleNotInstalled.class) != null) {
-            VrModuleProvider.setAlwaysUseFallbackDelegate(true);
+            Module.setForceUninstalled("vr");
         }
         TestVrShellDelegate.setDescription(desc);
 
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 268b2367..69f96c5 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -2750,15 +2750,21 @@
   <message name="IDS_SET_TIME_PROMPT" desc="Text prompting the user to check and set the system time.">
     Chrome was unable to set the system time. Please check the time below and correct it if needed.
   </message>
-  <message name="IDS_SET_TIME_BUTTON_CLOSE" desc="Text for the button to close the window.">
-    Done
-  </message>
   <message name="IDS_SET_TIME_DATE_LABEL" desc="Label for the date input element.">
     System date
   </message>
   <message name="IDS_SET_TIME_TIME_LABEL" desc="Label for the time input element.">
     System time
   </message>
+  <message name="IDS_MD_SET_TIME_DATE_LABEL" desc="Label for the Material Design date input element.">
+    Date
+  </message>
+  <message name="IDS_MD_SET_TIME_TIME_LABEL" desc="Label for the Material Design time input element.">
+    Time
+  </message>
+  <message name="IDS_MD_SET_TIME_TIMEZONE_LABEL" desc="Label for the Material Design timezone select element.">
+    Timezone
+  </message>
 
   <message name="IDS_FILE_SYSTEM_REQUEST_FILE_SYSTEM_DIALOG_TITLE" desc="Title of a prompt dialog for granting permissions to a volume (eg. USB drive, SD card, MTP device) with the specified name. Only used for screen readers (a11y); not visible.">
     Permission requested
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 0ea08a1f..165ea5c9 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5477,7 +5477,7 @@
           </message>
         </if>
         <message name="IDS_FEEDBACK_INCLUDE_ASSISTANT_INFORMATION_CHKBOX" desc="Checkbox for including Assistant debug information in the feedback report">
-          Include recent Assistant history via Sherlog. This may include your identity, location, and debug info <ph name="BEGIN_LINK">&lt;a href="#" id="assistant-logs-info-link"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph>
+          Include recent Assistant history via Sherlog. This may include your identity, location, and debug info. <ph name="BEGIN_LINK">&lt;a href="#" id="assistant-logs-info-link"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph>
         </message>
         <message name="IDS_FEEDBACK_ATTACH_FILE_NOTE" desc="Text for describing the maximum size for an attached file">
           File will be sent to Google for debugging
diff --git a/chrome/app/generated_resources_grd/IDS_FEEDBACK_INCLUDE_ASSISTANT_INFORMATION_CHKBOX.png.sha1 b/chrome/app/generated_resources_grd/IDS_FEEDBACK_INCLUDE_ASSISTANT_INFORMATION_CHKBOX.png.sha1
index d251630e..59ba087 100644
--- a/chrome/app/generated_resources_grd/IDS_FEEDBACK_INCLUDE_ASSISTANT_INFORMATION_CHKBOX.png.sha1
+++ b/chrome/app/generated_resources_grd/IDS_FEEDBACK_INCLUDE_ASSISTANT_INFORMATION_CHKBOX.png.sha1
@@ -1 +1 @@
-2c9d52746631404e5a57862c489a826669ae4e2c
\ No newline at end of file
+411f0ae0be273eba2d989059e4d8203eddb99fca
\ No newline at end of file
diff --git a/chrome/app/vr_strings_grd/OWNERS b/chrome/app/vr_strings_grdp/OWNERS
similarity index 100%
rename from chrome/app/vr_strings_grd/OWNERS
rename to chrome/app/vr_strings_grdp/OWNERS
diff --git a/chrome/app/vr_strings_grd/README.md b/chrome/app/vr_strings_grdp/README.md
similarity index 100%
rename from chrome/app/vr_strings_grd/README.md
rename to chrome/app/vr_strings_grdp/README.md
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4aef7c16..d0049d2 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1038,6 +1038,8 @@
     "page_load_metrics/page_load_metrics_util.h",
     "page_load_metrics/page_load_tracker.cc",
     "page_load_metrics/page_load_tracker.h",
+    "page_load_metrics/resource_tracker.cc",
+    "page_load_metrics/resource_tracker.h",
     "password_manager/chrome_password_manager_client.cc",
     "password_manager/chrome_password_manager_client.h",
     "password_manager/password_manager_util_linux.cc",
@@ -1884,6 +1886,7 @@
     "//components/language/content/browser",
     "//components/language/core/browser",
     "//components/language/core/common",
+    "//components/leveldb_proto",
     "//components/leveldb_proto/content:factory",
     "//components/live_tab_count_metrics",
     "//components/metrics:call_stack_profile_collector",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 2fef3a61..64aeef7 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -85,6 +85,7 @@
 #include "components/safe_browsing/features.h"
 #include "components/security_state/core/features.h"
 #include "components/security_state/core/security_state.h"
+#include "components/send_tab_to_self/features.h"
 #include "components/services/heap_profiling/public/cpp/switches.h"
 #include "components/signin/core/browser/account_reconcilor.h"
 #include "components/signin/core/browser/signin_buildflags.h"
@@ -3849,6 +3850,11 @@
      flag_descriptions::kSendTabToSelfDescription, kOsAll,
      FEATURE_VALUE_TYPE(switches::kSyncSendTabToSelf)},
 
+    {"enable-send-tab-to-self-receive",
+     flag_descriptions::kSendTabToSelfReceiveName,
+     flag_descriptions::kSendTabToSelfReceiveDescription, kOsAll,
+     FEATURE_VALUE_TYPE(send_tab_to_self::kSendTabToSelfReceive)},
+
     {"enable-data-reduction-proxy-with-network-service",
      flag_descriptions::kEnableDataReductionProxyNetworkServiceName,
      flag_descriptions::kEnableDataReductionProxyNetworkServiceDescription,
@@ -4055,10 +4061,12 @@
      FEATURE_VALUE_TYPE(signin::kMiceFeature)},
 #endif  // defined(OS_ANDROID)
 
-    {"autofill-show-full-disclosure-label",
-     flag_descriptions::kAutofillShowFullDisclosureLabelName,
-     flag_descriptions::kAutofillShowFullDisclosureLabelDescription, kOsAll,
-     FEATURE_VALUE_TYPE(autofill::features::kAutofillShowFullDisclosureLabel)},
+    {"autofill-use-improved-label-disambiguation",
+     flag_descriptions::kAutofillUseImprovedLabelDisambiguationName,
+     flag_descriptions::kAutofillUseImprovedLabelDisambiguationDescription,
+     kOsAll,
+     FEATURE_VALUE_TYPE(
+         autofill::features::kAutofillUseImprovedLabelDisambiguation)},
 
 #if defined(OS_CHROMEOS)
     {"ash-notification-stacking-bar-redesign",
diff --git a/chrome/browser/accessibility/image_annotation_browsertest.cc b/chrome/browser/accessibility/image_annotation_browsertest.cc
index 7efa8be..ffc76bc 100644
--- a/chrome/browser/accessibility/image_annotation_browsertest.cc
+++ b/chrome/browser/accessibility/image_annotation_browsertest.cc
@@ -64,6 +64,12 @@
 // API.
 class FakeAnnotator : public image_annotation::mojom::Annotator {
  public:
+  static void SetReturnOcrResults(bool ocr) { return_ocr_results_ = ocr; }
+
+  static void SetReturnLabelResults(bool label) {
+    return_label_results_ = label;
+  }
+
   FakeAnnotator() = default;
   ~FakeAnnotator() override = default;
 
@@ -88,10 +94,12 @@
             image_annotation::mojom::AnnotationType::kLabel, 1.0,
             image_filename + " Label");
 
-    // Return that result as an annotation.
+    // Return enabled results as an annotation.
     std::vector<image_annotation::mojom::AnnotationPtr> annotations;
-    annotations.push_back(std::move(ocr_annotation));
-    annotations.push_back(std::move(label_annotation));
+    if (return_ocr_results_)
+      annotations.push_back(std::move(ocr_annotation));
+    if (return_label_results_)
+      annotations.push_back(std::move(label_annotation));
 
     image_annotation::mojom::AnnotateImageResultPtr result =
         image_annotation::mojom::AnnotateImageResult::NewAnnotations(
@@ -101,10 +109,17 @@
 
  private:
   mojo::BindingSet<image_annotation::mojom::Annotator> bindings_;
+  static bool return_ocr_results_;
+  static bool return_label_results_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeAnnotator);
 };
 
+// static
+bool FakeAnnotator::return_ocr_results_ = false;
+// static
+bool FakeAnnotator::return_label_results_ = false;
+
 // The fake ImageAnnotationService, which handles mojo calls from the renderer
 // process and passes them to FakeAnnotator.
 class FakeImageAnnotationService : public service_manager::Service {
@@ -190,6 +205,8 @@
 
 IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
                        AnnotateImageInAccessibilityTree) {
+  FakeAnnotator::SetReturnOcrResults(true);
+  FakeAnnotator::SetReturnLabelResults(true);
   ui_test_utils::NavigateToURL(browser(),
                                https_server_.GetURL("/image_annotation.html"));
 
@@ -201,23 +218,25 @@
       "Appears to say: red.png Annotation. Appears to be: red.png Label");
 }
 
-// http://crbug.com/940043
-IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, DISABLED_ImagesInLinks) {
+IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImagesInLinks) {
+  FakeAnnotator::SetReturnOcrResults(true);
   ui_test_utils::NavigateToURL(
       browser(), https_server_.GetURL("/image_annotation_link.html"));
 
+  // Block until the accessibility tree has at least 8 annotations. If
+  // that never happens, the test will time out.
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-
-  content::WaitForAccessibilityTreeToContainNodeWithName(
-      web_contents, "Appears to say: red.png Annotation");
-
-  ui::AXTreeUpdate ax_tree_update =
-      content::GetAccessibilityTreeSnapshot(web_contents);
+  while (8 > DescribeNodesWithAnnotations(
+                 content::GetAccessibilityTreeSnapshot(web_contents))
+                 .size()) {
+    content::WaitForAccessibilityTreeToChange(web_contents);
+  }
 
   // All images should be annotated. Only links that contain exactly one image
   // should be annotated.
-
+  ui::AXTreeUpdate ax_tree_update =
+      content::GetAccessibilityTreeSnapshot(web_contents);
   EXPECT_THAT(
       DescribeNodesWithAnnotations(ax_tree_update),
       testing::ElementsAre("image Appears to say: red.png Annotation",
@@ -230,22 +249,25 @@
                            "image Appears to say: printer.png Annotation"));
 }
 
-// http://crbug.com/940043
-IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, DISABLED_ImageDoc) {
+IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImageDoc) {
+  FakeAnnotator::SetReturnOcrResults(true);
   ui_test_utils::NavigateToURL(
       browser(), https_server_.GetURL("/image_annotation_doc.html"));
 
+  // Block until the accessibility tree has at least 2 annotations. If
+  // that never happens, the test will time out.
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-
-  content::WaitForAccessibilityTreeToContainNodeWithName(
-      web_contents, "Appears to say: red.png Annotation");
-
-  ui::AXTreeUpdate ax_tree_update =
-      content::GetAccessibilityTreeSnapshot(web_contents);
+  while (2 > DescribeNodesWithAnnotations(
+                 content::GetAccessibilityTreeSnapshot(web_contents))
+                 .size()) {
+    content::WaitForAccessibilityTreeToChange(web_contents);
+  }
 
   // When a document contains exactly one image, the document should be
   // annotated with the image's annotation, too.
+  ui::AXTreeUpdate ax_tree_update =
+      content::GetAccessibilityTreeSnapshot(web_contents);
   EXPECT_THAT(
       DescribeNodesWithAnnotations(ax_tree_update),
       testing::ElementsAre("rootWebArea Appears to say: red.png Annotation",
diff --git a/chrome/browser/android/usage_stats/usage_stats_database.cc b/chrome/browser/android/usage_stats/usage_stats_database.cc
index 3ddb64e7..07b4ec8 100644
--- a/chrome/browser/android/usage_stats/usage_stats_database.cc
+++ b/chrome/browser/android/usage_stats/usage_stats_database.cc
@@ -39,8 +39,8 @@
       suspension_db_initialized_(false),
       token_mapping_db_initialized_(false),
       weak_ptr_factory_(this) {
-  ProtoDatabaseProvider* db_provider =
-      ProtoDatabaseProviderFactory::GetForBrowserContext(profile);
+  ProtoDatabaseProvider* db_provider = ProtoDatabaseProviderFactory::GetForKey(
+      profile->GetSimpleFactoryKey(), profile->GetPrefs());
 
   base::FilePath usage_stats_dir = profile->GetPath().Append(kNamespace);
 
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
index 1be1250..13e7609b 100644
--- a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
+++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
@@ -117,8 +117,8 @@
   InstallableManager* installable_manager =
       InstallableManager::FromWebContents(web_contents());
   installable_manager->GetData(
-      params, base::Bind(&WebApkUpdateDataFetcher::OnDidGetInstallableData,
-                         weak_ptr_factory_.GetWeakPtr()));
+      params, base::BindOnce(&WebApkUpdateDataFetcher::OnDidGetInstallableData,
+                             weak_ptr_factory_.GetWeakPtr()));
 }
 
 void WebApkUpdateDataFetcher::OnDidGetInstallableData(
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
index aa940ddb..9409cb8b 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -187,8 +187,8 @@
 
   installable_manager_->GetData(
       ParamsToPerformManifestAndIconFetch(),
-      base::Bind(&AddToHomescreenDataFetcher::OnDidGetManifestAndIcons,
-                 weak_ptr_factory_.GetWeakPtr()));
+      base::BindOnce(&AddToHomescreenDataFetcher::OnDidGetManifestAndIcons,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void AddToHomescreenDataFetcher::StopTimer() {
@@ -259,8 +259,8 @@
 
   installable_manager_->GetData(
       ParamsToPerformInstallableCheck(),
-      base::Bind(&AddToHomescreenDataFetcher::OnDidPerformInstallableCheck,
-                 weak_ptr_factory_.GetWeakPtr()));
+      base::BindOnce(&AddToHomescreenDataFetcher::OnDidPerformInstallableCheck,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void AddToHomescreenDataFetcher::OnDidPerformInstallableCheck(
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
index 655589c..93e03f02 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
@@ -133,7 +133,7 @@
   // data fetcher. We manually call the metrics logging method which is normally
   // called by the superclass method.
   void GetData(const InstallableParams& params,
-               const InstallableCallback& callback) override {
+               InstallableCallback callback) override {
     metrics_->Start();
 
     InstallableStatusCode code = NO_ERROR_DETECTED;
@@ -159,8 +159,8 @@
       // and isn't called (corresponding to InstallableManager finishing work
       // after the timeout, and when it never finishes at all).
       queued_metrics_callback_ =
-          base::Bind(&InstallableManager::ResolveMetrics,
-                     base::Unretained(this), params, is_installable);
+          base::BindOnce(&InstallableManager::ResolveMetrics,
+                         base::Unretained(this), params, is_installable);
       return;
     }
 
@@ -171,14 +171,15 @@
     std::vector<InstallableStatusCode> errors;
     if (code != NO_ERROR_DETECTED)
       errors.push_back(code);
-    callback.Run({std::move(errors), GURL(kDefaultManifestUrl), &manifest_,
-                  params.valid_primary_icon ? primary_icon_url_ : GURL(),
-                  params.valid_primary_icon ? primary_icon_.get() : nullptr,
-                  params.prefer_maskable_icon,
-                  params.valid_badge_icon ? badge_icon_url_ : GURL(),
-                  params.valid_badge_icon ? badge_icon_.get() : nullptr,
-                  params.valid_manifest ? is_installable : false,
-                  params.has_worker ? is_installable : false});
+    std::move(callback).Run(
+        {std::move(errors), GURL(kDefaultManifestUrl), &manifest_,
+         params.valid_primary_icon ? primary_icon_url_ : GURL(),
+         params.valid_primary_icon ? primary_icon_.get() : nullptr,
+         params.prefer_maskable_icon,
+         params.valid_badge_icon ? badge_icon_url_ : GURL(),
+         params.valid_badge_icon ? badge_icon_.get() : nullptr,
+         params.valid_manifest ? is_installable : false,
+         params.has_worker ? is_installable : false});
   }
 
   void SetInstallable(bool is_installable) { is_installable_ = is_installable; }
diff --git a/chrome/browser/apps/app_service/app_icon_source.cc b/chrome/browser/apps/app_service/app_icon_source.cc
index 88ae25b4..90cb9b3 100644
--- a/chrome/browser/apps/app_service/app_icon_source.cc
+++ b/chrome/browser/apps/app_service/app_icon_source.cc
@@ -97,10 +97,12 @@
     return;
   }
 
+  const apps::mojom::AppType app_type =
+      app_service_proxy->AppRegistryCache().GetAppType(app_id);
   constexpr bool allow_placeholder_icon = false;
-  app_service_proxy->LoadIcon(app_id, apps::mojom::IconCompression::kCompressed,
-                              size_in_dip, allow_placeholder_icon,
-                              base::BindOnce(&RunCallback, callback));
+  app_service_proxy->LoadIcon(
+      app_type, app_id, apps::mojom::IconCompression::kCompressed, size_in_dip,
+      allow_placeholder_icon, base::BindOnce(&RunCallback, callback));
 }
 
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/app_service_proxy.cc b/chrome/browser/apps/app_service/app_service_proxy.cc
index d512411..5b5b2f25 100644
--- a/chrome/browser/apps/app_service/app_service_proxy.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy.cc
@@ -36,6 +36,8 @@
 
 std::unique_ptr<IconLoader::Releaser>
 AppServiceProxy::InnerIconLoader::LoadIconFromIconKey(
+    apps::mojom::AppType app_type,
+    const std::string& app_id,
     apps::mojom::IconKeyPtr icon_key,
     apps::mojom::IconCompression icon_compression,
     int32_t size_hint_in_dip,
@@ -43,8 +45,8 @@
     apps::mojom::Publisher::LoadIconCallback callback) {
   if (overriding_icon_loader_for_testing_) {
     return overriding_icon_loader_for_testing_->LoadIconFromIconKey(
-        std::move(icon_key), icon_compression, size_hint_in_dip,
-        allow_placeholder_icon, std::move(callback));
+        app_type, app_id, std::move(icon_key), icon_compression,
+        size_hint_in_dip, allow_placeholder_icon, std::move(callback));
   }
 
   if (host_->app_service_.is_bound() && icon_key) {
@@ -57,9 +59,9 @@
     // for the app and app requested new icon. But new icon is not delivered
     // yet and you resolve old one instead. Now new icon arrives asynchronously
     // but you no longer notify the app or do?"
-    host_->app_service_->LoadIcon(std::move(icon_key), icon_compression,
-                                  size_hint_in_dip, allow_placeholder_icon,
-                                  std::move(callback));
+    host_->app_service_->LoadIcon(app_type, app_id, std::move(icon_key),
+                                  icon_compression, size_hint_in_dip,
+                                  allow_placeholder_icon, std::move(callback));
   } else {
     std::move(callback).Run(apps::mojom::IconValue::New());
   }
@@ -121,13 +123,15 @@
 
 std::unique_ptr<apps::IconLoader::Releaser>
 AppServiceProxy::LoadIconFromIconKey(
+    apps::mojom::AppType app_type,
+    const std::string& app_id,
     apps::mojom::IconKeyPtr icon_key,
     apps::mojom::IconCompression icon_compression,
     int32_t size_hint_in_dip,
     bool allow_placeholder_icon,
     apps::mojom::Publisher::LoadIconCallback callback) {
   return outer_icon_loader_.LoadIconFromIconKey(
-      std::move(icon_key), icon_compression, size_hint_in_dip,
+      app_type, app_id, std::move(icon_key), icon_compression, size_hint_in_dip,
       allow_placeholder_icon, std::move(callback));
 }
 
diff --git a/chrome/browser/apps/app_service/app_service_proxy.h b/chrome/browser/apps/app_service/app_service_proxy.h
index 0cb5c4a1..def5552a 100644
--- a/chrome/browser/apps/app_service/app_service_proxy.h
+++ b/chrome/browser/apps/app_service/app_service_proxy.h
@@ -48,6 +48,8 @@
   // apps::IconLoader overrides.
   apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override;
   std::unique_ptr<IconLoader::Releaser> LoadIconFromIconKey(
+      apps::mojom::AppType app_type,
+      const std::string& app_id,
       apps::mojom::IconKeyPtr icon_key,
       apps::mojom::IconCompression icon_compression,
       int32_t size_hint_in_dip,
@@ -114,6 +116,8 @@
     // apps::IconLoader overrides.
     apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override;
     std::unique_ptr<IconLoader::Releaser> LoadIconFromIconKey(
+        apps::mojom::AppType app_type,
+        const std::string& app_id,
         apps::mojom::IconKeyPtr icon_key,
         apps::mojom::IconCompression icon_compression,
         int32_t size_hint_in_dip,
diff --git a/chrome/browser/apps/app_service/app_service_proxy_unittest.cc b/chrome/browser/apps/app_service/app_service_proxy_unittest.cc
index e7f2d7f..cfad9c2 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_unittest.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_unittest.cc
@@ -36,11 +36,12 @@
 
    private:
     apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override {
-      return apps::mojom::IconKey::New(apps::mojom::AppType::kWeb, app_id, 0, 0,
-                                       0);
+      return apps::mojom::IconKey::New(0, 0, 0);
     }
 
     std::unique_ptr<Releaser> LoadIconFromIconKey(
+        apps::mojom::AppType app_type,
+        const std::string& app_id,
         apps::mojom::IconKeyPtr icon_key,
         apps::mojom::IconCompression icon_compression,
         int32_t size_hint_in_dip,
@@ -57,13 +58,14 @@
   };
 
   UniqueReleaser LoadIcon(apps::IconLoader* loader, const std::string& app_id) {
+    static constexpr auto app_type = apps::mojom::AppType::kWeb;
     static constexpr auto icon_compression =
         apps::mojom::IconCompression::kUncompressed;
     static constexpr int32_t size_hint_in_dip = 1;
     static bool allow_placeholder_icon = false;
 
-    return loader->LoadIcon(app_id, icon_compression, size_hint_in_dip,
-                            allow_placeholder_icon,
+    return loader->LoadIcon(app_type, app_id, icon_compression,
+                            size_hint_in_dip, allow_placeholder_icon,
                             base::BindOnce(&AppServiceProxyTest::OnLoadIcon,
                                            base::Unretained(this)));
   }
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc
index 2628edc..5b2cdc4 100644
--- a/chrome/browser/apps/app_service/arc_apps.cc
+++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -195,7 +195,8 @@
   subscribers_.AddPtr(std::move(subscriber));
 }
 
-void ArcApps::LoadIcon(apps::mojom::IconKeyPtr icon_key,
+void ArcApps::LoadIcon(const std::string& app_id,
+                       apps::mojom::IconKeyPtr icon_key,
                        apps::mojom::IconCompression icon_compression,
                        int32_t size_hint_in_dip,
                        bool allow_placeholder_icon,
@@ -207,7 +208,7 @@
     // the Play Store icon (the UI for enabling and installing Android apps)
     // should be showable even before the user has installed their first
     // Android app and before bringing up an Android VM for the first time.
-    if (icon_key->app_id == arc::kPlayStoreAppId) {
+    if (app_id == arc::kPlayStoreAppId) {
       LoadPlayStoreIcon(icon_compression, size_hint_in_dip,
                         static_cast<IconEffects>(icon_key->icon_effects),
                         std::move(callback));
@@ -218,10 +219,10 @@
     // LoadIconFromVM.
     LoadIconFromFileWithFallback(
         icon_compression, size_hint_in_dip,
-        GetCachedIconFilePath(icon_key->app_id, size_hint_in_dip),
+        GetCachedIconFilePath(app_id, size_hint_in_dip),
         static_cast<IconEffects>(icon_key->icon_effects), std::move(callback),
         base::BindOnce(&ArcApps::LoadIconFromVM, weak_ptr_factory_.GetWeakPtr(),
-                       icon_key->app_id, icon_compression, size_hint_in_dip,
+                       app_id, icon_compression, size_hint_in_dip,
                        allow_placeholder_icon,
                        static_cast<IconEffects>(icon_key->icon_effects)));
     return;
@@ -359,8 +360,7 @@
   apps::mojom::AppPtr app = apps::mojom::App::New();
   app->app_type = apps::mojom::AppType::kArc;
   app->app_id = app_id;
-  app->icon_key = icon_key_factory_.MakeIconKey(apps::mojom::AppType::kArc,
-                                                app_id, icon_effects);
+  app->icon_key = icon_key_factory_.MakeIconKey(icon_effects);
   Publish(std::move(app));
 }
 
@@ -476,8 +476,7 @@
   app->short_name = app->name;
 
   static constexpr uint32_t icon_effects = 0;
-  app->icon_key = icon_key_factory_.MakeIconKey(apps::mojom::AppType::kArc,
-                                                app_id, icon_effects);
+  app->icon_key = icon_key_factory_.MakeIconKey(icon_effects);
 
   app->last_launch_time = app_info.last_launch_time;
   app->install_time = app_info.install_time;
diff --git a/chrome/browser/apps/app_service/arc_apps.h b/chrome/browser/apps/app_service/arc_apps.h
index 70f209b0..6577f13 100644
--- a/chrome/browser/apps/app_service/arc_apps.h
+++ b/chrome/browser/apps/app_service/arc_apps.h
@@ -46,7 +46,8 @@
   // apps::mojom::Publisher overrides.
   void Connect(apps::mojom::SubscriberPtr subscriber,
                apps::mojom::ConnectOptionsPtr opts) override;
-  void LoadIcon(apps::mojom::IconKeyPtr icon_key,
+  void LoadIcon(const std::string& app_id,
+                apps::mojom::IconKeyPtr icon_key,
                 apps::mojom::IconCompression icon_compression,
                 int32_t size_hint_in_dip,
                 bool allow_placeholder_icon,
diff --git a/chrome/browser/apps/app_service/built_in_chromeos_apps.cc b/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
index cc4ab993..79eb234 100644
--- a/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
+++ b/chrome/browser/apps/app_service/built_in_chromeos_apps.cc
@@ -39,7 +39,7 @@
   }
 
   app->icon_key = apps::mojom::IconKey::New(
-      apps::mojom::AppType::kBuiltIn, internal_app.app_id, 0,
+      apps::mojom::IconKey::kDoesNotChangeOverTime,
       internal_app.icon_resource_id, apps::IconEffects::kNone);
 
   app->last_launch_time = base::Time();
@@ -111,6 +111,7 @@
 }
 
 void BuiltInChromeOsApps::LoadIcon(
+    const std::string& app_id,
     apps::mojom::IconKeyPtr icon_key,
     apps::mojom::IconCompression icon_compression,
     int32_t size_hint_in_dip,
diff --git a/chrome/browser/apps/app_service/built_in_chromeos_apps.h b/chrome/browser/apps/app_service/built_in_chromeos_apps.h
index 41360057..232c261 100644
--- a/chrome/browser/apps/app_service/built_in_chromeos_apps.h
+++ b/chrome/browser/apps/app_service/built_in_chromeos_apps.h
@@ -30,7 +30,8 @@
   // apps::mojom::Publisher overrides.
   void Connect(apps::mojom::SubscriberPtr subscriber,
                apps::mojom::ConnectOptionsPtr opts) override;
-  void LoadIcon(apps::mojom::IconKeyPtr icon_key,
+  void LoadIcon(const std::string& app_id,
+                apps::mojom::IconKeyPtr icon_key,
                 apps::mojom::IconCompression icon_compression,
                 int32_t size_hint_in_dip,
                 bool allow_placeholder_icon,
diff --git a/chrome/browser/apps/app_service/crostini_apps.cc b/chrome/browser/apps/app_service/crostini_apps.cc
index b424eccb..9e189ff0 100644
--- a/chrome/browser/apps/app_service/crostini_apps.cc
+++ b/chrome/browser/apps/app_service/crostini_apps.cc
@@ -60,7 +60,8 @@
   subscribers_.AddPtr(std::move(subscriber));
 }
 
-void CrostiniApps::LoadIcon(apps::mojom::IconKeyPtr icon_key,
+void CrostiniApps::LoadIcon(const std::string& app_id,
+                            apps::mojom::IconKeyPtr icon_key,
                             apps::mojom::IconCompression icon_compression,
                             int32_t size_hint_in_dip,
                             bool allow_placeholder_icon,
@@ -81,10 +82,10 @@
       // to LoadIconFromVM.
       LoadIconFromFileWithFallback(
           icon_compression, size_hint_in_dip,
-          registry_->GetIconPath(icon_key->app_id, scale_factor),
+          registry_->GetIconPath(app_id, scale_factor),
           static_cast<IconEffects>(icon_key->icon_effects), std::move(callback),
           base::BindOnce(&CrostiniApps::LoadIconFromVM,
-                         weak_ptr_factory_.GetWeakPtr(), icon_key->app_id,
+                         weak_ptr_factory_.GetWeakPtr(), app_id,
                          icon_compression, size_hint_in_dip,
                          allow_placeholder_icon, scale_factor,
                          static_cast<IconEffects>(icon_key->icon_effects)));
@@ -218,8 +219,6 @@
 apps::mojom::IconKeyPtr CrostiniApps::NewIconKey(const std::string& app_id) {
   DCHECK(!app_id.empty());
 
-  static constexpr uint32_t icon_effects = 0;
-
   // Treat the Crostini Terminal as a special case, loading an icon defined by
   // a resource instead of asking the Crostini VM (or the cache of previous
   // responses from the Crostini VM). Presumably this is for bootstrapping: the
@@ -227,12 +226,12 @@
   // should be showable even before the user has installed their first Crostini
   // app and before bringing up an Crostini VM for the first time.
   if (app_id == crostini::kCrostiniTerminalId) {
-    return apps::mojom::IconKey::New(apps::mojom::AppType::kCrostini, app_id, 0,
-                                     IDR_LOGO_CROSTINI_TERMINAL, icon_effects);
+    return apps::mojom::IconKey::New(
+        apps::mojom::IconKey::kDoesNotChangeOverTime,
+        IDR_LOGO_CROSTINI_TERMINAL, apps::IconEffects::kNone);
   }
 
-  return icon_key_factory_.MakeIconKey(apps::mojom::AppType::kCrostini, app_id,
-                                       icon_effects);
+  return icon_key_factory_.MakeIconKey(apps::IconEffects::kNone);
 }
 
 void CrostiniApps::PublishAppID(const std::string& app_id,
diff --git a/chrome/browser/apps/app_service/crostini_apps.h b/chrome/browser/apps/app_service/crostini_apps.h
index 2e2676d..79fe8da 100644
--- a/chrome/browser/apps/app_service/crostini_apps.h
+++ b/chrome/browser/apps/app_service/crostini_apps.h
@@ -45,7 +45,8 @@
   // apps::mojom::Publisher overrides.
   void Connect(apps::mojom::SubscriberPtr subscriber,
                apps::mojom::ConnectOptionsPtr opts) override;
-  void LoadIcon(apps::mojom::IconKeyPtr icon_key,
+  void LoadIcon(const std::string& app_id,
+                apps::mojom::IconKeyPtr icon_key,
                 apps::mojom::IconCompression icon_compression,
                 int32_t size_hint_in_dip,
                 bool allow_placeholder_icon,
diff --git a/chrome/browser/apps/app_service/extension_apps.cc b/chrome/browser/apps/app_service/extension_apps.cc
index a4d89e1..fbcc70a1 100644
--- a/chrome/browser/apps/app_service/extension_apps.cc
+++ b/chrome/browser/apps/app_service/extension_apps.cc
@@ -125,15 +125,16 @@
   subscribers_.AddPtr(std::move(subscriber));
 }
 
-void ExtensionApps::LoadIcon(apps::mojom::IconKeyPtr icon_key,
+void ExtensionApps::LoadIcon(const std::string& app_id,
+                             apps::mojom::IconKeyPtr icon_key,
                              apps::mojom::IconCompression icon_compression,
                              int32_t size_hint_in_dip,
                              bool allow_placeholder_icon,
                              LoadIconCallback callback) {
   if (icon_key) {
-    LoadIconFromExtension(
-        icon_compression, size_hint_in_dip, profile_, icon_key->app_id,
-        static_cast<IconEffects>(icon_key->icon_effects), std::move(callback));
+    LoadIconFromExtension(icon_compression, size_hint_in_dip, profile_, app_id,
+                          static_cast<IconEffects>(icon_key->icon_effects),
+                          std::move(callback));
     return;
   }
   // On failure, we still run the callback, with the zero IconValue.
@@ -440,8 +441,7 @@
     icon_effects =
         static_cast<IconEffects>(icon_effects | IconEffects::kRoundCorners);
   }
-  app->icon_key =
-      icon_key_factory_.MakeIconKey(app_type_, extension->id(), icon_effects);
+  app->icon_key = icon_key_factory_.MakeIconKey(icon_effects);
 
   if (profile_) {
     auto* prefs = extensions::ExtensionPrefs::Get(profile_);
diff --git a/chrome/browser/apps/app_service/extension_apps.h b/chrome/browser/apps/app_service/extension_apps.h
index cdf54ef..76ef9819 100644
--- a/chrome/browser/apps/app_service/extension_apps.h
+++ b/chrome/browser/apps/app_service/extension_apps.h
@@ -51,7 +51,8 @@
   // apps::mojom::Publisher overrides.
   void Connect(apps::mojom::SubscriberPtr subscriber,
                apps::mojom::ConnectOptionsPtr opts) override;
-  void LoadIcon(apps::mojom::IconKeyPtr icon_key,
+  void LoadIcon(const std::string& app_id,
+                apps::mojom::IconKeyPtr icon_key,
                 apps::mojom::IconCompression icon_compression,
                 int32_t size_hint_in_dip,
                 bool allow_placeholder_icon,
diff --git a/chrome/browser/apps/app_service/icon_key_util.cc b/chrome/browser/apps/app_service/icon_key_util.cc
index 7c22ca6..58c03c0 100644
--- a/chrome/browser/apps/app_service/icon_key_util.cc
+++ b/chrome/browser/apps/app_service/icon_key_util.cc
@@ -9,12 +9,9 @@
 IncrementingIconKeyFactory::IncrementingIconKeyFactory() : last_timeline_(0) {}
 
 apps::mojom::IconKeyPtr IncrementingIconKeyFactory::MakeIconKey(
-    apps::mojom::AppType app_type,
-    const std::string& app_id,
     uint32_t icon_effects) {
-  return apps::mojom::IconKey::New(app_type, app_id, ++last_timeline_,
-                                   apps::mojom::IconKey::kInvalidResourceId,
-                                   icon_effects);
+  return apps::mojom::IconKey::New(
+      ++last_timeline_, apps::mojom::IconKey::kInvalidResourceId, icon_effects);
 }
 
 }  // namespace apps_util
diff --git a/chrome/browser/apps/app_service/icon_key_util.h b/chrome/browser/apps/app_service/icon_key_util.h
index 958386b0..b79c204 100644
--- a/chrome/browser/apps/app_service/icon_key_util.h
+++ b/chrome/browser/apps/app_service/icon_key_util.h
@@ -29,9 +29,7 @@
  public:
   IncrementingIconKeyFactory();
 
-  apps::mojom::IconKeyPtr MakeIconKey(apps::mojom::AppType app_type,
-                                      const std::string& app_id,
-                                      uint32_t icon_effects);
+  apps::mojom::IconKeyPtr MakeIconKey(uint32_t icon_effects);
 
  private:
   uint64_t last_timeline_;
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index 99911c3..b89384a0 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -165,22 +165,11 @@
 
 namespace banners {
 
-void AppBannerManager::RequestAppBanner(const GURL& validated_url,
-                                        bool is_debug_mode) {
-  // The only time we should start the pipeline while it is already running is
-  // if it's been triggered from devtools.
-  if (state_ != State::INACTIVE) {
-    DCHECK(is_debug_mode);
-    weak_factory_.InvalidateWeakPtrs();
-    ResetBindings();
-  }
+void AppBannerManager::RequestAppBanner(const GURL& validated_url) {
+  DCHECK_EQ(State::INACTIVE, state_);
 
   UpdateState(State::ACTIVE);
-  triggered_by_devtools_ = is_debug_mode;
-
-  // We only need to use TrackingStatusReporter if we aren't in debug mode
-  // (this avoids skew from testing).
-  if (IsDebugMode())
+  if (ShouldBypassEngagementChecks())
     status_reporter_ = std::make_unique<ConsoleStatusReporter>(web_contents());
   else
     status_reporter_ = std::make_unique<TrackingStatusReporter>();
@@ -191,7 +180,7 @@
   UpdateState(State::FETCHING_MANIFEST);
   manager_->GetData(
       ParamsToGetManifest(),
-      base::Bind(&AppBannerManager::OnDidGetManifest, GetWeakPtr()));
+      base::BindOnce(&AppBannerManager::OnDidGetManifest, GetWeakPtr()));
 }
 
 void AppBannerManager::OnInstall(bool is_native,
@@ -243,7 +232,6 @@
       binding_(this),
       has_sufficient_engagement_(false),
       load_finished_(false),
-      triggered_by_devtools_(false),
       status_reporter_(std::make_unique<NullStatusReporter>()),
       install_animation_pending_(false),
       installable_(Installable::UNKNOWN),
@@ -256,7 +244,7 @@
 AppBannerManager::~AppBannerManager() { }
 
 bool AppBannerManager::CheckIfShouldShowBanner() {
-  if (IsDebugMode())
+  if (ShouldBypassEngagementChecks())
     return true;
 
   InstallableStatusCode code = ShouldShowBannerCode();
@@ -298,13 +286,12 @@
 
 
 bool AppBannerManager::HasSufficientEngagement() const {
-  return has_sufficient_engagement_ || IsDebugMode();
+  return has_sufficient_engagement_ || ShouldBypassEngagementChecks();
 }
 
-bool AppBannerManager::IsDebugMode() const {
-  return triggered_by_devtools_ ||
-         base::CommandLine::ForCurrentProcess()->HasSwitch(
-             switches::kBypassAppBannerEngagementChecks);
+bool AppBannerManager::ShouldBypassEngagementChecks() const {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kBypassAppBannerEngagementChecks);
 }
 
 bool AppBannerManager::IsWebAppConsideredInstalled(
@@ -336,8 +323,7 @@
   params.valid_primary_icon = true;
   params.valid_manifest = true;
   params.has_worker = true;
-  // Don't wait for the service worker if this was triggered from devtools.
-  params.wait_for_worker = !triggered_by_devtools_;
+  params.wait_for_worker = true;
 
   return params;
 }
@@ -348,9 +334,10 @@
 
   // Fetch and verify the other required information.
   UpdateState(State::PENDING_INSTALLABLE_CHECK);
-  manager_->GetData(ParamsToPerformInstallableCheck(),
-                    base::Bind(&AppBannerManager::OnDidPerformInstallableCheck,
-                               GetWeakPtr()));
+  manager_->GetData(
+      ParamsToPerformInstallableCheck(),
+      base::BindOnce(&AppBannerManager::OnDidPerformInstallableCheck,
+                     GetWeakPtr()));
 }
 
 void AppBannerManager::OnDidPerformInstallableCheck(
@@ -428,9 +415,10 @@
 }
 
 void AppBannerManager::Terminate() {
-  if (state_ == State::PENDING_PROMPT)
+  if (state_ == State::PENDING_PROMPT) {
     TrackBeforeInstallEvent(
         BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT);
+  }
 
   if (state_ == State::PENDING_ENGAGEMENT && !has_sufficient_engagement_)
     TrackDisplayEvent(DISPLAY_EVENT_NOT_VISITED_ENOUGH);
@@ -563,7 +551,7 @@
   // or if the experimental app banners feature is active.
   if (state_ == State::INACTIVE &&
       (has_sufficient_engagement_ || IsExperimentalAppBannersEnabled())) {
-    RequestAppBanner(validated_url, false /* is_debug_mode */);
+    RequestAppBanner(validated_url);
   }
 }
 
@@ -605,7 +593,7 @@
       // This performs some simple tests and starts async checks to test
       // installability. It should be safe to start in response to user input.
       // Don't call if we're already working on processing a banner request.
-      RequestAppBanner(url, false /* is_debug_mode */);
+      RequestAppBanner(url);
     }
   }
 }
@@ -704,7 +692,7 @@
   // the banner immediately.
   if (reply == blink::mojom::AppBannerPromptReply::CANCEL) {
     TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED);
-    if (IsDebugMode()) {
+    if (ShouldBypassEngagementChecks()) {
       web_contents()->GetMainFrame()->AddMessageToConsole(
           blink::mojom::ConsoleMessageLevel::kInfo,
           "Banner not shown: beforeinstallpromptevent.preventDefault() called. "
diff --git a/chrome/browser/banners/app_banner_manager.h b/chrome/browser/banners/app_banner_manager.h
index ec0d45a..de5c54a 100644
--- a/chrome/browser/banners/app_banner_manager.h
+++ b/chrome/browser/banners/app_banner_manager.h
@@ -152,9 +152,8 @@
   // this returns and consumes the animation prompt if it is available.
   bool MaybeConsumeInstallAnimation();
 
-  // Requests an app banner. If |is_debug_mode| is true, any failure in the
-  // pipeline will be reported to the devtools console.
-  virtual void RequestAppBanner(const GURL& validated_url, bool is_debug_mode);
+  // Requests an app banner.
+  virtual void RequestAppBanner(const GURL& validated_url);
 
   // Informs the page that it has been installed with appinstalled event and
   // performs logging related to the app installation. Appinstalled event is
@@ -223,13 +222,12 @@
   // alerting websites that a banner is about to be created.
   virtual std::string GetBannerType();
 
-  // Returns true if |has_sufficient_engagement_| is true or IsDebugMode()
-  // returns true.
+  // Returns true if |has_sufficient_engagement_| is true or
+  // ShouldBypassEngagementChecks() returns true.
   bool HasSufficientEngagement() const;
 
-  // Returns true if |triggered_by_devtools_| is true or the
-  // kBypassAppBannerEngagementChecks flag is set.
-  bool IsDebugMode() const;
+  // Returns true if the kBypassAppBannerEngagementChecks flag is set.
+  bool ShouldBypassEngagementChecks() const;
 
   // Returns true if the webapp at |start_url| has already been installed, or
   // should be considered installed. On Android, we rely on a heuristic that
@@ -387,9 +385,6 @@
   bool has_sufficient_engagement_;
   bool load_finished_;
 
-  // Whether the current flow was begun via devtools.
-  bool triggered_by_devtools_;
-
   std::unique_ptr<StatusReporter> status_reporter_;
   bool install_animation_pending_;
   Installable installable_;
diff --git a/chrome/browser/banners/app_banner_manager_android.cc b/chrome/browser/banners/app_banner_manager_android.cc
index ce87de2..efb53ae 100644
--- a/chrome/browser/banners/app_banner_manager_android.cc
+++ b/chrome/browser/banners/app_banner_manager_android.cc
@@ -116,13 +116,12 @@
       base::BindOnce(&AppBannerManager::OnAppIconFetched, GetWeakPtr()));
 }
 
-void AppBannerManagerAndroid::RequestAppBanner(const GURL& validated_url,
-                                               bool is_debug_mode) {
+void AppBannerManagerAndroid::RequestAppBanner(const GURL& validated_url) {
   JNIEnv* env = base::android::AttachCurrentThread();
   if (!Java_AppBannerManager_isEnabledForTab(env, java_banner_manager_))
     return;
 
-  AppBannerManager::RequestAppBanner(validated_url, is_debug_mode);
+  AppBannerManager::RequestAppBanner(validated_url);
 }
 
 void AppBannerManagerAndroid::SendBannerDismissed() {
diff --git a/chrome/browser/banners/app_banner_manager_android.h b/chrome/browser/banners/app_banner_manager_android.h
index 626d9d4..4724834 100644
--- a/chrome/browser/banners/app_banner_manager_android.h
+++ b/chrome/browser/banners/app_banner_manager_android.h
@@ -83,7 +83,7 @@
       const base::android::JavaParamRef<jstring>& jicon_url);
 
   // AppBannerManager overrides.
-  void RequestAppBanner(const GURL& validated_url, bool is_debug_mode) override;
+  void RequestAppBanner(const GURL& validated_url) override;
   void SendBannerDismissed() override;
 
   // InstallableAmbientBadgeInfoBarAndroid::Client overrides.
diff --git a/chrome/browser/banners/app_banner_manager_browsertest.cc b/chrome/browser/banners/app_banner_manager_browsertest.cc
index dc534bc..fcfe838 100644
--- a/chrome/browser/banners/app_banner_manager_browsertest.cc
+++ b/chrome/browser/banners/app_banner_manager_browsertest.cc
@@ -42,14 +42,13 @@
 
   ~AppBannerManagerTest() override {}
 
-  void RequestAppBanner(const GURL& validated_url,
-                        bool is_debug_mode) override {
+  void RequestAppBanner(const GURL& validated_url) override {
     // Filter out about:blank navigations - we use these in testing to force
     // Stop() to be called.
     if (validated_url == GURL("about:blank"))
       return;
 
-    AppBannerManager::RequestAppBanner(validated_url, is_debug_mode);
+    AppBannerManager::RequestAppBanner(validated_url);
   }
 
   bool banner_shown() { return banner_shown_.get() && *banner_shown_; }
@@ -667,33 +666,4 @@
                                 SHOWING_WEB_APP_BANNER, 1);
 }
 
-IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, OverlappingDebugRequest) {
-  base::HistogramTester histograms;
-  GURL test_url = GetBannerURL();
-  SiteEngagementService* service =
-      SiteEngagementService::Get(browser()->profile());
-  service->ResetBaseScoreForURL(test_url, 10);
-
-  ui_test_utils::NavigateToURL(browser(), test_url);
-
-  std::unique_ptr<AppBannerManagerTest> manager(
-      CreateAppBannerManager(browser()));
-  base::RunLoop run_loop;
-  manager->PrepareDone(run_loop.QuitClosure());
-
-  // Call RequestAppBanner to start the pipeline, then call it again in debug
-  // mode to ensure that this doesn't fail.
-  manager->RequestAppBanner(test_url, false);
-  EXPECT_EQ(State::FETCHING_MANIFEST, manager->state());
-  manager->RequestAppBanner(test_url, true);
-  run_loop.Run();
-
-  EXPECT_TRUE(manager->banner_shown());
-  EXPECT_EQ(WebappInstallSource::DEVTOOLS, manager->install_source());
-  EXPECT_EQ(State::COMPLETE, manager->state());
-
-  // Ensure that we do not record any histograms.
-  histograms.ExpectTotalCount(banners::kInstallableStatusCodeHistogram, 0);
-}
-
 }  // namespace banners
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 1b8a8ef4..2ce84fe 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -837,7 +837,7 @@
   ui_thread_profiler_->SetMainThreadTaskRunner(
       base::ThreadTaskRunnerHandle::Get());
 
-  heap_profiler_controller_->StartIfEnabled();
+  heap_profiler_controller_->Start();
 
   system_monitor_ = performance_monitor::SystemMonitor::Create();
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 34d0bdf6..aaab785 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2281,11 +2281,12 @@
 
 bool ChromeContentBrowserClient::IsDataSaverEnabled(
     content::BrowserContext* browser_context) {
-  Profile* profile = Profile::FromBrowserContext(browser_context);
-  if (!profile)
-    return false;
-  PrefService* prefs = profile->GetPrefs();
-  return prefs && prefs->GetBoolean(prefs::kDataSaverEnabled);
+  data_reduction_proxy::DataReductionProxySettings*
+      data_reduction_proxy_settings =
+          DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
+              browser_context);
+  return data_reduction_proxy_settings &&
+         data_reduction_proxy_settings->IsDataSaverEnabledByUser();
 }
 
 void ChromeContentBrowserClient::UpdateRendererPreferencesForWorker(
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index 829911f..1f88cc14 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -132,14 +132,6 @@
   *target_contents = opened_contents;
 }
 
-TEST_F(ChromeContentBrowserClientWindowTest, IsDataSaverEnabled) {
-  ChromeContentBrowserClient client;
-  content::BrowserContext* context = browser()->profile();
-  EXPECT_FALSE(client.IsDataSaverEnabled(context));
-  browser()->profile()->GetPrefs()->SetBoolean(prefs::kDataSaverEnabled, true);
-  EXPECT_TRUE(client.IsDataSaverEnabled(context));
-}
-
 // This test opens two URLs using ContentBrowserClient::OpenURL. It expects the
 // URLs to be opened in new tabs and activated, changing the active tabs after
 // each call and increasing the tab count by 2.
diff --git a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc
index 66a8dd76..361a87f 100644
--- a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc
+++ b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc
@@ -28,7 +28,6 @@
 #include "chromeos/components/account_manager/account_manager_factory.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/auth_policy/auth_policy_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
@@ -86,7 +85,7 @@
 
   // Connecting to the signal sent by authpolicyd notifying that Kerberos files
   // have changed.
-  DBusThreadManager::Get()->GetAuthPolicyClient()->ConnectToSignal(
+  AuthPolicyClient::Get()->ConnectToSignal(
       authpolicy::kUserKerberosFilesChangedSignal,
       base::Bind(
           &AuthPolicyCredentialsManager::OnUserKerberosFilesChangedCallback,
@@ -125,7 +124,7 @@
   authpolicy::GetUserStatusRequest request;
   request.set_user_principal_name(account_id_.GetUserEmail());
   request.set_account_id(account_id_.GetObjGuid());
-  DBusThreadManager::Get()->GetAuthPolicyClient()->GetUserStatus(
+  AuthPolicyClient::Get()->GetUserStatus(
       request,
       base::BindOnce(&AuthPolicyCredentialsManager::OnGetUserStatusCallback,
                      weak_factory_.GetWeakPtr()));
@@ -188,7 +187,7 @@
 }
 
 void AuthPolicyCredentialsManager::GetUserKerberosFiles() {
-  DBusThreadManager::Get()->GetAuthPolicyClient()->GetUserKerberosFiles(
+  AuthPolicyClient::Get()->GetUserKerberosFiles(
       account_id_.GetObjGuid(),
       base::BindOnce(
           &AuthPolicyCredentialsManager::OnGetUserKerberosFilesCallback,
diff --git a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager_unittest.cc b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager_unittest.cc
index 543e0016..7f14c6cc 100644
--- a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager_unittest.cc
+++ b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager_unittest.cc
@@ -52,6 +52,7 @@
   void SetUp() override {
     chromeos::DBusThreadManager::Initialize();
     chromeos::NetworkHandler::Initialize();
+    AuthPolicyClient::InitializeFake();
     fake_auth_policy_client()->DisableOperationDelayForTesting();
 
     TestingProfile::Builder profile_builder;
@@ -83,8 +84,9 @@
   void TearDown() override {
     EXPECT_CALL(*mock_user_manager(), Shutdown());
     profile_.reset();
-    chromeos::NetworkHandler::Shutdown();
-    chromeos::DBusThreadManager::Shutdown();
+    AuthPolicyClient::Shutdown();
+    NetworkHandler::Shutdown();
+    DBusThreadManager::Shutdown();
   }
 
  protected:
@@ -94,8 +96,7 @@
     return auth_policy_credentials_manager_;
   }
   chromeos::FakeAuthPolicyClient* fake_auth_policy_client() const {
-    return static_cast<chromeos::FakeAuthPolicyClient*>(
-        chromeos::DBusThreadManager::Get()->GetAuthPolicyClient());
+    return chromeos::FakeAuthPolicyClient::Get();
   }
 
   MockUserManager* mock_user_manager() {
diff --git a/chrome/browser/chromeos/dbus/dbus_helper.cc b/chrome/browser/chromeos/dbus/dbus_helper.cc
index 060b852..6bb0a5cf3 100644
--- a/chrome/browser/chromeos/dbus/dbus_helper.cc
+++ b/chrome/browser/chromeos/dbus/dbus_helper.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
+#include "chromeos/dbus/auth_policy/auth_policy_client.h"
 #include "chromeos/dbus/biod/biod_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/hammerd/hammerd_client.h"
@@ -39,12 +40,14 @@
   }
 
   if (bus) {
+    AuthPolicyClient::Initialize(bus);
     BiodClient::Initialize(bus);  // For device::Fingerprint.
     KerberosClient::Initialize(bus);
     PowerManagerClient::Initialize(bus);
     SystemClockClient::Initialize(bus);
     UpstartClient::Initialize(bus);
   } else {
+    AuthPolicyClient::InitializeFake();
     BiodClient::InitializeFake();  // For device::Fingerprint.
     KerberosClient::InitializeFake();
     PowerManagerClient::InitializeFake();
@@ -60,6 +63,7 @@
 }
 
 void ShutdownDBus() {
+  AuthPolicyClient::Shutdown();
   UpstartClient::Shutdown();
   SystemClockClient::Shutdown();
   PowerManagerClient::Shutdown();
diff --git a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
index ea0617b..5738b659 100644
--- a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
@@ -83,11 +83,11 @@
   void SetUpInProcessBrowserTestFixture() override {
     LoginManagerTest::SetUpInProcessBrowserTestFixture();
 
-    auto fake_client = std::make_unique<FakeAuthPolicyClient>();
-    fake_auth_policy_client_ = fake_client.get();
-    fake_auth_policy_client_->DisableOperationDelayForTesting();
-    DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
-        std::move(fake_client));
+    // This is called before ChromeBrowserMain initializes the fake dbus
+    // clients, and DisableOperationDelayForTesting() needs to be called before
+    // other ChromeBrowserMain initialization occurs.
+    AuthPolicyClient::InitializeFake();
+    FakeAuthPolicyClient::Get()->DisableOperationDelayForTesting();
 
     // Note: FakeCryptohomeClient needs paths to be set to load install attribs.
     active_directory_test_helper::OverridePaths();
@@ -286,7 +286,7 @@
     return "document.querySelector('#" + parent_id + "')." + selector;
   }
   FakeAuthPolicyClient* fake_auth_policy_client() {
-    return fake_auth_policy_client_;
+    return FakeAuthPolicyClient::Get();
   }
 
   const std::string test_realm_;
@@ -294,7 +294,6 @@
   std::string autocomplete_realm_;
 
  private:
-  FakeAuthPolicyClient* fake_auth_policy_client_;
 
   DISALLOW_COPY_AND_ASSIGN(ActiveDirectoryLoginTest);
 };
diff --git a/chrome/browser/chromeos/login/active_directory_test_helper.cc b/chrome/browser/chromeos/login/active_directory_test_helper.cc
index 0ecc814..be4160b8 100644
--- a/chrome/browser/chromeos/login/active_directory_test_helper.cc
+++ b/chrome/browser/chromeos/login/active_directory_test_helper.cc
@@ -15,7 +15,6 @@
 #include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/dbus/auth_policy/auth_policy_client.h"
 #include "chromeos/dbus/authpolicy/active_directory_info.pb.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/upstart/upstart_client.h"
 #include "chromeos/dbus/util/tpm_util.h"
 #include "chromeos/login/auth/authpolicy_login_helper.h"
@@ -69,14 +68,12 @@
   // Fetch device policy.
   {
     base::RunLoop run_loop;
-    chromeos::DBusThreadManager::Get()
-        ->GetAuthPolicyClient()
-        ->RefreshDevicePolicy(base::BindOnce(
-            [](base::OnceClosure quit_closure, authpolicy::ErrorType error) {
-              EXPECT_EQ(authpolicy::ERROR_NONE, error);
-              std::move(quit_closure).Run();
-            },
-            run_loop.QuitClosure()));
+    AuthPolicyClient::Get()->RefreshDevicePolicy(base::BindOnce(
+        [](base::OnceClosure quit_closure, authpolicy::ErrorType error) {
+          EXPECT_EQ(authpolicy::ERROR_NONE, error);
+          std::move(quit_closure).Run();
+        },
+        run_loop.QuitClosure()));
     run_loop.Run();
   }
 }
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
index 2c84b697..10d02480 100644
--- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -216,9 +216,9 @@
   ActiveDirectoryJoinTest() = default;
 
   void SetUp() override {
-    DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
-        std::make_unique<MockAuthPolicyClient>());
+    mock_auth_policy_client_ = new MockAuthPolicyClient();
     mock_auth_policy_client()->DisableOperationDelayForTesting();
+
     EnterpriseEnrollmentTestBase::SetUp();
   }
 
@@ -372,8 +372,7 @@
 
 
   MockAuthPolicyClient* mock_auth_policy_client() {
-    return static_cast<MockAuthPolicyClient*>(
-        DBusThreadManager::Get()->GetAuthPolicyClient());
+    return mock_auth_policy_client_;
   }
 
   void SetupActiveDirectoryJSNotifications() {
@@ -418,6 +417,9 @@
   }
 
  private:
+  // Owned by the AuthPolicyClient global instance.
+  MockAuthPolicyClient* mock_auth_policy_client_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(ActiveDirectoryJoinTest);
 };
 
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index 5662e479..371bdb5c 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -831,7 +831,13 @@
   // Overriden from ExistingUserControllerTest:
   void SetUpInProcessBrowserTestFixture() override {
     ExistingUserControllerTest::SetUpInProcessBrowserTestFixture();
-    fake_authpolicy_client()->DisableOperationDelayForTesting();
+
+    // This is called before ChromeBrowserMain initializes the fake dbus
+    // clients, and DisableOperationDelayForTesting() needs to be called before
+    // other ChromeBrowserMain initialization occurs.
+    AuthPolicyClient::InitializeFake();
+    FakeAuthPolicyClient::Get()->DisableOperationDelayForTesting();
+
     ASSERT_TRUE(
         tpm_util::LockDeviceActiveDirectoryForTesting(kActiveDirectoryRealm));
     RefreshDevicePolicy();
@@ -847,11 +853,6 @@
   }
 
  protected:
-  chromeos::FakeAuthPolicyClient* fake_authpolicy_client() {
-    return static_cast<chromeos::FakeAuthPolicyClient*>(
-        chromeos::DBusThreadManager::Get()->GetAuthPolicyClient());
-  }
-
   void LoginAdOnline() {
     ExpectLoginSuccess();
     UserContext user_context(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY,
@@ -899,7 +900,7 @@
   std::string GetExpectedKerberosConfig(bool enable_dns_cname_lookup) {
     std::string config(base::StringPrintf(
         kKrb5CnameSettings, enable_dns_cname_lookup ? "true" : "false"));
-    config += fake_authpolicy_client()->user_kerberos_conf();
+    config += FakeAuthPolicyClient::Get()->user_kerberos_conf();
     return config;
   }
 
@@ -913,7 +914,8 @@
 
     EXPECT_TRUE(base::ReadFileToString(
         base::FilePath(GetKerberosCredentialsCacheFileName()), &file_contents));
-    EXPECT_EQ(file_contents, fake_authpolicy_client()->user_kerberos_creds());
+    EXPECT_EQ(file_contents,
+              FakeAuthPolicyClient::Get()->user_kerberos_creds());
   }
 
   // Applies policy and waits until both config and credentials files changed.
@@ -944,7 +946,7 @@
     em::ChromeDeviceSettingsProto device_policy;
     device_policy.mutable_user_whitelist()->add_user_whitelist()->assign(
         kUserWhitelist);
-    fake_authpolicy_client()->set_device_policy(device_policy);
+    FakeAuthPolicyClient::Get()->set_device_policy(device_policy);
   }
 
   void SetUpLoginDisplay() override {
@@ -988,8 +990,8 @@
     DISABLED_UserKerberosFilesChangedSignalTriggersFileUpdate) {
   LoginAdOnline();
   KerberosFilesChangeWaiter files_change_waiter(true /* files_must_exist */);
-  fake_authpolicy_client()->SetUserKerberosFiles("new_kerberos_creds",
-                                                 "new_kerberos_config");
+  FakeAuthPolicyClient::Get()->SetUserKerberosFiles("new_kerberos_creds",
+                                                    "new_kerberos_config");
   files_change_waiter.Wait();
   CheckKerberosFiles(true /* enable_dns_cname_lookup */);
 }
diff --git a/chrome/browser/chromeos/policy/active_directory_policy_manager.cc b/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
index c15be7aa..09d5ef7a 100644
--- a/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
+++ b/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
@@ -44,13 +44,7 @@
 
 // Gets the AuthPolicy D-Bus interface.
 chromeos::AuthPolicyClient* GetAuthPolicyClient() {
-  chromeos::DBusThreadManager* thread_manager =
-      chromeos::DBusThreadManager::Get();
-  DCHECK(thread_manager);
-  chromeos::AuthPolicyClient* auth_policy_client =
-      thread_manager->GetAuthPolicyClient();
-  DCHECK(auth_policy_client);
-  return auth_policy_client;
+  return chromeos::AuthPolicyClient::Get();
 }
 
 bool IsComponentPolicyDisabled() {
diff --git a/chrome/browser/chromeos/policy/active_directory_policy_manager_unittest.cc b/chrome/browser/chromeos/policy/active_directory_policy_manager_unittest.cc
index 3783d7b14..b4fc979 100644
--- a/chrome/browser/chromeos/policy/active_directory_policy_manager_unittest.cc
+++ b/chrome/browser/chromeos/policy/active_directory_policy_manager_unittest.cc
@@ -29,8 +29,6 @@
 
 class TestAuthPolicyClient : public chromeos::AuthPolicyClient {
  public:
-  void Init(dbus::Bus* bus) override { NOTIMPLEMENTED(); }
-
   void JoinAdDomain(const authpolicy::JoinDomainRequest& request,
                     int password_fd,
                     JoinCallback callback) override {
@@ -101,16 +99,16 @@
 
   // testing::Test overrides:
   void SetUp() override {
-    auto mock_client_unique_ptr = std::make_unique<TestAuthPolicyClient>();
-    mock_client_ = mock_client_unique_ptr.get();
-    chromeos::DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
-        std::move(mock_client_unique_ptr));
+    // Base class constructor sets the global instance which will be destroyed
+    // in AuthPolicyClient::Shutdown().
+    mock_client_ = new TestAuthPolicyClient();
   }
 
   void TearDown() override {
     if (mock_external_data_manager())
       EXPECT_CALL(*mock_external_data_manager(), Disconnect());
     policy_manager_->Shutdown();
+    chromeos::AuthPolicyClient::Shutdown();
   }
 
  protected:
@@ -141,7 +139,7 @@
       testing::Mock::VerifyAndClearExpectations(mock_external_data_manager());
   }
 
-  // Owned by DBusThreadManager.
+  // Owned by the AuthPolicyClient global instance.
   TestAuthPolicyClient* mock_client_ = nullptr;
 
   // Used to set FakeUserManager.
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
index 561b79f..2b28c20 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -748,11 +748,9 @@
     // policy is accepted.
     chromeos::DeviceSettingsService::Get()->SetDeviceMode(
         install_attributes_->GetMode());
-    chromeos::DBusThreadManager::Get()
-        ->GetAuthPolicyClient()
-        ->RefreshDevicePolicy(base::BindOnce(
-            &EnrollmentHandlerChromeOS::HandleActiveDirectoryPolicyRefreshed,
-            weak_ptr_factory_.GetWeakPtr()));
+    chromeos::AuthPolicyClient::Get()->RefreshDevicePolicy(base::BindOnce(
+        &EnrollmentHandlerChromeOS::HandleActiveDirectoryPolicyRefreshed,
+        weak_ptr_factory_.GetWeakPtr()));
   } else {
     store_->InstallInitialPolicy(*policy_);
   }
diff --git a/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc b/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
index 2b76ee7..1fff02e 100644
--- a/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
@@ -165,19 +165,14 @@
     chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
         std::make_unique<chromeos::FakeCryptohomeClient>());
 
-    // Initialize UpstartClient here so that it is available for
-    // FakeAuthPolicyClient. It will be shutdown in ChromeBrowserMain.
+    // Initialize clients here so they are available during setup. They will be
+    // shutdown in ChromeBrowserMain.
     chromeos::UpstartClient::InitializeFake();
-
     chromeos::FakeAuthPolicyClient* fake_auth_policy_client = nullptr;
     if (GetParam().active_directory) {
-      auto fake_auth_policy_client_owned =
-          std::make_unique<chromeos::FakeAuthPolicyClient>();
-      fake_auth_policy_client = fake_auth_policy_client_owned.get();
+      chromeos::AuthPolicyClient::InitializeFake();
+      fake_auth_policy_client = chromeos::FakeAuthPolicyClient::Get();
       fake_auth_policy_client->DisableOperationDelayForTesting();
-      chromeos::DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
-          std::move(fake_auth_policy_client_owned));
-
       // PrepareLogin requires a message loop, which isn't available yet here.
       base::MessageLoop message_loop;
       chromeos::active_directory_test_helper::PrepareLogin(
diff --git a/chrome/browser/chromeos/set_time_dialog.cc b/chrome/browser/chromeos/set_time_dialog.cc
index d96d75a..4d215e5 100644
--- a/chrome/browser/chromeos/set_time_dialog.cc
+++ b/chrome/browser/chromeos/set_time_dialog.cc
@@ -20,8 +20,8 @@
 
 // Material design dialog width and height in DIPs.
 const int kDefaultWidthMd = 530;
-const int kDefaultHeightWithTimezone = 255;
-const int kDefaultHeightWithoutTimezone = 215;
+const int kDefaultHeightWithTimezone = 286;
+const int kDefaultHeightWithoutTimezone = 228;
 
 }  // namespace
 
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc
index bdc79934..ce7d41cf 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -221,10 +221,18 @@
                            bool use_chromad_kerberos,
                            bool should_open_file_manager_after_mount,
                            MountResponse callback) {
+  SmbUrl parsed_url(share_path.value());
+  if (!parsed_url.IsValid() || parsed_url.GetShare().empty()) {
+    // Handle invalid URLs early to avoid having unaccounted for UMA counts for
+    // authentication method.
+    std::move(callback).Run(
+        TranslateErrorToMountResult(base::File::Error::FILE_ERROR_INVALID_URL));
+    return;
+  }
+
   std::string username;
   std::string password;
   std::string workgroup;
-
   if (use_chromad_kerberos) {
     RecordAuthenticationMethod(AuthMethod::kSSOKerberos);
     // Get the user's username and workgroup from their email address to be used
@@ -254,13 +262,6 @@
     }
   }
 
-  SmbUrl parsed_url(share_path.value());
-  if (!parsed_url.IsValid()) {
-    std::move(callback).Run(
-        TranslateErrorToMountResult(base::File::Error::FILE_ERROR_INVALID_URL));
-    return;
-  }
-
   // If using kerberos, the hostname should not be resolved since kerberos
   // service tickets are keyed on hosname.
   const std::string url = use_chromad_kerberos
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h
index b74dd9d5..e5530c6 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.h
+++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -105,6 +105,8 @@
                        StartReadDirIfSuccessfulCallback reply);
 
  private:
+  friend class SmbServiceTest;
+
   // Calls SmbProviderClient::Mount(). |temp_file_manager_| must be initialized
   // before this is called.
   void CallMount(const file_system_provider::MountOptions& options,
diff --git a/chrome/browser/chromeos/smb_client/smb_service_unittest.cc b/chrome/browser/chromeos/smb_client/smb_service_unittest.cc
index 608709d0..e9a2629 100644
--- a/chrome/browser/chromeos/smb_client/smb_service_unittest.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service_unittest.cc
@@ -26,6 +26,14 @@
 namespace chromeos {
 namespace smb_client {
 
+namespace {
+
+void SaveMountResult(SmbMountResult* out, SmbMountResult result) {
+  *out = result;
+}
+
+}  // namespace
+
 class SmbServiceTest : public testing::Test {
  protected:
   SmbServiceTest() : profile_(NULL) {
@@ -59,6 +67,16 @@
 
   ~SmbServiceTest() override {}
 
+  void ExpectInvalidUrl(const std::string& url) {
+    SmbMountResult result = SmbMountResult::SUCCESS;
+    smb_service_->CallMount({} /* options */, base::FilePath(url),
+                            "" /* username */, "" /* password */,
+                            false /* use_chromad_kerberos */,
+                            false /* should_open_file_manager_after_mount */,
+                            base::BindOnce(&SaveMountResult, &result));
+    EXPECT_EQ(result, SmbMountResult::INVALID_URL);
+  }
+
   content::TestBrowserThreadBundle
       thread_bundle_;        // Included so tests magically don't crash.
   TestingProfile* profile_;  // Not owned.
@@ -71,5 +89,18 @@
   std::unique_ptr<extensions::ExtensionRegistry> extension_registry_;
 };
 
+TEST_F(SmbServiceTest, InvalidUrls) {
+  ExpectInvalidUrl("");
+  ExpectInvalidUrl("foo");
+  ExpectInvalidUrl("\\foo");
+  ExpectInvalidUrl("\\\\foo");
+  ExpectInvalidUrl("\\\\foo\\");
+  ExpectInvalidUrl("file://foo/bar");
+  ExpectInvalidUrl("smb://foo");
+  ExpectInvalidUrl("smb://user@password:foo");
+  ExpectInvalidUrl("smb:\\\\foo\\bar");
+  ExpectInvalidUrl("//foo/bar");
+}
+
 }  // namespace smb_client
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/smb_client/smb_url.cc b/chrome/browser/chromeos/smb_client/smb_url.cc
index 46818ab94..fbf7e26 100644
--- a/chrome/browser/chromeos/smb_client/smb_url.cc
+++ b/chrome/browser/chromeos/smb_client/smb_url.cc
@@ -4,7 +4,11 @@
 
 #include "chrome/browser/chromeos/smb_client/smb_url.h"
 
+#include <vector>
+
 #include "base/strings/strcat.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/chromeos/smb_client/smb_constants.h"
 #include "url/url_canon_stdstring.h"
@@ -76,6 +80,12 @@
   return url_.substr(host_.begin, host_.len);
 }
 
+std::string SmbUrl::GetShare() const {
+  DCHECK(IsValid());
+
+  return share_;
+}
+
 const std::string& SmbUrl::ToString() const {
   DCHECK(IsValid());
 
@@ -123,11 +133,11 @@
   canonical_output.push_back('/');
   canonical_output.push_back('/');
 
-  url::Component unused_path;
+  url::Component path;
   if (!(url::CanonicalizeHost(url.c_str(), initial_parsed.host,
                               &canonical_output, &host_) &&
         url::CanonicalizePath(url.c_str(), initial_parsed.path,
-                              &canonical_output, &unused_path))) {
+                              &canonical_output, &path))) {
     Reset();
     return;
   }
@@ -141,6 +151,20 @@
 
   canonical_output.Complete();
 
+  if (path.is_nonempty()) {
+    // Extract share name, which is the first path element.
+    // Paths always start with '/', but extra '/'s are not removed.
+    // So both "smb://foo" and "smb://foo//bar/" have the share name "", but
+    // "smb://foo/bar/" has the share name "bar".
+    std::string path_str = url_.substr(path.begin, path.len);
+    std::vector<base::StringPiece> split_path = base::SplitStringPiece(
+        path_str, "/", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+    if (split_path.size() >= 2) {
+      DCHECK_EQ(split_path[0], "");
+      share_ = split_path[1].as_string();
+    }
+  }
+
   DCHECK(host_.is_nonempty());
   DCHECK_EQ(url_.substr(scheme.begin, scheme.len), kSmbScheme);
 }
diff --git a/chrome/browser/chromeos/smb_client/smb_url.h b/chrome/browser/chromeos/smb_client/smb_url.h
index 3e23a45..4831f11 100644
--- a/chrome/browser/chromeos/smb_client/smb_url.h
+++ b/chrome/browser/chromeos/smb_client/smb_url.h
@@ -27,6 +27,9 @@
   // Returns the host of the URL which can be resolved or unresolved.
   std::string GetHost() const;
 
+  // Returns the share component of the URL.
+  std::string GetShare() const;
+
   // Returns the full URL.
   const std::string& ToString() const;
 
@@ -61,6 +64,9 @@
   // Holds the identified host of the URL. This does not store the host itself.
   url::Component host_;
 
+  // Share name component of the URL.
+  std::string share_;
+
   DISALLOW_COPY_AND_ASSIGN(SmbUrl);
 };
 
diff --git a/chrome/browser/chromeos/smb_client/smb_url_unittest.cc b/chrome/browser/chromeos/smb_client/smb_url_unittest.cc
index 92d9399..4aef1b2 100644
--- a/chrome/browser/chromeos/smb_client/smb_url_unittest.cc
+++ b/chrome/browser/chromeos/smb_client/smb_url_unittest.cc
@@ -24,11 +24,13 @@
 
   void ExpectValidUrl(const std::string& url,
                       const std::string& expected_url,
-                      const std::string& expected_host) {
+                      const std::string& expected_host,
+                      const std::string& expected_share) {
     SmbUrl smb_url(url);
     EXPECT_TRUE(smb_url.IsValid());
     EXPECT_EQ(expected_url, smb_url.ToString());
     EXPECT_EQ(expected_host, smb_url.GetHost());
+    EXPECT_EQ(expected_share, smb_url.GetShare());
   }
 
   void ExpectValidWindowsUNC(const std::string& url,
@@ -58,19 +60,24 @@
 }
 
 TEST_F(SmbUrlTest, ValidUrls) {
-  ExpectValidUrl("smb://x", "smb://x/", "x");
-  ExpectValidUrl("smb:///x", "smb://x/", "x");
+  ExpectValidUrl("smb://x", "smb://x/", "x", "");
+  ExpectValidUrl("smb:///x", "smb://x/", "x", "");
+  ExpectValidUrl("smb:///x/y", "smb://x/y", "x", "y");
+  ExpectValidUrl("smb:///x/y/", "smb://x/y/", "x", "y");
+  ExpectValidUrl("smb:///x//y", "smb://x//y", "x", "");
+  ExpectValidUrl("smb:///x//y//", "smb://x//y//", "x", "");
   ExpectValidUrl("smb://server/share/long/folder",
-                 "smb://server/share/long/folder", "server");
+                 "smb://server/share/long/folder", "server", "share");
   ExpectValidUrl("smb://server/share/folder.with.dots",
-                 "smb://server/share/folder.with.dots", "server");
+                 "smb://server/share/folder.with.dots", "server", "share");
   ExpectValidUrl("smb://server\\share/mixed\\slashes",
-                 "smb://server/share/mixed/slashes", "server");
-  ExpectValidUrl("\\\\server/share", "smb://server/share", "server");
+                 "smb://server/share/mixed/slashes", "server", "share");
+  ExpectValidUrl("\\\\server", "smb://server/", "server", "");
+  ExpectValidUrl("\\\\server/share", "smb://server/share", "server", "share");
   ExpectValidUrl("\\\\server\\share/mixed//slashes",
-                 "smb://server/share/mixed//slashes", "server");
+                 "smb://server/share/mixed//slashes", "server", "share");
   ExpectValidUrl("smb://192.168.0.1/share", "smb://192.168.0.1/share",
-                 "192.168.0.1");
+                 "192.168.0.1", "share");
 }
 
 TEST_F(SmbUrlTest, NotValidIfStartsWithoutSchemeOrDoubleBackslash) {
@@ -79,20 +86,20 @@
 
 TEST_F(SmbUrlTest, StartsWithBackslashRemovesBackslashAndAddsScheme) {
   ExpectValidUrl("\\\\192.168.0.1\\share", "smb://192.168.0.1/share",
-                 "192.168.0.1");
+                 "192.168.0.1", "share");
 }
 
 TEST_F(SmbUrlTest, GetHostWithIp) {
   ExpectValidUrl("smb://192.168.0.1/share", "smb://192.168.0.1/share",
-                 "192.168.0.1");
+                 "192.168.0.1", "share");
 }
 
 TEST_F(SmbUrlTest, GetHostWithDomain) {
-  ExpectValidUrl("smb://server/share", "smb://server/share", "server");
+  ExpectValidUrl("smb://server/share", "smb://server/share", "server", "share");
 }
 
 TEST_F(SmbUrlTest, HostBecomesLowerCase) {
-  ExpectValidUrl("smb://SERVER/share", "smb://server/share", "server");
+  ExpectValidUrl("smb://SERVER/share", "smb://server/share", "server", "share");
 }
 
 TEST_F(SmbUrlTest, ReplacesHost) {
diff --git a/chrome/browser/dom_distiller/dom_distiller_service_factory.cc b/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
index 73e3fd3b..b4c9bb8 100644
--- a/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
+++ b/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
@@ -50,22 +50,26 @@
 DomDistillerServiceFactory::DomDistillerServiceFactory()
     : BrowserContextKeyedServiceFactory(
           "DomDistillerService",
-          BrowserContextDependencyManager::GetInstance()) {}
+          BrowserContextDependencyManager::GetInstance()) {
+  // Add this when this factory is a SimpleKeyedServiceFactory:
+  // DependsOn(leveldb_proto::ProtoDatabaseProviderFactory::GetInstance());
+}
 
 DomDistillerServiceFactory::~DomDistillerServiceFactory() {}
 
 KeyedService* DomDistillerServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* profile) const {
+    content::BrowserContext* context) const {
+  Profile* profile = Profile::FromBrowserContext(context);
   scoped_refptr<base::SequencedTaskRunner> background_task_runner =
       base::CreateSequencedTaskRunnerWithTraits(
           {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
 
   base::FilePath database_dir(
-      profile->GetPath().Append(FILE_PATH_LITERAL("Articles")));
+      context->GetPath().Append(FILE_PATH_LITERAL("Articles")));
 
   leveldb_proto::ProtoDatabaseProvider* db_provider =
-      leveldb_proto::ProtoDatabaseProviderFactory::GetForBrowserContext(
-          profile);
+      leveldb_proto::ProtoDatabaseProviderFactory::GetForKey(
+          profile->GetSimpleFactoryKey(), profile->GetPrefs());
 
   auto db = db_provider->GetDB<ArticleEntry>(
       leveldb_proto::ProtoDbType::DOM_DISTILLER_STORE, database_dir,
@@ -75,10 +79,10 @@
       new DomDistillerStore(std::move(db)));
 
   std::unique_ptr<DistillerPageFactory> distiller_page_factory(
-      new DistillerPageWebContentsFactory(profile));
+      new DistillerPageWebContentsFactory(context));
   std::unique_ptr<DistillerURLFetcherFactory> distiller_url_fetcher_factory(
       new DistillerURLFetcherFactory(
-          content::BrowserContext::GetDefaultStoragePartition(profile)
+          content::BrowserContext::GetDefaultStoragePartition(context)
               ->GetURLLoaderFactoryForBrowserProcess()));
 
   dom_distiller::proto::DomDistillerOptions options;
@@ -94,7 +98,7 @@
   std::unique_ptr<DistillerFactory> distiller_factory(new DistillerFactoryImpl(
       std::move(distiller_url_fetcher_factory), options));
   std::unique_ptr<DistilledPagePrefs> distilled_page_prefs(
-      new DistilledPagePrefs(Profile::FromBrowserContext(profile)->GetPrefs()));
+      new DistilledPagePrefs(profile->GetPrefs()));
 
   DomDistillerContextKeyedService* service =
       new DomDistillerContextKeyedService(
diff --git a/chrome/browser/download/download_offline_content_provider.cc b/chrome/browser/download/download_offline_content_provider.cc
index cc9da61..0067d0d9 100644
--- a/chrome/browser/download/download_offline_content_provider.cc
+++ b/chrome/browser/download/download_offline_content_provider.cc
@@ -24,7 +24,6 @@
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/android/download/download_manager_bridge.h"
-#include "chrome/browser/android/download/download_manager_service.h"
 #endif
 
 using OfflineItemFilter = offline_items_collection::OfflineItemFilter;
@@ -57,11 +56,15 @@
 
 DownloadOfflineContentProvider::~DownloadOfflineContentProvider() {
   aggregator_->UnregisterProvider(name_space_);
+  if (manager_)
+    manager_->RemoveObserver(this);
 }
 
 void DownloadOfflineContentProvider::SetDownloadManager(
     DownloadManager* manager) {
+  DCHECK(manager);
   manager_ = manager;
+  manager_->AddObserver(this);
 }
 
 // TODO(shaktisahu) : Pass DownloadOpenSource.
@@ -201,6 +204,11 @@
   observers_.RemoveObserver(observer);
 }
 
+void DownloadOfflineContentProvider::ManagerGoingDown(
+    DownloadManager* manager) {
+  manager_ = nullptr;
+}
+
 void DownloadOfflineContentProvider::OnDownloadStarted(DownloadItem* item) {
   item->RemoveObserver(this);
   item->AddObserver(this);
@@ -261,27 +269,13 @@
 
 DownloadItem* DownloadOfflineContentProvider::GetDownload(
     const std::string& download_guid) {
-#if defined(OS_ANDROID)
-  bool incognito = manager_ && manager_->GetBrowserContext()
-                       ? manager_->GetBrowserContext()->IsOffTheRecord()
-                       : false;
-  return DownloadManagerService::GetInstance()->GetDownload(download_guid,
-                                                            incognito);
-#else
-  return manager_->GetDownloadByGuid(download_guid);
-#endif
+  return manager_ ? manager_->GetDownloadByGuid(download_guid) : nullptr;
 }
 
 void DownloadOfflineContentProvider::GetAllDownloads(
     DownloadManager::DownloadVector* all_items) {
-#if defined(OS_ANDROID)
-  bool incognito = manager_ && manager_->GetBrowserContext()
-                       ? manager_->GetBrowserContext()->IsOffTheRecord()
-                       : false;
-  DownloadManagerService::GetInstance()->GetAllDownloads(all_items, incognito);
-#else
-  manager_->GetAllDownloads(all_items);
-#endif
+  if (manager_)
+    manager_->GetAllDownloads(all_items);
 }
 
 void DownloadOfflineContentProvider::UpdateObservers(DownloadItem* item) {
diff --git a/chrome/browser/download/download_offline_content_provider.h b/chrome/browser/download/download_offline_content_provider.h
index 4798bbe..da0fff79 100644
--- a/chrome/browser/download/download_offline_content_provider.h
+++ b/chrome/browser/download/download_offline_content_provider.h
@@ -29,7 +29,8 @@
 // single DownloadManager (or in-progress download manager in service manager
 // only mode) and notifies UI about updates about various downloads.
 class DownloadOfflineContentProvider : public OfflineContentProvider,
-                                       public download::DownloadItem::Observer {
+                                       public download::DownloadItem::Observer,
+                                       public DownloadManager::Observer {
  public:
   explicit DownloadOfflineContentProvider(OfflineContentAggregator* aggregator,
                                           const std::string& name_space);
@@ -66,9 +67,13 @@
   void OnDownloadStarted(DownloadItem* download_item);
 
  private:
+  // DownloadItem::Observer overrides
   void OnDownloadUpdated(DownloadItem* item) override;
   void OnDownloadRemoved(DownloadItem* item) override;
 
+  // DownloadManager::Observer overrides
+  void ManagerGoingDown(DownloadManager* manager) override;
+
   void GetAllDownloads(DownloadManager::DownloadVector* all_items);
   DownloadItem* GetDownload(const std::string& download_guid);
   void OnThumbnailRetrieved(const ContentId& id,
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc
index c8e2913..8266f29 100644
--- a/chrome/browser/extensions/bookmark_app_helper.cc
+++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -296,8 +296,9 @@
       // Do not wait for a service worker if it doesn't exist.
       params.has_worker = !bypass_service_worker_check_;
       installable_manager_->GetData(
-          params, base::Bind(&BookmarkAppHelper::OnDidPerformInstallableCheck,
-                             weak_factory_.GetWeakPtr()));
+          params,
+          base::BindOnce(&BookmarkAppHelper::OnDidPerformInstallableCheck,
+                         weak_factory_.GetWeakPtr()));
     }
   } else {
     for_installable_site_ = web_app::ForInstallableSite::kNo;
diff --git a/chrome/browser/feature_engagement/tracker_factory.cc b/chrome/browser/feature_engagement/tracker_factory.cc
index 2ff6527..5c248c3 100644
--- a/chrome/browser/feature_engagement/tracker_factory.cc
+++ b/chrome/browser/feature_engagement/tracker_factory.cc
@@ -35,7 +35,8 @@
     : BrowserContextKeyedServiceFactory(
           "feature_engagement::Tracker",
           BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(leveldb_proto::ProtoDatabaseProviderFactory::GetInstance());
+  // Add this when this factory is a SimpleKeyedServiceFactory:
+  // DependsOn(leveldb_proto::ProtoDatabaseProviderFactory::GetInstance());
 }
 
 TrackerFactory::~TrackerFactory() = default;
@@ -52,8 +53,8 @@
       chrome::kFeatureEngagementTrackerStorageDirname);
 
   leveldb_proto::ProtoDatabaseProvider* db_provider =
-      leveldb_proto::ProtoDatabaseProviderFactory::GetInstance()
-          ->GetForBrowserContext(context);
+      leveldb_proto::ProtoDatabaseProviderFactory::GetInstance()->GetForKey(
+          profile->GetSimpleFactoryKey(), profile->GetPrefs());
   return feature_engagement::Tracker::Create(
       storage_dir, background_task_runner, db_provider);
 }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 576c115..55ae5f8b 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -272,7 +272,7 @@
     "expiry_milestone": 75
   },
   {
-    "name": "autofill-show-full-disclosure-label",
+    "name": "autofill-use-improved-label-disambiguation",
     "owners": [ "ftirelo", "tmartino" ],
     "expiry_milestone": 77
   },
@@ -1605,8 +1605,13 @@
   },
   {
     "name": "enable-send-tab-to-self",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
+    "owners": [ "//components/send_tab_to_self/OWNERS" ],
+    "expiry_milestone": 77
+  },
+  {
+    "name": "enable-send-tab-to-self-receive",
+    "owners": [ "//components/send_tab_to_self/OWNERS" ],
+    "expiry_milestone": 77
   },
   {
     "name": "enable-sensor-content-setting",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index d13f97f..4c4d145 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -153,11 +153,11 @@
 const char kAutofillProfileServerValidationDescription[] =
     "Allows autofill to use server side validation";
 
-const char kAutofillShowFullDisclosureLabelName[] =
-    "Autofill Show Full Disclosure Label";
-const char kAutofillShowFullDisclosureLabelDescription[] =
-    "When enabled, the Autofill dropdown's labels are displayed in the full "
-    "disclosure format.";
+const char kAutofillUseImprovedLabelDisambiguationName[] =
+    "Autofill Uses Improved Label Disambiguation";
+const char kAutofillUseImprovedLabelDisambiguationDescription[] =
+    "When enabled, the Autofill dropdown's suggestions' labels are displayed "
+    "using the improved disambiguation format.";
 
 const char kAutofillEnforceMinRequiredFieldsForHeuristicsName[] =
     "Autofill Enforce Min Required Fields For Heuristics";
@@ -1700,6 +1700,11 @@
     "Allows users to push tabs from Android devices to other synced "
     "devices, in order to easily transition those tabs to the new device ";
 
+const char kSendTabToSelfReceiveName[] = "Send tab to self receive";
+const char kSendTabToSelfReceiveDescription[] =
+    "Allows users to receive tabs that were pushed from other synced "
+    "devices, in order to easily transition those tabs to the new device ";
+
 const char kServiceWorkerImportedScriptUpdateCheckName[] =
     "Enable update check for service worker importScripts() resources";
 const char kServiceWorkerImportedScriptUpdateCheckDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index dd8711f..fb5c793 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -122,8 +122,8 @@
 extern const char kAutofillProfileServerValidationName[];
 extern const char kAutofillProfileServerValidationDescription[];
 
-extern const char kAutofillShowFullDisclosureLabelName[];
-extern const char kAutofillShowFullDisclosureLabelDescription[];
+extern const char kAutofillUseImprovedLabelDisambiguationName[];
+extern const char kAutofillUseImprovedLabelDisambiguationDescription[];
 
 extern const char kAutofillRestrictUnownedFieldsToFormlessCheckoutName[];
 extern const char kAutofillRestrictUnownedFieldsToFormlessCheckoutDescription[];
@@ -1012,6 +1012,9 @@
 extern const char kSendTabToSelfName[];
 extern const char kSendTabToSelfDescription[];
 
+extern const char kSendTabToSelfReceiveName[];
+extern const char kSendTabToSelfReceiveDescription[];
+
 extern const char kServiceWorkerImportedScriptUpdateCheckName[];
 extern const char kServiceWorkerImportedScriptUpdateCheckDescription[];
 
diff --git a/chrome/browser/installable/fake_installable_manager.cc b/chrome/browser/installable/fake_installable_manager.cc
index c3dc027..2a7a566 100644
--- a/chrome/browser/installable/fake_installable_manager.cc
+++ b/chrome/browser/installable/fake_installable_manager.cc
@@ -19,14 +19,14 @@
 FakeInstallableManager::~FakeInstallableManager() {}
 
 void FakeInstallableManager::GetData(const InstallableParams& params,
-                                     const InstallableCallback& callback) {
+                                     InstallableCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&FakeInstallableManager::RunCallback,
-                                base::Unretained(this), callback));
+                                base::Unretained(this), std::move(callback)));
 }
 
-void FakeInstallableManager::RunCallback(const InstallableCallback& callback) {
-  callback.Run(*data_);
+void FakeInstallableManager::RunCallback(InstallableCallback callback) {
+  std::move(callback).Run(*data_);
 }
 
 // static
diff --git a/chrome/browser/installable/fake_installable_manager.h b/chrome/browser/installable/fake_installable_manager.h
index eb06b0f..a3cb0e7 100644
--- a/chrome/browser/installable/fake_installable_manager.h
+++ b/chrome/browser/installable/fake_installable_manager.h
@@ -27,9 +27,9 @@
 
   // InstallableManager:
   void GetData(const InstallableParams& params,
-               const InstallableCallback& callback) override;
+               InstallableCallback callback) override;
 
-  void RunCallback(const InstallableCallback& callback);
+  void RunCallback(InstallableCallback callback);
 
   // Create the manager and attach it to |web_contents|.
   static FakeInstallableManager* CreateForWebContents(
diff --git a/chrome/browser/installable/installable_data.h b/chrome/browser/installable/installable_data.h
index e56fec6..5e97145e 100644
--- a/chrome/browser/installable/installable_data.h
+++ b/chrome/browser/installable/installable_data.h
@@ -76,6 +76,6 @@
   DISALLOW_COPY_AND_ASSIGN(InstallableData);
 };
 
-using InstallableCallback = base::Callback<void(const InstallableData&)>;
+using InstallableCallback = base::OnceCallback<void(const InstallableData&)>;
 
 #endif  // CHROME_BROWSER_INSTALLABLE_INSTALLABLE_DATA_H_
diff --git a/chrome/browser/installable/installable_logging.cc b/chrome/browser/installable/installable_logging.cc
index 07a3ff92..b80db18 100644
--- a/chrome/browser/installable/installable_logging.cc
+++ b/chrome/browser/installable/installable_logging.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/installable/installable_logging.h"
 
-#include "base/macros.h"
 #include "base/no_destructor.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/installable/installable_manager.h"
@@ -13,76 +12,66 @@
 
 namespace {
 
+// Error message strings corresponding to the InstallableStatusCode enum.
+static const char kNotInMainFrameMessage[] =
+    "Page is not loaded in the main frame";
+static const char kNotFromSecureOriginMessage[] =
+    "Page is not served from a secure origin";
+static const char kNoManifestMessage[] = "Page has no manifest <link> URL";
+static const char kManifestEmptyMessage[] =
+    "Manifest could not be fetched, is empty, or could not be parsed";
+static const char kStartUrlNotValidMessage[] =
+    "Manifest start URL is not valid";
+static const char kManifestMissingNameOrShortNameMessage[] =
+    "Manifest does not contain a 'name' or 'short_name' field";
+static const char kManifestDisplayNotSupportedMessage[] =
+    "Manifest 'display' property must be one of 'standalone', 'fullscreen', or "
+    "'minimal-ui'";
+static const char kManifestMissingSuitableIconMessage[] =
+    "Manifest does not contain a suitable icon - PNG format of at least "
+    "%dpx is required, the sizes attribute must be set, and the purpose "
+    "attribute, if set, must include \"any\".";
+static const char kNoMatchingServiceWorkerMessage[] =
+    "No matching service worker detected. You may need to reload the page, or "
+    "check that the service worker for the current page also controls the "
+    "start URL from the manifest";
+static const char kNoAcceptableIconMessage[] =
+    "No supplied icon is at least %dpx square in PNG format";
+static const char kCannotDownloadIconMessage[] =
+    "Could not download a required icon from the manifest";
+static const char kNoIconAvailableMessage[] =
+    "Downloaded icon was empty or corrupted";
+static const char kPlatformNotSupportedOnAndroidMessage[] =
+    "The specified application platform is not supported on Android";
+static const char kNoIdSpecifiedMessage[] = "No Play store ID provided";
+static const char kIdsDoNotMatchMessage[] =
+    "The Play Store app URL and Play Store ID do not match";
+static const char kAlreadyInstalledMessage[] = "The app is already installed";
+static const char kUrlNotSupportedForWebApkMessage[] =
+    "A URL in the manifest contains a username, password, or port";
+static const char kInIncognitoMessage[] =
+    "Page is loaded in an incognito window";
+static const char kNotOfflineCapable[] = "the page does not work offline";
+static const char kNoUrlForServiceWorker[] =
+    "Could not check service worker without a 'start_url' field in the "
+    "manifest";
+
 const std::string& GetMessagePrefix() {
   static base::NoDestructor<std::string> message_prefix(
       "Site cannot be installed: ");
   return *message_prefix;
 }
 
-// Error message strings corresponding to the InstallableStatusCode enum.
-static const char kRendererExitingMessage[] =
-    "the page is in the process of being closed";
-static const char kRendererCancelledMessage[] =
-    "the page has requested the banner prompt be cancelled";
-static const char kUserNavigatedMessage[] =
-    "the page was navigated before the banner could be shown";
-static const char kNotInMainFrameMessage[] =
-    "the page is not loaded in the main frame";
-static const char kNotFromSecureOriginMessage[] =
-    "the page is not served from a secure origin";
-static const char kNoManifestMessage[] =
-    "the page has no manifest <link> URL";
-static const char kManifestEmptyMessage[] =
-    "the manifest could not be fetched, is empty, or could not be parsed";
-static const char kStartUrlNotValidMessage[] =
-    "the manifest start URL is not valid";
-static const char kManifestMissingNameOrShortNameMessage[] =
-    "one of manifest name or short name must be specified";
-static const char kManifestDisplayNotSupportedMessage[] =
-    "the manifest display property must be set to 'standalone' or 'fullscreen'";
-static const char kManifestMissingSuitableIconMessage[] =
-    "the manifest does not contain a suitable icon - PNG format of at least "
-    "%dpx is required, the sizes attribute must be set, and the purpose "
-    "attribute, if set, must include \"any\".";
-static const char kNoMatchingServiceWorkerMessage[] =
-    "no matching service worker detected. You may need to reload the page, or "
-    "check that the service worker for the current page also controls the "
-    "start URL from the manifest";
-static const char kNoAcceptableIconMessage[] =
-    "a %dpx square PNG icon is required, but no supplied icon meets this "
-    "requirement";
-static const char kCannotDownloadIconMessage[] =
-    "could not download a required icon from the manifest";
-static const char kNoIconAvailableMessage[] =
-    "icon downloaded from the manifest was empty or corrupted";
-static const char kPlatformNotSupportedOnAndroidMessage[] =
-    "the specified application platform is not supported on Android";
-static const char kNoIdSpecifiedMessage[] =
-    "no Play store ID provided";
-static const char kIdsDoNotMatchMessage[] =
-    "a Play Store app URL and Play Store ID were specified in the manifest, "
-    "but they do not match";
-static const char kUrlNotSupportedForWebApkMessage[] =
-    "a URL in the manifest contains a username, password, or port";
-static const char kInIncognitoMessage[] =
-    "the page is loaded in an incognito window";
-static const char kNotOfflineCapable[] = "the page does not work offline";
-static const char kNoUrlForServiceWorker[] =
-    "could not check service worker for null start URL";
 }  // namespace
 
-void LogErrorToConsole(content::WebContents* web_contents,
-                       InstallableStatusCode code) {
-  if (!web_contents)
-    return;
-
-  blink::mojom::ConsoleMessageLevel severity =
-      blink::mojom::ConsoleMessageLevel::kError;
+std::string GetErrorMessage(InstallableStatusCode code) {
   std::string message;
   switch (code) {
     case NO_ERROR_DETECTED:
     // These codes are solely used for UMA reporting.
-    case ALREADY_INSTALLED:
+    case RENDERER_EXITING:
+    case RENDERER_CANCELLED:
+    case USER_NAVIGATED:
     case INSUFFICIENT_ENGAGEMENT:
     case PACKAGE_NAME_OR_START_URL_EMPTY:
     case PREVIOUSLY_BLOCKED:
@@ -96,17 +85,6 @@
     case WAITING_FOR_NATIVE_DATA:
     case SHOWING_APP_INSTALLATION_DIALOG:
     case MAX_ERROR_CODE:
-      return;
-    case RENDERER_EXITING:
-      message = kRendererExitingMessage;
-      break;
-    case RENDERER_CANCELLED:
-      message = kRendererCancelledMessage;
-      severity = blink::mojom::ConsoleMessageLevel::kInfo;
-      break;
-    case USER_NAVIGATED:
-      message = kUserNavigatedMessage;
-      severity = blink::mojom::ConsoleMessageLevel::kWarning;
       break;
     case NOT_IN_MAIN_FRAME:
       message = kNotInMainFrameMessage;
@@ -150,7 +128,6 @@
       break;
     case PLATFORM_NOT_SUPPORTED_ON_ANDROID:
       message = kPlatformNotSupportedOnAndroidMessage;
-      severity = blink::mojom::ConsoleMessageLevel::kWarning;
       break;
     case NO_ID_SPECIFIED:
       message = kNoIdSpecifiedMessage;
@@ -158,6 +135,9 @@
     case IDS_DO_NOT_MATCH:
       message = kIdsDoNotMatchMessage;
       break;
+    case ALREADY_INSTALLED:
+      message = kAlreadyInstalledMessage;
+      break;
     case URL_NOT_SUPPORTED_FOR_WEBAPK:
       message = kUrlNotSupportedForWebApkMessage;
       break;
@@ -172,6 +152,19 @@
       break;
   }
 
+  return message;
+}
+
+void LogErrorToConsole(content::WebContents* web_contents,
+                       InstallableStatusCode code) {
+  if (!web_contents)
+    return;
+
+  std::string message = GetErrorMessage(code);
+
+  if (message.empty())
+    return;
+
   web_contents->GetMainFrame()->AddMessageToConsole(
-      severity, GetMessagePrefix() + message);
+      blink::mojom::ConsoleMessageLevel::kError, GetMessagePrefix() + message);
 }
diff --git a/chrome/browser/installable/installable_logging.h b/chrome/browser/installable/installable_logging.h
index c8902ad..7cf4e3a 100644
--- a/chrome/browser/installable/installable_logging.h
+++ b/chrome/browser/installable/installable_logging.h
@@ -56,6 +56,10 @@
   MAX_ERROR_CODE,
 };
 
+// Returns a user-readable description for |code|, or an empty string if |code|
+// should not be exposed.
+std::string GetErrorMessage(InstallableStatusCode code);
+
 // Logs a message associated with |code| to the devtools console attached to
 // |web_contents|. Does nothing if |web_contents| is nullptr.
 void LogErrorToConsole(content::WebContents* web_contents,
diff --git a/chrome/browser/installable/installable_manager.cc b/chrome/browser/installable/installable_manager.cc
index 3a05c64..e899743 100644
--- a/chrome/browser/installable/installable_manager.cc
+++ b/chrome/browser/installable/installable_manager.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/browser/installable/installable_manager.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/callback.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
@@ -130,6 +133,19 @@
          params.valid_primary_icon;
 }
 
+void OnDidCompleteGetAllErrors(
+    base::OnceCallback<void(std::vector<std::string> errors)> callback,
+    const InstallableData& data) {
+  std::vector<std::string> error_messages;
+  for (auto error : data.errors) {
+    std::string message = GetErrorMessage(error);
+    if (!message.empty())
+      error_messages.push_back(std::move(message));
+  }
+
+  std::move(callback).Run(std::move(error_messages));
+}
+
 }  // namespace
 
 InstallableManager::EligiblityProperty::EligiblityProperty() = default;
@@ -185,7 +201,7 @@
 }
 
 void InstallableManager::GetData(const InstallableParams& params,
-                                 const InstallableCallback& callback) {
+                                 InstallableCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (IsParamsForPwaCheck(params))
@@ -194,7 +210,7 @@
   // Return immediately if we're already working on a task. The new task will be
   // looked at once the current task is finished.
   bool was_active = task_queue_.HasCurrent();
-  task_queue_.Add({params, callback});
+  task_queue_.Add({params, std::move(callback)});
   if (was_active)
     return;
 
@@ -202,6 +218,20 @@
   WorkOnTask();
 }
 
+void InstallableManager::GetAllErrors(
+    base::OnceCallback<void(std::vector<std::string> errors)> callback) {
+  InstallableParams params;
+  params.check_eligibility = true;
+  params.valid_manifest = true;
+  params.check_webapp_manifest_display = true;
+  params.has_worker = true;
+  params.valid_primary_icon = true;
+  params.wait_for_worker = false;
+  params.is_debug_mode = true;
+  GetData(params,
+          base::BindOnce(OnDidCompleteGetAllErrors, std::move(callback)));
+}
+
 void InstallableManager::RecordMenuOpenHistogram() {
   metrics_->RecordMenuOpen();
 }
@@ -406,7 +436,7 @@
 }
 
 void InstallableManager::RunCallback(
-    const InstallableTask& task,
+    InstallableTask task,
     std::vector<InstallableStatusCode> errors) {
   const InstallableParams& params = task.params;
   IconProperty null_icon;
@@ -429,18 +459,21 @@
       worker_->has_worker,
   };
 
-  task.callback.Run(data);
+  std::move(task.callback).Run(data);
 }
 
 void InstallableManager::WorkOnTask() {
-  const InstallableTask& task = task_queue_.Current();
-  const InstallableParams& params = task.params;
+  if (!task_queue_.HasCurrent())
+    return;
+
+  const InstallableParams& params = task_queue_.Current().params;
 
   auto errors = GetErrors(params);
   bool check_passed = errors.empty();
   if ((!check_passed && !params.is_debug_mode) || IsComplete(params)) {
+    auto task = std::move(task_queue_.Current());
     ResolveMetrics(params, check_passed);
-    RunCallback(task, std::move(errors));
+    RunCallback(std::move(task), std::move(errors));
 
     // Sites can always register a service worker after we finish checking, so
     // don't cache a missing service worker error to ensure we always check
@@ -449,10 +482,7 @@
       worker_ = std::make_unique<ServiceWorkerProperty>();
 
     task_queue_.Next();
-
-    if (task_queue_.HasCurrent())
-      WorkOnTask();
-
+    WorkOnTask();
     return;
   }
 
@@ -504,8 +534,8 @@
   content::WebContents* web_contents = GetWebContents();
   DCHECK(web_contents);
 
-  web_contents->GetManifest(base::Bind(&InstallableManager::OnDidGetManifest,
-                                       weak_factory_.GetWeakPtr()));
+  web_contents->GetManifest(base::BindOnce(
+      &InstallableManager::OnDidGetManifest, weak_factory_.GetWeakPtr()));
 }
 
 void InstallableManager::OnDidGetManifest(const GURL& manifest_url,
@@ -589,8 +619,8 @@
   // Check to see if there is a service worker for the manifest's start url.
   service_worker_context_->CheckHasServiceWorker(
       manifest().start_url,
-      base::Bind(&InstallableManager::OnDidCheckHasServiceWorker,
-                 weak_factory_.GetWeakPtr()));
+      base::BindOnce(&InstallableManager::OnDidCheckHasServiceWorker,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void InstallableManager::OnDidCheckHasServiceWorker(
@@ -614,9 +644,7 @@
         task.params.wait_for_worker = false;
         OnWaitingForServiceWorker();
         task_queue_.PauseCurrent();
-        if (task_queue_.HasCurrent())
-          WorkOnTask();
-
+        WorkOnTask();
         return;
       }
       worker_->has_worker = false;
@@ -659,11 +687,10 @@
 void InstallableManager::OnIconFetched(const GURL icon_url,
                                        const IconPurpose purpose,
                                        const SkBitmap& bitmap) {
-  IconProperty& icon = icons_[purpose];
-
   if (!GetWebContents())
     return;
 
+  IconProperty& icon = icons_[purpose];
   if (bitmap.drawsNothing()) {
     icon.error = NO_ICON_AVAILABLE;
   } else {
@@ -694,8 +721,7 @@
   if (was_active)
     return;  // If the pipeline was already running, we don't restart it.
 
-  if (task_queue_.HasCurrent())
-    WorkOnTask();
+  WorkOnTask();
 }
 
 void InstallableManager::DidFinishNavigation(
diff --git a/chrome/browser/installable/installable_manager.h b/chrome/browser/installable/installable_manager.h
index 5995a75..9b6716a8 100644
--- a/chrome/browser/installable/installable_manager.h
+++ b/chrome/browser/installable/installable_manager.h
@@ -7,9 +7,9 @@
 
 #include <map>
 #include <memory>
-#include <utility>
 #include <vector>
 
+#include "base/callback_forward.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -40,18 +40,23 @@
   static int GetMinimumIconSizeInPx();
 
   // Get the installable data, fetching the resources specified in |params|.
-  // |callback| is invoked synchronously (i.e. no via PostTask on the UI thread
+  // |callback| is invoked synchronously (i.e. not via PostTask on the UI thread
   // when the data is ready; the synchronous execution ensures that the
   // references |callback| receives in its InstallableData argument are valid.
   //
-  // Clients must be prepared for |callback| to not ever be invoked. For
-  // instance, if installability checking is requested, this method will wait
-  // until the site registers a service worker (and hence not invoke |callback|
-  // at all if a service worker is never registered).
+  // |callback| may never be invoked if |params.wait_for_worker| is true, or if
+  // the user navigates the page before fetching is complete.
   //
-  // Calls requesting data that is already fetched will return the cached data.
+  // Calls requesting data that has already been fetched will return the cached
+  // data.
   virtual void GetData(const InstallableParams& params,
-                       const InstallableCallback& callback);
+                       InstallableCallback callback);
+
+  // Runs the full installability check, and when finished, runs |callback|
+  // passing a list of human-readable strings describing the errors encountered
+  // during the run. The list is empty if no errors were encountered.
+  void GetAllErrors(
+      base::OnceCallback<void(std::vector<std::string> errors)> callback);
 
   // Called via AppBannerManagerAndroid to record metrics on how often the
   // installable check is completed when the menu or add to homescreen menu item
@@ -183,7 +188,7 @@
   void SetManifestDependentTasksComplete();
 
   // Methods coordinating and dispatching work for the current task.
-  void RunCallback(const InstallableTask& task,
+  void RunCallback(InstallableTask task,
                    std::vector<InstallableStatusCode> errors);
   void WorkOnTask();
 
diff --git a/chrome/browser/installable/installable_manager_browsertest.cc b/chrome/browser/installable/installable_manager_browsertest.cc
index 80c42fd5..53725cf 100644
--- a/chrome/browser/installable/installable_manager_browsertest.cc
+++ b/chrome/browser/installable/installable_manager_browsertest.cc
@@ -8,8 +8,10 @@
 #include "base/command_line.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/banners/app_banner_manager_desktop.h"
+#include "chrome/browser/installable/installable_logging.h"
 #include "chrome/browser/installable/installable_manager.h"
 #include "chrome/browser/installable/installable_metrics.h"
 #include "chrome/browser/ui/browser.h"
@@ -129,7 +131,7 @@
     quit_closure_.Run();
   }
 
-  const std::vector<InstallableStatusCode> errors() const { return errors_; }
+  const std::vector<InstallableStatusCode>& errors() const { return errors_; }
   const GURL& manifest_url() const { return manifest_url_; }
   const blink::Manifest& manifest() const { return manifest_; }
   const GURL& primary_icon_url() const { return primary_icon_url_; }
@@ -162,9 +164,9 @@
       : manager_(manager), params_(params), quit_closure_(quit_closure) {}
 
   void Run() {
-    manager_->GetData(params_,
-                      base::Bind(&NestedCallbackTester::OnDidFinishFirstCheck,
-                                 base::Unretained(this)));
+    manager_->GetData(
+        params_, base::BindOnce(&NestedCallbackTester::OnDidFinishFirstCheck,
+                                base::Unretained(this)));
   }
 
   void OnDidFinishFirstCheck(const InstallableData& data) {
@@ -177,9 +179,9 @@
     valid_manifest_ = data.valid_manifest;
     has_worker_ = data.has_worker;
 
-    manager_->GetData(params_,
-                      base::Bind(&NestedCallbackTester::OnDidFinishSecondCheck,
-                                 base::Unretained(this)));
+    manager_->GetData(
+        params_, base::BindOnce(&NestedCallbackTester::OnDidFinishSecondCheck,
+                                base::Unretained(this)));
   }
 
   void OnDidFinishSecondCheck(const InstallableData& data) {
@@ -238,13 +240,31 @@
     RunInstallableManager(browser, tester, params);
   }
 
+  std::vector<std::string> NavigateAndGetAllErrors(Browser* browser,
+                                                   const std::string& url) {
+    GURL test_url = embedded_test_server()->GetURL(url);
+    ui_test_utils::NavigateToURL(browser, test_url);
+    InstallableManager* manager = GetManager(browser);
+
+    base::RunLoop run_loop;
+    std::vector<std::string> result;
+
+    manager->GetAllErrors(
+        base::BindLambdaForTesting([&](std::vector<std::string> errors) {
+          result = std::move(errors);
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+    return result;
+  }
+
   void RunInstallableManager(Browser* browser,
                              CallbackTester* tester,
                              const InstallableParams& params) {
     InstallableManager* manager = GetManager(browser);
-    manager->GetData(params,
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(tester)));
+    manager->GetData(
+        params, base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                               base::Unretained(tester)));
   }
 
   InstallableManager* GetManager(Browser* browser) {
@@ -949,9 +969,10 @@
 
     // Set up a GetData call which will not record an installable metric to
     // ensure we wait until the previous check has finished.
-    manager->GetData(GetManifestParams(),
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(tester.get())));
+    manager->GetData(
+        GetManifestParams(),
+        base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                       base::Unretained(tester.get())));
     run_loop.Run();
 
     ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
@@ -980,9 +1001,10 @@
 
     // Set up a GetData call which will not record an installable metric to
     // ensure we wait until the previous check has finished.
-    manager->GetData(GetManifestParams(),
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(tester.get())));
+    manager->GetData(
+        GetManifestParams(),
+        base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                       base::Unretained(tester.get())));
     run_loop.Run();
 
     ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
@@ -1085,9 +1107,10 @@
     ui_test_utils::NavigateToURL(browser(), test_url);
 
     // Kick off fetching the data. This should block on waiting for a worker.
-    manager->GetData(GetWebAppParams(),
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(tester.get())));
+    manager->GetData(
+        GetWebAppParams(),
+        base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                       base::Unretained(tester.get())));
     sw_run_loop.Run();
   }
 
@@ -1113,9 +1136,10 @@
     base::RunLoop run_loop;
     std::unique_ptr<CallbackTester> nested_tester(
         new CallbackTester(run_loop.QuitClosure()));
-    manager->GetData(GetPrimaryIconParams(),
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(nested_tester.get())));
+    manager->GetData(
+        GetPrimaryIconParams(),
+        base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                       base::Unretained(nested_tester.get())));
     run_loop.Run();
 
     EXPECT_FALSE(nested_tester->manifest().IsEmpty());
@@ -1179,8 +1203,8 @@
 
   // Kick off fetching the data. This should block on waiting for a worker.
   manager->GetData(GetWebAppParams(),
-                   base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                              base::Unretained(tester.get())));
+                   base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                                  base::Unretained(tester.get())));
   sw_run_loop.Run();
 
   // We should now be waiting for the service worker.
@@ -1228,9 +1252,10 @@
     ui_test_utils::NavigateToURL(browser(), test_url);
 
     // Kick off fetching the data. This should block on waiting for a worker.
-    manager->GetData(GetWebAppParams(),
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(tester.get())));
+    manager->GetData(
+        GetWebAppParams(),
+        base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                       base::Unretained(tester.get())));
     sw_run_loop.Run();
   }
 
@@ -1284,9 +1309,9 @@
 
     InstallableParams params = GetWebAppParams();
     params.wait_for_worker = false;
-    manager->GetData(params,
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(tester.get())));
+    manager->GetData(
+        params, base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                               base::Unretained(tester.get())));
     tester_run_loop.Run();
 
     // We should have returned with an error.
@@ -1303,9 +1328,9 @@
         new CallbackTester(tester_run_loop.QuitClosure()));
 
     InstallableParams params = GetWebAppParams();
-    manager->GetData(params,
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(tester.get())));
+    manager->GetData(
+        params, base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                               base::Unretained(tester.get())));
     sw_run_loop.Run();
 
     EXPECT_TRUE(content::ExecuteScript(
@@ -1495,9 +1520,10 @@
     std::unique_ptr<CallbackTester> tester(
         new CallbackTester(run_loop.QuitClosure()));
 
-    manager->GetData(GetWebAppParams(),
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(tester.get())));
+    manager->GetData(
+        GetWebAppParams(),
+        base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                       base::Unretained(tester.get())));
     run_loop.Run();
 
     EXPECT_TRUE(tester->manifest().IsEmpty());
@@ -1523,9 +1549,10 @@
     std::unique_ptr<CallbackTester> tester(
         new CallbackTester(run_loop.QuitClosure()));
 
-    manager->GetData(GetWebAppParams(),
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(tester.get())));
+    manager->GetData(
+        GetWebAppParams(),
+        base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                       base::Unretained(tester.get())));
     run_loop.Run();
 
     EXPECT_FALSE(tester->manifest().IsEmpty());
@@ -1555,9 +1582,10 @@
     std::unique_ptr<CallbackTester> tester(
         new CallbackTester(run_loop.QuitClosure()));
 
-    manager->GetData(GetWebAppParams(),
-                     base::Bind(&CallbackTester::OnDidFinishInstallableCheck,
-                                base::Unretained(tester.get())));
+    manager->GetData(
+        GetWebAppParams(),
+        base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
+                       base::Unretained(tester.get())));
     run_loop.Run();
 
     EXPECT_FALSE(tester->manifest().IsEmpty());
@@ -1606,6 +1634,33 @@
             tester->errors());
 }
 
+IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, GetAllErrorsNoErrors) {
+  EXPECT_EQ(
+      std::vector<std::string>{},
+      NavigateAndGetAllErrors(browser(), "/banners/manifest_test_page.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
+                       GetAllErrorsWithNoManifest) {
+  EXPECT_EQ(std::vector<std::string>{GetErrorMessage(NO_MANIFEST)},
+            NavigateAndGetAllErrors(browser(),
+                                    "/banners/no_manifest_test_page.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
+                       GetAllErrorsWithPlayAppManifest) {
+  EXPECT_EQ(std::vector<std::string>(
+                {GetErrorMessage(START_URL_NOT_VALID),
+                 GetErrorMessage(MANIFEST_MISSING_NAME_OR_SHORT_NAME),
+                 GetErrorMessage(MANIFEST_DISPLAY_NOT_SUPPORTED),
+                 GetErrorMessage(MANIFEST_MISSING_SUITABLE_ICON),
+                 GetErrorMessage(NO_URL_FOR_SERVICE_WORKER),
+                 GetErrorMessage(NO_ACCEPTABLE_ICON)}),
+            NavigateAndGetAllErrors(browser(),
+                                    GetURLOfPageWithServiceWorkerAndManifest(
+                                        "/banners/play_app_manifest.json")));
+}
+
 IN_PROC_BROWSER_TEST_F(InstallableManagerWhitelistOriginBrowserTest,
                        SecureOriginCheckRespectsUnsafeFlag) {
   // The whitelisted origin should be regarded as secure.
diff --git a/chrome/browser/installable/installable_task_queue.cc b/chrome/browser/installable/installable_task_queue.cc
index 6672db3..0151c8757 100644
--- a/chrome/browser/installable/installable_task_queue.cc
+++ b/chrome/browser/installable/installable_task_queue.cc
@@ -2,34 +2,41 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "chrome/browser/installable/installable_task_queue.h"
 
-InstallableTask::InstallableTask() {}
-InstallableTask::InstallableTask(const InstallableParams& params,
-                                 const InstallableCallback& callback)
-    : params(params), callback(callback) {}
-InstallableTask::~InstallableTask() {}
-InstallableTask::InstallableTask(const InstallableTask& other) = default;
-InstallableTask& InstallableTask::operator=(const InstallableTask& other) =
-    default;
+InstallableTask::InstallableTask() = default;
 
-InstallableTaskQueue::InstallableTaskQueue() {}
-InstallableTaskQueue::~InstallableTaskQueue() {}
+InstallableTask::InstallableTask(const InstallableParams& params,
+                                 InstallableCallback callback)
+    : params(params), callback(std::move(callback)) {}
+
+InstallableTask::~InstallableTask() = default;
+
+InstallableTask::InstallableTask(InstallableTask&& other) = default;
+
+InstallableTask& InstallableTask::operator=(InstallableTask&& other) = default;
+
+InstallableTaskQueue::InstallableTaskQueue() = default;
+
+InstallableTaskQueue::~InstallableTaskQueue() = default;
 
 void InstallableTaskQueue::Add(InstallableTask task) {
-  tasks_.push_back(task);
+  tasks_.push_back(std::move(task));
 }
 
 void InstallableTaskQueue::PauseCurrent() {
-  paused_tasks_.push_back(Current());
+  DCHECK(HasCurrent());
+  paused_tasks_.push_back(std::move(Current()));
   Next();
 }
 
 void InstallableTaskQueue::UnpauseAll() {
-  for (const auto& task : paused_tasks_)
-    Add(task);
-
-  paused_tasks_.clear();
+  while (!paused_tasks_.empty()) {
+    Add(std::move(paused_tasks_.front()));
+    paused_tasks_.pop_front();
+  }
 }
 
 bool InstallableTaskQueue::HasCurrent() const {
@@ -41,13 +48,13 @@
 }
 
 InstallableTask& InstallableTaskQueue::Current() {
-  DCHECK(!tasks_.empty());
-  return tasks_[0];
+  DCHECK(HasCurrent());
+  return tasks_.front();
 }
 
 void InstallableTaskQueue::Next() {
-  DCHECK(!tasks_.empty());
-  tasks_.erase(tasks_.begin());
+  DCHECK(HasCurrent());
+  tasks_.pop_front();
 }
 
 void InstallableTaskQueue::Reset() {
diff --git a/chrome/browser/installable/installable_task_queue.h b/chrome/browser/installable/installable_task_queue.h
index 4f4ca9f..2a8b4e5 100644
--- a/chrome/browser/installable/installable_task_queue.h
+++ b/chrome/browser/installable/installable_task_queue.h
@@ -5,23 +5,27 @@
 #ifndef CHROME_BROWSER_INSTALLABLE_INSTALLABLE_TASK_QUEUE_H_
 #define CHROME_BROWSER_INSTALLABLE_INSTALLABLE_TASK_QUEUE_H_
 
-#include "chrome/browser/installable/installable_data.h"
-#include "chrome/browser/installable/installable_params.h"
+#include <deque>
 
 #include "base/callback.h"
 #include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "chrome/browser/installable/installable_data.h"
+#include "chrome/browser/installable/installable_params.h"
 
 struct InstallableTask {
   InstallableTask();
   InstallableTask(const InstallableParams& params,
-                  const InstallableCallback& callback);
-  InstallableTask(const InstallableTask& other);
+                  InstallableCallback callback);
+  InstallableTask(InstallableTask&& other);
   ~InstallableTask();
 
-  InstallableTask& operator=(const InstallableTask& other);
+  InstallableTask& operator=(InstallableTask&& other);
 
   InstallableParams params;
   InstallableCallback callback;
+
+  DISALLOW_COPY_AND_ASSIGN(InstallableTask);
 };
 
 // InstallableTaskQueue keeps track of pending tasks.
@@ -55,19 +59,19 @@
   void Reset();
 
  private:
-  // The list of <params, callback> pairs that have come from a call to
-  // InstallableManager::GetData.
-  std::vector<InstallableTask> tasks_;
-
-  // Tasks which are waiting indefinitely for a service worker to be detected.
-  std::vector<InstallableTask> paused_tasks_;
-
   friend class InstallableManagerBrowserTest;
   FRIEND_TEST_ALL_PREFIXES(InstallableManagerBrowserTest,
                            CheckLazyServiceWorkerPassesWhenWaiting);
 
   FRIEND_TEST_ALL_PREFIXES(InstallableManagerBrowserTest,
                            CheckLazyServiceWorkerNoFetchHandlerFails);
+
+  // The list of <params, callback> pairs that have come from a call to
+  // InstallableManager::GetData.
+  std::deque<InstallableTask> tasks_;
+
+  // Tasks which are waiting indefinitely for a service worker to be detected.
+  std::deque<InstallableTask> paused_tasks_;
 };
 
 #endif  // CHROME_BROWSER_INSTALLABLE_INSTALLABLE_TASK_QUEUE_H_
diff --git a/chrome/browser/installable/installable_task_queue_unittest.cc b/chrome/browser/installable/installable_task_queue_unittest.cc
index a9ecf0c..710c0c7b 100644
--- a/chrome/browser/installable/installable_task_queue_unittest.cc
+++ b/chrome/browser/installable/installable_task_queue_unittest.cc
@@ -1,73 +1,101 @@
 // 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.
-#include "chrome/browser/installable/installable_manager.h"
 
+#include "chrome/browser/installable/installable_task_queue.h"
+
+#include "chrome/browser/installable/installable_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using IconPurpose = blink::Manifest::ImageResource::Purpose;
-
-class InstallableTaskQueueUnitTest : public testing::Test {};
+// A POD struct which holds booleans for creating and comparing against
+// a (move-only) InstallableTask.
+struct TaskParams {
+  bool valid_manifest = false;
+  bool has_worker = false;
+  bool valid_primary_icon = false;
+  bool valid_badge_icon = false;
+};
 
 // Constructs an InstallableTask, with the supplied bools stored in it.
-InstallableTask CreateTask(bool valid_manifest,
-                           bool has_worker,
-                           bool valid_primary_icon,
-                           bool valid_badge_icon) {
+InstallableTask CreateTask(const TaskParams& params) {
   InstallableTask task;
-  task.params.valid_manifest = valid_manifest;
-  task.params.has_worker = has_worker;
-  task.params.valid_primary_icon = valid_primary_icon;
-  task.params.valid_badge_icon = valid_badge_icon;
+  task.params.valid_manifest = params.valid_manifest;
+  task.params.has_worker = params.has_worker;
+  task.params.valid_primary_icon = params.valid_primary_icon;
+  task.params.valid_badge_icon = params.valid_badge_icon;
   return task;
 }
 
-bool IsEqual(const InstallableTask& task1, const InstallableTask& task2) {
-  return task1.params.valid_manifest == task2.params.valid_manifest &&
-         task1.params.has_worker == task2.params.has_worker &&
-         task1.params.valid_primary_icon == task2.params.valid_primary_icon &&
-         task1.params.valid_badge_icon == task2.params.valid_badge_icon;
+bool IsEqual(const TaskParams& params, const InstallableTask& task) {
+  return task.params.valid_manifest == params.valid_manifest &&
+         task.params.has_worker == params.has_worker &&
+         task.params.valid_primary_icon == params.valid_primary_icon &&
+         task.params.valid_badge_icon == params.valid_badge_icon;
 }
 
+class InstallableTaskQueueUnitTest : public testing::Test {};
+
 TEST_F(InstallableTaskQueueUnitTest, PausingMakesNextTaskAvailable) {
   InstallableTaskQueue task_queue;
-  InstallableTask task1 = CreateTask(false, false, false, false);
-  InstallableTask task2 = CreateTask(true, true, true, true);
+  TaskParams task1 = {false, false, false, false};
+  TaskParams task2 = {true, true, true, true};
 
-  task_queue.Add(task1);
-  task_queue.Add(task2);
+  EXPECT_FALSE(task_queue.HasCurrent());
+  EXPECT_FALSE(task_queue.HasPaused());
 
+  task_queue.Add(CreateTask(task1));
+  task_queue.Add(CreateTask(task2));
+
+  EXPECT_TRUE(task_queue.HasCurrent());
+  EXPECT_FALSE(task_queue.HasPaused());
   EXPECT_TRUE(IsEqual(task1, task_queue.Current()));
+
   // There is another task in the main queue, so it becomes current.
   task_queue.PauseCurrent();
+  EXPECT_TRUE(task_queue.HasCurrent());
+  EXPECT_TRUE(task_queue.HasPaused());
   EXPECT_TRUE(IsEqual(task2, task_queue.Current()));
+
+  task_queue.Reset();
+  EXPECT_FALSE(task_queue.HasCurrent());
+  EXPECT_FALSE(task_queue.HasPaused());
 }
 
 TEST_F(InstallableTaskQueueUnitTest, PausedTaskCanBeRetrieved) {
   InstallableTaskQueue task_queue;
-  InstallableTask task1 = CreateTask(false, false, false, false);
-  InstallableTask task2 = CreateTask(true, true, true, true);
+  TaskParams task1 = {false, false, false, false};
+  TaskParams task2 = {true, true, true, true};
 
-  task_queue.Add(task1);
-  task_queue.Add(task2);
+  task_queue.Add(CreateTask(task1));
+  task_queue.Add(CreateTask(task2));
 
   EXPECT_TRUE(IsEqual(task1, task_queue.Current()));
   task_queue.PauseCurrent();
+  EXPECT_TRUE(task_queue.HasCurrent());
+  EXPECT_TRUE(task_queue.HasPaused());
   EXPECT_TRUE(IsEqual(task2, task_queue.Current()));
   task_queue.UnpauseAll();
+
   // We've unpaused "1", but "2" is still current.
+  EXPECT_TRUE(task_queue.HasCurrent());
+  EXPECT_FALSE(task_queue.HasPaused());
   EXPECT_TRUE(IsEqual(task2, task_queue.Current()));
   task_queue.Next();
+  EXPECT_TRUE(task_queue.HasCurrent());
   EXPECT_TRUE(IsEqual(task1, task_queue.Current()));
+
+  task_queue.Reset();
+  EXPECT_FALSE(task_queue.HasCurrent());
+  EXPECT_FALSE(task_queue.HasPaused());
 }
 
 TEST_F(InstallableTaskQueueUnitTest, NextDiscardsTask) {
   InstallableTaskQueue task_queue;
-  InstallableTask task1 = CreateTask(false, false, false, false);
-  InstallableTask task2 = CreateTask(true, true, true, true);
+  TaskParams task1 = {false, false, false, false};
+  TaskParams task2 = {true, true, true, true};
 
-  task_queue.Add(task1);
-  task_queue.Add(task2);
+  task_queue.Add(CreateTask(task1));
+  task_queue.Add(CreateTask(task2));
 
   EXPECT_TRUE(IsEqual(task1, task_queue.Current()));
   task_queue.Next();
diff --git a/chrome/browser/metrics/google_update_metrics_provider_win.cc b/chrome/browser/metrics/google_update_metrics_provider_win.cc
index f19ff2a8..e1cb5c3 100644
--- a/chrome/browser/metrics/google_update_metrics_provider_win.cc
+++ b/chrome/browser/metrics/google_update_metrics_provider_win.cc
@@ -5,9 +5,13 @@
 #include "chrome/browser/metrics/google_update_metrics_provider_win.h"
 
 #include "base/location.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/metrics_hashes.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "chrome/install_static/install_details.h"
 #include "third_party/metrics_proto/system_profile.pb.h"
 
 typedef metrics::SystemProfileProto::GoogleUpdate::ProductInfo ProductInfo;
@@ -17,7 +21,7 @@
 // Helper function for checking if this is an official build. Used instead of
 // the macro to allow checking for successful code compilation on non-official
 // builds.
-bool IsOfficialBuild() {
+bool IsGoogleChromeBuild() {
 #if defined(GOOGLE_CHROME_BUILD)
   return true;
 #else
@@ -49,7 +53,7 @@
 
 void GoogleUpdateMetricsProviderWin::AsyncInit(
     const base::Closure& done_callback) {
-  if (!IsOfficialBuild()) {
+  if (!IsGoogleChromeBuild()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, done_callback);
     return;
   }
@@ -65,9 +69,16 @@
 
 void GoogleUpdateMetricsProviderWin::ProvideSystemProfileMetrics(
     metrics::SystemProfileProto* system_profile_proto) {
-  if (!IsOfficialBuild())
+  // Do nothing for chromium builds.
+  if (!IsGoogleChromeBuild())
     return;
-
+  // Convert wstring to string.
+  std::string update_cohort_name = base::WideToUTF8(
+      install_static::InstallDetails::Get().update_cohort_name());
+  // TODO(nikunjb): Once update_cohort_name is added to system profile
+  // update the code here.
+  base::UmaHistogramSparse("GoogleUpdate.InstallDetails.UpdateCohort",
+                           base::HashMetricName(update_cohort_name));
   metrics::SystemProfileProto::GoogleUpdate* google_update =
       system_profile_proto->mutable_google_update();
 
@@ -107,7 +118,7 @@
 GoogleUpdateMetricsProviderWin::GetGoogleUpdateDataBlocking() {
   GoogleUpdateMetrics google_update_metrics;
 
-  if (!IsOfficialBuild())
+  if (!IsGoogleChromeBuild())
     return google_update_metrics;
 
   const bool is_system_install = GoogleUpdateSettings::IsSystemInstall();
diff --git a/chrome/browser/metrics/tab_stats_tracker.cc b/chrome/browser/metrics/tab_stats_tracker.cc
index 87334be..fc5ec1a 100644
--- a/chrome/browser/metrics/tab_stats_tracker.cc
+++ b/chrome/browser/metrics/tab_stats_tracker.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/power_monitor/power_monitor.h"
+#include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit.h"
@@ -115,6 +116,17 @@
     "Discarding.ReloadsPer10Minutes.Urgent",
 };
 
+static_assert(base::size(kTabDiscardCountHistogramNames) ==
+                  static_cast<size_t>(LifecycleUnitDiscardReason::kMaxValue) +
+                      1,
+              "There must be an entry in kTabDiscardCountHistogramNames for "
+              "each discard reason.");
+static_assert(base::size(kTabReloadCountHistogramNames) ==
+                  static_cast<size_t>(LifecycleUnitDiscardReason::kMaxValue) +
+                      1,
+              "There must be an entry in kTabReloadCountHistogramNames for "
+              "each discard reason.");
+
 const TabStatsDataStore::TabsStats& TabStatsTracker::tab_stats() const {
   return tab_stats_data_store_->tab_stats();
 }
@@ -353,7 +365,7 @@
 
 void TabStatsTracker::OnTabDiscardCountReportInterval() {
   for (size_t reason = 0;
-       reason < static_cast<size_t>(LifecycleUnitDiscardReason::kMaxValue);
+       reason < static_cast<size_t>(LifecycleUnitDiscardReason::kMaxValue) + 1;
        reason++) {
     base::UmaHistogramCounts100(
         kTabDiscardCountHistogramNames[reason],
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
index be00203..2cb825db 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -14,8 +14,10 @@
 #include "base/time/default_tick_clock.h"
 #include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
+#include "chrome/browser/page_load_metrics/resource_tracker.h"
 #include "components/subresource_filter/core/common/common_features.h"
 #include "components/ukm/content/source_url_recorder.h"
+#include "content/public/browser/global_request_id.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -132,7 +134,7 @@
 
   // The main frame is never considered an ad.
   ad_frames_data_[navigation_handle->GetFrameTreeNodeId()] = nullptr;
-  ProcessOngoingNavigationResource(navigation_handle->GetFrameTreeNodeId());
+  ProcessOngoingNavigationResource(navigation_handle->GetRenderFrameHost());
   return CONTINUE_OBSERVING;
 }
 
@@ -177,7 +179,7 @@
   if (id_and_data != ad_frames_data_.end() && id_and_data->second) {
     DCHECK(frame_navigated);
     if (id_and_data->second->frame_navigated()) {
-      ProcessOngoingNavigationResource(ad_id);
+      ProcessOngoingNavigationResource(ad_host);
       return;
     }
     previous_data = id_and_data->second;
@@ -269,7 +271,7 @@
 
   RecordAdFrameData(frame_tree_node_id, is_adframe, ad_host,
                     /*frame_navigated=*/true);
-  ProcessOngoingNavigationResource(frame_tree_node_id);
+  ProcessOngoingNavigationResource(ad_host);
 }
 
 void AdsPageLoadMetricsObserver::FrameReceivedFirstUserActivation(
@@ -332,8 +334,11 @@
     content::RenderFrameHost* rfh,
     const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
         resources) {
-  for (auto const& resource : resources)
-    UpdateResource(rfh, resource);
+  for (auto const& resource : resources) {
+    ProcessResourceForPage(rfh->GetProcess()->GetID(), resource);
+    ProcessResourceForFrame(rfh->GetFrameTreeNodeId(),
+                            rfh->GetProcess()->GetID(), resource);
+  }
 }
 
 void AdsPageLoadMetricsObserver::OnSubframeNavigationEvaluated(
@@ -435,13 +440,56 @@
   return DetectSubresourceFilterAd(navigation_handle->GetFrameTreeNodeId());
 }
 
+int AdsPageLoadMetricsObserver::GetUnaccountedAdBytes(
+    int process_id,
+    const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) const {
+  if (!resource->reported_as_ad_resource)
+    return 0;
+  content::GlobalRequestID global_request_id(process_id, resource->request_id);
+
+  // Resource just started loading.
+  if (!GetDelegate()->GetResourceTracker().HasPreviousUpdateForResource(
+          global_request_id))
+    return 0;
+
+  // If the resource had already started loading, and is now labeled as an ad,
+  // but was not before, we need to account for all the previously received
+  // bytes.
+  auto const& previous_update =
+      GetDelegate()->GetResourceTracker().GetPreviousUpdateForResource(
+          global_request_id);
+  bool is_new_ad = !previous_update->reported_as_ad_resource;
+  return is_new_ad ? resource->received_data_length - resource->delta_bytes : 0;
+}
+
+void AdsPageLoadMetricsObserver::ProcessResourceForPage(
+    int process_id,
+    const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
+  // Log per-resource histograms for complete resources.
+  if (resource->is_complete)
+    RecordResourceHistograms(resource);
+
+  auto mime_type = FrameData::GetResourceMimeType(resource);
+  int unaccounted_ad_bytes = GetUnaccountedAdBytes(process_id, resource);
+  aggregate_frame_data_->ProcessResourceLoadInFrame(resource);
+  if (unaccounted_ad_bytes)
+    aggregate_frame_data_->AdjustAdBytes(unaccounted_ad_bytes, mime_type);
+  if (resource->is_main_frame_resource) {
+    main_frame_data_->ProcessResourceLoadInFrame(resource);
+    if (unaccounted_ad_bytes)
+      main_frame_data_->AdjustAdBytes(unaccounted_ad_bytes, mime_type);
+  }
+}
+
 void AdsPageLoadMetricsObserver::ProcessResourceForFrame(
     FrameTreeNodeId frame_tree_node_id,
+    int process_id,
     const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
   const auto& id_and_data = ad_frames_data_.find(frame_tree_node_id);
   if (id_and_data == ad_frames_data_.end()) {
     if (resource->is_primary_frame_resource) {
-      // Only hold onto primary resources if their load has finished.
+      // Only hold onto primary resources if their load has finished, otherwise
+      // we will receive a future update for them if the navigation finishes.
       if (!resource->is_complete)
         return;
 
@@ -461,16 +509,17 @@
     return;
   }
 
-  aggregate_frame_data_->ProcessResourceLoadInFrame(resource);
-  if (resource->is_main_frame_resource)
-    main_frame_data_->ProcessResourceLoadInFrame(resource);
-
   // Determine if the frame (or its ancestor) is an ad, if so attribute the
   // bytes to the highest ad ancestor.
   FrameData* ancestor_data = id_and_data->second;
   if (!ancestor_data)
     return;
+
+  auto mime_type = FrameData::GetResourceMimeType(resource);
+  int unaccounted_ad_bytes = GetUnaccountedAdBytes(process_id, resource);
   ancestor_data->ProcessResourceLoadInFrame(resource);
+  if (unaccounted_ad_bytes)
+    ancestor_data->AdjustAdBytes(unaccounted_ad_bytes, mime_type);
 
   if (ancestor_data->size_intervention_status() ==
       FrameData::FrameSizeInterventionStatus::kTriggered) {
@@ -480,57 +529,6 @@
   }
 }
 
-void AdsPageLoadMetricsObserver::AdjustAdBytesForFrame(
-    FrameTreeNodeId frame_tree_node_id,
-    const page_load_metrics::mojom::ResourceDataUpdatePtr& resource,
-    int64_t unaccounted_ad_bytes) {
-  const auto& id_and_data = ad_frames_data_.find(frame_tree_node_id);
-  FrameData* ancestor_data = id_and_data->second;
-  if (!ancestor_data)
-    return;
-  ancestor_data->AdjustAdBytes(unaccounted_ad_bytes,
-                               FrameData::GetResourceMimeType(resource));
-}
-
-void AdsPageLoadMetricsObserver::UpdateResource(
-    content::RenderFrameHost* rfh,
-    const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
-  content::GlobalRequestID global_id(rfh->GetProcess()->GetID(),
-                                     resource->request_id);
-  ProcessResourceForFrame(rfh->GetFrameTreeNodeId(), resource);
-  auto it = page_resources_.find(global_id);
-
-  if (resource->reported_as_ad_resource) {
-    // If the resource had already started loading, and is now labeled as an ad,
-    // but was not before, we need to account for all the previously received
-    // bytes.
-    bool is_new_ad =
-        (it != page_resources_.end()) && !it->second->reported_as_ad_resource;
-    int unaccounted_ad_bytes =
-        is_new_ad ? resource->received_data_length - resource->delta_bytes : 0;
-    if (unaccounted_ad_bytes)
-      AdjustAdBytesForFrame(rfh->GetFrameTreeNodeId(), resource,
-                            unaccounted_ad_bytes);
-  }
-
-  // Update resource map.
-  if (resource->is_complete) {
-    RecordResourceHistograms(resource);
-    if (it != page_resources_.end())
-      page_resources_.erase(it);
-  } else {
-    // Must clone resource so it will be accessible when the observer is
-    // destroyed.
-    if (it != page_resources_.end()) {
-      it->second = resource->Clone();
-    } else {
-      page_resources_.emplace(std::piecewise_construct,
-                              std::forward_as_tuple(global_id),
-                              std::forward_as_tuple(resource->Clone()));
-    }
-  }
-}
-
 void AdsPageLoadMetricsObserver::RecordResourceMimeHistograms(
     const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
   int64_t data_length = resource->was_fetched_via_cache
@@ -590,11 +588,11 @@
   PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Resources.Bytes.Ads",
                        aggregate_frame_data_->ad_bytes());
   size_t unfinished_bytes = 0;
-  for (auto const& kv : page_resources_)
+  for (auto const& kv :
+       GetDelegate()->GetResourceTracker().unfinished_resources())
     unfinished_bytes += kv.second->received_data_length;
   PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Resources.Bytes.Unfinished",
                        unfinished_bytes);
-
   auto* ukm_recorder = ukm::UkmRecorder::Get();
   ukm::builders::AdPageLoad builder(source_id);
   builder.SetTotalBytes(aggregate_frame_data_->network_bytes() >> 10)
@@ -632,8 +630,10 @@
   RecordHistogramsForAdTagging(FrameData::FrameVisibility::kVisible);
   RecordHistogramsForAdTagging(FrameData::FrameVisibility::kAnyVisibility);
   RecordPageResourceTotalHistograms(source_id);
-  for (auto const& kv : page_resources_)
+  for (auto const& kv :
+       GetDelegate()->GetResourceTracker().unfinished_resources()) {
     RecordResourceHistograms(kv.second);
+  }
 }
 
 // Computes a percentage given the numerator and denominator, bounded to 100%.
@@ -886,12 +886,14 @@
 }
 
 void AdsPageLoadMetricsObserver::ProcessOngoingNavigationResource(
-    FrameTreeNodeId frame_tree_node_id) {
+    content::RenderFrameHost* rfh) {
+  if (!rfh)
+    return;
   const auto& frame_id_and_request =
-      ongoing_navigation_resources_.find(frame_tree_node_id);
+      ongoing_navigation_resources_.find(rfh->GetFrameTreeNodeId());
   if (frame_id_and_request == ongoing_navigation_resources_.end())
     return;
-
-  ProcessResourceForFrame(frame_tree_node_id, frame_id_and_request->second);
+  ProcessResourceForFrame(rfh->GetFrameTreeNodeId(), rfh->GetProcess()->GetID(),
+                          frame_id_and_request->second);
   ongoing_navigation_resources_.erase(frame_id_and_request);
 }
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
index cc7dcab..a5b493ea 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h
@@ -19,7 +19,6 @@
 #include "components/subresource_filter/content/browser/subresource_filter_observer.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
 #include "components/subresource_filter/core/common/load_policy.h"
-#include "content/public/browser/global_request_id.h"
 #include "net/http/http_response_info.h"
 #include "services/metrics/public/cpp/ukm_source.h"
 
@@ -107,20 +106,19 @@
   // each call in order to free up memory.
   bool DetectAds(content::NavigationHandle* navigation_handle);
 
+  // Gets the number of bytes that we may have not attributed to ad
+  // resources due to the resource being reported as an ad late.
+  int GetUnaccountedAdBytes(
+      int process_id,
+      const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) const;
+
+  // Updates page level counters for resource loads.
+  void ProcessResourceForPage(
+      int process_id,
+      const page_load_metrics::mojom::ResourceDataUpdatePtr& resource);
   void ProcessResourceForFrame(
       FrameTreeNodeId frame_tree_node_id,
-      const page_load_metrics::mojom::ResourceDataUpdatePtr& resource);
-
-  void AdjustAdBytesForFrame(
-      FrameTreeNodeId frame_tree_node_id,
-      const page_load_metrics::mojom::ResourceDataUpdatePtr& resource,
-      int64_t unaccounted_ad_bytes);
-
-  // Update all of the per-resource page counters given a new resource data
-  // update. Updates |page_resources_| to reflect the new state of the resource.
-  // Called once per ResourceDataUpdate.
-  void UpdateResource(
-      content::RenderFrameHost* rfh,
+      int process_id,
       const page_load_metrics::mojom::ResourceDataUpdatePtr& resource);
 
   // Records size of resources by mime type.
@@ -134,10 +132,11 @@
   void RecordHistograms(ukm::SourceId source_id);
   void RecordHistogramsForAdTagging(FrameData::FrameVisibility visibility);
   void RecordHistogramsForCpuUsage(FrameData::FrameVisibility visibility);
-  // Checks to see if a resource is waiting for a navigation with the given
-  // |frame_tree_node_id| to commit before it can be processed. If so, call
+
+  // Checks to see if a resource is waiting for a navigation in the given
+  // RenderFrameHost to commit before it can be processed. If so, call
   // OnResourceDataUpdate for the delayed resource.
-  void ProcessOngoingNavigationResource(FrameTreeNodeId frame_tree_node_id);
+  void ProcessOngoingNavigationResource(content::RenderFrameHost* rfh);
 
   // Stores the size data of each ad frame. Pointed to by ad_frames_ so use a
   // data structure that won't move the data around.
@@ -161,15 +160,6 @@
   std::map<FrameTreeNodeId, page_load_metrics::mojom::ResourceDataUpdatePtr>
       ongoing_navigation_resources_;
 
-  // Maps a GlobalRequestId consisting of (request_id, process_id) for a blink
-  // resource to the metadata for the resource load. GlobalRequestIds are used
-  // because this map aggregates across renderers and blink request ids are
-  // unique per-renderer. Only contains resources that have not completed
-  // loading.
-  std::map<content::GlobalRequestID,
-           page_load_metrics::mojom::ResourceDataUpdatePtr>
-      page_resources_;
-
   // Tracks byte counts only for resources loaded in the main frame.
   std::unique_ptr<FrameData> main_frame_data_;
 
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
index 08c694e..9b680f5 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -291,7 +291,8 @@
                           ResourceCached resource_cached,
                           int resource_size_in_kbyte,
                           std::string mime_type = "",
-                          bool is_ad_resource = false) {
+                          bool is_ad_resource = false,
+                          bool is_main_frame_resource = false) {
     std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources;
     page_load_metrics::mojom::ResourceDataUpdatePtr resource =
         page_load_metrics::mojom::ResourceDataUpdate::New();
@@ -304,6 +305,9 @@
     resource->was_fetched_via_cache = static_cast<bool>(resource_cached);
     resource->mime_type = mime_type;
     resource->is_primary_frame_resource = true;
+    resource->is_main_frame_resource =
+        render_frame_host->GetFrameTreeNodeId() ==
+        main_rfh()->GetFrameTreeNodeId();
     resources.push_back(std::move(resource));
     tester_->SimulateResourceDataUseUpdate(resources, render_frame_host);
   }
@@ -689,14 +693,16 @@
   ConfigureAsSubresourceFilterOnlyURL(GURL(kNonAdUrl));
   NavigateMainFrame(kNonAdUrl);
 
-  ResourceDataUpdate(main_rfh(), ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_rfh(), ResourceCached::NOT_CACHED, 10,
+                     "" /* mime_type */, false /* is_ad_resource */);
 
   RenderFrameHost* subframe =
       RenderFrameHostTester::For(main_rfh())->AppendChild("foo");
   std::unique_ptr<NavigationSimulator> simulator =
       NavigationSimulator::CreateRendererInitiated(GURL(kDefaultDisallowedUrl),
                                                    subframe);
-  ResourceDataUpdate(subframe, ResourceCached::CACHED, 10);
+  ResourceDataUpdate(subframe, ResourceCached::NOT_CACHED, 10,
+                     "" /* mime_type */, true /* is_ad_resource */);
   simulator->Commit();
 
   EXPECT_NE(content::NavigationThrottle::PROCEED,
@@ -705,6 +711,8 @@
   NavigateMainFrame(kNonAdUrl);
   TestHistograms(histogram_tester(), std::vector<ExpectedFrameBytes>(),
                  0u /* non_ad_cached_kb */, 0u /* non_ad_uncached_kb */);
+  histogram_tester().ExpectUniqueSample(
+      "Ads.ResourceUsage.Size.Network.Subframe.AdResource", 10, 1);
 }
 
 // UKM metrics for ad page load are recorded correctly.
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer_delegate.h b/chrome/browser/page_load_metrics/page_load_metrics_observer_delegate.h
index 6171fa5..38cf1fc 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_observer_delegate.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_observer_delegate.h
@@ -7,12 +7,15 @@
 
 #include "base/optional.h"
 #include "base/time/time.h"
+#include "chrome/browser/page_load_metrics/resource_tracker.h"
 #include "chrome/browser/scoped_visibility_tracker.h"
 
 namespace content {
 class WebContents;
 }  // namespace content
 
+namespace page_load_metrics {
+
 // This class tracks global state for the page load that should be accessible
 // from any PageLoadMetricsObserver.
 class PageLoadMetricsObserverDelegate {
@@ -22,8 +25,12 @@
   virtual bool DidCommit() const = 0;
   virtual const ScopedVisibilityTracker& GetVisibilityTracker() const = 0;
 
+  virtual const ResourceTracker& GetResourceTracker() const = 0;
+
   // TODO(crbug/939403): Consider migrating PageLoadExtraInfo data to this API
   // and deprecating that struct.
 };
 
+}  // namespace page_load_metrics
+
 #endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_OBSERVER_DELEGATE_H_
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc
index 7af9b16..901cde1 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.cc
+++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -21,6 +21,7 @@
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
@@ -704,6 +705,8 @@
 void PageLoadTracker::UpdateResourceDataUse(
     content::RenderFrameHost* rfh,
     const std::vector<mojom::ResourceDataUpdatePtr>& resources) {
+  resource_tracker_.UpdateResourceDataUse(rfh->GetProcess()->GetID(),
+                                          resources);
   for (const auto& observer : observers_) {
     observer->OnResourceDataUseObserved(rfh, resources);
   }
@@ -732,4 +735,8 @@
   return visibility_tracker_;
 }
 
+const ResourceTracker& PageLoadTracker::GetResourceTracker() const {
+  return resource_tracker_;
+}
+
 }  // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.h b/chrome/browser/page_load_metrics/page_load_tracker.h
index 025866a..316ead692 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.h
+++ b/chrome/browser/page_load_metrics/page_load_tracker.h
@@ -14,6 +14,7 @@
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer_delegate.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h"
+#include "chrome/browser/page_load_metrics/resource_tracker.h"
 #include "chrome/browser/scoped_visibility_tracker.h"
 #include "chrome/common/page_load_metrics/page_load_timing.h"
 #include "content/public/browser/global_request_id.h"
@@ -198,6 +199,7 @@
   base::TimeTicks GetNavigationStart() const override;
   bool DidCommit() const override;
   const ScopedVisibilityTracker& GetVisibilityTracker() const override;
+  const ResourceTracker& GetResourceTracker() const override;
 
   void Redirect(content::NavigationHandle* navigation_handle);
   void WillProcessNavigationResponse(
@@ -400,6 +402,9 @@
   // always be less than or equal to |aborted_chain_size_|.
   const int aborted_chain_size_same_url_;
 
+  // Keeps track of actively loading resources on the page.
+  ResourceTracker resource_tracker_;
+
   // Interface to chrome features. Must outlive the class.
   PageLoadMetricsEmbedderInterface* const embedder_interface_;
 
diff --git a/chrome/browser/page_load_metrics/resource_tracker.cc b/chrome/browser/page_load_metrics/resource_tracker.cc
new file mode 100644
index 0000000..f7ffd3e
--- /dev/null
+++ b/chrome/browser/page_load_metrics/resource_tracker.cc
@@ -0,0 +1,69 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/page_load_metrics/resource_tracker.h"
+
+#include <tuple>
+
+namespace page_load_metrics {
+
+ResourceTracker::ResourceTracker() = default;
+
+ResourceTracker::~ResourceTracker() = default;
+
+void ResourceTracker::UpdateResourceDataUse(
+    int process_id,
+    const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
+        resources) {
+  // Clear the map of previous updates to prevent completed resources from
+  // remaining in the map. This is safe because the map is only expected
+  // to contain updates for resources that have actively received new data.
+  previous_resource_updates_.clear();
+  for (auto const& resource : resources) {
+    ProcessResourceUpdate(process_id, resource);
+  }
+}
+
+void ResourceTracker::ProcessResourceUpdate(
+    int process_id,
+    const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
+  content::GlobalRequestID global_id(process_id, resource->request_id);
+  auto it = unfinished_resources_.find(global_id);
+
+  // This is the first update received for a resource.
+  if (it == unfinished_resources_.end()) {
+    if (!resource->is_complete) {
+      unfinished_resources_.emplace(std::piecewise_construct,
+                                    std::forward_as_tuple(global_id),
+                                    std::forward_as_tuple(resource->Clone()));
+    }
+    return;
+  }
+
+  // Update the map of previous resource data now that we have a new data update
+  // for a tracked resource.
+  previous_resource_updates_[global_id] = it->second->Clone();
+
+  // Either update the unfinished resource data or remove it from the map if it
+  // completed. Must clone resource so it will be accessible when the observer
+  // is destroyed.
+  if (resource->is_complete)
+    unfinished_resources_.erase(it);
+  else
+    it->second = resource->Clone();
+}
+
+bool ResourceTracker::HasPreviousUpdateForResource(
+    content::GlobalRequestID request_id) const {
+  return previous_resource_updates_.count(request_id) != 0;
+}
+
+const page_load_metrics::mojom::ResourceDataUpdatePtr&
+ResourceTracker::GetPreviousUpdateForResource(
+    content::GlobalRequestID request_id) const {
+  DCHECK(HasPreviousUpdateForResource(request_id));
+  return previous_resource_updates_.find(request_id)->second;
+}
+
+}  // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/resource_tracker.h b/chrome/browser/page_load_metrics/resource_tracker.h
new file mode 100644
index 0000000..e1476b46
--- /dev/null
+++ b/chrome/browser/page_load_metrics/resource_tracker.h
@@ -0,0 +1,68 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_RESOURCE_TRACKER_H_
+#define CHROME_BROWSER_PAGE_LOAD_METRICS_RESOURCE_TRACKER_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "chrome/common/page_load_metrics/page_load_metrics.mojom.h"
+#include "content/public/browser/global_request_id.h"
+
+namespace page_load_metrics {
+
+// Tracks individual resource loads on the page.
+class ResourceTracker {
+ public:
+  // Maps a request id for a blink resource to the metadata for the resource
+  // load.  GlobalRequestIDs are used because this map may aggregate across
+  // renderers and blink request ids are unique per-renderer.
+  using ResourceMap = std::map<content::GlobalRequestID,
+                               page_load_metrics::mojom::ResourceDataUpdatePtr>;
+
+  ResourceTracker();
+  ~ResourceTracker();
+
+  // Updates map of ongoing resource loads given a new update. |process_id| is
+  // the id of renderer process where the update originated and is used to
+  // create globally unique resource ids.
+  void UpdateResourceDataUse(
+      int process_id,
+      const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
+          resources);
+
+  const ResourceMap& unfinished_resources() const {
+    return unfinished_resources_;
+  }
+
+  // Previous ResourceDataUseUpdate objects are only stored for resources that
+  // are still actively loaded. These methods should only be used for resources
+  // that were received by observers in
+  // PageLoadMetricsObserver::OnResourceDataUseObserved().
+  bool HasPreviousUpdateForResource(content::GlobalRequestID request_id) const;
+  const page_load_metrics::mojom::ResourceDataUpdatePtr&
+  GetPreviousUpdateForResource(content::GlobalRequestID request_id) const;
+
+ private:
+  void ProcessResourceUpdate(
+      int process_id,
+      const page_load_metrics::mojom::ResourceDataUpdatePtr& resource);
+
+  // Stores all resources that have started loading on the page but have
+  // not completed loading.
+  ResourceMap unfinished_resources_;
+
+  // Maps a request_id for a blink resource to the previous ResourceDataUpdate
+  // received for the resource. This only stores previous updates for
+  // resources that are still actively receiving updates. A resource that was
+  // unfinished then completes will have its previous update in this map until
+  // the next call to UpdateResourceDataUse().
+  ResourceMap previous_resource_updates_;
+};
+
+}  // namespace page_load_metrics
+
+#endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_RESOURCE_TRACKER_H_
diff --git a/chrome/browser/page_load_metrics/resource_tracker_unittest.cc b/chrome/browser/page_load_metrics/resource_tracker_unittest.cc
new file mode 100644
index 0000000..21d45b1e
--- /dev/null
+++ b/chrome/browser/page_load_metrics/resource_tracker_unittest.cc
@@ -0,0 +1,151 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "chrome/browser/page_load_metrics/resource_tracker.h"
+#include "chrome/common/page_load_metrics/page_load_metrics.mojom.h"
+#include "content/public/browser/global_request_id.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+class ResourceTrackerTest : public testing::Test {
+ public:
+  ResourceTrackerTest() = default;
+
+  void StartResourceLoad(int resource_id, bool is_complete = false) {
+    CreateResourceUpdate(resource_id, 0 /* delta_bytes */,
+                         is_complete /* is_complete */);
+  }
+
+  void AdvanceResourceLoad(int resource_id, int bytes = 0) {
+    CreateResourceUpdate(resource_id, bytes /* delta_bytes */,
+                         false /* is_complete */);
+  }
+
+  void CompleteResourceLoad(int resource_id) {
+    CreateResourceUpdate(resource_id, 0 /* delta_bytes */,
+                         true /* is_complete */);
+  }
+
+  bool HasUnfinishedResource(int resource_id) {
+    return resource_tracker_.unfinished_resources().find(
+               content::GlobalRequestID(process_id_, resource_id)) !=
+           resource_tracker_.unfinished_resources().end();
+  }
+
+  int GetUnfinishedResourceBytes(int resource_id) {
+    return resource_tracker_.unfinished_resources()
+        .find(content::GlobalRequestID(process_id_, resource_id))
+        ->second->delta_bytes;
+  }
+
+  bool HasPreviousUpdateForResource(int resource_id) {
+    return resource_tracker_.HasPreviousUpdateForResource(
+        content::GlobalRequestID(process_id_, resource_id));
+  }
+
+  int GetPreviousResourceUpdateBytes(int resource_id) {
+    return resource_tracker_
+        .GetPreviousUpdateForResource(
+            content::GlobalRequestID(process_id_, resource_id))
+        ->delta_bytes;
+  }
+
+ private:
+  void CreateResourceUpdate(int request_id,
+                            int64_t delta_bytes,
+                            bool is_complete) {
+    std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources;
+    auto resource_data_update =
+        page_load_metrics::mojom::ResourceDataUpdate::New();
+    resource_data_update->request_id = request_id;
+    resource_data_update->delta_bytes = delta_bytes;
+    resource_data_update->is_complete = is_complete;
+    resources.push_back(std::move(resource_data_update));
+    resource_tracker_.UpdateResourceDataUse(process_id_, resources);
+  }
+
+  const int process_id_ = 0;
+
+  page_load_metrics::ResourceTracker resource_tracker_;
+};
+
+// Verifies that resources are added to and removed from the map
+// of ongoing resource loads as expected.
+TEST_F(ResourceTrackerTest, UnfinishedResourceMap) {
+  StartResourceLoad(0 /* resource_id */);
+  StartResourceLoad(1 /* resource_id */);
+  StartResourceLoad(2 /* resource_id */);
+
+  // Verify completed resources are not stored in the unfinished map.
+  EXPECT_TRUE(HasUnfinishedResource(0 /* resource_id */));
+  CompleteResourceLoad(0 /* resource_id */);
+  EXPECT_FALSE(HasUnfinishedResource(0 /* resource_id */));
+
+  // Verify that resources receiving multiple updates are not removed from the
+  // map.
+  AdvanceResourceLoad(1 /* resource_id */, 10 /* bytes */);
+  AdvanceResourceLoad(1 /* resource_id */, 20 /* bytes */);
+  EXPECT_TRUE(HasUnfinishedResource(1 /* resource_id */));
+  CompleteResourceLoad(1 /* resource_id */);
+  EXPECT_FALSE(HasUnfinishedResource(1 /* resource_id */));
+
+  // Verify the unfinished map stores the most recent resource update.
+  EXPECT_EQ(0, GetUnfinishedResourceBytes(2 /* resource_id */));
+  AdvanceResourceLoad(2 /* resource_id */, 10 /* bytes */);
+  EXPECT_EQ(10, GetUnfinishedResourceBytes(2 /* resource_id */));
+  AdvanceResourceLoad(2 /* resource_id */, 20 /* bytes */);
+  AdvanceResourceLoad(2 /* resource_id */, 30 /* bytes */);
+  EXPECT_EQ(30, GetUnfinishedResourceBytes(2 /* resource_id */));
+}
+
+// Verifies that resources are added to and removed from the map
+// of previous resource updates as expected.
+TEST_F(ResourceTrackerTest, PreviousUpdateResourceMap) {
+  StartResourceLoad(0 /* resource_id */);
+  StartResourceLoad(1 /* resource_id */);
+  EXPECT_FALSE(HasPreviousUpdateForResource(0 /* resource_id */));
+  EXPECT_FALSE(HasPreviousUpdateForResource(1 /* resource_id */));
+
+  AdvanceResourceLoad(1 /* resource_id */, 10 /* bytes */);
+  EXPECT_TRUE(HasPreviousUpdateForResource(1 /* resource_id */));
+
+  // Previous resource update should only be available for resources
+  // who received resource updates in the previous call to
+  // ResourceTracker::UpdateResourceDataUse(). resource_id "1" should not be
+  // available in this case.
+  AdvanceResourceLoad(0 /* resource_id */, 0 /* bytes */);
+  EXPECT_FALSE(HasPreviousUpdateForResource(1 /* resource_id */));
+
+  // The update should not be available because the load for resource_id "1" was
+  // still ongoing. This should hold the data for the last update, 10 bytes.
+  AdvanceResourceLoad(1 /* resource_id */, 20 /* bytes */);
+  EXPECT_TRUE(HasPreviousUpdateForResource(1 /* resource_id */));
+  EXPECT_EQ(10, GetPreviousResourceUpdateBytes(1 /* resource_id */));
+
+  // Verify previous resource update is available for newly complete resources.
+  CompleteResourceLoad(1 /* resource_id */);
+  EXPECT_TRUE(HasPreviousUpdateForResource(1 /* resource_id */));
+  EXPECT_EQ(20, GetPreviousResourceUpdateBytes(1 /* resource_id */));
+
+  // Verify this completed resource update is removed once other resources are
+  // loaded.
+  CompleteResourceLoad(0 /* resource_id */);
+  EXPECT_FALSE(HasPreviousUpdateForResource(1 /* resource_id */));
+}
+
+TEST_F(ResourceTrackerTest, SingleUpdateResourceNotStored) {
+  // Verify that resources who only receive one update and complete are never
+  // stored.
+  StartResourceLoad(0 /* resource_id */, true /* is_complete */);
+  EXPECT_FALSE(HasUnfinishedResource(0 /* resource_id */));
+  EXPECT_FALSE(HasPreviousUpdateForResource(0 /* resource_id */));
+
+  // Load new resource and verify we don't have a previous update for the
+  // resource that completed.
+  StartResourceLoad(1 /* resource_id */, true /* is_complete */);
+  EXPECT_FALSE(HasUnfinishedResource(0 /* resource_id */));
+  EXPECT_FALSE(HasPreviousUpdateForResource(0 /* resource_id */));
+}
diff --git a/chrome/browser/resource_coordinator/tab_activity_watcher.cc b/chrome/browser/resource_coordinator/tab_activity_watcher.cc
index 35a20ef..b4b16399 100644
--- a/chrome/browser/resource_coordinator/tab_activity_watcher.cc
+++ b/chrome/browser/resource_coordinator/tab_activity_watcher.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/tabs/window_activity_watcher.h"
 #include "components/ukm/content/source_url_recorder.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_handle.h"
@@ -415,7 +414,7 @@
 
     // For window features.
     tab_ranker::WindowFeatures window =
-        WindowActivityWatcher::CreateWindowFeatures(browser);
+        TabMetricsLogger::CreateWindowFeatures(browser);
     tab.window_is_active = window.is_active;
     tab.window_show_state = window.show_state;
     tab.window_tab_count = window.tab_count;
@@ -512,10 +511,6 @@
     : tab_metrics_logger_(std::make_unique<TabMetricsLogger>()),
       browser_tab_strip_tracker_(this, this, this) {
   browser_tab_strip_tracker_.Init();
-
-  // TabMetrics UKMs reference WindowMetrics UKM entries, so ensure the
-  // WindowActivityWatcher is initialized.
-  WindowActivityWatcher::GetInstance();
 }
 
 TabActivityWatcher::~TabActivityWatcher() = default;
diff --git a/chrome/browser/resource_coordinator/tab_metrics_logger.cc b/chrome/browser/resource_coordinator/tab_metrics_logger.cc
index 28493d78..f00efa8 100644
--- a/chrome/browser/resource_coordinator/tab_metrics_logger.cc
+++ b/chrome/browser/resource_coordinator/tab_metrics_logger.cc
@@ -7,16 +7,20 @@
 #include <algorithm>
 #include <string>
 
+#include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/tab_metrics_event.pb.h"
 #include "chrome/browser/resource_coordinator/tab_ranker/mru_features.h"
 #include "chrome/browser/resource_coordinator/tab_ranker/tab_features.h"
+#include "chrome/browser/resource_coordinator/tab_ranker/window_features.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/recently_audible_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/browser/render_frame_host.h"
@@ -28,6 +32,7 @@
 #include "url/gurl.h"
 
 using metrics::TabMetricsEvent;
+using metrics::WindowMetricsEvent;
 
 namespace {
 
@@ -197,3 +202,37 @@
       .SetTimeSinceNavigation(time_since_navigation.InMilliseconds())
       .Record(ukm::UkmRecorder::Get());
 }
+
+// static
+tab_ranker::WindowFeatures TabMetricsLogger::CreateWindowFeatures(
+    const Browser* browser) {
+  DCHECK(browser->window());
+
+  WindowMetricsEvent::Type window_type = WindowMetricsEvent::TYPE_UNKNOWN;
+  switch (browser->type()) {
+    case Browser::TYPE_TABBED:
+      window_type = WindowMetricsEvent::TYPE_TABBED;
+      break;
+    case Browser::TYPE_POPUP:
+      window_type = WindowMetricsEvent::TYPE_POPUP;
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  WindowMetricsEvent::ShowState show_state =
+      WindowMetricsEvent::SHOW_STATE_UNKNOWN;
+  if (browser->window()->IsFullscreen())
+    show_state = WindowMetricsEvent::SHOW_STATE_FULLSCREEN;
+  else if (browser->window()->IsMinimized())
+    show_state = WindowMetricsEvent::SHOW_STATE_MINIMIZED;
+  else if (browser->window()->IsMaximized())
+    show_state = WindowMetricsEvent::SHOW_STATE_MAXIMIZED;
+  else
+    show_state = WindowMetricsEvent::SHOW_STATE_NORMAL;
+
+  const bool is_active = browser->window()->IsActive();
+  const int tab_count = browser->tab_strip_model()->count();
+
+  return {window_type, show_state, is_active, tab_count};
+}
diff --git a/chrome/browser/resource_coordinator/tab_metrics_logger.h b/chrome/browser/resource_coordinator/tab_metrics_logger.h
index 519d188..f1f0f0f 100644
--- a/chrome/browser/resource_coordinator/tab_metrics_logger.h
+++ b/chrome/browser/resource_coordinator/tab_metrics_logger.h
@@ -22,6 +22,7 @@
 
 namespace tab_ranker {
 struct TabFeatures;
+struct WindowFeatures;
 }  // namespace tab_ranker
 
 // Logs metrics for a tab and its WebContents when requested.
@@ -100,6 +101,10 @@
       const TabMetrics& tab_metrics,
       base::TimeDelta inactive_duration);
 
+  // Returns a populated WindowFeatures for the browser.
+  static tab_ranker::WindowFeatures CreateWindowFeatures(
+      const Browser* browser);
+
   void set_query_id(int64_t query_id) { query_id_ = query_id; }
 
  private:
diff --git a/chrome/browser/resource_coordinator/tab_metrics_logger_interactive_uitest.cc b/chrome/browser/resource_coordinator/tab_metrics_logger_interactive_uitest.cc
new file mode 100644
index 0000000..68f10a3
--- /dev/null
+++ b/chrome/browser/resource_coordinator/tab_metrics_logger_interactive_uitest.cc
@@ -0,0 +1,186 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/tab_metrics_logger.h"
+
+#include <memory>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "chrome/browser/resource_coordinator/tab_metrics_event.pb.h"
+#include "chrome/browser/resource_coordinator/tab_ranker/window_features.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using metrics::WindowMetricsEvent;
+using tab_ranker::WindowFeatures;
+
+const char* kTestUrl = "https://example.com/";
+
+// Tests WindowFeatures generated by TabMetricsLogger::CreateWindowFeatures due
+// to interactive changes to window state.
+class CreateWindowFeaturesTest : public InProcessBrowserTest {
+ protected:
+  CreateWindowFeaturesTest() = default;
+
+  // InProcessBrowserTest:
+  void PreRunTestOnMainThread() override {
+    InProcessBrowserTest::PreRunTestOnMainThread();
+  }
+
+  void SetUpOnMainThread() override {
+#if defined(OS_MACOSX)
+    // On Mac, the browser window needs to be forced to the front. This will
+    // create a UKM entry for the activation because it happens after the
+    // WindowActivityWatcher creation. On other platforms, activation happens
+    // before creation, and as a result, no UKM entry is created.
+    // TODO(crbug.com/650859): Reassess after activation is restored in the
+    // focus manager.
+    ui_test_utils::BrowserActivationWaiter waiter(browser());
+    ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+    waiter.WaitForActivation();
+    ASSERT_TRUE(browser()->window()->IsActive());
+#endif
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CreateWindowFeaturesTest);
+};
+
+// Tests WindowMetrics of the current browser window.
+IN_PROC_BROWSER_TEST_F(CreateWindowFeaturesTest, Basic) {
+  WindowFeatures expected_metrics{WindowMetricsEvent::TYPE_TABBED,
+                                  WindowMetricsEvent::SHOW_STATE_NORMAL, true,
+                                  1};
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
+            expected_metrics);
+
+  // Updated metrics after adding tabs.
+  {
+    SCOPED_TRACE("");
+    AddTabAtIndex(1, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
+    expected_metrics.tab_count++;
+    EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
+              expected_metrics);
+  }
+  {
+    SCOPED_TRACE("");
+    AddTabAtIndex(0, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
+    expected_metrics.tab_count++;
+    EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
+              expected_metrics);
+  }
+
+  // Closing the window doesn't log more WindowMetrics UKMs.
+  CloseBrowserSynchronously(browser());
+}
+
+// TODO(https://crbug.com/51364): Implement BrowserWindow::Deactivate() on Mac.
+#if !defined(OS_MACOSX)
+// Tests WindowMetrics by activating/deactivating the window.
+IN_PROC_BROWSER_TEST_F(CreateWindowFeaturesTest, WindowActivation) {
+  WindowFeatures expected_metrics{WindowMetricsEvent::TYPE_TABBED,
+                                  WindowMetricsEvent::SHOW_STATE_NORMAL, false,
+                                  1};
+
+  {
+    SCOPED_TRACE("");
+    ui_test_utils::BrowserDeactivationWaiter waiter(browser());
+    browser()->window()->Deactivate();
+    waiter.WaitForDeactivation();
+    EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
+              expected_metrics);
+  }
+
+  {
+    SCOPED_TRACE("");
+    ui_test_utils::BrowserActivationWaiter waiter(browser());
+    browser()->window()->Activate();
+    waiter.WaitForActivation();
+    ASSERT_TRUE(browser()->window()->IsActive());
+    expected_metrics.is_active = true;
+    EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
+              expected_metrics);
+  }
+
+  // Closing the window doesn't log more WindowMetrics UKMs.
+  CloseBrowserSynchronously(browser());
+}
+
+// Tests WindowMetrics when switching between windows.
+IN_PROC_BROWSER_TEST_F(CreateWindowFeaturesTest, MultipleWindows) {
+  // Create a new browser window.
+  Browser* browser_2 = CreateBrowser(browser()->profile());
+  WindowFeatures expected_metrics{WindowMetricsEvent::TYPE_TABBED,
+                                  WindowMetricsEvent::SHOW_STATE_NORMAL, false,
+                                  1};
+  WindowFeatures expected_metrics_2{WindowMetricsEvent::TYPE_TABBED,
+                                    WindowMetricsEvent::SHOW_STATE_NORMAL,
+                                    false, 1};
+
+  // Wait for the old window to be deactivated and the new window to be
+  // activated if they aren't yet.
+  {
+    ui_test_utils::BrowserActivationWaiter waiter(browser_2);
+    waiter.WaitForActivation();
+    expected_metrics_2.is_active = true;
+  }
+  {
+    ui_test_utils::BrowserDeactivationWaiter waiter(browser());
+    waiter.WaitForDeactivation();
+  }
+  {
+    SCOPED_TRACE("");
+    // Check for activation and deactivation.
+    EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser_2),
+              expected_metrics_2);
+    EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
+              expected_metrics);
+  }
+  {
+    SCOPED_TRACE("");
+    ui_test_utils::BrowserActivationWaiter activation_waiter(browser());
+    ui_test_utils::BrowserDeactivationWaiter deactivation_waiter(browser_2);
+
+    // Switch back to the first window.
+    // Note: use Activate() rather than Show() because on some platforms, Show()
+    // calls SetLastActive() before doing anything else.
+    browser()->window()->Activate();
+
+    activation_waiter.WaitForActivation();
+    deactivation_waiter.WaitForDeactivation();
+
+    expected_metrics.is_active = true;
+    expected_metrics_2.is_active = false;
+    EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser()),
+              expected_metrics);
+    EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser_2),
+              expected_metrics_2);
+  }
+
+  CloseBrowserSynchronously(browser());
+
+  // GetLastActive could return browser2 if browser1 was active and then was
+  // removed, so browser2 might not actually be active.
+  {
+    ui_test_utils::BrowserActivationWaiter activation_waiter(browser_2);
+    browser_2->window()->Activate();
+    activation_waiter.WaitForActivation();
+  }
+  EXPECT_TRUE(BrowserList::GetInstance()->GetLastActive() == browser_2);
+  EXPECT_TRUE(browser_2->window()->IsActive());
+  {
+    SCOPED_TRACE("");
+    expected_metrics_2.is_active = true;
+    EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser_2),
+              expected_metrics_2);
+  }
+}
+
+#endif  // !defined(OS_MACOSX)
diff --git a/chrome/browser/resource_coordinator/tab_metrics_logger_unittest.cc b/chrome/browser/resource_coordinator/tab_metrics_logger_unittest.cc
index 37af7826..b36cf31 100644
--- a/chrome/browser/resource_coordinator/tab_metrics_logger_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_metrics_logger_unittest.cc
@@ -4,13 +4,20 @@
 
 #include "chrome/browser/resource_coordinator/tab_metrics_logger.h"
 
+#include <memory>
+#include <vector>
+
 #include "base/containers/flat_map.h"
+#include "base/macros.h"
 #include "base/test/scoped_task_environment.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
+#include "chrome/browser/resource_coordinator/tab_metrics_event.pb.h"
 #include "chrome/browser/resource_coordinator/tab_ranker/tab_features.h"
 #include "chrome/browser/resource_coordinator/tab_ranker/tab_features_test_helper.h"
+#include "chrome/browser/resource_coordinator/tab_ranker/window_features.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_activity_simulator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -20,13 +27,88 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ui_base_types.h"
 
 using content::WebContentsTester;
+using metrics::WindowMetricsEvent;
+using tab_ranker::WindowFeatures;
 
 // Sanity checks for functions in TabMetricsLogger.
 // See TabActivityWatcherTest for more thorough tab usage UKM tests.
 using TabMetricsLoggerTest = ChromeRenderViewHostTestHarness;
 
+namespace {
+
+const char* kTestUrl = "https://example.com/";
+
+// TestBrowserWindow whose show state can be modified.
+class FakeBrowserWindow : public TestBrowserWindow {
+ public:
+  FakeBrowserWindow() = default;
+  ~FakeBrowserWindow() override = default;
+
+  // Helper function to handle FakeBrowserWindow lifetime. Modeled after
+  // CreateBrowserWithTestWindowForParams.
+  static std::unique_ptr<Browser> CreateBrowserWithFakeWindowForParams(
+      Browser::CreateParams* params) {
+    // TestBrowserWindowOwner takes ownersip of the window and will destroy the
+    // window (along with itself) automatically when the browser is closed.
+    FakeBrowserWindow* window = new FakeBrowserWindow;
+    new TestBrowserWindowOwner(window);
+
+    params->window = window;
+    auto browser = std::make_unique<Browser>(*params);
+    window->browser_ = browser.get();
+    window->Activate();
+    return browser;
+  }
+
+  // TestBrowserWindow:
+  void Activate() override {
+    if (is_active_)
+      return;
+    is_active_ = true;
+    // With a real view, activating would update the BrowserList.
+    BrowserList::SetLastActive(browser_);
+  }
+  void Deactivate() override {
+    if (!is_active_)
+      return;
+    is_active_ = false;
+    // With a real view, deactivating would notify the BrowserList.
+    BrowserList::NotifyBrowserNoLongerActive(browser_);
+  }
+  bool IsActive() const override { return is_active_; }
+  bool IsMaximized() const override {
+    return show_state_ == ui::SHOW_STATE_MAXIMIZED;
+  }
+  bool IsMinimized() const override {
+    return show_state_ == ui::SHOW_STATE_MINIMIZED;
+  }
+  void Maximize() override {
+    show_state_ = ui::SHOW_STATE_MAXIMIZED;
+    Activate();
+  }
+  void Minimize() override {
+    show_state_ = ui::SHOW_STATE_MINIMIZED;
+    Deactivate();
+  }
+  void Restore() override {
+    // This isn't true "restore" behavior.
+    show_state_ = ui::SHOW_STATE_NORMAL;
+    Activate();
+  }
+
+ private:
+  Browser* browser_;
+  bool is_active_ = false;
+  ui::WindowShowState show_state_ = ui::SHOW_STATE_NORMAL;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBrowserWindow);
+};
+
+}  // namespace
+
 // Tests creating a flat TabFeatures structure for logging a tab and its
 // TabMetrics state.
 TEST_F(TabMetricsLoggerTest, GetTabFeatures) {
@@ -239,3 +321,160 @@
                                 {"TotalTabCount", foc_metrics.total_tab_count},
                             });
 }
+
+// Tests WindowFeatures generated by CreateWindowFeatures.
+class CreateWindowFeaturesTest : public ChromeRenderViewHostTestHarness {
+ protected:
+  CreateWindowFeaturesTest() = default;
+  ~CreateWindowFeaturesTest() override = default;
+
+  // Adds a tab and simulates a basic navigation.
+  void AddTab(Browser* browser) {
+    content::WebContentsTester::For(
+        tab_activity_simulator_.AddWebContentsAndNavigate(
+            browser->tab_strip_model(), GURL(kTestUrl)))
+        ->TestSetIsLoading(false);
+  }
+
+ private:
+  TabActivitySimulator tab_activity_simulator_;
+
+  DISALLOW_COPY_AND_ASSIGN(CreateWindowFeaturesTest);
+};
+
+// Tests CreateWindowFeatures of two browser windows.
+TEST_F(CreateWindowFeaturesTest, Basic) {
+  Browser::CreateParams params(profile(), true);
+  std::unique_ptr<Browser> browser =
+      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
+
+  AddTab(browser.get());
+  WindowFeatures expected_metrics{WindowMetricsEvent::TYPE_TABBED,
+                                  WindowMetricsEvent::SHOW_STATE_NORMAL, true,
+                                  1};
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser.get()),
+            expected_metrics);
+
+  AddTab(browser.get());
+  expected_metrics.tab_count++;
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser.get()),
+            expected_metrics);
+
+  browser->window()->Minimize();
+  expected_metrics.show_state = WindowMetricsEvent::SHOW_STATE_MINIMIZED;
+  expected_metrics.is_active = false;
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser.get()),
+            expected_metrics);
+
+  // Create a second browser.
+  Browser::CreateParams params_2(Browser::TYPE_POPUP, profile(), true);
+  std::unique_ptr<Browser> browser_2 =
+      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params_2);
+
+  AddTab(browser_2.get());
+  WindowFeatures expected_metrics_2{WindowMetricsEvent::TYPE_POPUP,
+                                    WindowMetricsEvent::SHOW_STATE_NORMAL, true,
+                                    1};
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser_2.get()),
+            expected_metrics_2);
+
+  // Switching the active browser.
+  browser_2->window()->Deactivate();
+  expected_metrics_2.is_active = false;
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser_2.get()),
+            expected_metrics_2);
+
+  browser->window()->Restore();
+  expected_metrics.show_state = WindowMetricsEvent::SHOW_STATE_NORMAL;
+  expected_metrics.is_active = true;
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser.get()),
+            expected_metrics);
+
+  browser->tab_strip_model()->CloseAllTabs();
+  browser_2->tab_strip_model()->CloseAllTabs();
+}
+
+// Tests moving a tab between browser windows.
+TEST_F(CreateWindowFeaturesTest, MoveTabToOtherWindow) {
+  Browser::CreateParams params(profile(), true);
+  std::unique_ptr<Browser> starting_browser =
+      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
+  AddTab(starting_browser.get());
+  WindowFeatures starting_browser_metrics{WindowMetricsEvent::TYPE_TABBED,
+                                          WindowMetricsEvent::SHOW_STATE_NORMAL,
+                                          true, 1};
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(starting_browser.get()),
+            starting_browser_metrics);
+
+  // Add a second tab, so we can detach it while leaving the original window
+  // behind.
+  AddTab(starting_browser.get());
+  starting_browser_metrics.tab_count++;
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(starting_browser.get()),
+            starting_browser_metrics);
+
+  // Drag the tab out of its window.
+  std::unique_ptr<content::WebContents> dragged_tab =
+      starting_browser->tab_strip_model()->DetachWebContentsAt(1);
+  starting_browser_metrics.tab_count--;
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(starting_browser.get()),
+            starting_browser_metrics);
+
+  starting_browser->window()->Deactivate();
+  starting_browser_metrics.is_active = false;
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(starting_browser.get()),
+            starting_browser_metrics);
+
+  // Create a new Browser for the tab.
+  std::unique_ptr<Browser> created_browser =
+      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
+  created_browser->window()->Activate();
+  created_browser->tab_strip_model()->InsertWebContentsAt(
+      0, std::move(dragged_tab), TabStripModel::ADD_ACTIVE);
+
+  WindowFeatures created_browser_metrics{WindowMetricsEvent::TYPE_TABBED,
+                                         WindowMetricsEvent::SHOW_STATE_NORMAL,
+                                         true, 1};
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(created_browser.get()),
+            created_browser_metrics);
+
+  starting_browser->tab_strip_model()->CloseAllTabs();
+  created_browser->tab_strip_model()->CloseAllTabs();
+}
+
+// Tests replacing a tab.
+TEST_F(CreateWindowFeaturesTest, ReplaceTab) {
+  Browser::CreateParams params(profile(), true);
+  std::unique_ptr<Browser> browser =
+      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
+  AddTab(browser.get());
+  WindowFeatures expected_metrics{WindowMetricsEvent::TYPE_TABBED,
+                                  WindowMetricsEvent::SHOW_STATE_NORMAL, true,
+                                  1};
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser.get()),
+            expected_metrics);
+
+  // Add a tab that will be replaced.
+  AddTab(browser.get());
+  expected_metrics.tab_count++;
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser.get()),
+            expected_metrics);
+
+  // Replace the tab.
+  content::WebContents::CreateParams web_contents_params(profile(), nullptr);
+  std::unique_ptr<content::WebContents> new_contents = base::WrapUnique(
+      content::WebContentsTester::CreateTestWebContents(web_contents_params));
+  std::unique_ptr<content::WebContents> old_contents =
+      browser->tab_strip_model()->ReplaceWebContentsAt(1,
+                                                       std::move(new_contents));
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser.get()),
+            expected_metrics);
+
+  // Close the replaced tab. This should update TabCount.
+  browser->tab_strip_model()->CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
+  expected_metrics.tab_count--;
+  EXPECT_EQ(TabMetricsLogger::CreateWindowFeatures(browser.get()),
+            expected_metrics);
+
+  browser->tab_strip_model()->CloseAllTabs();
+}
diff --git a/chrome/browser/resource_coordinator/tab_ranker/window_features.cc b/chrome/browser/resource_coordinator/tab_ranker/window_features.cc
index 197e75e..5d3eccf 100644
--- a/chrome/browser/resource_coordinator/tab_ranker/window_features.cc
+++ b/chrome/browser/resource_coordinator/tab_ranker/window_features.cc
@@ -6,18 +6,19 @@
 
 namespace tab_ranker {
 
-WindowFeatures::WindowFeatures(SessionID window_id,
-                               metrics::WindowMetricsEvent::Type type)
-    : window_id(window_id), type(type) {}
-
-WindowFeatures::WindowFeatures(const WindowFeatures& other) = default;
-
-WindowFeatures::~WindowFeatures() = default;
+WindowFeatures::WindowFeatures(
+    metrics::WindowMetricsEvent::Type type,
+    metrics::WindowMetricsEvent::ShowState show_state,
+    bool is_active,
+    int tab_count)
+    : type(type),
+      show_state(show_state),
+      is_active(is_active),
+      tab_count(tab_count) {}
 
 bool WindowFeatures::operator==(const WindowFeatures& other) const {
-  return window_id == other.window_id && type == other.type &&
-         show_state == other.show_state && is_active == other.is_active &&
-         tab_count == other.tab_count;
+  return type == other.type && show_state == other.show_state &&
+         is_active == other.is_active && tab_count == other.tab_count;
 }
 
 bool WindowFeatures::operator!=(const WindowFeatures& other) const {
diff --git a/chrome/browser/resource_coordinator/tab_ranker/window_features.h b/chrome/browser/resource_coordinator/tab_ranker/window_features.h
index 3d4cbf2..3bd97ff 100644
--- a/chrome/browser/resource_coordinator/tab_ranker/window_features.h
+++ b/chrome/browser/resource_coordinator/tab_ranker/window_features.h
@@ -15,15 +15,16 @@
 // Window features used for logging a Tab Ranker example to UKM or calculating a
 // Tab Ranker score.
 struct WindowFeatures {
-  WindowFeatures(SessionID window_id, metrics::WindowMetricsEvent::Type type);
-  WindowFeatures(const WindowFeatures& other);
-  ~WindowFeatures();
+  WindowFeatures(metrics::WindowMetricsEvent::Type type,
+                 metrics::WindowMetricsEvent::ShowState show_state,
+                 bool is_active,
+                 int tab_count);
+
+  ~WindowFeatures() = default;
 
   bool operator==(const WindowFeatures& other) const;
   bool operator!=(const WindowFeatures& other) const;
 
-  // ID for the window, unique within the Chrome session.
-  const SessionID window_id;
   const metrics::WindowMetricsEvent::Type type;
   metrics::WindowMetricsEvent::ShowState show_state =
       metrics::WindowMetricsEvent::SHOW_STATE_UNKNOWN;
diff --git a/chrome/browser/resources/chromeos/md_set_time/set_time.html b/chrome/browser/resources/chromeos/md_set_time/set_time.html
index 5abb4fd9..874d998 100644
--- a/chrome/browser/resources/chromeos/md_set_time/set_time.html
+++ b/chrome/browser/resources/chromeos/md_set_time/set_time.html
@@ -10,6 +10,7 @@
 <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/html/load_time_data.html">
+<link rel="import" href="chrome://resources/html/md_select_css.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="set_time_browser_proxy.html">
@@ -23,9 +24,10 @@
 <body>
   <dom-module id="set-time">
     <template>
-      <style include="cr-shared-style paper-button-style">
+      <style include="cr-shared-style md-select paper-button-style">
         :host {
           @apply --cr-page-host;
+          user-select: none;
         }
 
         cr-dialog {
@@ -36,17 +38,43 @@
           }
         }
 
-        .row {
-          margin: 0.65em 0;
+        cr-dialog [slot=title] {
+          /* The native dialog caption area has enough visual whitespace. */
+          padding-top: 0;
         }
 
+        cr-dialog [slot=button-container] {
+          /* Align right edge of "Done" button with right edge of time input. */
+          padding-inline-end: 20px;
+        }
+
+        .row {
+          display: flex;
+          margin-top: 16px;
+        }
+
+        div.row:first-of-type {
+          margin-top: 0;
+        }
+
+        .column {
+          flex: 1;
+        }
+
+        /* Style to match md-select. */
         input[type='date'],
         input[type='time'] {
+          background-color: var(--google-grey-refresh-100);
+          border: none;
+          border-radius: 4px;
+          box-sizing: border-box;
+          color: var(--google-grey-900);
           font-family: inherit;
-          font-size: 16px;
-          letter-spacing: 1px;
-          margin-bottom: 4px;
-          margin-inline-end: 8px;
+          font-size: inherit;
+          /* Ensure space for focus border. */
+          margin-bottom: 2px;
+          padding: 6px 8px;
+          width: 100%;
         }
 
         input[type='date']::-webkit-clear-button,
@@ -54,13 +82,23 @@
           display: none;
         }
 
-        label {
-          margin-inline-end: 5px;
+        #timeColumn {
+          margin-inline-start: 20px;
+        }
+
+        #timezone {
+          display: block;
+          /* No bottom margin to minimize height of dialog body. */
+          margin-bottom: 0;
         }
 
         #timezoneSelect {
+          cursor: default;
           font-family: inherit;
           font-size: inherit;
+          /* Ensure space for focus border. */
+          margin-bottom: 2px;
+          width: 100%;
         }
       </style>
 
@@ -69,16 +107,26 @@
         <div slot="body" id="dialogBody">
           <div class="row">$i18n{prompt}</div>
 
-          <div>
-            <input id="dateInput" type="date" title="$i18n{dateLabel}"
-                on-blur="onTimeBlur_">
-            <input id="timeInput" type="time" title="$i18n{timeLabel}"
-                on-blur="onTimeBlur_">
+          <div class="row">
+            <div class="column">
+              <div id="label">$i18n{dateLabel}</div>
+              <input id="dateInput" type="date" aria-label="$i18n{dateLabel}"
+                  on-blur="onTimeBlur_">
+            </div>
+            <div class="column" id="timeColumn">
+              <div id="label">$i18n{timeLabel}</div>
+              <input id="timeInput" type="time" aria-label="$i18n{timeLabel}"
+                  on-blur="onTimeBlur_">
+            </div>
           </div>
 
           <div id="timezone" class="row" hidden>
-            <label for="timezoneSelect">$i18n{timezone}</label>
-            <select id="timezoneSelect" on-change="onTimezoneChange_"></select>
+            <div id="label">$i18n{timezoneLabel}</div>
+            <select id="timezoneSelect"
+                class="md-select"
+                aria-label="$i18n{timezoneLabel}"
+                on-change="onTimezoneChange_">
+            </select>
           </div>
         </div>
 
diff --git a/chrome/browser/resources/feed_internals/feed_internals.html b/chrome/browser/resources/feed_internals/feed_internals.html
index 5d4c9c00..78054e8 100644
--- a/chrome/browser/resources/feed_internals/feed_internals.html
+++ b/chrome/browser/resources/feed_internals/feed_internals.html
@@ -123,6 +123,15 @@
     </template>
   </div>
 
+  <h2>Feed Histograms</h2>
+  <button id="load-feed-histograms">
+    Load Feed Histograms
+  </button>
+  <details id="feed-histograms-details">
+    <summary>Show/Hide</summary>
+    <pre id="feed-histograms-log"></pre>
+  </details>
+
   <h2>Feed Process Scope</h2>
   <button id="dump-feed-process-scope">
     Dump Feed Process Scope
diff --git a/chrome/browser/resources/feed_internals/feed_internals.js b/chrome/browser/resources/feed_internals/feed_internals.js
index 224f5bd..02f22a2 100644
--- a/chrome/browser/resources/feed_internals/feed_internals.js
+++ b/chrome/browser/resources/feed_internals/feed_internals.js
@@ -142,6 +142,13 @@
       $('feed-process-scope-details').open = true;
     });
   });
+
+  $('load-feed-histograms').addEventListener('click', function() {
+    pageHandler.getFeedHistograms().then(response => {
+      $('feed-histograms-log').textContent = response.log;
+      $('feed-histograms-details').open = true;
+    });
+  });
 }
 
 document.addEventListener('DOMContentLoaded', function() {
diff --git a/chrome/browser/resources/ntp4/incognito_tab.css b/chrome/browser/resources/ntp4/incognito_tab.css
index 5a06e02..e4bdbe6 100644
--- a/chrome/browser/resources/ntp4/incognito_tab.css
+++ b/chrome/browser/resources/ntp4/incognito_tab.css
@@ -14,14 +14,13 @@
   /* This is identical to the default background color. It's necessary to set it
      for the case when a theme with a background image is installed. */
   background-color: rgb(50, 54, 57);
-  color: rgb(189, 193, 198);
+  color: rgb(232, 234, 237);  /* --google-grey-200 */
   font-size: calc(100% - 2px);
   line-height: calc(100% + 6px);
   min-width: 240px;
 }
 
 h1 {
-  color: rgb(218, 220, 224);
   font-size: calc(100% + 8px);
   font-weight: 400;
   line-height: calc(100% + 8px);
diff --git a/chrome/browser/resources/ntp4/incognito_tab.js b/chrome/browser/resources/ntp4/incognito_tab.js
index 8aaf797..b2d5eb7 100644
--- a/chrome/browser/resources/ntp4/incognito_tab.js
+++ b/chrome/browser/resources/ntp4/incognito_tab.js
@@ -33,7 +33,10 @@
   content.style.maxWidth = maxWidth + 'px';
 }
 
-window.addEventListener('load', recomputeLayoutWidth);
+window.addEventListener('load', function() {
+  recomputeLayoutWidth();
+  chrome.send('observeThemeChanges');
+});
 
 // Handle the bookmark bar, theme, and font size change requests
 // from the C++ side.
diff --git a/chrome/browser/resources/ntp4/new_tab.js b/chrome/browser/resources/ntp4/new_tab.js
index 0c3d114..88a3159 100644
--- a/chrome/browser/resources/ntp4/new_tab.js
+++ b/chrome/browser/resources/ntp4/new_tab.js
@@ -139,10 +139,11 @@
       newTabView.cardSlider.currentCardValue.navigationDot.classList.add(
           'selected');
 
-      cr.dispatchSimpleEvent(document, 'ntpLoaded', true, true);
       document.documentElement.classList.remove('starting-up');
 
       startTime = Date.now();
+
+      chrome.send('observeThemeChanges');
     });
   }
 
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
index 738f8af..da512b7 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -242,7 +242,6 @@
     this.networkProperties_ = {
       GUID: this.guid,
       Type: type,
-      ConnectionState: CrOnc.ConnectionState.NOT_CONNECTED,
       Name: {Active: name},
     };
     this.didSetFocus_ = false;
@@ -251,8 +250,17 @@
 
   close: function() {
     this.guid = '';
+
     // Delay navigating to allow other subpages to load first.
-    requestAnimationFrame(() => settings.navigateToPreviousRoute());
+    requestAnimationFrame(() => {
+      // Clear network properties before navigating away to ensure that a future
+      // navigation back to the details page does not show a flicker of
+      // incorrect text. See https://crbug.com/905986.
+      this.networkProperties_ = undefined;
+      this.networkPropertiesReceived_ = false;
+
+      settings.navigateToPreviousRoute();
+    });
   },
 
   /** @private */
@@ -585,8 +593,7 @@
   showDisconnect_: function(networkProperties) {
     return !!networkProperties &&
         networkProperties.Type != CrOnc.Type.ETHERNET &&
-        networkProperties.ConnectionState !=
-        CrOnc.ConnectionState.NOT_CONNECTED;
+        CrOnc.isConnectingOrConnected(networkProperties);
   },
 
   /**
@@ -654,8 +661,7 @@
       }
     }
     if ((type == CrOnc.Type.WI_FI || type == CrOnc.Type.WI_MAX) &&
-        networkProperties.ConnectionState !=
-            CrOnc.ConnectionState.NOT_CONNECTED) {
+        CrOnc.isConnectingOrConnected(networkProperties)) {
       return false;
     }
     if (this.isArcVpn_(networkProperties) &&
diff --git a/chrome/browser/resources/settings/people_page/users_add_user_dialog.html b/chrome/browser/resources/settings/people_page/users_add_user_dialog.html
index df9f676..7915b03 100644
--- a/chrome/browser/resources/settings/people_page/users_add_user_dialog.html
+++ b/chrome/browser/resources/settings/people_page/users_add_user_dialog.html
@@ -18,8 +18,9 @@
     <cr-dialog id="dialog" close-text="$i18n{close}">
       <div slot="title">$i18n{addUsers}</div>
       <div slot="body">
-        <cr-input id="addUserInput" label="$i18n{addUsersEmail}" autofocus
-            on-input="validate_" invalid="[[!isValid_]]">
+        <cr-input id="addUserInput" label="$i18n{addUsersEmail}"
+            invalid="[[shouldShowError_(isEmail_, isEmpty_)]]"
+            on-value-changed="onInput_" autofocus>
         </cr-input>
       </div>
       <div slot="button-container">
@@ -27,7 +28,7 @@
           $i18n{cancel}
         </paper-button>
         <paper-button on-click="addUser_" class="action-button"
-            disabled$="[[!isValid_]]">
+            disabled$="[[!canAddUser_(isEmail_, isEmpty_)]]">
           $i18n{add}
         </paper-button>
       </div>
diff --git a/chrome/browser/resources/settings/people_page/users_add_user_dialog.js b/chrome/browser/resources/settings/people_page/users_add_user_dialog.js
index 35fb0351..37210248 100644
--- a/chrome/browser/resources/settings/people_page/users_add_user_dialog.js
+++ b/chrome/browser/resources/settings/people_page/users_add_user_dialog.js
@@ -34,37 +34,30 @@
 
   properties: {
     /** @private */
-    isValid_: {
+    isEmail_: {
       type: Boolean,
       value: false,
     },
+
+    /** @private */
+    isEmpty_: {
+      type: Boolean,
+      value: true,
+    },
   },
 
   open: function() {
-    this.isValid_ = false;
+    this.$.addUserInput.value = '';
+    this.onInput_();
     this.$.dialog.showModal();
-  },
-
-  /** @private */
-  onCancelTap_: function() {
-    this.$.dialog.cancel();
-  },
-
-  /**
-   * Validates that the new user entered is valid.
-   * @private
-   * @return {boolean}
-   */
-  validate_: function() {
-    const input = this.$.addUserInput.value;
-    this.isValid_ = NAME_ONLY_REGEX.test(input) || EMAIL_REGEX.test(input);
-    return this.isValid_;
+    // Set to valid initially since the user has not typed anything yet.
+    this.$.addUserInput.invalid = false;
   },
 
   /** @private */
   addUser_: function() {
     // May be submitted by the Enter key even if the input value is invalid.
-    if (!this.validate_()) {
+    if (this.$.addUserInput.disabled) {
       return;
     }
 
@@ -87,6 +80,34 @@
     this.$.addUserInput.value = '';
     this.$.dialog.close();
   },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  canAddUser_: function() {
+    return this.isEmail_ && !this.isEmpty_;
+  },
+
+  /** @private */
+  onCancelTap_: function() {
+    this.$.dialog.cancel();
+  },
+
+  /** @private */
+  onInput_: function() {
+    const input = this.$.addUserInput.value;
+    this.isEmail_ = NAME_ONLY_REGEX.test(input) || EMAIL_REGEX.test(input);
+    this.isEmpty_ = input.length == 0;
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
+  shouldShowError_: function() {
+    return !this.isEmail_ && !this.isEmpty_;
+  },
 });
 
 })();
diff --git a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
index 437d19c..26c46a34 100644
--- a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
+++ b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
@@ -187,15 +187,14 @@
               value="{{activePrinter.ppdModel}}">
           </cr-searchable-drop-down>
         </div>
-        <div class="settings-box two-line last">
+        <div class="settings-box two-line">
           <cr-input class="browse-file-input" readonly value="[[newUserPPD_]]"
               label="$i18n{selectDriver}" invalid="[[invalidPPD_]]"
               error-message="$i18n{selectDriverErrorMessage}" tabindex="-1">
-            <paper-button class="browse-button" on-click="onBrowseFile_"
-                slot="suffix">
-              $i18n{selectDriverButtonText}
-            </paper-button>
           </cr-input>
+          <paper-button class="browse-button" on-click="onBrowseFile_">
+            $i18n{selectDriverButtonText}
+          </paper-button>
         </div>
       </div>
       <div slot="dialog-buttons">
diff --git a/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html b/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html
index 7086f2d50..23eef54 100644
--- a/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html
+++ b/chrome/browser/resources/settings/printing_page/cups_edit_printer_dialog.html
@@ -12,15 +12,7 @@
 
 <dom-module id="settings-cups-edit-printer-dialog">
   <template>
-    <style include="cups-printer-shared">
-      /* This is needed to line up the existing PDD text with cr-input.
-         TODO(scottchen): move away from using .settings-box just for margin,
-         and then remove this hacky alignment. */
-      .last {
-        align-items: start;
-        flex-direction: column;
-      }
-    </style>
+    <style include="cups-printer-shared"> </style>
     <add-printer-dialog>
       <div slot="dialog-title">$i18n{editPrinterDialogTitle}</div>
       <div slot="dialog-body" scrollable>
@@ -102,16 +94,15 @@
               value="{{activePrinter.ppdModel}}">
           </cr-searchable-drop-down>
         </div>
-        <div class="settings-box two-line last">
+        <div class="settings-box two-line">
           <cr-input class="browse-file-input" readonly tabindex="-1"
               value="[[newUserPPD_]]" label="$i18n{selectDriver}"
               error-message="$i18n{selectDriverErrorMessage}"
               invalid="[[invalidPPD_]]">
-            <paper-button class="browse-button" on-click="onBrowseFile_"
-                slot="suffix">
-              $i18n{selectDriverButtonText}
-            </paper-button>
           </cr-input>
+          <paper-button class="browse-button" on-click="onBrowseFile_">
+            $i18n{selectDriverButtonText}
+          </paper-button>
           <template is="dom-if" if="[[existingUserPPDMessage_]]">
             <div class="secondary" id="existingUserPPD">
               [[existingUserPPDMessage_]]
diff --git a/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html b/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html
index 8b3f8c47..dc5d1fb7 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html
+++ b/chrome/browser/resources/settings/printing_page/cups_printer_shared_css.html
@@ -47,7 +47,8 @@
       }
 
       [slot='dialog-body'] .settings-box .browse-button {
-        margin-inline-start: 5px;
+        margin-bottom: 8px;
+        margin-inline-start: 12px;
       }
 
       [slot='dialog-body'] .last {
diff --git a/chrome/browser/send_tab_to_self/receiving_ui_handler.h b/chrome/browser/send_tab_to_self/receiving_ui_handler.h
index 65bd57053..d1125f1 100644
--- a/chrome/browser/send_tab_to_self/receiving_ui_handler.h
+++ b/chrome/browser/send_tab_to_self/receiving_ui_handler.h
@@ -27,8 +27,7 @@
   // Dismiss any UI associated with this entry.
   // Entry object is owned by the the model and should not be
   // modified by any implementors of this class.
-  // TODO(crbug.com/935719): Figure out whether we need to pass the entire entry
-  // or we can pass a smaller subset of information.
+  // TODO(crbug.com/944591): Pass a string at a time instead.
   virtual void DismissEntries(const std::vector<std::string>& guids) = 0;
 };
 
diff --git a/chrome/browser/send_tab_to_self/receiving_ui_handler_registry.cc b/chrome/browser/send_tab_to_self/receiving_ui_handler_registry.cc
index 61a6148d..1ad569aa 100644
--- a/chrome/browser/send_tab_to_self/receiving_ui_handler_registry.cc
+++ b/chrome/browser/send_tab_to_self/receiving_ui_handler_registry.cc
@@ -41,8 +41,8 @@
 #endif
 }
 
-std::vector<std::unique_ptr<ReceivingUiHandler>>&
-ReceivingUiHandlerRegistry::GetHandlers() {
+const std::vector<std::unique_ptr<ReceivingUiHandler>>&
+ReceivingUiHandlerRegistry::GetHandlers() const {
   return applicable_handlers_;
 }
 
diff --git a/chrome/browser/send_tab_to_self/receiving_ui_handler_registry.h b/chrome/browser/send_tab_to_self/receiving_ui_handler_registry.h
index f8e5d3d..45e5b3b2 100644
--- a/chrome/browser/send_tab_to_self/receiving_ui_handler_registry.h
+++ b/chrome/browser/send_tab_to_self/receiving_ui_handler_registry.h
@@ -33,7 +33,7 @@
 
   // Returns all the handlers to perform UI updates for the platform.
   // Called by the SendTabToSelfClientService.
-  std::vector<std::unique_ptr<ReceivingUiHandler>>& GetHandlers();
+  const std::vector<std::unique_ptr<ReceivingUiHandler>>& GetHandlers() const;
 
  private:
   friend struct base::DefaultSingletonTraits<ReceivingUiHandlerRegistry>;
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_client_service.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_client_service.cc
index f3f1862..b692b73 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_client_service.cc
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_client_service.cc
@@ -21,8 +21,7 @@
   model_ = model;
   model_->AddObserver(this);
 
-  registry_ = ReceivingUiHandlerRegistry::GetInstance();
-  registry_->InstantiatePlatformSpecificHandlers(profile);
+  SetupHandlerRegistry(profile);
 }
 
 SendTabToSelfClientService::~SendTabToSelfClientService() {
@@ -37,8 +36,7 @@
 void SendTabToSelfClientService::EntriesAddedRemotely(
     const std::vector<const SendTabToSelfEntry*>& new_entries) {
   for (const SendTabToSelfEntry* entry : new_entries) {
-    for (std::unique_ptr<ReceivingUiHandler>& handler :
-         registry_->GetHandlers()) {
+    for (const std::unique_ptr<ReceivingUiHandler>& handler : GetHandlers()) {
       handler->DisplayNewEntry(entry);
     }
   }
@@ -46,10 +44,19 @@
 
 void SendTabToSelfClientService::EntriesRemovedRemotely(
     const std::vector<std::string>& guids) {
-  for (std::unique_ptr<ReceivingUiHandler>& handler :
-       registry_->GetHandlers()) {
+  for (const std::unique_ptr<ReceivingUiHandler>& handler : GetHandlers()) {
     handler->DismissEntries(guids);
   }
 }
 
+void SendTabToSelfClientService::SetupHandlerRegistry(Profile* profile) {
+  registry_ = ReceivingUiHandlerRegistry::GetInstance();
+  registry_->InstantiatePlatformSpecificHandlers(profile);
+}
+
+const std::vector<std::unique_ptr<ReceivingUiHandler>>&
+SendTabToSelfClientService::GetHandlers() const {
+  return registry_->GetHandlers();
+}
+
 }  // namespace send_tab_to_self
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_client_service.h b/chrome/browser/send_tab_to_self/send_tab_to_self_client_service.h
index 4fc750e..0478846c 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_client_service.h
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_client_service.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "chrome/browser/send_tab_to_self/receiving_ui_handler.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/send_tab_to_self/send_tab_to_self_model.h"
 #include "components/send_tab_to_self/send_tab_to_self_model_observer.h"
@@ -41,6 +42,13 @@
  protected:
   ~SendTabToSelfClientService() override;
 
+  // Sets up the ReceivingUiHandlerRegistry.
+  virtual void SetupHandlerRegistry(Profile* profile);
+
+  // Returns a vector containing the registered ReceivingUiHandlers.
+  virtual const std::vector<std::unique_ptr<ReceivingUiHandler>>& GetHandlers()
+      const;
+
  private:
   // Owned by the SendTabToSelfSyncService which should outlive this class
   SendTabToSelfModel* model_;
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_unittest.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_unittest.cc
new file mode 100644
index 0000000..58da259
--- /dev/null
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/send_tab_to_self/send_tab_to_self_client_service.h"
+
+#include <memory>
+
+#include "base/time/time.h"
+#include "chrome/browser/send_tab_to_self/receiving_ui_handler.h"
+#include "components/send_tab_to_self/send_tab_to_self_model.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace send_tab_to_self {
+
+namespace {
+
+// A fake version of the SendTabToSelf model that doesn't do anything and return
+// null pointers. Needed to setup the SendTabToSelfClientService.
+class FakeSendTabToSelfModel : public SendTabToSelfModel {
+ public:
+  FakeSendTabToSelfModel() = default;
+  ~FakeSendTabToSelfModel() override = default;
+
+  std::vector<std::string> GetAllGuids() const override { return {}; }
+  void DeleteAllEntries() override {}
+  const SendTabToSelfEntry* GetEntryByGUID(
+      const std::string& guid) const override {
+    return nullptr;
+  }
+  const SendTabToSelfEntry* AddEntry(const GURL& url,
+                                     const std::string& title,
+                                     base::Time navigation_time) override {
+    return nullptr;
+  }
+  void DeleteEntry(const std::string& guid) override {}
+  void DismissEntry(const std::string& guid) override {}
+};
+
+// A test ReceivingUiHandler that keeps track of the number of entries for which
+// DisplayNewEntry was called.
+class TestReceivingUiHandler : public ReceivingUiHandler {
+ public:
+  TestReceivingUiHandler() = default;
+  ~TestReceivingUiHandler() override {}
+
+  void DisplayNewEntry(const SendTabToSelfEntry* entry) override {
+    ++number_displayed_entries_;
+  }
+
+  void DismissEntries(const std::vector<std::string>& guids) override {}
+
+  size_t number_displayed_entries() const { return number_displayed_entries_; }
+
+ private:
+  size_t number_displayed_entries_ = 0;
+};
+
+// A test SendTabToSelfClientService that exposes the TestReceivingUiHandler.
+class TestSendTabToSelfClientService : public SendTabToSelfClientService {
+ public:
+  explicit TestSendTabToSelfClientService(SendTabToSelfModel* model)
+      : SendTabToSelfClientService(nullptr, model) {}
+
+  ~TestSendTabToSelfClientService() override = default;
+
+  void SetupHandlerRegistry(Profile* profile) override {}
+
+  TestReceivingUiHandler* SetupTestHandler() {
+    test_handlers_.clear();
+    std::unique_ptr<TestReceivingUiHandler> handler =
+        std::make_unique<TestReceivingUiHandler>();
+    TestReceivingUiHandler* handler_ptr = handler.get();
+    test_handlers_.push_back(std::move(handler));
+    return handler_ptr;
+  }
+
+  const std::vector<std::unique_ptr<ReceivingUiHandler>>& GetHandlers()
+      const override {
+    return test_handlers_;
+  }
+
+ protected:
+  std::vector<std::unique_ptr<ReceivingUiHandler>> test_handlers_;
+};
+
+// Tests that the UI handlers gets notified of each entries that were added
+// remotely.
+TEST(SendTabToSelfClientServiceTest, MultipleEntriesAdded) {
+  // Set up the test objects.
+  FakeSendTabToSelfModel fake_model_;
+  TestSendTabToSelfClientService client_service(&fake_model_);
+  TestReceivingUiHandler* test_handler = client_service.SetupTestHandler();
+
+  // Create 2 entries and simulated that they were both added remotely.
+  SendTabToSelfEntry entry1("a", GURL("http://www.example-a.com"), "a site",
+                            base::Time(), base::Time(), "device a");
+  SendTabToSelfEntry entry2("b", GURL("http://www.example-b.com"), "b site",
+                            base::Time(), base::Time(), "device b");
+  client_service.EntriesAddedRemotely({&entry1, &entry2});
+
+  EXPECT_EQ(2u, test_handler->number_displayed_entries());
+}
+
+}  // namespace
+
+}  // namespace send_tab_to_self
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index a97b211..18e2d3f 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -265,7 +265,6 @@
     TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE,
     TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_ACTIVE,
     TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_INACTIVE,
-    TP::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND,
     TP::COLOR_INFOBAR,
     TP::COLOR_DOWNLOAD_SHELF,
     TP::COLOR_STATUS_BUBBLE,
@@ -1373,7 +1372,6 @@
   // was introduced).
   SkColor toolbar_color;
   if (GetColor(TP::COLOR_TOOLBAR, &toolbar_color)) {
-    SetColor(TP::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND, toolbar_color);
     SetColor(TP::COLOR_INFOBAR, toolbar_color);
     SetColor(TP::COLOR_DOWNLOAD_SHELF, toolbar_color);
     SetColor(TP::COLOR_STATUS_BUBBLE, toolbar_color);
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index b0595bc0..bce43a0f 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -1011,19 +1011,15 @@
                           pack.get());
 
   SkColor infobar_color;
-  SkColor bookmark_bar_color;
   SkColor download_shelf_color;
   SkColor status_bubble_color;
 
   EXPECT_TRUE(pack->GetColor(TP::COLOR_INFOBAR, &infobar_color));
-  EXPECT_TRUE(pack->GetColor(TP::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND,
-                             &bookmark_bar_color));
   EXPECT_TRUE(pack->GetColor(TP::COLOR_DOWNLOAD_SHELF, &download_shelf_color));
   EXPECT_TRUE(pack->GetColor(TP::COLOR_STATUS_BUBBLE, &status_bubble_color));
 
   constexpr SkColor kExpectedColor = SkColorSetRGB(0, 255, 0);
   EXPECT_EQ(infobar_color, kExpectedColor);
-  EXPECT_EQ(infobar_color, bookmark_bar_color);
   EXPECT_EQ(infobar_color, download_shelf_color);
   EXPECT_EQ(infobar_color, status_bubble_color);
 }
@@ -1036,19 +1032,15 @@
   BuildTestExtensionTheme("theme_test_toolbar_color_no_image", pack.get());
 
   SkColor infobar_color;
-  SkColor bookmark_bar_color;
   SkColor download_shelf_color;
   SkColor status_bubble_color;
 
   EXPECT_TRUE(pack->GetColor(TP::COLOR_INFOBAR, &infobar_color));
-  EXPECT_TRUE(pack->GetColor(TP::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND,
-                             &bookmark_bar_color));
   EXPECT_TRUE(pack->GetColor(TP::COLOR_DOWNLOAD_SHELF, &download_shelf_color));
   EXPECT_TRUE(pack->GetColor(TP::COLOR_STATUS_BUBBLE, &status_bubble_color));
 
   constexpr SkColor kExpectedColor = SkColorSetRGB(0, 255, 0);
   EXPECT_EQ(infobar_color, kExpectedColor);
-  EXPECT_EQ(infobar_color, bookmark_bar_color);
   EXPECT_EQ(infobar_color, download_shelf_color);
   EXPECT_EQ(infobar_color, status_bubble_color);
 }
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc
index 065a69d..0257cdf4 100644
--- a/chrome/browser/themes/theme_properties.cc
+++ b/chrome/browser/themes/theme_properties.cc
@@ -46,7 +46,6 @@
     case ThemeProperties::COLOR_STATUS_BUBBLE:
     case ThemeProperties::COLOR_INFOBAR:
     case ThemeProperties::COLOR_TOOLBAR:
-    case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND:
     case ThemeProperties::COLOR_NTP_BACKGROUND:
       return SkColorSetRGB(0x32, 0x36, 0x39);
     case ThemeProperties::COLOR_BOOKMARK_TEXT:
@@ -254,13 +253,6 @@
       return gfx::kGoogleBlue600;
     case COLOR_CONTROL_BACKGROUND:
       return SK_ColorWHITE;
-    case COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR:
-      // We shouldn't reach this case because the color is calculated from
-      // others.
-      NOTREACHED();
-      return gfx::kPlaceholderColor;
-    case COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND:
-      return SK_ColorWHITE;
     case COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR:
       return SkColorSetRGB(0xB6, 0xB4, 0xB6);
     case COLOR_TOOLBAR_TOP_SEPARATOR:
diff --git a/chrome/browser/themes/theme_properties.h b/chrome/browser/themes/theme_properties.h
index e10916a..0db9494 100644
--- a/chrome/browser/themes/theme_properties.h
+++ b/chrome/browser/themes/theme_properties.h
@@ -110,10 +110,6 @@
     // shelf.
     COLOR_TOOLBAR_VERTICAL_SEPARATOR,
 
-    // Colors used for the detached (NTP) bookmark bar.
-    COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND,
-    COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR,
-
     // Color used for various 'shelves' and 'bars'.
     COLOR_DOWNLOAD_SHELF,
     COLOR_INFOBAR,
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index 52fe12b..eae7007 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -614,14 +614,6 @@
       if (UsingDefaultTheme())
         break;
       return GetColor(ThemeProperties::COLOR_LOCATION_BAR_BORDER, incognito);
-    case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND:
-      if (UsingDefaultTheme())
-        break;
-      return GetColor(ThemeProperties::COLOR_TOOLBAR, incognito);
-    case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR:
-      // Use a faint version of the text color as the separator color.
-      return SkColorSetA(
-          GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT, incognito), 0x26);
     case ThemeProperties::COLOR_NTP_TEXT_LIGHT:
       return IncreaseLightness(GetColor(kNtpText, incognito), 0.40);
     case ThemeProperties::COLOR_TAB_THROBBER_SPINNING:
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index db993e16..50341e58 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1050,8 +1050,6 @@
       "tabs/tab_switch_event_latency_recorder.h",
       "tabs/tab_utils.cc",
       "tabs/tab_utils.h",
-      "tabs/window_activity_watcher.cc",
-      "tabs/window_activity_watcher.h",
       "task_manager/task_manager_columns.cc",
       "task_manager/task_manager_columns.h",
       "task_manager/task_manager_table_model.cc",
diff --git a/chrome/browser/ui/app_list/app_service_app_item.cc b/chrome/browser/ui/app_list/app_service_app_item.cc
index e158a87..f993165f 100644
--- a/chrome/browser/ui/app_list/app_service_app_item.cc
+++ b/chrome/browser/ui/app_list/app_service_app_item.cc
@@ -128,7 +128,8 @@
 void AppServiceAppItem::CallLoadIcon(bool allow_placeholder_icon) {
   apps::AppServiceProxy* proxy = apps::AppServiceProxy::Get(profile());
   if (proxy) {
-    proxy->LoadIcon(id(), apps::mojom::IconCompression::kUncompressed,
+    proxy->LoadIcon(app_type_, id(),
+                    apps::mojom::IconCompression::kUncompressed,
                     app_list::AppListConfig::instance().grid_icon_dimension(),
                     allow_placeholder_icon,
                     base::BindOnce(&AppServiceAppItem::OnLoadIcon,
diff --git a/chrome/browser/ui/app_list/search/app_service_app_result.cc b/chrome/browser/ui/app_list/search/app_service_app_result.cc
index 2bfd6c1..02215215 100644
--- a/chrome/browser/ui/app_list/search/app_service_app_result.cc
+++ b/chrome/browser/ui/app_list/search/app_service_app_result.cc
@@ -126,7 +126,7 @@
   apps::AppServiceProxy* proxy = apps::AppServiceProxy::Get(profile());
   if (proxy) {
     proxy->LoadIcon(
-        app_id(), apps::mojom::IconCompression::kUncompressed,
+        app_type_, app_id(), apps::mojom::IconCompression::kUncompressed,
         chip ? AppListConfig::instance().suggestion_chip_icon_dimension()
              : AppListConfig::instance().GetPreferredIconDimension(
                    display_type()),
diff --git a/chrome/browser/ui/autofill/autofill_ui_util.cc b/chrome/browser/ui/autofill/autofill_ui_util.cc
index fcd3e04..96fc99f 100644
--- a/chrome/browser/ui/autofill/autofill_ui_util.cc
+++ b/chrome/browser/ui/autofill/autofill_ui_util.cc
@@ -16,7 +16,8 @@
 
 namespace autofill {
 
-void UpdateLocalCardMigrationIcon(content::WebContents* web_contents) {
+void UpdateCreditCardIcon(PageActionIconType icon_type,
+                          content::WebContents* web_contents) {
 #if !defined(OS_ANDROID)
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
   if (!browser)
@@ -31,15 +32,27 @@
     if (!toolbar_page_action_container)
       return;
 
-    toolbar_page_action_container->UpdatePageActionIcon(
-        PageActionIconType::kLocalCardMigration);
+    toolbar_page_action_container->UpdatePageActionIcon(icon_type);
   } else {
     // Otherwise the icon will be in the LocationBar.
     LocationBar* location_bar = browser->window()->GetLocationBar();
     if (!location_bar)
       return;
 
-    location_bar->UpdateLocalCardMigrationIcon();
+    switch (icon_type) {
+      case PageActionIconType::kLocalCardMigration:
+        location_bar->UpdateLocalCardMigrationIcon();
+        break;
+      case PageActionIconType::kSaveCard:
+        location_bar->UpdateSaveCreditCardIcon();
+        break;
+      case PageActionIconType::kFind:
+      case PageActionIconType::kManagePasswords:
+      case PageActionIconType::kPwaInstall:
+      case PageActionIconType::kTranslate:
+      case PageActionIconType::kZoom:
+        NOTREACHED();
+    }
   }
 #endif
 }
diff --git a/chrome/browser/ui/autofill/autofill_ui_util.h b/chrome/browser/ui/autofill/autofill_ui_util.h
index 9f3c054d..21317e5 100644
--- a/chrome/browser/ui/autofill/autofill_ui_util.h
+++ b/chrome/browser/ui/autofill/autofill_ui_util.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_UI_UTIL_H_
 #define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_UI_UTIL_H_
 
+#include "chrome/browser/ui/page_action/page_action_icon_container.h"
 #include "content/public/browser/web_contents.h"
 
 namespace autofill {
@@ -13,8 +14,9 @@
 // ToolbarPageActionContainerView once the status chip is fully
 // launched.
 
-// Update the state of local card migration icon view.
-void UpdateLocalCardMigrationIcon(content::WebContents* web_contents);
+// Update the state of credit card icon.
+void UpdateCreditCardIcon(PageActionIconType icon_type,
+                          content::WebContents* web_contents);
 
 }  // namespace autofill
 
diff --git a/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl.cc b/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl.cc
index b4d5e8e..19a7cd0c 100644
--- a/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl.cc
@@ -101,7 +101,7 @@
 
 void LocalCardMigrationBubbleControllerImpl::OnBubbleClosed() {
   local_card_migration_bubble_ = nullptr;
-  UpdateLocalCardMigrationIcon(web_contents());
+  UpdateLocalCardMigrationIcon();
   if (should_add_strikes_on_bubble_close_ &&
       base::FeatureList::IsEnabled(
           features::kAutofillLocalCardMigrationUsesStrikeSystemV2)) {
@@ -142,7 +142,7 @@
     local_card_migration_bubble_->Hide();
     OnBubbleClosed();
   } else {
-    UpdateLocalCardMigrationIcon(web_contents());
+    UpdateLocalCardMigrationIcon();
   }
 
   AutofillMetrics::LogLocalCardMigrationBubbleUserInteractionMetric(
@@ -170,20 +170,25 @@
 
   // Update the visibility and toggled state of the credit card icon in either
   // Location bar or in Status Chip.
-  UpdateLocalCardMigrationIcon(web_contents());
+  UpdateLocalCardMigrationIcon();
 
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   local_card_migration_bubble_ =
       browser->window()->ShowLocalCardMigrationBubble(web_contents(), this,
                                                       is_reshow_);
   DCHECK(local_card_migration_bubble_);
-  UpdateLocalCardMigrationIcon(web_contents());
+  UpdateLocalCardMigrationIcon();
   timer_.reset(new base::ElapsedTimer());
 
   AutofillMetrics::LogLocalCardMigrationBubbleOfferMetric(
       AutofillMetrics::LOCAL_CARD_MIGRATION_BUBBLE_SHOWN, is_reshow_);
 }
 
+void LocalCardMigrationBubbleControllerImpl::UpdateLocalCardMigrationIcon() {
+  ::autofill::UpdateCreditCardIcon(PageActionIconType::kLocalCardMigration,
+                                   web_contents());
+}
+
 void LocalCardMigrationBubbleControllerImpl::AddStrikesForBubbleClose() {
   LocalCardMigrationStrikeDatabase local_card_migration_strike_database(
       StrikeDatabaseFactory::GetForProfile(
diff --git a/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl.h b/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl.h
index fd512e3..3f653d2ff 100644
--- a/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl.h
+++ b/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl.h
@@ -69,6 +69,8 @@
 
   void ShowBubbleImplementation();
 
+  void UpdateLocalCardMigrationIcon();
+
   // Add strikes for local card migration, to be called on user closing the
   // promo bubble.
   void AddStrikesForBubbleClose();
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
index 90c5994..1d072e7 100644
--- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
@@ -69,14 +69,14 @@
 
   view_state_ = LocalCardMigrationDialogState::kOffered;
   // Need to create the icon first otherwise the dialog will not be shown.
-  UpdateLocalCardMigrationIcon(web_contents());
+  UpdateLocalCardMigrationIcon();
   local_card_migration_dialog_ =
       CreateLocalCardMigrationDialogView(this, web_contents());
   start_migrating_cards_callback_ = std::move(start_migrating_cards_callback);
   migratable_credit_cards_ = migratable_credit_cards;
   user_email_ = user_email;
   local_card_migration_dialog_->ShowDialog();
-  UpdateLocalCardMigrationIcon(web_contents());
+  UpdateLocalCardMigrationIcon();
   dialog_is_visible_duration_timer_ = base::ElapsedTimer();
 
   AutofillMetrics::LogLocalCardMigrationDialogOfferMetric(
@@ -102,7 +102,7 @@
       break;
     }
   }
-  UpdateLocalCardMigrationIcon(web_contents());
+  UpdateLocalCardMigrationIcon();
 }
 
 void LocalCardMigrationDialogControllerImpl::ShowFeedbackDialog() {
@@ -112,7 +112,7 @@
   local_card_migration_dialog_ =
       CreateLocalCardMigrationDialogView(this, web_contents());
   local_card_migration_dialog_->ShowDialog();
-  UpdateLocalCardMigrationIcon(web_contents());
+  UpdateLocalCardMigrationIcon();
   dialog_is_visible_duration_timer_ = base::ElapsedTimer();
 }
 
@@ -122,7 +122,7 @@
 
   local_card_migration_dialog_ =
       CreateLocalCardMigrationErrorDialogView(this, web_contents());
-  UpdateLocalCardMigrationIcon(web_contents());
+  UpdateLocalCardMigrationIcon();
   local_card_migration_dialog_->ShowDialog();
   dialog_is_visible_duration_timer_ = base::ElapsedTimer();
 }
@@ -243,7 +243,7 @@
   if (local_card_migration_dialog_)
     local_card_migration_dialog_ = nullptr;
 
-  UpdateLocalCardMigrationIcon(web_contents());
+  UpdateLocalCardMigrationIcon();
 }
 
 bool LocalCardMigrationDialogControllerImpl::AllCardsInvalid() const {
@@ -273,6 +273,11 @@
       ui::PAGE_TRANSITION_LINK, false));
 }
 
+void LocalCardMigrationDialogControllerImpl::UpdateLocalCardMigrationIcon() {
+  ::autofill::UpdateCreditCardIcon(PageActionIconType::kLocalCardMigration,
+                                   web_contents());
+}
+
 bool LocalCardMigrationDialogControllerImpl::HasFailedCard() const {
   return std::find_if(
              migratable_credit_cards_.begin(), migratable_credit_cards_.end(),
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
index 3da8ab01..0da5b5e 100644
--- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
@@ -86,6 +86,8 @@
 
   void OpenUrl(const GURL& url);
 
+  void UpdateLocalCardMigrationIcon();
+
   // The dialog is showing cards of which the migration failed. We will show
   // the "Almost done" dialog in this case.
   bool HasFailedCard() const;
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
index ff9e36b..7a9ab184 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/ui/autofill/autofill_ui_util.h"
 #include "chrome/browser/ui/autofill/popup_constants.h"
 #include "chrome/browser/ui/autofill/save_card_bubble_view.h"
 #include "chrome/browser/ui/autofill/save_card_ui.h"
@@ -23,6 +24,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
+#include "chrome/browser/ui/page_action/page_action_icon_container.h"
 #include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/common/url_constants.h"
 #include "components/autofill/core/browser/autofill_experiments.h"
@@ -325,7 +327,7 @@
     case BubbleType::LOCAL_SAVE:
       DCHECK(!local_save_card_prompt_callback_.is_null());
       // Show an animated card saved confirmation message next time
-      // UpdateIcon() is called.
+      // UpdateSaveCardIcon() is called.
       can_animate_ = base::FeatureList::IsEnabled(
           features::kAutofillSaveCardSignInAfterLocalSave);
 
@@ -422,14 +424,14 @@
   // reopening the bubble will show the card management bubble.
   if (current_bubble_type_ == BubbleType::SIGN_IN_PROMO)
     current_bubble_type_ = BubbleType::MANAGE_CARDS;
-  UpdateIcon();
+  UpdateSaveCardIcon();
   if (observer_for_testing_)
     observer_for_testing_->OnBubbleClosed();
 }
 
 void SaveCardBubbleControllerImpl::OnAnimationEnded() {
-  // Do not repeat the animation next time UpdateIcon() is called, unless
-  // explicitly set somewhere else.
+  // Do not repeat the animation next time UpdateSaveCardIcon() is called,
+  // unless explicitly set somewhere else.
   can_animate_ = false;
 
   // We do not want to show the promo if the user clicked on the icon and the
@@ -484,7 +486,7 @@
     save_card_bubble_view_->Hide();
     OnBubbleClosed();
   } else {
-    UpdateIcon();
+    UpdateSaveCardIcon();
   }
 
   if (previous_bubble_type == BubbleType::LOCAL_SAVE ||
@@ -544,7 +546,7 @@
 
   // Need to create location bar icon before bubble, otherwise bubble will be
   // unanchored.
-  UpdateIcon();
+  UpdateSaveCardIcon();
 
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   save_card_bubble_view_ = browser->window()->ShowSaveCreditCardBubble(
@@ -553,7 +555,7 @@
 
   // Update icon after creating |save_card_bubble_view_| so that icon will show
   // its "toggled on" state.
-  UpdateIcon();
+  UpdateSaveCardIcon();
 
   bubble_shown_timestamp_ = AutofillClock::Now();
 
@@ -594,7 +596,7 @@
 
   // Show the icon only. The bubble can still be displayed if the user
   // explicitly clicks the icon.
-  UpdateIcon();
+  UpdateSaveCardIcon();
 
   bubble_shown_timestamp_ = AutofillClock::Now();
 
@@ -615,12 +617,9 @@
   }
 }
 
-void SaveCardBubbleControllerImpl::UpdateIcon() {
-  Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
-  if (!browser)
-    return;
-  LocationBar* location_bar = browser->window()->GetLocationBar();
-  location_bar->UpdateSaveCreditCardIcon();
+void SaveCardBubbleControllerImpl::UpdateSaveCardIcon() {
+  ::autofill::UpdateCreditCardIcon(PageActionIconType::kSaveCard,
+                                   web_contents());
 }
 
 void SaveCardBubbleControllerImpl::OpenUrl(const GURL& url) {
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
index 203aa75c..637d9c2 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
@@ -151,8 +151,7 @@
   // Displays the omnibox icon without popping up the offer-to-save bubble.
   void ShowIconOnly();
 
-  // Update the visibility and toggled state of the Omnibox save card icon.
-  void UpdateIcon();
+  void UpdateSaveCardIcon();
 
   void OpenUrl(const GURL& url);
 
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.cc b/chrome/browser/ui/libgtkui/gtk_ui.cc
index 8733e118..98505d4 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.cc
+++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -836,8 +836,6 @@
   colors_[ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR] = tab_border;
   // Separates entries in the downloads bar.
   colors_[ThemeProperties::COLOR_TOOLBAR_VERTICAL_SEPARATOR] = tab_border;
-  // Separates the detached bookmark bar from the NTP.
-  colors_[ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR] = tab_border;
 
   colors_[ThemeProperties::COLOR_NTP_BACKGROUND] =
       native_theme_->GetSystemColor(
@@ -912,9 +910,6 @@
     color_map[ThemeProperties::COLOR_TOOLBAR] = tab_color;
     color_map[ThemeProperties::COLOR_CONTROL_BACKGROUND] = tab_color;
 
-    color_map[ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND] =
-        tab_color;
-
     const SkColor background_tab_text_color =
         GetFgColor(header_selector + " GtkLabel.title");
     const SkColor background_tab_text_color_inactive =
diff --git a/chrome/browser/ui/page_action/page_action_icon_container.h b/chrome/browser/ui/page_action/page_action_icon_container.h
index 7d01f70..08fe659e 100644
--- a/chrome/browser/ui/page_action/page_action_icon_container.h
+++ b/chrome/browser/ui/page_action/page_action_icon_container.h
@@ -12,6 +12,7 @@
   kLocalCardMigration,
   kManagePasswords,
   kPwaInstall,
+  kSaveCard,
   kTranslate,
   kZoom,
 };
diff --git a/chrome/browser/ui/tabs/window_activity_watcher.cc b/chrome/browser/ui/tabs/window_activity_watcher.cc
deleted file mode 100644
index 7915d58..0000000
--- a/chrome/browser/ui/tabs/window_activity_watcher.cc
+++ /dev/null
@@ -1,239 +0,0 @@
-// 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.
-
-#include "chrome/browser/ui/tabs/window_activity_watcher.h"
-
-#include "base/logging.h"
-#include "base/optional.h"
-#include "base/scoped_observer.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/resource_coordinator/tab_metrics_event.pb.h"
-#include "chrome/browser/resource_coordinator/tab_ranker/window_features.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "services/metrics/public/cpp/metrics_utils.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
-#include "services/metrics/public/cpp/ukm_source_id.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/window.h"
-#endif
-
-using metrics::WindowMetricsEvent;
-using tab_ranker::WindowFeatures;
-
-namespace {
-
-// Sets feature values that are dependent on the current window state.
-void UpdateWindowFeatures(const Browser* browser,
-                          WindowFeatures* window_features,
-                          bool is_active) {
-  DCHECK(browser->window());
-
-  // TODO(michaelpg): Observe the show state and log when it changes.
-  if (browser->window()->IsFullscreen())
-    window_features->show_state = WindowMetricsEvent::SHOW_STATE_FULLSCREEN;
-  else if (browser->window()->IsMinimized())
-    window_features->show_state = WindowMetricsEvent::SHOW_STATE_MINIMIZED;
-  else if (browser->window()->IsMaximized())
-    window_features->show_state = WindowMetricsEvent::SHOW_STATE_MAXIMIZED;
-  else
-    window_features->show_state = WindowMetricsEvent::SHOW_STATE_NORMAL;
-
-  window_features->is_active = is_active;
-  window_features->tab_count = browser->tab_strip_model()->count();
-}
-
-// Returns a populated WindowFeatures for the browser.
-// |is_active| is provided because IsActive() may be incorrect while browser
-// activation is changing (namely, when deactivating a window on Windows).
-WindowFeatures CreateWindowFeatures(const Browser* browser, bool is_active) {
-  WindowMetricsEvent::Type window_type = WindowMetricsEvent::TYPE_UNKNOWN;
-  switch (browser->type()) {
-    case Browser::TYPE_TABBED:
-      window_type = WindowMetricsEvent::TYPE_TABBED;
-      break;
-    case Browser::TYPE_POPUP:
-      window_type = WindowMetricsEvent::TYPE_POPUP;
-      break;
-    default:
-      NOTREACHED();
-  }
-
-  WindowFeatures window_features(browser->session_id(), window_type);
-  UpdateWindowFeatures(browser, &window_features, is_active);
-  return window_features;
-}
-
-// Logs a UKM entry with the metrics from |window_features|.
-void LogWindowMetricsUkmEntry(const WindowFeatures& window_features) {
-  ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
-  if (!ukm_recorder)
-    return;
-
-  ukm::builders::TabManager_WindowMetrics entry(ukm::AssignNewSourceId());
-  entry.SetWindowId(window_features.window_id.id())
-      .SetIsActive(window_features.is_active)
-      .SetShowState(window_features.show_state)
-      .SetType(window_features.type);
-
-  // Bucketize values for privacy considerations. Use a spacing factor that
-  // ensures values up to 3 can be logged exactly; after that, the precise
-  // number becomes less significant.
-  int tab_count = window_features.tab_count;
-  if (tab_count > 3)
-    tab_count = ukm::GetExponentialBucketMin(tab_count, 1.5);
-  entry.SetTabCount(tab_count);
-
-  entry.Record(ukm_recorder);
-}
-
-}  // namespace
-
-// Observes a browser window's tab strip and logs a WindowMetrics UKM event for
-// the window upon changes to metrics like TabCount.
-class WindowActivityWatcher::BrowserWatcher : public TabStripModelObserver {
- public:
-  explicit BrowserWatcher(Browser* browser)
-      : browser_(browser), observer_(this) {
-    DCHECK(!browser->profile()->IsOffTheRecord());
-    MaybeLogWindowMetricsUkmEntry();
-    observer_.Add(browser->tab_strip_model());
-  }
-
-  ~BrowserWatcher() override = default;
-
-  void MaybeLogWindowMetricsUkmEntry() {
-    MaybeLogWindowMetricsUkmEntry(browser_->window()->IsActive());
-  }
-
-  // Logs a new WindowMetrics entry to the UKM recorder if the entry would be
-  // different than the last one we logged.
-  // |is_active| is provided because IsActive() may be incorrect while browser
-  // activation is changing (namely, when deactivating a window on Windows).
-  void MaybeLogWindowMetricsUkmEntry(bool is_active) {
-    // Do nothing if the window has no tabs (which can happen when a window is
-    // opened, before a tab is added) or is being closed.
-    if (browser_->tab_strip_model()->empty() ||
-        browser_->tab_strip_model()->closing_all()) {
-      return;
-    }
-
-    if (!last_window_features_) {
-      last_window_features_.emplace(
-          ::CreateWindowFeatures(browser_, is_active));
-      LogWindowMetricsUkmEntry(last_window_features_.value());
-      return;
-    }
-
-    // Copy old state to compare with.
-    WindowFeatures old_features(last_window_features_.value());
-    UpdateWindowFeatures(browser_, &last_window_features_.value(), is_active);
-
-    // We only need to create a new UKM entry if the metrics have changed.
-    if (old_features != last_window_features_.value())
-      LogWindowMetricsUkmEntry(last_window_features_.value());
-  }
-
- private:
-  // TabStripModelObserver:
-  void OnTabStripModelChanged(
-      TabStripModel* tab_strip_model,
-      const TabStripModelChange& change,
-      const TabStripSelectionChange& selection) override {
-    if (change.type() != TabStripModelChange::kInserted &&
-        change.type() != TabStripModelChange::kRemoved)
-      return;
-
-    MaybeLogWindowMetricsUkmEntry();
-  }
-
-  // The browser whose tab strip we track. WindowActivityWatcher should ensure
-  // this outlives us.
-  Browser* browser_;
-
-  // The most recent WindowFeatures entry logged. We only log a new UKM entry if
-  // some metric value has changed.
-  base::Optional<WindowFeatures> last_window_features_;
-
-  // Used to update the tab count for browser windows.
-  ScopedObserver<TabStripModel, TabStripModelObserver> observer_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserWatcher);
-};
-
-// static
-WindowActivityWatcher* WindowActivityWatcher::GetInstance() {
-  static base::NoDestructor<WindowActivityWatcher> instance;
-  return instance.get();
-}
-
-// static
-WindowFeatures WindowActivityWatcher::CreateWindowFeatures(
-    const Browser* browser) {
-  DCHECK(browser->window());
-  return ::CreateWindowFeatures(browser, browser->window()->IsActive());
-}
-
-WindowActivityWatcher::WindowActivityWatcher() {
-  BrowserList::AddObserver(this);
-  for (Browser* browser : *BrowserList::GetInstance())
-    OnBrowserAdded(browser);
-}
-
-WindowActivityWatcher::~WindowActivityWatcher() {
-  BrowserList::RemoveObserver(this);
-}
-
-bool WindowActivityWatcher::ShouldTrackBrowser(Browser* browser) {
-  // Don't track incognito browsers. This is also enforced by UKM.
-  return !browser->profile()->IsOffTheRecord();
-}
-
-void WindowActivityWatcher::OnBrowserAdded(Browser* browser) {
-  if (ShouldTrackBrowser(browser))
-    browser_watchers_[browser] = std::make_unique<BrowserWatcher>(browser);
-}
-
-void WindowActivityWatcher::OnBrowserRemoved(Browser* browser) {
-  browser_watchers_.erase(browser);
-}
-
-void WindowActivityWatcher::OnBrowserSetLastActive(Browser* browser) {
-  // The browser may not have a window yet if activation calls happen during
-  // initialization.
-  // TODO(michaelpg): The browser window check should be unnecessary
-  // (https://crbug.com/811191, https://crbug.com/811243).
-  if (ShouldTrackBrowser(browser) && browser->window())
-    browser_watchers_[browser]->MaybeLogWindowMetricsUkmEntry();
-}
-
-void WindowActivityWatcher::OnBrowserNoLongerActive(Browser* browser) {
-  // The browser may not have a window yet if activation calls happen during
-  // initialization.
-  // TODO(michaelpg): The browser window check should be unnecessary
-  // (https://crbug.com/811191, https://crbug.com/811243).
-  if (!ShouldTrackBrowser(browser) || !browser->window())
-    return;
-
-#if defined(USE_AURA)
-  // On some platforms, the window is hidden (and deactivated) before it starts
-  // closing. Unless the window is minimized, assume that being deactivated
-  // while hidden means it's about to close, and don't log in that case.
-  if (browser->window()->GetNativeWindow() &&
-      !browser->window()->GetNativeWindow()->IsVisible() &&
-      !browser->window()->IsMinimized()) {
-    return;
-  }
-#endif
-
-  // On Windows, the browser window's IsActive() may still return true until the
-  // WM updates the focused window, and BrowserList::GetLastActive() still
-  // returns this browser until another one is activated. So we explicitly pass
-  // along that the window should be considered inactive.
-  browser_watchers_[browser]->MaybeLogWindowMetricsUkmEntry(
-      /*is_active=*/false);
-}
diff --git a/chrome/browser/ui/tabs/window_activity_watcher.h b/chrome/browser/ui/tabs/window_activity_watcher.h
deleted file mode 100644
index 1cf2d98..0000000
--- a/chrome/browser/ui/tabs/window_activity_watcher.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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 CHROME_BROWSER_UI_TABS_WINDOW_ACTIVITY_WATCHER_H_
-#define CHROME_BROWSER_UI_TABS_WINDOW_ACTIVITY_WATCHER_H_
-
-#include <memory>
-
-#include "base/containers/flat_map.h"
-#include "base/macros.h"
-#include "base/no_destructor.h"
-#include "chrome/browser/ui/browser_list_observer.h"
-
-namespace tab_ranker {
-struct WindowFeatures;
-}  // namespace tab_ranker
-
-// Observes browser window activity in order to log WindowMetrics UKMs for
-// browser events relative to tab activation and discarding.
-// Multiple tabs in the same browser can refer to the same WindowMetrics entry.
-// Must be used on the UI thread.
-// TODO(michaelpg): Observe app and ARC++ windows as well.
-class WindowActivityWatcher : public BrowserListObserver {
- public:
-  class BrowserWatcher;
-
-  // Returns the single instance, creating it if necessary.
-  static WindowActivityWatcher* GetInstance();
-
-  // Returns a populated WindowFeatures for the browser.
-  static tab_ranker::WindowFeatures CreateWindowFeatures(
-      const Browser* browser);
-
- private:
-  friend class base::NoDestructor<WindowActivityWatcher>;
-
-  WindowActivityWatcher();
-  ~WindowActivityWatcher() override;
-
-  bool ShouldTrackBrowser(Browser* browser);
-
-  // BrowserListObserver:
-  void OnBrowserAdded(Browser* browser) override;
-  void OnBrowserRemoved(Browser* browser) override;
-  void OnBrowserSetLastActive(Browser* browser) override;
-  void OnBrowserNoLongerActive(Browser* browser) override;
-
-  // Per-browser observers responsible for tracking the tab strip and logging
-  // new UKM entries on changes.
-  base::flat_map<Browser*, std::unique_ptr<BrowserWatcher>> browser_watchers_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowActivityWatcher);
-};
-
-#endif  // CHROME_BROWSER_UI_TABS_WINDOW_ACTIVITY_WATCHER_H_
diff --git a/chrome/browser/ui/tabs/window_activity_watcher_interactive_uitest.cc b/chrome/browser/ui/tabs/window_activity_watcher_interactive_uitest.cc
deleted file mode 100644
index 082053a..0000000
--- a/chrome/browser/ui/tabs/window_activity_watcher_interactive_uitest.cc
+++ /dev/null
@@ -1,313 +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 <memory>
-
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "chrome/browser/resource_coordinator/tab_metrics_event.pb.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/tabs/tab_ukm_test_helper.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/interactive_test_utils.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/ukm/test_ukm_recorder.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using metrics::WindowMetricsEvent;
-using ukm::builders::TabManager_TabMetrics;
-using ukm::builders::TabManager_WindowMetrics;
-
-namespace {
-
-const char* kEntryName = TabManager_WindowMetrics::kEntryName;
-const char* kTestUrl = "https://example.com/";
-
-}  // namespace
-
-// Tests UKM entries generated by WindowActivityWatcher due to interactive
-// changes to window state.
-class WindowActivityWatcherTest : public InProcessBrowserTest {
- protected:
-  WindowActivityWatcherTest() = default;
-
-  // InProcessBrowserTest:
-  void PreRunTestOnMainThread() override {
-    InProcessBrowserTest::PreRunTestOnMainThread();
-    ukm_entry_checker_ = std::make_unique<UkmEntryChecker>();
-  }
-
-  void SetUpOnMainThread() override {
-    // Browser is created in BrowserMain() before the test UKM recorder.
-    ASSERT_EQ(0u, ukm_entry_checker_->NumEntries(kEntryName));
-
-#if defined(OS_MACOSX)
-    // On Mac, the browser window needs to be forced to the front. This will
-    // create a UKM entry for the activation because it happens after the
-    // WindowActivityWatcher creation. On other platforms, activation happens
-    // before creation, and as a result, no UKM entry is created.
-    // TODO(crbug.com/650859): Reassess after activation is restored in the
-    // focus manager.
-    ui_test_utils::BrowserActivationWaiter waiter(browser());
-    ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-    waiter.WaitForActivation();
-    ASSERT_TRUE(browser()->window()->IsActive());
-
-    UkmMetricMap expected_metrics({
-        {TabManager_WindowMetrics::kWindowIdName, browser()->session_id().id()},
-        {TabManager_WindowMetrics::kShowStateName,
-         WindowMetricsEvent::SHOW_STATE_NORMAL},
-        {TabManager_WindowMetrics::kTypeName, WindowMetricsEvent::TYPE_TABBED},
-        {TabManager_WindowMetrics::kIsActiveName, 1},
-        {TabManager_WindowMetrics::kTabCountName, 1},
-    });
-    ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-#endif
-  }
-
- protected:
-  std::unique_ptr<UkmEntryChecker> ukm_entry_checker_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(WindowActivityWatcherTest);
-};
-
-// Tests WindowMetrics UKMs logged by the current browser window.
-IN_PROC_BROWSER_TEST_F(WindowActivityWatcherTest, Basic) {
-  UkmMetricMap expected_metrics({
-      {TabManager_WindowMetrics::kWindowIdName, browser()->session_id().id()},
-      {TabManager_WindowMetrics::kShowStateName,
-       WindowMetricsEvent::SHOW_STATE_NORMAL},
-      {TabManager_WindowMetrics::kTypeName, WindowMetricsEvent::TYPE_TABBED},
-      {TabManager_WindowMetrics::kIsActiveName, 1},
-      {TabManager_WindowMetrics::kTabCountName, 1},
-  });
-
-  // Updated metrics are logged after adding tabs.
-  {
-    SCOPED_TRACE("");
-    AddTabAtIndex(1, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
-    expected_metrics[TabManager_WindowMetrics::kTabCountName] = 2;
-    ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-  {
-    SCOPED_TRACE("");
-    AddTabAtIndex(0, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
-    expected_metrics[TabManager_WindowMetrics::kTabCountName] = 3;
-    ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  // Closing the window doesn't log more WindowMetrics UKMs.
-  CloseBrowserSynchronously(browser());
-}
-
-// TODO(https://crbug.com/51364): Implement BrowserWindow::Deactivate() on Mac.
-#if !defined(OS_MACOSX)
-// Tests WindowMetrics UKMs logged by activating/deactivating the window.
-IN_PROC_BROWSER_TEST_F(WindowActivityWatcherTest, WindowActivation) {
-  UkmMetricMap expected_metrics({
-      {TabManager_WindowMetrics::kWindowIdName, browser()->session_id().id()},
-      {TabManager_WindowMetrics::kShowStateName,
-       WindowMetricsEvent::SHOW_STATE_NORMAL},
-      {TabManager_WindowMetrics::kTypeName, WindowMetricsEvent::TYPE_TABBED},
-      {TabManager_WindowMetrics::kIsActiveName, 0},
-      {TabManager_WindowMetrics::kTabCountName, 1},
-  });
-
-  {
-    SCOPED_TRACE("");
-    ui_test_utils::BrowserDeactivationWaiter waiter(browser());
-    browser()->window()->Deactivate();
-    waiter.WaitForDeactivation();
-    ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  {
-    SCOPED_TRACE("");
-    ui_test_utils::BrowserActivationWaiter waiter(browser());
-    browser()->window()->Activate();
-    waiter.WaitForActivation();
-    ASSERT_TRUE(browser()->window()->IsActive());
-    expected_metrics[TabManager_WindowMetrics::kIsActiveName] = 1;
-    ukm_entry_checker_->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  // Closing the window doesn't log more WindowMetrics UKMs.
-  CloseBrowserSynchronously(browser());
-}
-
-// Tests WindowMetrics UKMs logged when switching between windows.
-IN_PROC_BROWSER_TEST_F(WindowActivityWatcherTest, MultipleWindows) {
-  // Create a new browser window.
-  Browser* browser_2 = CreateBrowser(browser()->profile());
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker_->ExpectNewEntry(
-        kEntryName, GURL(),
-        {
-            {TabManager_WindowMetrics::kWindowIdName,
-             browser_2->session_id().id()},
-            {TabManager_WindowMetrics::kIsActiveName, 0},
-        });
-  }
-
-  // Wait for the old window to be deactivated and the new window to be
-  // activated if they aren't yet.
-  {
-    ui_test_utils::BrowserActivationWaiter waiter(browser_2);
-    waiter.WaitForActivation();
-  }
-  {
-    ui_test_utils::BrowserDeactivationWaiter waiter(browser());
-    waiter.WaitForDeactivation();
-  }
-  {
-    SCOPED_TRACE("");
-    // Check for activation and deactivation events. The exact order is
-    // platform-dependent.
-    ukm_entry_checker_->ExpectNewEntries(
-        kEntryName, {{
-                         {TabManager_WindowMetrics::kWindowIdName,
-                          browser_2->session_id().id()},
-                         {TabManager_WindowMetrics::kIsActiveName, 1},
-                     },
-                     {
-                         {TabManager_WindowMetrics::kWindowIdName,
-                          browser()->session_id().id()},
-                         {TabManager_WindowMetrics::kIsActiveName, 0},
-                     }});
-  }
-
-  {
-    SCOPED_TRACE("");
-    ui_test_utils::BrowserActivationWaiter activation_waiter(browser());
-    ui_test_utils::BrowserDeactivationWaiter deactivation_waiter(browser_2);
-
-    // Switch back to the first window.
-    // Note: use Activate() rather than Show() because on some platforms, Show()
-    // calls SetLastActive() before doing anything else.
-    browser()->window()->Activate();
-
-    activation_waiter.WaitForActivation();
-    deactivation_waiter.WaitForDeactivation();
-
-    // Check for activation and deactivation events. The exact order is
-    // platform-dependent.
-    ukm_entry_checker_->ExpectNewEntries(
-        kEntryName, {{
-                         {TabManager_WindowMetrics::kWindowIdName,
-                          browser()->session_id().id()},
-                         {TabManager_WindowMetrics::kIsActiveName, 1},
-                     },
-                     {
-                         {TabManager_WindowMetrics::kWindowIdName,
-                          browser_2->session_id().id()},
-                         {TabManager_WindowMetrics::kIsActiveName, 0},
-                     }});
-  }
-
-  // Closing the active window activates the second window.
-  ASSERT_EQ(0, ukm_entry_checker_->NumNewEntriesRecorded(kEntryName));
-
-  CloseBrowserSynchronously(browser());
-
-  // GetLastActive could return browser2 if browser1 was active and then was
-  // removed, so browser2 might not actually be active.
-  {
-    ui_test_utils::BrowserActivationWaiter activation_waiter(browser_2);
-    browser_2->window()->Activate();
-    activation_waiter.WaitForActivation();
-  }
-  EXPECT_TRUE(BrowserList::GetInstance()->GetLastActive() == browser_2);
-  EXPECT_TRUE(browser_2->window()->IsActive());
-  {
-    SCOPED_TRACE("");
-    // Check for activation and deactivation events. The exact order is
-    // platform-dependent.
-    ukm_entry_checker_->ExpectNewEntries(
-        kEntryName, {{
-                        {TabManager_WindowMetrics::kWindowIdName,
-                         browser_2->session_id().id()},
-                        {TabManager_WindowMetrics::kIsActiveName, 1},
-                    }});
-  }
-
-  // Occasionally, X sends an extraneous deactivate/reactivate cycle.
-  if (ukm_entry_checker_->NumNewEntriesRecorded(kEntryName) == 2) {
-    SCOPED_TRACE("");
-    LOG(WARNING) << "Extra deactivate/reactivate detected.";
-    ukm_entry_checker_->ExpectNewEntries(
-        kEntryName, {{
-                         {TabManager_WindowMetrics::kWindowIdName,
-                          browser_2->session_id().id()},
-                         {TabManager_WindowMetrics::kIsActiveName, 0},
-                     },
-                     {
-                         {TabManager_WindowMetrics::kWindowIdName,
-                          browser_2->session_id().id()},
-                         {TabManager_WindowMetrics::kIsActiveName, 1},
-                     }});
-  }
-
-  // Ignore UKMs that might be logged from spurious activation events.
-  ukm_entry_checker_.reset();
-}
-
-// Tests we don't emit a ridiculous number of UKMs, which may indicate
-// unintended log entries or unexpected interactions between events.
-IN_PROC_BROWSER_TEST_F(WindowActivityWatcherTest, DontFloodUkm) {
-  // TODO(michaelpg): Update once window metrics are folded into tab metrics.
-  constexpr int kTooManyWindowMetricsEntries = 40;
-  constexpr int kTooManyTabMetricsEntries = 20;
-
-  // Add and activate some tabs.
-  for (int i = 0; i < 3; i++)
-    AddTabAtIndex(1, GURL(kTestUrl), ui::PAGE_TRANSITION_LINK);
-
-  // Make more windows with tabs.
-  constexpr bool kCheckNavigationSuccess = false;
-  Browser* browser_2 = CreateBrowser(browser()->profile());
-  for (int i = 0; i < 3; i++) {
-    AddTabAtIndexToBrowser(browser_2, 1, GURL(kTestUrl),
-                           ui::PAGE_TRANSITION_LINK, kCheckNavigationSuccess);
-  }
-  Browser* browser_3 = CreateBrowser(browser()->profile());
-  for (int i = 0; i < 3; i++) {
-    AddTabAtIndexToBrowser(browser_3, 1, GURL(kTestUrl),
-                           ui::PAGE_TRANSITION_LINK, kCheckNavigationSuccess);
-  }
-
-  // Cycle between windows.
-  for (Browser* next_browser :
-       {browser_2, browser_3, browser(), browser_2, browser_3}) {
-    next_browser->window()->Activate();
-    ui_test_utils::BrowserActivationWaiter(next_browser).WaitForActivation();
-  }
-
-  // Manage windows.
-  browser_2->window()->Minimize();
-  browser_2->window()->Maximize();
-  browser_3->window()->Maximize();
-  browser_2->window()->Restore();
-  browser_3->window()->Minimize();
-
-  CloseBrowserSynchronously(browser());
-  CloseBrowserSynchronously(browser_2);
-  CloseBrowserSynchronously(browser_3);
-
-  ASSERT_GT(ukm_entry_checker_->NumNewEntriesRecorded(kEntryName), 0);
-  ASSERT_LT(ukm_entry_checker_->NumNewEntriesRecorded(kEntryName),
-            kTooManyWindowMetricsEntries);
-
-  ASSERT_GT(ukm_entry_checker_->NumNewEntriesRecorded(
-                TabManager_TabMetrics::kEntryName),
-            0);
-  ASSERT_LT(ukm_entry_checker_->NumNewEntriesRecorded(
-                TabManager_TabMetrics::kEntryName),
-            kTooManyTabMetricsEntries);
-}
-#endif  // !defined(OS_MACOSX)
diff --git a/chrome/browser/ui/tabs/window_activity_watcher_unittest.cc b/chrome/browser/ui/tabs/window_activity_watcher_unittest.cc
deleted file mode 100644
index 3a62ca0..0000000
--- a/chrome/browser/ui/tabs/window_activity_watcher_unittest.cc
+++ /dev/null
@@ -1,369 +0,0 @@
-// 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.
-
-#include "chrome/browser/ui/tabs/window_activity_watcher.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/resource_coordinator/tab_activity_watcher.h"
-#include "chrome/browser/resource_coordinator/tab_metrics_event.pb.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/tabs/tab_activity_simulator.h"
-#include "chrome/browser/ui/tabs/tab_ukm_test_helper.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/test_browser_window.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/web_contents_tester.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "services/metrics/public/mojom/ukm_interface.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/ui_base_types.h"
-
-using metrics::WindowMetricsEvent;
-using ukm::builders::TabManager_WindowMetrics;
-
-namespace {
-
-const char* kEntryName = TabManager_WindowMetrics::kEntryName;
-const char* kTestUrl = "https://example.com/";
-
-// TestBrowserWindow whose show state can be modified.
-class FakeBrowserWindow : public TestBrowserWindow {
- public:
-  FakeBrowserWindow() = default;
-  ~FakeBrowserWindow() override = default;
-
-  // Helper function to handle FakeBrowserWindow lifetime. Modeled after
-  // CreateBrowserWithTestWindowForParams.
-  static std::unique_ptr<Browser> CreateBrowserWithFakeWindowForParams(
-      Browser::CreateParams* params) {
-    // TestBrowserWindowOwner takes ownersip of the window and will destroy the
-    // window (along with itself) automatically when the browser is closed.
-    FakeBrowserWindow* window = new FakeBrowserWindow;
-    new TestBrowserWindowOwner(window);
-
-    params->window = window;
-    auto browser = std::make_unique<Browser>(*params);
-    window->browser_ = browser.get();
-    window->Activate();
-    return browser;
-  }
-
-  // TestBrowserWindow:
-  void Activate() override {
-    if (is_active_)
-      return;
-    is_active_ = true;
-    // With a real view, activating would update the BrowserList.
-    BrowserList::SetLastActive(browser_);
-  }
-  void Deactivate() override {
-    if (!is_active_)
-      return;
-    is_active_ = false;
-    // With a real view, deactivating would notify the BrowserList.
-    BrowserList::NotifyBrowserNoLongerActive(browser_);
-  }
-  bool IsActive() const override { return is_active_; }
-  bool IsMaximized() const override {
-    return show_state_ == ui::SHOW_STATE_MAXIMIZED;
-  }
-  bool IsMinimized() const override {
-    return show_state_ == ui::SHOW_STATE_MINIMIZED;
-  }
-  void Maximize() override {
-    show_state_ = ui::SHOW_STATE_MAXIMIZED;
-    Activate();
-  }
-  void Minimize() override {
-    show_state_ = ui::SHOW_STATE_MINIMIZED;
-    Deactivate();
-  }
-  void Restore() override {
-    // This isn't true "restore" behavior.
-    show_state_ = ui::SHOW_STATE_NORMAL;
-    Activate();
-  }
-
- private:
-  Browser* browser_;
-  bool is_active_ = false;
-  ui::WindowShowState show_state_ = ui::SHOW_STATE_NORMAL;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeBrowserWindow);
-};
-
-}  // namespace
-
-// Tests UKM entries generated by WindowMetricsLogger at the request of
-// WindowActivityWatcher.
-class WindowActivityWatcherTest : public ChromeRenderViewHostTestHarness {
- protected:
-  WindowActivityWatcherTest() = default;
-  ~WindowActivityWatcherTest() override { EXPECT_FALSE(WasNewEntryRecorded()); }
-
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-
-    // Start TabActivityWatcher so it logs TabMetrics UKMs.
-    resource_coordinator::TabActivityWatcher::GetInstance();
-  }
-
-  // Adds a tab and simulates a basic navigation.
-  void AddTab(Browser* browser) {
-    content::WebContentsTester::For(
-        tab_activity_simulator_.AddWebContentsAndNavigate(
-            browser->tab_strip_model(), GURL(kTestUrl)))
-        ->TestSetIsLoading(false);
-  }
-
-  bool WasNewEntryRecorded() {
-    return ukm_entry_checker_.NumNewEntriesRecorded(kEntryName) > 0;
-  }
-
-  UkmEntryChecker* ukm_entry_checker() { return &ukm_entry_checker_; }
-
- private:
-  UkmEntryChecker ukm_entry_checker_;
-  TabActivitySimulator tab_activity_simulator_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowActivityWatcherTest);
-};
-
-// Tests UKM logging of two browser windows.
-// Test is flaky. See https://crbug.com/938055.
-TEST_F(WindowActivityWatcherTest, DISABLED_Basic) {
-  Browser::CreateParams params(profile(), true);
-  std::unique_ptr<Browser> browser =
-      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
-  AddTab(browser.get());
-
-  UkmMetricMap expected_metrics({
-      {TabManager_WindowMetrics::kWindowIdName, browser->session_id().id()},
-      {TabManager_WindowMetrics::kShowStateName,
-       WindowMetricsEvent::SHOW_STATE_NORMAL},
-      {TabManager_WindowMetrics::kTypeName, WindowMetricsEvent::TYPE_TABBED},
-      {TabManager_WindowMetrics::kIsActiveName, 1},
-      {TabManager_WindowMetrics::kTabCountName, 1},
-  });
-  {
-    SCOPED_TRACE("");
-    // Window UKMs are not expected to be associated with any particular URL.
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  AddTab(browser.get());
-  expected_metrics[TabManager_WindowMetrics::kTabCountName].value()++;
-  {
-    SCOPED_TRACE("");
-    // Window UKMs are not expected to be associated with any particular URL.
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  browser->window()->Minimize();
-  expected_metrics[TabManager_WindowMetrics::kShowStateName] =
-      WindowMetricsEvent::SHOW_STATE_MINIMIZED;
-  expected_metrics[TabManager_WindowMetrics::kIsActiveName] = 0;
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  // A new entry is not created if nothing changes.
-  EXPECT_FALSE(WasNewEntryRecorded());
-
-  // A second browser can be logged.
-  Browser::CreateParams params_2(Browser::TYPE_POPUP, profile(), true);
-  std::unique_ptr<Browser> browser_2 =
-      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params_2);
-
-  // An entry is not logged until a tab is added to the new window.
-  EXPECT_FALSE(WasNewEntryRecorded());
-
-  AddTab(browser_2.get());
-  UkmMetricMap expected_metrics_2({
-      {TabManager_WindowMetrics::kWindowIdName, browser_2->session_id().id()},
-      {TabManager_WindowMetrics::kShowStateName,
-       WindowMetricsEvent::SHOW_STATE_NORMAL},
-      {TabManager_WindowMetrics::kTypeName, WindowMetricsEvent::TYPE_POPUP},
-      {TabManager_WindowMetrics::kIsActiveName, 1},
-      {TabManager_WindowMetrics::kTabCountName, 1},
-  });
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(), expected_metrics_2);
-  }
-
-  // Switching the active browser logs two events.
-  browser_2->window()->Deactivate();
-  expected_metrics_2[TabManager_WindowMetrics::kIsActiveName] = 0;
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(), expected_metrics_2);
-  }
-
-  browser->window()->Restore();
-  expected_metrics[TabManager_WindowMetrics::kShowStateName] =
-      WindowMetricsEvent::SHOW_STATE_NORMAL;
-  expected_metrics[TabManager_WindowMetrics::kIsActiveName] = 1;
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  browser->tab_strip_model()->CloseAllTabs();
-  browser_2->tab_strip_model()->CloseAllTabs();
-}
-
-// Tests moving a tab between browser windows.
-TEST_F(WindowActivityWatcherTest, MoveTabToOtherWindow) {
-  Browser::CreateParams params(profile(), true);
-  std::unique_ptr<Browser> starting_browser =
-      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
-  AddTab(starting_browser.get());
-  UkmMetricMap starting_browser_metrics({
-      {TabManager_WindowMetrics::kWindowIdName,
-       starting_browser->session_id().id()},
-      {TabManager_WindowMetrics::kIsActiveName, 1},
-      {TabManager_WindowMetrics::kTabCountName, 1},
-  });
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(),
-                                        starting_browser_metrics);
-  }
-
-  // Add a second tab, so we can detach it while leaving the original window
-  // behind.
-  AddTab(starting_browser.get());
-  starting_browser_metrics[TabManager_WindowMetrics::kTabCountName].value() = 2;
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(),
-                                        starting_browser_metrics);
-  }
-
-  // Drag the tab out of its window.
-  std::unique_ptr<content::WebContents> dragged_tab =
-      starting_browser->tab_strip_model()->DetachWebContentsAt(1);
-  starting_browser_metrics[TabManager_WindowMetrics::kTabCountName].value() = 1;
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(),
-                                        starting_browser_metrics);
-  }
-  starting_browser->window()->Deactivate();
-  starting_browser_metrics[TabManager_WindowMetrics::kIsActiveName].value() =
-      false;
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(),
-                                        starting_browser_metrics);
-  }
-
-  // Create a new Browser for the tab.
-  std::unique_ptr<Browser> created_browser =
-      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
-  created_browser->window()->Activate();
-  created_browser->tab_strip_model()->InsertWebContentsAt(
-      0, std::move(dragged_tab), TabStripModel::ADD_ACTIVE);
-  UkmMetricMap created_browser_metrics({
-      {TabManager_WindowMetrics::kWindowIdName,
-       created_browser->session_id().id()},
-      {TabManager_WindowMetrics::kIsActiveName, 1},
-      {TabManager_WindowMetrics::kTabCountName, 1},
-  });
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(),
-                                        created_browser_metrics);
-  }
-
-  starting_browser->tab_strip_model()->CloseAllTabs();
-  created_browser->tab_strip_model()->CloseAllTabs();
-}
-
-// Tests that a replaced tab still causes event logging upon being detached.
-// Test is flaky. See https://crbug.com/938055.
-TEST_F(WindowActivityWatcherTest, DISABLED_ReplaceTab) {
-  Browser::CreateParams params(profile(), true);
-  std::unique_ptr<Browser> browser =
-      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
-  AddTab(browser.get());
-  UkmMetricMap expected_metrics({
-      {TabManager_WindowMetrics::kWindowIdName, browser->session_id().id()},
-      {TabManager_WindowMetrics::kTabCountName, 1},
-  });
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  // Add a tab that will be replaced.
-  AddTab(browser.get());
-  expected_metrics[TabManager_WindowMetrics::kTabCountName].value() = 2;
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  // Replace the tab.
-  content::WebContents::CreateParams web_contents_params(profile(), nullptr);
-  std::unique_ptr<content::WebContents> new_contents = base::WrapUnique(
-      content::WebContentsTester::CreateTestWebContents(web_contents_params));
-  std::unique_ptr<content::WebContents> old_contents =
-      browser->tab_strip_model()->ReplaceWebContentsAt(1,
-                                                       std::move(new_contents));
-
-  // Close the replaced tab. This should log an event with an updated TabCount.
-  browser->tab_strip_model()->CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
-  expected_metrics[TabManager_WindowMetrics::kTabCountName].value() = 1;
-  {
-    SCOPED_TRACE("");
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  browser->tab_strip_model()->CloseAllTabs();
-}
-
-// Tests that counts are properly bucketized.
-TEST_F(WindowActivityWatcherTest, Counts) {
-  Browser::CreateParams params(profile(), true);
-  std::unique_ptr<Browser> browser =
-      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
-  UkmMetricMap expected_metrics;
-
-  // Expected buckets for each tab count using a spacing factor of 1.5.
-  std::vector<int> expected_buckets = {
-      0,        // Not actually tested, since we don't log windows with 0 tabs.
-      1, 2, 3,  // Values up to 3 should be represented exactly.
-      4, 4, 6, 6, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 18,
-  };
-
-  for (size_t i = 1; i < expected_buckets.size(); i++) {
-    SCOPED_TRACE(base::StringPrintf("Tab count: %zd", i));
-    AddTab(browser.get());
-    expected_metrics[TabManager_WindowMetrics::kTabCountName] =
-        expected_buckets[i];
-    ukm_entry_checker()->ExpectNewEntry(kEntryName, GURL(), expected_metrics);
-  }
-
-  browser->tab_strip_model()->CloseAllTabs();
-}
-
-// Tests that incognito windows are ignored.
-TEST_F(WindowActivityWatcherTest, Incognito) {
-  Browser::CreateParams params(profile()->GetOffTheRecordProfile(), true);
-  std::unique_ptr<Browser> browser =
-      FakeBrowserWindow::CreateBrowserWithFakeWindowForParams(&params);
-  AddTab(browser.get());
-  EXPECT_EQ(0u, ukm_entry_checker()->NumEntries(kEntryName));
-
-  browser->tab_strip_model()->CloseAllTabs();
-}
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
index 1b7d23b8..294f3017 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -284,7 +284,7 @@
                    base::Unretained(this)));
     menu_runner_->RunMenuAt(source->GetWidget(), NULL,
                             gfx::Rect(p, gfx::Size(0, 0)),
-                            views::MENU_ANCHOR_TOPLEFT, source_type);
+                            views::MenuAnchorPosition::kTopLeft, source_type);
   } else {
     menu_model_.reset();
   }
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc
index 705b80a1..b525e12 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/ui/views/autofill/save_card_bubble_views.h"
 #include "chrome/browser/ui/views/autofill/save_card_icon_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
@@ -646,10 +647,25 @@
   SaveCardIconView* GetSaveCardIconView() {
     if (!browser())
       return nullptr;
-    LocationBarView* location_bar_view =
-        static_cast<LocationBarView*>(browser()->window()->GetLocationBar());
-    DCHECK(location_bar_view->save_credit_card_icon_view());
-    return location_bar_view->save_credit_card_icon_view();
+
+    SaveCardIconView* icon_view = nullptr;
+    if (base::FeatureList::IsEnabled(
+            features::kAutofillEnableToolbarStatusChip)) {
+      ToolbarPageActionIconContainerView*
+          toolbar_page_action_icon_container_view =
+              static_cast<ToolbarPageActionIconContainerView*>(
+                  browser()->window()->GetToolbarPageActionIconContainer());
+      DCHECK(toolbar_page_action_icon_container_view->save_card_icon_view());
+      icon_view =
+          toolbar_page_action_icon_container_view->save_card_icon_view();
+    } else {
+      LocationBarView* location_bar_view =
+          static_cast<LocationBarView*>(browser()->window()->GetLocationBar());
+      DCHECK(location_bar_view->save_credit_card_icon_view());
+      icon_view = location_bar_view->save_credit_card_icon_view();
+    }
+
+    return icon_view;
   }
 
   content::WebContents* GetActiveWebContents() {
@@ -696,6 +712,25 @@
   DISALLOW_COPY_AND_ASSIGN(SaveCardBubbleViewsFullFormBrowserTest);
 };
 
+// TODO(crbug.com/932818): Remove this class after experiment flag is cleaned
+// up. Otherwise we need it because the toolbar is init-ed before each test is
+// set up. Thus need to enable the feature in the general browsertest SetUp().
+class SaveCardBubbleViewsFullFormBrowserTestForStatusChip
+    : public SaveCardBubbleViewsFullFormBrowserTest {
+ protected:
+  SaveCardBubbleViewsFullFormBrowserTestForStatusChip()
+      : SaveCardBubbleViewsFullFormBrowserTest() {}
+  ~SaveCardBubbleViewsFullFormBrowserTestForStatusChip() override {}
+
+  void SetUp() override {
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitAndEnableFeature(
+        features::kAutofillEnableToolbarStatusChip);
+
+    SaveCardBubbleViewsFullFormBrowserTest::SetUp();
+  }
+};
+
 // Tests the local save bubble. Ensures that clicking the [Save] button
 // successfully causes the bubble to go away.
 IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
@@ -2715,4 +2750,33 @@
       AutofillMetrics::SAVE_CARD_ICON_SHOWN_WITHOUT_PROMPT, 1);
 }
 
+// Ensures that the credit card icon will show in status chip.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTestForStatusChip,
+                       CreditCardIconShownInStatusChip) {
+  ResetEventWaiterForSequence({DialogEvent::OFFERED_LOCAL_SAVE});
+  NavigateTo(kCreditCardUploadForm);
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+  EXPECT_TRUE(GetSaveCardIconView());
+  EXPECT_TRUE(GetSaveCardIconView()->visible());
+}
+
+// Ensures that the clicking on the credit card icon will reshow bubble.
+IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTestForStatusChip,
+                       ClickingOnCreditCardIconInStatusChipReshowsBubble) {
+  ResetEventWaiterForSequence({DialogEvent::OFFERED_LOCAL_SAVE});
+  NavigateTo(kCreditCardUploadForm);
+  FillAndSubmitForm();
+  WaitForObservedEvent();
+
+  ClickOnCloseButton();
+  AddEventObserverToController();
+  ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
+  ClickOnView(GetSaveCardIconView());
+  WaitForObservedEvent();
+
+  EXPECT_TRUE(GetSaveCardBubbleViews());
+  EXPECT_TRUE(GetSaveCardBubbleViews()->visible());
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index bf09da8f..92e092746 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -678,10 +678,11 @@
 void BookmarkBarView::GetAnchorPositionForButton(
     views::MenuButton* button,
     views::MenuAnchorPosition* anchor) {
+  using Position = views::MenuAnchorPosition;
   if (button == other_bookmarks_button_ || button == overflow_button_)
-    *anchor = views::MENU_ANCHOR_TOPRIGHT;
+    *anchor = Position::kTopRight;
   else
-    *anchor = views::MENU_ANCHOR_TOPLEFT;
+    *anchor = Position::kTopLeft;
 }
 
 views::MenuItemView* BookmarkBarView::GetMenu() {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_context_menu.cc b/chrome/browser/ui/views/bookmarks/bookmark_context_menu.cc
index cd2b00e..9749a873 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_context_menu.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_context_menu.cc
@@ -79,7 +79,7 @@
   // width/height don't matter here.
   menu_runner_->RunMenuAt(parent_widget_, nullptr,
                           gfx::Rect(point.x(), point.y(), 0, 0),
-                          views::MENU_ANCHOR_TOPLEFT, source_type);
+                          views::MenuAnchorPosition::kTopLeft, source_type);
 }
 
 void BookmarkContextMenu::SetPageNavigator(PageNavigator* navigator) {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
index 935ba24..ea4a7c6 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
@@ -248,7 +248,8 @@
 
   context_menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(),
                                   NULL, gfx::Rect(point, gfx::Size()),
-                                  views::MENU_ANCHOR_TOPRIGHT, source_type);
+                                  views::MenuAnchorPosition::kTopRight,
+                                  source_type);
 }
 
 const char* BookmarkEditorView::GetClassName() const {
diff --git a/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc b/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc
index 47d2295..675e3a2 100644
--- a/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc
+++ b/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc
@@ -25,6 +25,7 @@
     const gfx::Rect& rect,
     ui::MenuSourceType source_type,
     const base::Closure& on_menu_closed_callback) {
+  using Position = views::MenuAnchorPosition;
   ui::MenuModel* menu_model = GetMenuModel();
   // Run() should not be getting called if the DownloadItem was destroyed.
   DCHECK(menu_model);
@@ -36,11 +37,11 @@
                           base::Unretained(this), on_menu_closed_callback)));
 
   // The menu's alignment is determined based on the UI layout.
-  views::MenuAnchorPosition position;
+  Position position;
   if (base::i18n::IsRTL())
-    position = views::MENU_ANCHOR_TOPRIGHT;
+    position = Position::kTopRight;
   else
-    position = views::MENU_ANCHOR_TOPLEFT;
+    position = Position::kTopLeft;
 
   menu_runner_->RunMenuAt(parent_widget, NULL, rect, position, source_type);
 }
diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
index 763eaf5a..cf3b11d3 100644
--- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
+++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
@@ -316,7 +316,7 @@
   context_menu_runner_->RunMenuAt(
       GetWidget(), NULL,
       gfx::Rect(point.x(), point.y(), views::GridLayout::kFixedSize, 0),
-      views::MENU_ANCHOR_TOPLEFT, source_type);
+      views::MenuAnchorPosition::kTopLeft, source_type);
 }
 
 bool MediaGalleriesDialogViews::ControllerHasWebContents() const {
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc
index c03e309..116ad93 100644
--- a/chrome/browser/ui/views/frame/browser_frame.cc
+++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -257,7 +257,7 @@
                             base::Unretained(this))));
     menu_runner_->RunMenuAt(source->GetWidget(), nullptr,
                             gfx::Rect(p, gfx::Size(0, 0)),
-                            views::MENU_ANCHOR_TOPLEFT, source_type);
+                            views::MenuAnchorPosition::kTopLeft, source_type);
   }
 }
 
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 90a6abd..abfffb8 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1316,41 +1316,57 @@
                                bookmark_bar_view_.get());
 }
 
+// TODO(crbug.com/932818): Clean up this two functions and add helper for shared
+// code.
 autofill::SaveCardBubbleView* BrowserView::ShowSaveCreditCardBubble(
     content::WebContents* web_contents,
     autofill::SaveCardBubbleController* controller,
     bool user_gesture) {
-  LocationBarView* location_bar = GetLocationBarView();
-  PageActionIconView* card_view = location_bar->save_credit_card_icon_view();
-
   autofill::BubbleType bubble_type = controller->GetBubbleType();
-  autofill::SaveCardBubbleViews* bubble = nullptr;
+  PageActionIconView* icon_view = nullptr;
+  views::View* anchor_view = nullptr;
 
+  if (base::FeatureList::IsEnabled(
+          autofill::features::kAutofillEnableToolbarStatusChip)) {
+    // Icon will be shown in the status chip when feature is enabled. The anchor
+    // view for the bubble is the status chip container.
+    ToolbarPageActionIconContainerView* toolbar_page_action_container =
+        toolbar_->toolbar_page_action_container();
+    icon_view = toolbar_page_action_container->GetIconView(
+        PageActionIconType::kSaveCard);
+    anchor_view = toolbar_page_action_container;
+  } else {
+    // Otherwise the bubble is anchored to the credit card icon in the location
+    // bar. This will be removed when the feature is fully enabled.
+    LocationBarView* location_bar = GetLocationBarView();
+    icon_view = location_bar->save_credit_card_icon_view();
+    anchor_view = location_bar;
+  }
+
+  autofill::SaveCardBubbleViews* bubble = nullptr;
   switch (bubble_type) {
     case autofill::BubbleType::LOCAL_SAVE:
     case autofill::BubbleType::UPLOAD_SAVE:
-      bubble = new autofill::SaveCardOfferBubbleViews(
-          location_bar, gfx::Point(), web_contents, controller);
+      bubble = new autofill::SaveCardOfferBubbleViews(anchor_view, gfx::Point(),
+                                                      web_contents, controller);
       break;
     case autofill::BubbleType::SIGN_IN_PROMO:
       bubble = new autofill::SaveCardSignInPromoBubbleViews(
-          location_bar, gfx::Point(), web_contents, controller);
+          anchor_view, gfx::Point(), web_contents, controller);
       break;
     case autofill::BubbleType::MANAGE_CARDS:
       bubble = new autofill::SaveCardManageCardsBubbleViews(
-          location_bar, gfx::Point(), web_contents, controller);
+          anchor_view, gfx::Point(), web_contents, controller);
       break;
     case autofill::BubbleType::INACTIVE:
       break;
   }
-
   DCHECK(bubble);
 
-  if (card_view)
-    bubble->SetHighlightedButton(card_view);
+  if (icon_view)
+    bubble->SetHighlightedButton(icon_view);
 
   views::BubbleDialogDelegateView::CreateBubble(bubble);
-
   bubble->Show(user_gesture ? autofill::SaveCardBubbleViews::USER_GESTURE
                             : autofill::SaveCardBubbleViews::AUTOMATIC);
   return bubble;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index 4cf12e1..43d9fa4 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -357,7 +357,8 @@
                                 views::MenuRunner::HAS_MNEMONICS);
   menu_runner.RunMenuAt(browser_view()->GetWidget(), window_icon_,
                         window_icon_->GetBoundsInScreen(),
-                        views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_MOUSE);
+                        views::MenuAnchorPosition::kTopLeft,
+                        ui::MENU_SOURCE_MOUSE);
 #endif
 }
 
diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc
index d5d52ce0..a7451a8e 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.cc
+++ b/chrome/browser/ui/views/infobars/infobar_view.cc
@@ -205,7 +205,7 @@
 
   if (ShouldDrawSeparator()) {
     const SkColor color =
-        GetColor(ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR);
+        GetColor(ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR);
     BrowserView::Paint1pxHorizontalLine(canvas, color, GetLocalBounds(), false);
   }
 }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 4384187..fa5b068 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -264,7 +264,6 @@
   }
 
   for (PageActionIconView* icon_view : page_action_icons_) {
-    icon_view->Init();
     icon_view->SetVisible(false);
     icon_view->SetIconColor(icon_color);
     AddChildView(icon_view);
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_view.cc b/chrome/browser/ui/views/media_router/cast_dialog_view.cc
index 7871b6c..855469d06 100644
--- a/chrome/browser/ui/views/media_router/cast_dialog_view.cc
+++ b/chrome/browser/ui/views/media_router/cast_dialog_view.cc
@@ -367,9 +367,9 @@
   sources_menu_runner_ = std::make_unique<views::MenuRunner>(
       sources_menu_model_.get(), views::MenuRunner::COMBOBOX);
   const gfx::Rect& screen_bounds = sources_button_->GetBoundsInScreen();
-  sources_menu_runner_->RunMenuAt(sources_button_->GetWidget(), nullptr,
-                                  screen_bounds, views::MENU_ANCHOR_TOPLEFT,
-                                  ui::MENU_SOURCE_MOUSE);
+  sources_menu_runner_->RunMenuAt(
+      sources_button_->GetWidget(), nullptr, screen_bounds,
+      views::MenuAnchorPosition::kTopLeft, ui::MENU_SOURCE_MOUSE);
 }
 
 void CastDialogView::SelectSource(SourceType source) {
diff --git a/chrome/browser/ui/views/menu_interactive_uitest.cc b/chrome/browser/ui/views/menu_interactive_uitest.cc
index 1ed4e47..4acc26b 100644
--- a/chrome/browser/ui/views/menu_interactive_uitest.cc
+++ b/chrome/browser/ui/views/menu_interactive_uitest.cc
@@ -39,7 +39,8 @@
     menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
     // Run the menu, so that the menu item size will be calculated.
     menu_runner_->RunMenuAt(widget, nullptr, gfx::Rect(),
-                            views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_NONE);
+                            views::MenuAnchorPosition::kTopLeft,
+                            ui::MENU_SOURCE_NONE);
     RunPendingMessages();
     // Figure out the middle of the first menu item.
     mouse_pos_.set_x(first_item_->width() / 2);
@@ -88,7 +89,8 @@
   // when we run the menu.
   SetupMenu(widget);
   menu_runner_->RunMenuAt(widget, nullptr, gfx::Rect(),
-                          views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_NONE);
+                          views::MenuAnchorPosition::kTopLeft,
+                          ui::MENU_SOURCE_NONE);
   // One or two mouse events are posted by the menu being shown.
   // Process event(s), and check what's selected in the menu.
   RunPendingMessages();
@@ -123,7 +125,8 @@
       menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
   menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
   menu_runner->RunMenuAt(nullptr, nullptr, gfx::Rect(),
-                         views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_NONE);
+                         views::MenuAnchorPosition::kTopLeft,
+                         ui::MENU_SOURCE_NONE);
   base::RunLoop loop;
   // SendKeyPress fails if the window doesn't have focus.
   ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
diff --git a/chrome/browser/ui/views/menu_model_adapter_test.cc b/chrome/browser/ui/views/menu_model_adapter_test.cc
index 5fafbf9..78ea1d3 100644
--- a/chrome/browser/ui/views/menu_model_adapter_test.cc
+++ b/chrome/browser/ui/views/menu_model_adapter_test.cc
@@ -195,7 +195,8 @@
     views::View::ConvertPointToScreen(source, &screen_location);
     gfx::Rect bounds(screen_location, source->size());
     menu_runner_->RunMenuAt(source->GetWidget(), button_, bounds,
-                            views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_NONE);
+                            views::MenuAnchorPosition::kTopLeft,
+                            ui::MENU_SOURCE_NONE);
   }
 
   // ViewEventTestBase implementation
diff --git a/chrome/browser/ui/views/menu_test_base.cc b/chrome/browser/ui/views/menu_test_base.cc
index 5c892519..3b38b1e 100644
--- a/chrome/browser/ui/views/menu_test_base.cc
+++ b/chrome/browser/ui/views/menu_test_base.cc
@@ -82,7 +82,8 @@
   views::View::ConvertPointToScreen(source, &screen_location);
   gfx::Rect bounds(screen_location, source->size());
   menu_runner_->RunMenuAt(source->GetWidget(), button_, bounds,
-                          views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_NONE);
+                          views::MenuAnchorPosition::kTopLeft,
+                          ui::MENU_SOURCE_NONE);
 }
 
 void MenuTestBase::ExecuteCommand(int id) {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 210f888..e3a1f6a 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -436,9 +436,9 @@
       &context_menu_contents_,
       views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU,
       set_hovered_false);
-  context_menu_runner_->RunMenuAt(GetWidget(), nullptr,
-                                  gfx::Rect(point, gfx::Size()),
-                                  views::MENU_ANCHOR_TOPLEFT, source_type);
+  context_menu_runner_->RunMenuAt(
+      GetWidget(), nullptr, gfx::Rect(point, gfx::Size()),
+      views::MenuAnchorPosition::kTopLeft, source_type);
 
   // Opening the context menu unsets the hover state, but we still want the
   // result 'hovered' as long as the context menu is open.
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index df68c3d..76014ee 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -1180,3 +1180,23 @@
     EXPECT_EQ(0U, end);
   }
 }
+
+TEST_F(OmniboxViewViewsSteadyStateElisionsAndQueryInOmniboxTest,
+       NoEmphasisForUrlLikeQueries) {
+  // Prevents regressions for crbug.com/942945. Set the displayed search terms
+  // to something somewhat URL-like.
+  location_bar_model()->set_display_search_terms(base::ASCIIToUTF16("foo:bar"));
+  omnibox_view()->model()->ResetDisplayTexts();
+  omnibox_view()->RevertAll();
+  EXPECT_EQ(base::ASCIIToUTF16("foo:bar"), omnibox_view()->text());
+  EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
+
+  omnibox_view()->ResetEmphasisTestState();
+  omnibox_view()->EmphasizeURLComponents();
+
+  // Expect that no part is de-emphasized, there is no "scheme" range.
+  EXPECT_EQ(TestingOmniboxView::BaseTextEmphasis::EMPHASIZED,
+            omnibox_view()->base_text_emphasis());
+  EXPECT_FALSE(omnibox_view()->emphasis_range().IsValid());
+  EXPECT_FALSE(omnibox_view()->scheme_range().IsValid());
+}
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_container_view.cc b/chrome/browser/ui/views/page_action/page_action_icon_container_view.cc
index e38c809f..38d9b54 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_container_view.cc
+++ b/chrome/browser/ui/views/page_action/page_action_icon_container_view.cc
@@ -60,6 +60,7 @@
         page_action_icons_.push_back(zoom_view_);
         break;
       case PageActionIconType::kLocalCardMigration:
+      case PageActionIconType::kSaveCard:
         NOTREACHED();
         break;
     }
@@ -68,7 +69,6 @@
   for (PageActionIconView* icon : page_action_icons_) {
     icon->SetVisible(false);
     icon->set_icon_size(params.icon_size);
-    icon->Init();
     icon->SetIconColor(params.icon_color);
     AddChildView(icon);
   }
@@ -98,6 +98,7 @@
     case PageActionIconType::kZoom:
       return zoom_view_;
     case PageActionIconType::kLocalCardMigration:
+    case PageActionIconType::kSaveCard:
       NOTREACHED();
       return nullptr;
   }
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.cc b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
index 4f2521f..2fe912f9 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_view.cc
+++ b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
 
 #include "chrome/browser/command_updater.h"
-#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/omnibox/omnibox_theme.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
 #include "ui/accessibility/ax_node_data.h"
@@ -31,27 +30,19 @@
 
 }  // namespace
 
-void PageActionIconView::Init() {
-  AddChildView(image());
-  image()->set_can_process_events_within_subtree(false);
-  image()->EnableCanvasFlippingForRTLUI(true);
-  SetInkDropMode(InkDropMode::ON);
-  SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
-}
-
 PageActionIconView::PageActionIconView(CommandUpdater* command_updater,
                                        int command_id,
                                        PageActionIconView::Delegate* delegate,
                                        const gfx::FontList& font_list)
     : IconLabelBubbleView(font_list),
-      icon_size_(GetLayoutConstant(LOCATION_BAR_ICON_SIZE)),
       command_updater_(command_updater),
       delegate_(delegate),
-      command_id_(command_id),
-      active_(false),
-      suppress_mouse_released_action_(false) {
+      command_id_(command_id) {
+  image()->EnableCanvasFlippingForRTLUI(true);
+  SetInkDropMode(InkDropMode::ON);
   set_ink_drop_visible_opacity(
       GetOmniboxStateOpacity(OmniboxPartState::SELECTED));
+  SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
 }
 
 PageActionIconView::~PageActionIconView() {}
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.h b/chrome/browser/ui/views/page_action/page_action_icon_view.h
index 0ad8eb7f..b9dd25a 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_view.h
+++ b/chrome/browser/ui/views/page_action/page_action_icon_view.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/omnibox/omnibox_theme.h"
 #include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -43,8 +44,6 @@
     virtual content::WebContents* GetWebContentsForPageActionIconView() = 0;
   };
 
-  void Init();
-
   // Updates the color of the icon, this must be set before the icon is drawn.
   void SetIconColor(SkColor icon_color);
 
@@ -142,7 +141,7 @@
 
  private:
   // The size of the icon image (excluding the ink drop).
-  int icon_size_;
+  int icon_size_ = GetLayoutConstant(LOCATION_BAR_ICON_SIZE);
 
   // What color to paint the icon with.
   SkColor icon_color_ = gfx::kPlaceholderColor;
@@ -159,12 +158,12 @@
   // The active node_data. The precise definition of "active" is unique to each
   // subclass, but generally indicates that the associated feature is acting on
   // the web page.
-  bool active_;
+  bool active_ = false;
 
   // This is used to check if the bookmark bubble was showing during the mouse
   // pressed event. If this is true then the mouse released event is ignored to
   // prevent the bubble from reshowing.
-  bool suppress_mouse_released_action_;
+  bool suppress_mouse_released_action_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(PageActionIconView);
 };
diff --git a/chrome/browser/ui/views/profiles/dice_accounts_menu.cc b/chrome/browser/ui/views/profiles/dice_accounts_menu.cc
index 14840d0..ff9d008 100644
--- a/chrome/browser/ui/views/profiles/dice_accounts_menu.cc
+++ b/chrome/browser/ui/views/profiles/dice_accounts_menu.cc
@@ -68,7 +68,8 @@
     anchor_bounds.Inset(anchor_bounds.width(), 0, 0, 0);
 
   runner_->RunMenuAt(anchor_view->GetWidget(), menu_button, anchor_bounds,
-                     views::MENU_ANCHOR_TOPRIGHT, ui::MENU_SOURCE_MOUSE);
+                     views::MenuAnchorPosition::kTopRight,
+                     ui::MENU_SOURCE_MOUSE);
 }
 
 DiceAccountsMenu::~DiceAccountsMenu() {}
diff --git a/chrome/browser/ui/views/status_icons/status_icon_win.cc b/chrome/browser/ui/views/status_icons/status_icon_win.cc
index 9673855..909f1ba 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_win.cc
+++ b/chrome/browser/ui/views/status_icons/status_icon_win.cc
@@ -64,7 +64,8 @@
   menu_runner_.reset(new views::MenuRunner(menu_model_,
                                            views::MenuRunner::HAS_MNEMONICS));
   menu_runner_->RunMenuAt(NULL, NULL, gfx::Rect(cursor_pos, gfx::Size()),
-                          views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_MOUSE);
+                          views::MenuAnchorPosition::kTopLeft,
+                          ui::MENU_SOURCE_MOUSE);
 }
 
 void StatusIconWin::HandleBalloonClickEvent() {
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 2d1b6ecb..50d45952 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -111,7 +111,7 @@
   void RunMenuAt(const gfx::Point& point, ui::MenuSourceType source_type) {
     menu_runner_->RunMenuAt(tab_->GetWidget(), NULL,
                             gfx::Rect(point, gfx::Size()),
-                            views::MENU_ANCHOR_TOPLEFT, source_type);
+                            views::MenuAnchorPosition::kTopLeft, source_type);
   }
 
   // Overridden from ui::SimpleMenuModel::Delegate:
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index 653db3d5..0a3a2ba 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -288,7 +288,7 @@
                                            views::MenuRunner::CONTEXT_MENU));
 
   menu_runner_->RunMenuAt(GetWidget(), nullptr, gfx::Rect(point, gfx::Size()),
-                          views::MENU_ANCHOR_TOPLEFT, source_type);
+                          views::MenuAnchorPosition::kTopLeft, source_type);
 }
 
 bool TaskManagerView::IsCommandIdChecked(int id) const {
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index 771baf7d..67d3fa8 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -813,9 +813,9 @@
 void AppMenu::RunMenu(views::MenuButton* host) {
   base::RecordAction(UserMetricsAction("ShowAppMenu"));
 
-  menu_runner_->RunMenuAt(host->GetWidget(), host,
-                          host->GetAnchorBoundsInScreen(),
-                          views::MENU_ANCHOR_TOPRIGHT, ui::MENU_SOURCE_NONE);
+  menu_runner_->RunMenuAt(
+      host->GetWidget(), host, host->GetAnchorBoundsInScreen(),
+      views::MenuAnchorPosition::kTopRight, ui::MENU_SOURCE_NONE);
 }
 
 void AppMenu::CloseMenu() {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
index 55993269..a9f3ec9 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -349,7 +349,7 @@
   menu_runner_.reset(new views::MenuRunner(menu_, run_types));
 
   menu_runner_->RunMenuAt(parent, this, GetAnchorBoundsInScreen(),
-                          views::MENU_ANCHOR_TOPLEFT, source_type);
+                          views::MenuAnchorPosition::kTopLeft, source_type);
 }
 
 bool ToolbarActionView::CloseActiveMenuIfNeeded() {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc
index a9aaf0b..0e3f452 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -372,7 +372,7 @@
   menu_runner_ = std::make_unique<views::MenuRunner>(
       menu_model_adapter_->CreateMenu(), views::MenuRunner::HAS_MNEMONICS);
   menu_runner_->RunMenuAt(GetWidget(), nullptr, menu_anchor_bounds,
-                          views::MENU_ANCHOR_TOPLEFT, source_type);
+                          views::MenuAnchorPosition::kTopLeft, source_type);
 }
 
 void ToolbarButton::OnMenuClosed() {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.cc b/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.cc
index 5e097da..1491e3b 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.cc
@@ -16,13 +16,21 @@
     : ToolbarIconContainerView(), browser_(browser) {
   local_card_migration_icon_view_ = new autofill::LocalCardMigrationIconView(
       command_updater, browser, this,
-      // TODO(932818): The font list and the icon color may not be what we want
-      // here. Put placeholders for now.
+      // TODO(crbug.com/932818): The font list and the icon color may not be
+      // what we want here. Put placeholders for now.
       views::style::GetFont(CONTEXT_TOOLBAR_BUTTON,
                             views::style::STYLE_PRIMARY));
-  local_card_migration_icon_view_->Init();
   local_card_migration_icon_view_->SetVisible(false);
   AddChildView(local_card_migration_icon_view_);
+
+  save_card_icon_view_ = new autofill::SaveCardIconView(
+      command_updater, browser, this,
+      // TODO(crbug.com/932818): The font list and the icon color may not be
+      // what we want here. Put placeholders for now.
+      views::style::GetFont(CONTEXT_TOOLBAR_BUTTON,
+                            views::style::STYLE_PRIMARY));
+  save_card_icon_view_->SetVisible(false);
+  AddChildView(save_card_icon_view_);
 }
 
 ToolbarPageActionIconContainerView::~ToolbarPageActionIconContainerView() =
@@ -31,6 +39,9 @@
 void ToolbarPageActionIconContainerView::UpdateAllIcons() {
   if (local_card_migration_icon_view_)
     local_card_migration_icon_view_->Update();
+
+  if (save_card_icon_view_)
+    save_card_icon_view_->Update();
 }
 
 PageActionIconView* ToolbarPageActionIconContainerView::GetIconView(
@@ -38,7 +49,10 @@
   switch (icon_type) {
     case PageActionIconType::kLocalCardMigration:
       return local_card_migration_icon_view_;
+    case PageActionIconType::kSaveCard:
+      return save_card_icon_view_;
     default:
+      NOTREACHED();
       return nullptr;
   }
 }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.h b/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.h
index 5b208ebb..62018c7f 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.h
@@ -15,6 +15,7 @@
 
 namespace autofill {
 class LocalCardMigrationIconView;
+class SaveCardIconView;
 }  // namespace autofill
 
 // A container view for user-account-related PageActionIconViews and the profile
@@ -41,13 +42,18 @@
   SkColor GetPageActionInkDropColor() const override;
   content::WebContents* GetWebContentsForPageActionIconView() override;
 
-  autofill::LocalCardMigrationIconView* local_card_migration_icon_view() {
+  autofill::LocalCardMigrationIconView* local_card_migration_icon_view() const {
     return local_card_migration_icon_view_;
   }
 
+  autofill::SaveCardIconView* save_card_icon_view() const {
+    return save_card_icon_view_;
+  }
+
  private:
   autofill::LocalCardMigrationIconView* local_card_migration_icon_view_ =
       nullptr;
+  autofill::SaveCardIconView* save_card_icon_view_ = nullptr;
 
   Browser* const browser_;
 
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.cc b/chrome/browser/ui/views/translate/translate_bubble_view.cc
index 764c461f..a9042d8 100644
--- a/chrome/browser/ui/views/translate/translate_bubble_view.cc
+++ b/chrome/browser/ui/views/translate/translate_bubble_view.cc
@@ -362,7 +362,7 @@
       options_menu_model_.get(), views::MenuRunner::COMBOBOX));
   gfx::Rect screen_bounds = source->GetBoundsInScreen();
   options_menu_runner_->RunMenuAt(source->GetWidget(), nullptr, screen_bounds,
-                                  views::MENU_ANCHOR_TOPRIGHT,
+                                  views::MenuAnchorPosition::kTopRight,
                                   ui::MENU_SOURCE_MOUSE);
 }
 
diff --git a/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc b/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc
index 619302f..db06f38 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc
@@ -257,7 +257,8 @@
   gfx::Rect anchor_bounds = other_transports_button_->GetBoundsInScreen();
   other_transports_menu_runner_->RunMenuAt(
       other_transports_button_->GetWidget(), nullptr /* menu_button */,
-      anchor_bounds, views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_MOUSE);
+      anchor_bounds, views::MenuAnchorPosition::kTopLeft,
+      ui::MENU_SOURCE_MOUSE);
 }
 
 void AuthenticatorRequestDialogView::ReplaceCurrentSheetWith(
diff --git a/chrome/browser/ui/webui/chromeos/set_time_ui.cc b/chrome/browser/ui/webui/chromeos/set_time_ui.cc
index f9c80ba..92ff3fa6 100644
--- a/chrome/browser/ui/webui/chromeos/set_time_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/set_time_ui.cc
@@ -24,6 +24,7 @@
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/system_clock/system_clock_client.h"
 #include "chromeos/settings/timezone_settings.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -137,11 +138,17 @@
 
   source->AddLocalizedString("setTimeTitle", IDS_SET_TIME_TITLE);
   source->AddLocalizedString("prompt", IDS_SET_TIME_PROMPT);
-  source->AddLocalizedString("doneButton", IDS_SET_TIME_BUTTON_CLOSE);
-  source->AddLocalizedString("timezone",
-                             IDS_OPTIONS_SETTINGS_TIMEZONE_DESCRIPTION);
-  source->AddLocalizedString("dateLabel", IDS_SET_TIME_DATE_LABEL);
-  source->AddLocalizedString("timeLabel", IDS_SET_TIME_TIME_LABEL);
+  if (chromeos::features::IsSetTimeDialogMd()) {
+    source->AddLocalizedString("timezoneLabel", IDS_MD_SET_TIME_TIMEZONE_LABEL);
+    source->AddLocalizedString("dateLabel", IDS_MD_SET_TIME_DATE_LABEL);
+    source->AddLocalizedString("timeLabel", IDS_MD_SET_TIME_TIME_LABEL);
+  } else {
+    source->AddLocalizedString("timezone",
+                               IDS_OPTIONS_SETTINGS_TIMEZONE_DESCRIPTION);
+    source->AddLocalizedString("dateLabel", IDS_SET_TIME_DATE_LABEL);
+    source->AddLocalizedString("timeLabel", IDS_SET_TIME_TIME_LABEL);
+  }
+  source->AddLocalizedString("doneButton", IDS_DONE);
 
   base::DictionaryValue values;
   // List of list of strings: [[ID, name], [ID, name], ...]
diff --git a/chrome/browser/ui/webui/feed_internals/feed_internals.mojom b/chrome/browser/ui/webui/feed_internals/feed_internals.mojom
index 4382879..bf6f965 100644
--- a/chrome/browser/ui/webui/feed_internals/feed_internals.mojom
+++ b/chrome/browser/ui/webui/feed_internals/feed_internals.mojom
@@ -102,4 +102,7 @@
 
   // Internal state dump of the Feed library's process scope.
   GetFeedProcessScopeDump() => (string dump);
+
+  // Record all Feed metrics into a log.
+  GetFeedHistograms() => (string log);
 };
diff --git a/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.cc b/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.cc
index e210b27..51c01b6 100644
--- a/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.cc
+++ b/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/feature_list.h"
+#include "base/metrics/statistics_recorder.h"
 #include "base/time/time.h"
 #include "chrome/browser/android/feed/feed_debugging_bridge.h"
 #include "chrome/browser/android/feed/feed_lifecycle_bridge.h"
@@ -23,6 +24,8 @@
 
 namespace {
 
+const char kFeedHistogramPrefix[] = "ContentSuggestions.Feed.";
+
 feed_internals::mojom::TimePtr ToMojoTime(base::Time time) {
   return time.is_null() ? nullptr
                         : feed_internals::mojom::Time::New(time.ToJsTime());
@@ -155,3 +158,10 @@
 bool FeedInternalsPageHandler::IsFeedAllowed() {
   return pref_service_->GetBoolean(feed::prefs::kEnableSnippets);
 }
+
+void FeedInternalsPageHandler::GetFeedHistograms(
+    GetFeedHistogramsCallback callback) {
+  std::string log;
+  base::StatisticsRecorder::WriteGraph(kFeedHistogramPrefix, &log);
+  std::move(callback).Run(log);
+}
diff --git a/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.h b/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.h
index d3070c7..67f1327f 100644
--- a/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.h
+++ b/chrome/browser/ui/webui/feed_internals/feed_internals_page_handler.h
@@ -42,6 +42,7 @@
   void RefreshFeed() override;
   void GetCurrentContent(GetCurrentContentCallback) override;
   void GetFeedProcessScopeDump(GetFeedProcessScopeDumpCallback) override;
+  void GetFeedHistograms(GetFeedHistogramsCallback) override;
 
  private:
   // Binding from the mojo interface to concrete implementation.
diff --git a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
index b1982c6..99048ab 100644
--- a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
@@ -24,7 +24,9 @@
 CrostiniHandler::CrostiniHandler(Profile* profile)
     : profile_(profile), weak_ptr_factory_(this) {}
 
-CrostiniHandler::~CrostiniHandler() = default;
+CrostiniHandler::~CrostiniHandler() {
+  DisallowJavascript();
+}
 
 void CrostiniHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
diff --git a/chrome/browser/ui/webui/theme_handler.cc b/chrome/browser/ui/webui/theme_handler.cc
index d0696a7..033a87d 100644
--- a/chrome/browser/ui/webui/theme_handler.cc
+++ b/chrome/browser/ui/webui/theme_handler.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/bind.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
@@ -15,38 +16,64 @@
 #include "chrome/grit/theme_resources.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_ui.h"
+#include "ui/native_theme/native_theme.h"
 
 ///////////////////////////////////////////////////////////////////////////////
 // ThemeHandler
 
-ThemeHandler::ThemeHandler() {
-}
+ThemeHandler::ThemeHandler() : theme_observer_(this) {}
 
-ThemeHandler::~ThemeHandler() {
-}
+ThemeHandler::~ThemeHandler() {}
 
 void ThemeHandler::RegisterMessages() {
   // These are not actual message registrations, but can't be done in the
   // constructor since they need the web_ui value to be set, which is done
   // post-construction, but before registering messages.
   InitializeCSSCaches();
+  web_ui()->RegisterMessageCallback(
+      "observeThemeChanges",
+      base::BindRepeating(&ThemeHandler::HandleObserveThemeChanges,
+                          base::Unretained(this)));
+}
+
+void ThemeHandler::OnJavascriptAllowed() {
   // Listen for theme installation.
   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
                  content::Source<ThemeService>(
                      ThemeServiceFactory::GetForProfile(GetProfile())));
+  // Or native theme change.
+  theme_observer_.Add(ui::NativeTheme::GetInstanceForNativeUi());
+}
+
+void ThemeHandler::OnJavascriptDisallowed() {
+  registrar_.RemoveAll();
+  theme_observer_.RemoveAll();
 }
 
 void ThemeHandler::Observe(int type,
                            const content::NotificationSource& source,
                            const content::NotificationDetails& details) {
   DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
+  SendThemeChanged();
+}
+
+void ThemeHandler::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
+  DCHECK_EQ(observed_theme, ui::NativeTheme::GetInstanceForNativeUi());
+  SendThemeChanged();
+}
+
+void ThemeHandler::HandleObserveThemeChanges(const base::ListValue* /*args*/) {
+  AllowJavascript();
+}
+
+void ThemeHandler::SendThemeChanged() {
   InitializeCSSCaches();
   bool has_custom_bg = ThemeService::GetThemeProviderForProfile(GetProfile())
                            .HasCustomImage(IDR_THEME_NTP_BACKGROUND);
   // TODO(dbeam): why does this need to be a dictionary?
   base::DictionaryValue dictionary;
   dictionary.SetBoolean("hasCustomBackground", has_custom_bg);
-  web_ui()->CallJavascriptFunctionUnsafe("ntp.themeChanged", dictionary);
+  CallJavascriptFunction("ntp.themeChanged", dictionary);
 }
 
 void ThemeHandler::InitializeCSSCaches() {
diff --git a/chrome/browser/ui/webui/theme_handler.h b/chrome/browser/ui/webui/theme_handler.h
index 7c2b88b..5e52e81d1 100644
--- a/chrome/browser/ui/webui/theme_handler.h
+++ b/chrome/browser/ui/webui/theme_handler.h
@@ -6,22 +6,31 @@
 #define CHROME_BROWSER_UI_WEBUI_THEME_HANDLER_H_
 
 #include "base/macros.h"
+#include "base/scoped_observer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_ui_message_handler.h"
+#include "ui/native_theme/native_theme_observer.h"
 
 class Profile;
 
+namespace ui {
+class NativeTheme;
+}
+
 // A class to keep the ThemeSource up to date when theme changes.
 class ThemeHandler : public content::WebUIMessageHandler,
-                     public content::NotificationObserver {
+                     public content::NotificationObserver,
+                     public ui::NativeThemeObserver {
  public:
-  explicit ThemeHandler();
+  ThemeHandler();
   ~ThemeHandler() override;
 
  private:
-  // content::WebUIMessageHandler implementation.
+  // content::WebUIMessageHandler:
   void RegisterMessages() override;
+  void OnJavascriptAllowed() override;
+  void OnJavascriptDisallowed() override;
 
   // Re/set the CSS caches.
   void InitializeCSSCaches();
@@ -31,10 +40,21 @@
                const content::NotificationSource& source,
                const content::NotificationDetails& details) override;
 
+  // ui::NativeThemeObserver:
+  void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
+
+  // Handler for "observeThemeChanges" chrome.send() message. No arguments.
+  void HandleObserveThemeChanges(const base::ListValue* args);
+
+  // Notify the page (if allowed) that the theme has changed.
+  void SendThemeChanged();
+
   Profile* GetProfile() const;
 
   content::NotificationRegistrar registrar_;
 
+  ScopedObserver<ui::NativeTheme, ThemeHandler> theme_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(ThemeHandler);
 };
 
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 0dd334a8..ec18992 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -156,6 +156,7 @@
   deps = [
     ":web_app_group",
     "//chrome/browser/web_applications/bookmark_apps:browser_tests",
+    "//chrome/browser/web_applications/components:browser_tests",
     "//chrome/browser/web_applications/extensions:browser_tests",
   ]
 }
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 91e65fa..6a201e1 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -22,6 +22,10 @@
     "web_app_icon_generator.h",
     "web_app_install_utils.cc",
     "web_app_install_utils.h",
+    "web_app_provider_base.cc",
+    "web_app_provider_base.h",
+    "web_app_provider_base_factory.cc",
+    "web_app_provider_base_factory.h",
     "web_app_shortcut.cc",
     "web_app_shortcut.h",
     "web_app_shortcut_chromeos.cc",
@@ -31,6 +35,8 @@
     "web_app_shortcut_win.h",
     "web_app_tab_helper_base.cc",
     "web_app_tab_helper_base.h",
+    "web_app_url_loader.cc",
+    "web_app_url_loader.h",
 
     # TODO(nigeltao): move these two files from
     # //chrome/browser/web_applications/components to a stand-alone
@@ -59,6 +65,7 @@
     "//chrome/common",
     "//components/crx_file",
     "//components/favicon/content",
+    "//components/keyed_service/content",
     "//content/public/browser",
     "//skia",
   ]
@@ -111,3 +118,20 @@
     "//testing/gtest",
   ]
 }
+
+source_set("browser_tests") {
+  testonly = true
+
+  sources = [
+    "web_app_url_loader_browsertest.cc",
+  ]
+
+  defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+
+  deps = [
+    "//chrome/browser/web_applications/components",
+    "//chrome/test:test_support",
+    "//chrome/test:test_support_ui",
+    "//net:test_support",
+  ]
+}
diff --git a/chrome/browser/web_applications/components/web_app_data_retriever.cc b/chrome/browser/web_applications/components/web_app_data_retriever.cc
index 70cc13a..f82d7f8 100644
--- a/chrome/browser/web_applications/components/web_app_data_retriever.cc
+++ b/chrome/browser/web_applications/components/web_app_data_retriever.cc
@@ -82,9 +82,9 @@
   params.has_worker = true;
   // Do not wait_for_worker. OnDidPerformInstallableCheck is always invoked.
   installable_manager->GetData(
-      params, base::BindRepeating(
-                  &WebAppDataRetriever::OnDidPerformInstallableCheck,
-                  weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
+      params,
+      base::BindOnce(&WebAppDataRetriever::OnDidPerformInstallableCheck,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void WebAppDataRetriever::GetIcons(content::WebContents* web_contents,
diff --git a/chrome/browser/web_applications/components/web_app_provider_base.cc b/chrome/browser/web_applications/components/web_app_provider_base.cc
new file mode 100644
index 0000000..6e4eb6c
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_provider_base.cc
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/web_app_provider_base.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/components/web_app_provider_base_factory.h"
+
+namespace web_app {
+
+// static
+WebAppProviderBase* WebAppProviderBase::GetProviderBase(Profile* profile) {
+  return WebAppProviderBaseFactory::GetForProfile(profile);
+}
+
+WebAppProviderBase::WebAppProviderBase() = default;
+
+WebAppProviderBase::~WebAppProviderBase() = default;
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_provider_base.h b/chrome/browser/web_applications/components/web_app_provider_base.h
new file mode 100644
index 0000000..c950fde6
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_provider_base.h
@@ -0,0 +1,40 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_PROVIDER_BASE_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_PROVIDER_BASE_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+class Profile;
+
+namespace web_app {
+
+// Forward declarations of generalized interfaces.
+class PendingAppManager;
+class InstallManager;
+class AppRegistrar;
+
+class WebAppProviderBase : public KeyedService {
+ public:
+  static WebAppProviderBase* GetProviderBase(Profile* profile);
+
+  WebAppProviderBase();
+  ~WebAppProviderBase() override;
+
+  // The app registry manager.
+  virtual AppRegistrar& registrar() = 0;
+  // UIs can use InstallManager for user-initiated Web Apps install.
+  virtual InstallManager& install_manager() = 0;
+  // Clients can use PendingAppManager to install, uninstall, and update
+  // Web Apps.
+  virtual PendingAppManager& pending_app_manager() = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(WebAppProviderBase);
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_PROVIDER_BASE_H_
diff --git a/chrome/browser/web_applications/components/web_app_provider_base_factory.cc b/chrome/browser/web_applications/components/web_app_provider_base_factory.cc
new file mode 100644
index 0000000..0c4eb01
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_provider_base_factory.cc
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/web_app_provider_base_factory.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/components/web_app_provider_base.h"
+
+namespace web_app {
+
+namespace {
+WebAppProviderBaseFactory* g_factory = nullptr;
+}  // namespace
+
+// static
+WebAppProviderBase* WebAppProviderBaseFactory::GetForProfile(Profile* profile) {
+  return static_cast<WebAppProviderBase*>(
+      GetInstance()->GetServiceForBrowserContext(profile, /* create=*/true));
+}
+
+// static
+WebAppProviderBaseFactory* WebAppProviderBaseFactory::GetInstance() {
+  DCHECK(g_factory);
+  return g_factory;
+}
+
+// static
+void WebAppProviderBaseFactory::SetInstance(
+    WebAppProviderBaseFactory* factory) {
+  g_factory = factory;
+}
+
+WebAppProviderBaseFactory::WebAppProviderBaseFactory(
+    const char* service_name,
+    BrowserContextDependencyManager* dependency_manager)
+    : BrowserContextKeyedServiceFactory(service_name, dependency_manager) {}
+
+WebAppProviderBaseFactory::~WebAppProviderBaseFactory() = default;
+
+}  //  namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_provider_base_factory.h b/chrome/browser/web_applications/components/web_app_provider_base_factory.h
new file mode 100644
index 0000000..41a3f50
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_provider_base_factory.h
@@ -0,0 +1,37 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_PROVIDER_BASE_FACTORY_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_PROVIDER_BASE_FACTORY_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class BrowserContextDependencyManager;
+class Profile;
+
+namespace web_app {
+
+class WebAppProviderBase;
+
+// Singleton that associates WebAppProviderBase with Profile.
+class WebAppProviderBaseFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static WebAppProviderBase* GetForProfile(Profile* profile);
+
+  static WebAppProviderBaseFactory* GetInstance();
+  static void SetInstance(WebAppProviderBaseFactory* factory);
+
+ protected:
+  WebAppProviderBaseFactory(
+      const char* service_name,
+      BrowserContextDependencyManager* dependency_manager);
+  ~WebAppProviderBaseFactory() override;
+
+  DISALLOW_COPY_AND_ASSIGN(WebAppProviderBaseFactory);
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_PROVIDER_BASE_FACTORY_H_
diff --git a/chrome/browser/web_applications/components/web_app_url_loader.cc b/chrome/browser/web_applications/components/web_app_url_loader.cc
new file mode 100644
index 0000000..27ee82a
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_url_loader.cc
@@ -0,0 +1,135 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/web_app_url_loader.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/timer/timer.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace web_app {
+
+constexpr base::TimeDelta WebAppUrlLoader::kSecondsToWaitForWebContentsLoad;
+
+namespace {
+
+class LoaderTask : public content::WebContentsObserver {
+ public:
+  LoaderTask() = default;
+  ~LoaderTask() override = default;
+
+  void LoadUrl(const GURL& url,
+               content::WebContents* web_contents,
+               WebAppUrlLoader::ResultCallback callback) {
+    url_ = url;
+    callback_ = std::move(callback);
+    Observe(web_contents);
+
+    content::NavigationController::LoadURLParams load_params(url);
+    load_params.transition_type = ui::PAGE_TRANSITION_GENERATED;
+
+    web_contents->GetController().LoadURLWithParams(load_params);
+
+    timer_.Start(FROM_HERE, WebAppUrlLoader::kSecondsToWaitForWebContentsLoad,
+                 base::BindOnce(&LoaderTask::OnLoadUrlTimeout,
+                                // OneShotTimer is owned by this class and
+                                // it guarantees that it will never run after
+                                // it's destroyed.
+                                base::Unretained(this)));
+  }
+
+  // WebContentsObserver
+  // DidFinishLoad doesn't always get called after the page has fully loaded.
+  // TODO(ortuno): Use DidStopLoading instead.
+  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
+                     const GURL& validated_url) override {
+    // Ignore subframe loads.
+    if (web_contents()->GetMainFrame() != render_frame_host) {
+      return;
+    }
+
+    timer_.Stop();
+
+    if (validated_url != url_) {
+      LOG(ERROR) << "Error loading " << url_;
+      LOG(ERROR) << "  page redirected to " << validated_url;
+      PostResultTask(WebAppUrlLoader::Result::kRedirectedUrlLoaded);
+      return;
+    }
+    PostResultTask(WebAppUrlLoader::Result::kUrlLoaded);
+  }
+
+  void DidFailLoad(content::RenderFrameHost* render_frame_host,
+                   const GURL& validated_url,
+                   int error_code,
+                   const base::string16& error_description) override {
+    // Ignore subframe loads.
+    if (web_contents()->GetMainFrame() != render_frame_host) {
+      return;
+    }
+
+    timer_.Stop();
+
+    LOG(ERROR) << "Error loading " << url_ << "  page failed to load.";
+    PostResultTask(WebAppUrlLoader::Result::kFailedUnknownReason);
+  }
+
+  void WebContentsDestroyed() override {
+    timer_.Stop();
+    PostResultTask(WebAppUrlLoader::Result::kFailedWebContentsDestroyed);
+  }
+
+ private:
+  void OnLoadUrlTimeout() {
+    web_contents()->Stop();
+    LOG(ERROR) << "Error loading " << url_ << " page took too long to load.";
+    PostResultTask(WebAppUrlLoader::Result::kFailedPageTookTooLong);
+  }
+
+  void PostResultTask(WebAppUrlLoader::Result result) {
+    Observe(nullptr);
+    // Post a task to avoid reentrancy issues e.g. adding a WebContentsObserver
+    // while a previous observer call is being executed.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback_), result));
+  }
+
+  WebAppUrlLoader::ResultCallback callback_;
+  GURL url_;
+  base::OneShotTimer timer_;
+
+  base::WeakPtrFactory<LoaderTask> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(LoaderTask);
+};
+
+}  // namespace
+
+WebAppUrlLoader::WebAppUrlLoader() = default;
+
+WebAppUrlLoader::~WebAppUrlLoader() = default;
+
+void WebAppUrlLoader::LoadUrl(const GURL& url,
+                              content::WebContents* web_contents,
+                              ResultCallback callback) {
+  auto loader_task = std::make_unique<LoaderTask>();
+  auto* loader_task_ptr = loader_task.get();
+  loader_task_ptr->LoadUrl(
+      url, web_contents,
+      base::BindOnce(
+          [](ResultCallback callback, std::unique_ptr<LoaderTask> task,
+             Result result) {
+            std::move(callback).Run(result);
+            task.reset();
+          },
+          std::move(callback), std::move(loader_task)));
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_url_loader.h b/chrome/browser/web_applications/components/web_app_url_loader.h
new file mode 100644
index 0000000..a98b848a
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_url_loader.h
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_URL_LOADER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_URL_LOADER_H_
+
+#include "base/callback.h"
+#include "base/time/time.h"
+
+class GURL;
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace web_app {
+
+// Callback-based wrapper around NavigationController::LoadUrl.
+class WebAppUrlLoader {
+ public:
+  enum class Result {
+    kUrlLoaded,
+    // The provided URL redirected to another URL and the final URL
+    // was loaded.
+    kRedirectedUrlLoaded,
+    kFailedUnknownReason,
+    kFailedPageTookTooLong,
+    kFailedWebContentsDestroyed,
+  };
+
+  using ResultCallback = base::OnceCallback<void(Result)>;
+
+  WebAppUrlLoader();
+  ~WebAppUrlLoader();
+
+  // Navigates |web_contents| to |url| and runs callback with the result code.
+  void LoadUrl(const GURL& url,
+               content::WebContents* web_contents,
+               ResultCallback callback);
+
+  // Exposed for testing.
+  static constexpr base::TimeDelta kSecondsToWaitForWebContentsLoad =
+      base::TimeDelta::FromSeconds(30);
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_URL_LOADER_H_
diff --git a/chrome/browser/web_applications/components/web_app_url_loader_browsertest.cc b/chrome/browser/web_applications/components/web_app_url_loader_browsertest.cc
new file mode 100644
index 0000000..5174c23a
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_url_loader_browsertest.cc
@@ -0,0 +1,166 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/web_app_url_loader.h"
+
+#include "base/barrier_closure.h"
+#include "base/callback.h"
+#include "base/optional.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/browser/web_contents.h"
+#include "net/base/escape.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace web_app {
+
+using Result = WebAppUrlLoader::Result;
+
+class WebAppUrlLoaderTest : public InProcessBrowserTest {
+ public:
+  WebAppUrlLoaderTest() = default;
+  ~WebAppUrlLoaderTest() override = default;
+
+  void SetUpOnMainThread() override {
+    web_contents_ = content::WebContents::Create(
+        content::WebContents::CreateParams(browser()->profile()));
+
+    host_resolver()->AddRule("*", "127.0.0.1");
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
+  void TearDownOnMainThread() override {
+    // The WebContents needs to be destroyed before the profile.
+    web_contents_.reset();
+  }
+
+  Result LoadUrlAndWait(WebAppUrlLoader* loader, const std::string& path) {
+    base::Optional<Result> result;
+    base::RunLoop run_loop;
+    loader->LoadUrl(embedded_test_server()->GetURL(path), web_contents(),
+                    base::BindLambdaForTesting([&](Result r) {
+                      result = r;
+                      run_loop.Quit();
+                    }));
+    EXPECT_TRUE(web_contents()->IsLoading());
+    run_loop.Run();
+    // Currently WebAppUrlLoader uses DidFinishLoad which might get called
+    // even if WebContents::IsLoading() is true.
+    // TODO(ortuno): Check that the WebContents is no longer loading after
+    // the callback is called.
+
+    return result.value();
+  }
+
+ protected:
+  content::WebContents* web_contents() { return web_contents_.get(); }
+
+  void ResetWebContents() { web_contents_.reset(); }
+
+ private:
+  std::unique_ptr<content::WebContents> web_contents_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebAppUrlLoaderTest);
+};
+
+IN_PROC_BROWSER_TEST_F(WebAppUrlLoaderTest, Success) {
+  WebAppUrlLoader loader;
+  EXPECT_EQ(Result::kUrlLoaded, LoadUrlAndWait(&loader, "/simple.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppUrlLoaderTest, 302FoundRedirect) {
+  WebAppUrlLoader loader;
+
+  const GURL final_url = embedded_test_server()->GetURL("/simple.html");
+  EXPECT_EQ(
+      Result::kRedirectedUrlLoaded,
+      LoadUrlAndWait(&loader, "/server-redirect-302?" + final_url.spec()));
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppUrlLoaderTest, Hung) {
+  auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+  base::TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner);
+
+  WebAppUrlLoader loader;
+  base::Optional<Result> result;
+
+  loader.LoadUrl(embedded_test_server()->GetURL("/hung"), web_contents(),
+                 base::BindLambdaForTesting([&](Result r) { result = r; }));
+
+  // Run all pending tasks. The URL should still be loading.
+  EXPECT_TRUE(web_contents()->IsLoading());
+  task_runner->RunUntilIdle();
+  EXPECT_TRUE(web_contents()->IsLoading());
+
+  // The callback didn't run yet because the site is still loading.
+  EXPECT_FALSE(result.has_value());
+
+  // Forward the clock so that |loader| times out.
+  task_runner->FastForwardBy(WebAppUrlLoader::kSecondsToWaitForWebContentsLoad);
+  EXPECT_FALSE(web_contents()->IsLoading());
+  EXPECT_EQ(Result::kFailedPageTookTooLong, result.value());
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppUrlLoaderTest, WebContentsDestroyed) {
+  WebAppUrlLoader loader;
+  base::Optional<Result> result;
+
+  base::RunLoop run_loop;
+  loader.LoadUrl(embedded_test_server()->GetURL("/hung"), web_contents(),
+                 base::BindLambdaForTesting([&](Result r) {
+                   result = r;
+                   run_loop.Quit();
+                 }));
+
+  // Run all pending tasks. The URL should still be loading.
+  EXPECT_TRUE(web_contents()->IsLoading());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(web_contents()->IsLoading());
+
+  // The callback didn't run yet because the site is still loading.
+  EXPECT_FALSE(result.has_value());
+
+  ResetWebContents();
+  run_loop.Run();
+
+  EXPECT_EQ(Result::kFailedWebContentsDestroyed, result.value());
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppUrlLoaderTest, MultipleLoadUrlCalls) {
+  WebAppUrlLoader loader;
+  base::Optional<Result> title1_result;
+  base::Optional<Result> title2_result;
+
+  std::unique_ptr<content::WebContents> web_contents1 =
+      content::WebContents::Create(
+          content::WebContents::CreateParams(browser()->profile()));
+  std::unique_ptr<content::WebContents> web_contents2 =
+      content::WebContents::Create(
+          content::WebContents::CreateParams(browser()->profile()));
+
+  base::RunLoop run_loop;
+  base::RepeatingClosure barrier_closure =
+      base::BarrierClosure(2, run_loop.QuitClosure());
+
+  loader.LoadUrl(embedded_test_server()->GetURL("/title1.html"),
+                 web_contents1.get(), base::BindLambdaForTesting([&](Result r) {
+                   title1_result = r;
+                   barrier_closure.Run();
+                 }));
+  loader.LoadUrl(embedded_test_server()->GetURL("/title2.html"),
+                 web_contents2.get(), base::BindLambdaForTesting([&](Result r) {
+                   title2_result = r;
+                   barrier_closure.Run();
+                 }));
+  run_loop.Run();
+  EXPECT_EQ(Result::kUrlLoaded, title1_result.value());
+  EXPECT_EQ(Result::kUrlLoaded, title2_result.value());
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
index d8de5dc..0637775 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
@@ -10,21 +10,16 @@
 #include <vector>
 
 #include "base/bind.h"
-#include "base/strings/string16.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
-#include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/web_contents.h"
 
 namespace extensions {
 
 namespace {
 
-const int kSecondsToWaitForWebContentsLoad = 30;
-
 std::unique_ptr<content::WebContents> WebContentsCreateWrapper(
     Profile* profile) {
   return content::WebContents::Create(
@@ -58,9 +53,9 @@
       uninstaller_(
           std::make_unique<BookmarkAppUninstaller>(profile_, registrar_)),
       extension_ids_map_(profile->GetPrefs()),
+      url_loader_(std::make_unique<web_app::WebAppUrlLoader>()),
       web_contents_factory_(base::BindRepeating(&WebContentsCreateWrapper)),
-      task_factory_(base::BindRepeating(&InstallationTaskCreateWrapper)),
-      timer_(std::make_unique<base::OneShotTimer>()) {}
+      task_factory_(base::BindRepeating(&InstallationTaskCreateWrapper)) {}
 
 PendingBookmarkAppManager::~PendingBookmarkAppManager() = default;
 
@@ -122,11 +117,6 @@
   uninstaller_ = std::move(uninstaller);
 }
 
-void PendingBookmarkAppManager::SetTimerForTesting(
-    std::unique_ptr<base::OneShotTimer> timer) {
-  timer_ = std::move(timer);
-}
-
 base::Optional<bool> PendingBookmarkAppManager::IsExtensionPresentAndInstalled(
     const std::string& extension_id) {
   if (registrar_->IsInstalled(extension_id)) {
@@ -190,16 +180,11 @@
   current_task_and_callback_ = std::move(task);
 
   CreateWebContentsIfNecessary();
-  Observe(web_contents_.get());
 
-  content::NavigationController::LoadURLParams load_params(
-      current_task_and_callback_->task->app_info().url);
-  load_params.transition_type = ui::PAGE_TRANSITION_GENERATED;
-  web_contents_->GetController().LoadURLWithParams(load_params);
-  timer_->Start(
-      FROM_HERE, base::TimeDelta::FromSeconds(kSecondsToWaitForWebContentsLoad),
-      base::BindOnce(&PendingBookmarkAppManager::OnWebContentsLoadTimedOut,
-                     weak_ptr_factory_.GetWeakPtr()));
+  url_loader_->LoadUrl(current_task_and_callback_->task->app_info().url,
+                       web_contents_.get(),
+                       base::BindOnce(&PendingBookmarkAppManager::OnUrlLoaded,
+                                      weak_ptr_factory_.GetWeakPtr()));
 }
 
 void PendingBookmarkAppManager::CreateWebContentsIfNecessary() {
@@ -210,26 +195,34 @@
   BookmarkAppInstallationTask::CreateTabHelpers(web_contents_.get());
 }
 
+void PendingBookmarkAppManager::OnUrlLoaded(
+    web_app::WebAppUrlLoader::Result result) {
+  if (result != web_app::WebAppUrlLoader::Result::kUrlLoaded) {
+    CurrentInstallationFinished(base::nullopt);
+    return;
+  }
+
+  current_task_and_callback_->task->Install(
+      web_contents_.get(),
+      base::BindOnce(&PendingBookmarkAppManager::OnInstalled,
+                     // Safe because the installation task will not run its
+                     // callback after being deleted and this class owns the
+                     // task.
+                     base::Unretained(this)));
+}
+
 void PendingBookmarkAppManager::OnInstalled(
     BookmarkAppInstallationTask::Result result) {
   CurrentInstallationFinished(result.app_id);
 }
 
-void PendingBookmarkAppManager::OnWebContentsLoadTimedOut() {
-  web_contents_->Stop();
-  LOG(ERROR) << "Error installing "
-             << current_task_and_callback_->task->app_info().url.spec();
-  LOG(ERROR) << "  page took too long to load.";
-  Observe(nullptr);
-  CurrentInstallationFinished(base::nullopt);
-}
-
 void PendingBookmarkAppManager::CurrentInstallationFinished(
     const base::Optional<std::string>& app_id) {
-  // Post a task to avoid reentrancy issues e.g. adding a WebContentsObserver
-  // while a previous observer call is being executed. Post a task before
+  // Post a task to avoid InstallableManager crashing and do so before
   // running the callback in case the callback tries to install another
   // app.
+  // TODO(crbug.com/943848): Run next installation synchronously once
+  // InstallableManager is fixed.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&PendingBookmarkAppManager::MaybeStartNextInstallation,
@@ -245,47 +238,4 @@
       .Run(task_and_callback->task->app_info().url, install_result_code);
 }
 
-void PendingBookmarkAppManager::DidFinishLoad(
-    content::RenderFrameHost* render_frame_host,
-    const GURL& validated_url) {
-  timer_->Stop();
-  if (web_contents_->GetMainFrame() != render_frame_host) {
-    return;
-  }
-
-  if (validated_url != current_task_and_callback_->task->app_info().url) {
-    LOG(ERROR) << "Error installing "
-               << current_task_and_callback_->task->app_info().url.spec();
-    LOG(ERROR) << "  page redirected to " << validated_url.spec();
-    CurrentInstallationFinished(base::nullopt);
-    return;
-  }
-
-  Observe(nullptr);
-  current_task_and_callback_->task->Install(
-      web_contents_.get(),
-      base::BindOnce(&PendingBookmarkAppManager::OnInstalled,
-                     // Safe because the installation task will not run its
-                     // callback after being deleted and this class owns the
-                     // task.
-                     base::Unretained(this)));
-}
-
-void PendingBookmarkAppManager::DidFailLoad(
-    content::RenderFrameHost* render_frame_host,
-    const GURL& validated_url,
-    int error_code,
-    const base::string16& error_description) {
-  timer_->Stop();
-  if (web_contents_->GetMainFrame() != render_frame_host) {
-    return;
-  }
-
-  LOG(ERROR) << "Error installing "
-             << current_task_and_callback_->task->app_info().url.spec();
-  LOG(ERROR) << "  page failed to load.";
-  Observe(nullptr);
-  CurrentInstallationFinished(base::nullopt);
-}
-
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h
index 696de12..18cb00e 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h
@@ -14,18 +14,16 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
-#include "base/timer/timer.h"
 #include "chrome/browser/web_applications/components/pending_app_manager.h"
+#include "chrome/browser/web_applications/components/web_app_url_loader.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_installation_task.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_uninstaller.h"
 #include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h"
-#include "content/public/browser/web_contents_observer.h"
 
 class GURL;
 class Profile;
 
 namespace content {
-class RenderFrameHost;
 class WebContents;
 }  // namespace content
 
@@ -40,8 +38,7 @@
 //
 // WebAppProvider creates an instance of this class and manages its
 // lifetime. This class should only be used from the UI thread.
-class PendingBookmarkAppManager final : public web_app::PendingAppManager,
-                                        public content::WebContentsObserver {
+class PendingBookmarkAppManager final : public web_app::PendingAppManager {
  public:
   using WebContentsFactory =
       base::RepeatingCallback<std::unique_ptr<content::WebContents>(Profile*)>;
@@ -66,7 +63,6 @@
                               TaskFactory task_factory);
   void SetUninstallerForTesting(
       std::unique_ptr<BookmarkAppUninstaller> uninstaller);
-  void SetTimerForTesting(std::unique_ptr<base::OneShotTimer> timer);
 
  private:
   struct TaskAndCallback;
@@ -84,30 +80,24 @@
 
   void CreateWebContentsIfNecessary();
 
+  void OnUrlLoaded(web_app::WebAppUrlLoader::Result result);
+
   void OnInstalled(BookmarkAppInstallationTask::Result result);
 
-  void OnWebContentsLoadTimedOut();
-
   void CurrentInstallationFinished(const base::Optional<std::string>& app_id);
 
-  // WebContentsObserver
-  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
-                     const GURL& validated_url) override;
-  void DidFailLoad(content::RenderFrameHost* render_frame_host,
-                   const GURL& validated_url,
-                   int error_code,
-                   const base::string16& error_description) override;
-
   Profile* profile_;
   web_app::AppRegistrar* registrar_;
   std::unique_ptr<BookmarkAppUninstaller> uninstaller_;
   web_app::ExtensionIdsMap extension_ids_map_;
 
+  // unique_ptr so that it can be replaced in tests.
+  std::unique_ptr<web_app::WebAppUrlLoader> url_loader_;
+
   WebContentsFactory web_contents_factory_;
   TaskFactory task_factory_;
 
   std::unique_ptr<content::WebContents> web_contents_;
-  std::unique_ptr<base::OneShotTimer> timer_;
 
   std::unique_ptr<TaskAndCallback> current_task_and_callback_;
 
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
index 1c6000a3..cda7af5 100644
--- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
@@ -34,7 +34,6 @@
 const char kFooWebAppUrl[] = "https://foo.example";
 const char kBarWebAppUrl[] = "https://bar.example";
 const char kQuxWebAppUrl[] = "https://qux.example";
-const char kXyzWebAppUrl[] = "https://xyz.example";
 
 const char kWrongUrl[] = "https://foobar.example";
 
@@ -65,13 +64,6 @@
   return info;
 }
 
-web_app::PendingAppManager::AppInfo GetXyzAppInfo() {
-  web_app::PendingAppManager::AppInfo info(
-      GURL(kXyzWebAppUrl), web_app::LaunchContainer::kWindow,
-      web_app::InstallSource::kExternalPolicy);
-  return info;
-}
-
 std::string GenerateFakeAppId(const GURL& url) {
   return std::string("fake_app_id_for:") + url.spec();
 }
@@ -286,6 +278,7 @@
   void SuccessfullyLoad(const GURL& url) {
     web_contents_tester_->NavigateAndCommit(url);
     web_contents_tester_->TestDidFinishLoad(url);
+    base::RunLoop().RunUntilIdle();
   }
 
   content::WebContentsTester* web_contents_tester() {
@@ -581,15 +574,6 @@
   EXPECT_TRUE(app_installed());
   EXPECT_EQ(GetFooAppInfo(), last_app_info());
   EXPECT_EQ(GURL(kFooWebAppUrl), install_callback_url());
-  ResetResults();
-
-  base::RunLoop().RunUntilIdle();
-
-  // The second installation should succeed even though the app is installed
-  // already.
-  EXPECT_EQ(0u, installation_task_run_count());
-  EXPECT_TRUE(app_installed());
-  EXPECT_EQ(GURL(kFooWebAppUrl), install_callback_url());
 }
 
 TEST_F(PendingBookmarkAppManagerTest, Install_AlwaysUpdate) {
@@ -851,88 +835,6 @@
   EXPECT_EQ(GURL(kBarWebAppUrl), install_callback_url());
 }
 
-TEST_F(PendingBookmarkAppManagerTest, WebContentsLoadTimedOut) {
-  auto pending_app_manager = GetPendingBookmarkAppManagerWithTestFactories();
-  auto timer_to_pass = std::make_unique<base::MockOneShotTimer>();
-  auto* timer = timer_to_pass.get();
-
-  pending_app_manager->SetTimerForTesting(std::move(timer_to_pass));
-
-  // Queue an app through Install.
-  pending_app_manager->Install(
-      GetQuxAppInfo(),
-      base::BindOnce(&PendingBookmarkAppManagerTest::InstallCallback,
-                     base::Unretained(this)));
-  base::RunLoop().RunUntilIdle();
-
-  // Verify that the timer is stopped after a successful load.
-  EXPECT_TRUE(timer->IsRunning());
-  SuccessfullyLoad(GURL(kQuxWebAppUrl));
-  EXPECT_FALSE(timer->IsRunning());
-  EXPECT_EQ(1u, installation_task_run_count());
-  EXPECT_TRUE(app_installed());
-  EXPECT_EQ(GURL(kQuxWebAppUrl), install_callback_url());
-  ResetResults();
-
-  // Queue a different app through Install.
-  pending_app_manager->Install(
-      GetXyzAppInfo(),
-      base::BindOnce(&PendingBookmarkAppManagerTest::InstallCallback,
-                     base::Unretained(this)));
-  base::RunLoop().RunUntilIdle();
-
-  // Fire the timer to simulate a failed load.
-  EXPECT_TRUE(timer->IsRunning());
-  timer->Fire();
-  EXPECT_FALSE(app_installed());
-  EXPECT_EQ(GURL(kXyzWebAppUrl), install_callback_url());
-  ResetResults();
-
-  // Queue two more apps, different from all those before, through InstallApps.
-  std::vector<web_app::PendingAppManager::AppInfo> apps_to_install;
-  apps_to_install.push_back(GetFooAppInfo());
-  apps_to_install.push_back(GetBarAppInfo());
-
-  pending_app_manager->InstallApps(
-      std::move(apps_to_install),
-      base::BindRepeating(&PendingBookmarkAppManagerTest::InstallCallback,
-                          base::Unretained(this)));
-
-  base::RunLoop().RunUntilIdle();
-
-  // Fire the timer to simulate a failed load.
-  EXPECT_TRUE(timer->IsRunning());
-  timer->Fire();
-  EXPECT_FALSE(app_installed());
-  EXPECT_EQ(GURL(kFooWebAppUrl), install_callback_url());
-  ResetResults();
-
-  base::RunLoop().RunUntilIdle();
-
-  // Fire the timer to simulate a failed load.
-  EXPECT_TRUE(timer->IsRunning());
-  timer->Fire();
-  EXPECT_FALSE(app_installed());
-  EXPECT_EQ(GURL(kBarWebAppUrl), install_callback_url());
-  ResetResults();
-
-  // Ensure a successful load after a timer fire works.
-  pending_app_manager->Install(
-      GetBarAppInfo(),
-      base::BindOnce(&PendingBookmarkAppManagerTest::InstallCallback,
-                     base::Unretained(this)));
-  base::RunLoop().RunUntilIdle();
-
-  // Verify that the timer is stopped after a successful load.
-  EXPECT_TRUE(timer->IsRunning());
-  SuccessfullyLoad(GURL(kBarWebAppUrl));
-  EXPECT_FALSE(timer->IsRunning());
-  EXPECT_EQ(1u, installation_task_run_count());
-  EXPECT_TRUE(app_installed());
-  EXPECT_EQ(GetBarAppInfo(), last_app_info());
-  EXPECT_EQ(GURL(kBarWebAppUrl), install_callback_url());
-}
-
 TEST_F(PendingBookmarkAppManagerTest, ExtensionUninstalled) {
   auto pending_app_manager = GetPendingBookmarkAppManagerWithTestFactories();
   pending_app_manager->Install(
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 86f74cde..7d5a30b7d 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -82,6 +82,18 @@
                                   weak_ptr_factory_.GetWeakPtr()));
 }
 
+AppRegistrar& WebAppProvider::registrar() {
+  return *registrar_;
+}
+
+InstallManager& WebAppProvider::install_manager() {
+  return *install_manager_;
+}
+
+PendingAppManager& WebAppProvider::pending_app_manager() {
+  return *pending_app_manager_;
+}
+
 void WebAppProvider::CreateWebAppsSubsystems(Profile* profile) {
   database_factory_ = std::make_unique<WebAppDatabaseFactory>(profile);
   database_ = std::make_unique<WebAppDatabase>(database_factory_.get());
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h
index fd72c4a7..0e6cc36 100644
--- a/chrome/browser/web_applications/web_app_provider.h
+++ b/chrome/browser/web_applications/web_app_provider.h
@@ -14,7 +14,7 @@
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/pending_app_manager.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
-#include "components/keyed_service/core/keyed_service.h"
+#include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
@@ -49,7 +49,7 @@
 // Connects Web App features, such as the installation of default and
 // policy-managed web apps, with Profiles (as WebAppProvider is a
 // Profile-linked KeyedService) and their associated PrefService.
-class WebAppProvider : public KeyedService,
+class WebAppProvider : public WebAppProviderBase,
                        public content::NotificationObserver {
  public:
   static WebAppProvider* Get(Profile* profile);
@@ -63,14 +63,10 @@
   // Start registry. All subsystems depend on it.
   void StartRegistry();
 
-  AppRegistrar& registrar() { return *registrar_; }
-
-  // UIs can use InstallManager for user-initiated Web Apps install.
-  InstallManager& install_manager() { return *install_manager_; }
-
-  // Clients can use PendingAppManager to install, uninstall, and update
-  // Web Apps.
-  PendingAppManager& pending_app_manager() { return *pending_app_manager_; }
+  // WebAppProviderBase:
+  AppRegistrar& registrar() override;
+  InstallManager& install_manager() override;
+  PendingAppManager& pending_app_manager() override;
 
   const SystemWebAppManager& system_web_app_manager() {
     return *system_web_app_manager_;
diff --git a/chrome/browser/web_applications/web_app_provider_factory.cc b/chrome/browser/web_applications/web_app_provider_factory.cc
index 297a911..4209d59 100644
--- a/chrome/browser/web_applications/web_app_provider_factory.cc
+++ b/chrome/browser/web_applications/web_app_provider_factory.cc
@@ -26,14 +26,18 @@
 }
 
 WebAppProviderFactory::WebAppProviderFactory()
-    : BrowserContextKeyedServiceFactory(
+    : WebAppProviderBaseFactory(
           "WebAppProvider",
           BrowserContextDependencyManager::GetInstance()) {
+  WebAppProviderBaseFactory::SetInstance(this);
+
   DependsOn(
       extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
 }
 
-WebAppProviderFactory::~WebAppProviderFactory() = default;
+WebAppProviderFactory::~WebAppProviderFactory() {
+  WebAppProviderBaseFactory::SetInstance(nullptr);
+}
 
 KeyedService* WebAppProviderFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
diff --git a/chrome/browser/web_applications/web_app_provider_factory.h b/chrome/browser/web_applications/web_app_provider_factory.h
index ec7dc86..7a8c53b 100644
--- a/chrome/browser/web_applications/web_app_provider_factory.h
+++ b/chrome/browser/web_applications/web_app_provider_factory.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "chrome/browser/web_applications/components/web_app_provider_base_factory.h"
 
 namespace content {
 class BrowserContext;
@@ -21,7 +21,7 @@
 
 // Singleton that owns all WebAppProviderFactories and associates them with
 // Profile.
-class WebAppProviderFactory : public BrowserContextKeyedServiceFactory {
+class WebAppProviderFactory : public WebAppProviderBaseFactory {
  public:
   static WebAppProvider* GetForProfile(Profile* profile);
 
diff --git a/chrome/common/heap_profiler_controller.cc b/chrome/common/heap_profiler_controller.cc
index e1943de..738953fb 100644
--- a/chrome/common/heap_profiler_controller.cc
+++ b/chrome/common/heap_profiler_controller.cc
@@ -23,14 +23,6 @@
 namespace {
 
 constexpr char kMetadataSizeField[] = "HeapProfiler.AllocationInBytes";
-
-constexpr base::Feature kSamplingHeapProfilerFeature{
-    "SamplingHeapProfiler", base::FEATURE_DISABLED_BY_DEFAULT};
-
-constexpr char kSamplingHeapProfilerFeatureSamplingRateKB[] =
-    "sampling-rate-kb";
-
-constexpr size_t kDefaultSamplingRateKB = 128;
 constexpr base::TimeDelta kHeapCollectionInterval =
     base::TimeDelta::FromHours(24);
 
@@ -61,35 +53,7 @@
 HeapProfilerController::HeapProfilerController() = default;
 HeapProfilerController::~HeapProfilerController() = default;
 
-void HeapProfilerController::StartIfEnabled() {
-  DCHECK(!started_);
-  size_t sampling_rate_kb = 0;
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kSamplingHeapProfiler)) {
-    unsigned value;
-    bool parsed = base::StringToUint(
-        command_line->GetSwitchValueASCII(switches::kSamplingHeapProfiler),
-        &value);
-    sampling_rate_kb = parsed ? value : kDefaultSamplingRateKB;
-  }
-
-  bool on_trial = base::FeatureList::IsEnabled(kSamplingHeapProfilerFeature);
-  if (on_trial && !sampling_rate_kb) {
-    sampling_rate_kb = std::max(
-        base::GetFieldTrialParamByFeatureAsInt(
-            kSamplingHeapProfilerFeature,
-            kSamplingHeapProfilerFeatureSamplingRateKB, kDefaultSamplingRateKB),
-        0);
-  }
-
-  if (!sampling_rate_kb)
-    return;
-
-  started_ = true;
-  auto* profiler = base::SamplingHeapProfiler::Get();
-  profiler->SetSamplingInterval(sampling_rate_kb * 1024);
-  profiler->Start();
-
+void HeapProfilerController::Start() {
   ScheduleNextSnapshot();
 }
 
diff --git a/chrome/common/heap_profiler_controller.h b/chrome/common/heap_profiler_controller.h
index aef276b5..5f6bc53 100644
--- a/chrome/common/heap_profiler_controller.h
+++ b/chrome/common/heap_profiler_controller.h
@@ -22,7 +22,7 @@
   ~HeapProfilerController();
 
   // Starts periodic heap snapshot collection.
-  void StartIfEnabled();
+  void Start();
 
   void SetTaskRunnerForTest(scoped_refptr<base::TaskRunner> task_runner) {
     task_runner_ = std::move(task_runner);
@@ -33,7 +33,6 @@
   void TakeSnapshot();
   void RetrieveAndSendSnapshot();
 
-  bool started_ = false;
   scoped_refptr<base::TaskRunner> task_runner_;
   base::WeakPtrFactory<HeapProfilerController> weak_factory_{this};
 
diff --git a/chrome/common/heap_profiler_controller_unittest.cc b/chrome/common/heap_profiler_controller_unittest.cc
index 7d5c379..8f9ae673 100644
--- a/chrome/common/heap_profiler_controller_unittest.cc
+++ b/chrome/common/heap_profiler_controller_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/metrics/metrics_hashes.h"
-#include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
+#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "build/build_config.h"
 #include "components/metrics/call_stack_profile_builder.h"
@@ -52,26 +52,23 @@
   ++*profiles_count;
 }
 
-#if !defined(OS_ANDROID) || \
-    BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && defined(OFFICIAL_BUILD)
-#define MAYBE_ProfileCollectionsScheduler ProfileCollectionsScheduler
-#else
-#define MAYBE_ProfileCollectionsScheduler DISABLED_ProfileCollectionsScheduler
-#endif
-TEST(HeapProfilerControllerTest, MAYBE_ProfileCollectionsScheduler) {
+// Sampling profiler is not capable of unwinding stack on Android under tests.
+#if !defined(OS_ANDROID)
+TEST(HeapProfilerControllerTest, ProfileCollectionsScheduler) {
   auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
   base::TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner.get());
 
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  command_line->AppendSwitchASCII(switches::kSamplingHeapProfiler, "1");
+  base::SamplingHeapProfiler::Init();
+  auto* profiler = base::SamplingHeapProfiler::Get();
+  profiler->SetSamplingInterval(1024);
+  profiler->Start();
 
   int profiles_collected = 0;
   metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback(
       base::BindRepeating(&CheckProfile, &profiles_collected));
-  base::PoissonAllocationSampler::Init();
   HeapProfilerController controller;
   controller.SetTaskRunnerForTest(task_runner.get());
-  controller.StartIfEnabled();
+  controller.Start();
   auto* sampler = base::PoissonAllocationSampler::Get();
   sampler->SuppressRandomnessForTest(true);
   sampler->RecordAlloc(reinterpret_cast<void*>(0x1337), kAllocationSize,
@@ -82,3 +79,4 @@
     task_runner->FastForwardBy(base::TimeDelta::FromHours(1));
   } while (profiles_collected < 2);
 }
+#endif
diff --git a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
index 498537a..2922a51 100644
--- a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
+++ b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
@@ -192,8 +192,19 @@
     case ui::AXEventGenerator::Event::STATE_CHANGED:
       return api::automation::EVENT_TYPE_ARIAATTRIBUTECHANGED;
 
+    case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED:
+    case ui::AXEventGenerator::Event::CLASS_NAME_CHANGED:
+    case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
+    case ui::AXEventGenerator::Event::FLOW_TO_CHANGED:
+    case ui::AXEventGenerator::Event::HIERARCHICAL_LEVEL_CHANGED:
+    case ui::AXEventGenerator::Event::KEY_SHORTCUTS_CHANGED:
+    case ui::AXEventGenerator::Event::LABELED_BY_CHANGED:
+    case ui::AXEventGenerator::Event::LANGUAGE_CHANGED:
     case ui::AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED:
+    case ui::AXEventGenerator::Event::PLACEHOLDER_CHANGED:
+    case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
+    case ui::AXEventGenerator::Event::SET_SIZE_CHANGED:
       return api::automation::EVENT_TYPE_NONE;
   }
 
diff --git a/chrome/services/app_service/README.md b/chrome/services/app_service/README.md
index af494d0..7d4fdf9 100644
--- a/chrome/services/app_service/README.md
+++ b/chrome/services/app_service/README.md
@@ -258,19 +258,21 @@
 `Publisher` sends an `IconKey`: enough information to load the icon at given
 resolutions.
 
-An `IconKey` holds an `AppType app_type` and `string app_id`, plus additional
-data. For example, some icons are statically built into the Chrome or Chrome OS
-binary, as PNG-formatted resources, and can be loaded (synchronously, without
-sandboxing). They can be loaded from the `IconKey.resource_id`. Other icons are
-dynamically (and asynchronously) loaded from the extension database on disk.
-They can be loaded just from the `app_id` alone.
+An `IconKey` augments the `AppType app_type` and `string app_id`. For example,
+some icons are statically built into the Chrome or Chrome OS binary, as
+PNG-formatted resources, and can be loaded (synchronously, without sandboxing).
+They can be loaded from the `IconKey.resource_id`. Other icons are dynamically
+(and asynchronously) loaded from the extension database on disk. The base icon
+can be loaded just from the `app_id` alone.
 
 In either case, the `IconKey.icon_effects` bitmask holds whether to apply
-various image processing effects such as desaturation to gray.
+further image processing effects such as desaturation to gray.
 
     interface AppService {
       // App Icon Factory methods.
       LoadIcon(
+          AppType app_type,
+          string app_id,
           IconKey icon_key,
           IconCompression icon_compression,
           int32 size_hint_in_dip,
@@ -282,6 +284,7 @@
     interface Publisher {
       // App Icon Factory methods.
       LoadIcon(
+          string app_id,
           IconKey icon_key,
           IconCompression icon_compression,
           int32 size_hint_in_dip,
@@ -291,8 +294,6 @@
     };
 
     struct IconKey {
-      AppType app_type,
-      string app_id,
       // A monotonically increasing number so that, after an icon update, a new
       // IconKey, one that is different in terms of field-by-field equality, can be
       // broadcast by a Publisher.
diff --git a/chrome/services/app_service/app_service_impl.cc b/chrome/services/app_service/app_service_impl.cc
index 903dbbb..6a5b24f 100644
--- a/chrome/services/app_service/app_service_impl.cc
+++ b/chrome/services/app_service/app_service_impl.cc
@@ -63,17 +63,19 @@
   subscribers_.AddPtr(std::move(subscriber));
 }
 
-void AppServiceImpl::LoadIcon(apps::mojom::IconKeyPtr icon_key,
+void AppServiceImpl::LoadIcon(apps::mojom::AppType app_type,
+                              const std::string& app_id,
+                              apps::mojom::IconKeyPtr icon_key,
                               apps::mojom::IconCompression icon_compression,
                               int32_t size_hint_in_dip,
                               bool allow_placeholder_icon,
                               LoadIconCallback callback) {
-  auto iter = publishers_.find(icon_key->app_type);
+  auto iter = publishers_.find(app_type);
   if (iter == publishers_.end()) {
     std::move(callback).Run(apps::mojom::IconValue::New());
     return;
   }
-  iter->second->LoadIcon(std::move(icon_key), icon_compression,
+  iter->second->LoadIcon(app_id, std::move(icon_key), icon_compression,
                          size_hint_in_dip, allow_placeholder_icon,
                          std::move(callback));
 }
diff --git a/chrome/services/app_service/app_service_impl.h b/chrome/services/app_service/app_service_impl.h
index 4ff73651..61688131 100644
--- a/chrome/services/app_service/app_service_impl.h
+++ b/chrome/services/app_service/app_service_impl.h
@@ -31,7 +31,9 @@
                          apps::mojom::AppType app_type) override;
   void RegisterSubscriber(apps::mojom::SubscriberPtr subscriber,
                           apps::mojom::ConnectOptionsPtr opts) override;
-  void LoadIcon(apps::mojom::IconKeyPtr icon_key,
+  void LoadIcon(apps::mojom::AppType app_type,
+                const std::string& app_id,
+                apps::mojom::IconKeyPtr icon_key,
                 apps::mojom::IconCompression icon_compression,
                 int32_t size_hint_in_dip,
                 bool allow_placeholder_icon,
diff --git a/chrome/services/app_service/app_service_impl_unittest.cc b/chrome/services/app_service/app_service_impl_unittest.cc
index 17c190e..fbf69105 100644
--- a/chrome/services/app_service/app_service_impl_unittest.cc
+++ b/chrome/services/app_service/app_service_impl_unittest.cc
@@ -46,12 +46,13 @@
     subscribers_.AddPtr(std::move(subscriber));
   }
 
-  void LoadIcon(apps::mojom::IconKeyPtr icon_key,
+  void LoadIcon(const std::string& app_id,
+                apps::mojom::IconKeyPtr icon_key,
                 apps::mojom::IconCompression icon_compression,
                 int32_t size_hint_in_dip,
                 bool allow_placeholder_icon,
                 LoadIconCallback callback) override {
-    load_icon_app_id = icon_key->app_id;
+    load_icon_app_id = app_id;
     std::move(callback).Run(apps::mojom::IconValue::New());
   }
 
@@ -196,11 +197,12 @@
     pub0.load_icon_app_id = "-";
     pub1.load_icon_app_id = "-";
     pub2.load_icon_app_id = "-";
-    auto icon_key = apps::mojom::IconKey::New(app_type, "o", 0, 0, 0);
+    auto icon_key = apps::mojom::IconKey::New(0, 0, 0);
     constexpr bool allow_placeholder_icon = false;
     impl.LoadIcon(
-        std::move(icon_key), apps::mojom::IconCompression::kUncompressed,
-        size_hint_in_dip, allow_placeholder_icon,
+        app_type, "o", std::move(icon_key),
+        apps::mojom::IconCompression::kUncompressed, size_hint_in_dip,
+        allow_placeholder_icon,
         base::BindOnce(
             [](bool* ran, apps::mojom::IconValuePtr iv) { *ran = true; },
             &callback_ran));
diff --git a/chrome/services/app_service/public/cpp/app_update_unittest.cc b/chrome/services/app_service/public/cpp/app_update_unittest.cc
index 62e4dc7..574c959a 100644
--- a/chrome/services/app_service/public/cpp/app_update_unittest.cc
+++ b/chrome/services/app_service/public/cpp/app_update_unittest.cc
@@ -241,7 +241,7 @@
     // IconKey tests.
 
     if (state) {
-      auto x = apps::mojom::IconKey::New(app_type, app_id, 100, 0, 0);
+      auto x = apps::mojom::IconKey::New(100, 0, 0);
       state->icon_key = x.Clone();
       expect_icon_key_ = x.Clone();
       expect_icon_key_changed_ = false;
@@ -249,7 +249,7 @@
     }
 
     if (delta) {
-      auto x = apps::mojom::IconKey::New(app_type, app_id, 200, 0, 0);
+      auto x = apps::mojom::IconKey::New(200, 0, 0);
       delta->icon_key = x.Clone();
       expect_icon_key_ = x.Clone();
       expect_icon_key_changed_ = true;
diff --git a/chrome/services/app_service/public/cpp/icon_cache.cc b/chrome/services/app_service/public/cpp/icon_cache.cc
index 4c55201..ac86fe99 100644
--- a/chrome/services/app_service/public/cpp/icon_cache.cc
+++ b/chrome/services/app_service/public/cpp/icon_cache.cc
@@ -34,6 +34,8 @@
 }
 
 std::unique_ptr<IconLoader::Releaser> IconCache::LoadIconFromIconKey(
+    apps::mojom::AppType app_type,
+    const std::string& app_id,
     apps::mojom::IconKeyPtr icon_key,
     apps::mojom::IconCompression icon_compression,
     int32_t size_hint_in_dip,
@@ -42,7 +44,8 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   apps::mojom::IconKey null_icon_key;
   IconLoader::Key key(
-      icon_key ? *icon_key : null_icon_key, icon_compression, size_hint_in_dip,
+      app_type, app_id, icon_key ? *icon_key : null_icon_key, icon_compression,
+      size_hint_in_dip,
       // We pass false instead of allow_placeholder_icon, as the Value
       // already records placeholder-ness. If the allow_placeholder_icon
       // arg to this function is true, we can re-use a cache hit regardless
@@ -71,8 +74,8 @@
     std::move(callback).Run(cache_hit->AsIconValue());
   } else if (wrapped_loader_) {
     releaser = wrapped_loader_->LoadIconFromIconKey(
-        std::move(icon_key), icon_compression, size_hint_in_dip,
-        allow_placeholder_icon,
+        app_type, app_id, std::move(icon_key), icon_compression,
+        size_hint_in_dip, allow_placeholder_icon,
         base::BindOnce(&IconCache::OnLoadIcon, weak_ptr_factory_.GetWeakPtr(),
                        key, std::move(callback)));
   } else {
diff --git a/chrome/services/app_service/public/cpp/icon_cache.h b/chrome/services/app_service/public/cpp/icon_cache.h
index 0f567fc..6ee992d 100644
--- a/chrome/services/app_service/public/cpp/icon_cache.h
+++ b/chrome/services/app_service/public/cpp/icon_cache.h
@@ -72,6 +72,8 @@
   // IconLoader overrides.
   apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override;
   std::unique_ptr<IconLoader::Releaser> LoadIconFromIconKey(
+      apps::mojom::AppType app_type,
+      const std::string& app_id,
       apps::mojom::IconKeyPtr icon_key,
       apps::mojom::IconCompression icon_compression,
       int32_t size_hint_in_dip,
diff --git a/chrome/services/app_service/public/cpp/icon_cache_unittest.cc b/chrome/services/app_service/public/cpp/icon_cache_unittest.cc
index 6cb7fd9..a0ab7e0 100644
--- a/chrome/services/app_service/public/cpp/icon_cache_unittest.cc
+++ b/chrome/services/app_service/public/cpp/icon_cache_unittest.cc
@@ -30,11 +30,12 @@
 
    private:
     apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override {
-      return apps::mojom::IconKey::New(apps::mojom::AppType::kWeb, app_id, 0, 0,
-                                       0);
+      return apps::mojom::IconKey::New(0, 0, 0);
     }
 
     std::unique_ptr<Releaser> LoadIconFromIconKey(
+        apps::mojom::AppType app_type,
+        const std::string& app_id,
         apps::mojom::IconKeyPtr icon_key,
         apps::mojom::IconCompression icon_compression,
         int32_t size_hint_in_dip,
@@ -63,6 +64,7 @@
                           const std::string& app_id,
                           HitOrMiss expect_hom,
                           bool allow_placeholder_icon = false) {
+    static constexpr auto app_type = apps::mojom::AppType::kWeb;
     static constexpr auto icon_compression =
         apps::mojom::IconCompression::kUncompressed;
     static constexpr int32_t size_hint_in_dip = 1;
@@ -70,7 +72,7 @@
     int before = fake->NumLoadIconFromIconKeyCalls();
 
     UniqueReleaser releaser =
-        loader->LoadIcon(app_id, icon_compression, size_hint_in_dip,
+        loader->LoadIcon(app_type, app_id, icon_compression, size_hint_in_dip,
                          allow_placeholder_icon, base::DoNothing());
 
     int after = fake->NumLoadIconFromIconKeyCalls();
diff --git a/chrome/services/app_service/public/cpp/icon_loader.cc b/chrome/services/app_service/public/cpp/icon_loader.cc
index b06b875..3f405dd 100644
--- a/chrome/services/app_service/public/cpp/icon_loader.cc
+++ b/chrome/services/app_service/public/cpp/icon_loader.cc
@@ -18,12 +18,14 @@
   std::move(closure_).Run();
 }
 
-IconLoader::Key::Key(const apps::mojom::IconKey& icon_key,
+IconLoader::Key::Key(apps::mojom::AppType app_type,
+                     const std::string& app_id,
+                     const apps::mojom::IconKey& icon_key,
                      apps::mojom::IconCompression icon_compression,
                      int32_t size_hint_in_dip,
                      bool allow_placeholder_icon)
-    : app_type_(icon_key.app_type),
-      app_id_(icon_key.app_id),
+    : app_type_(app_type),
+      app_id_(app_id),
       timeline_(icon_key.timeline),
       resource_id_(icon_key.resource_id),
       icon_effects_(icon_key.icon_effects),
@@ -59,14 +61,15 @@
 }
 
 std::unique_ptr<IconLoader::Releaser> IconLoader::LoadIcon(
+    apps::mojom::AppType app_type,
     const std::string& app_id,
     apps::mojom::IconCompression icon_compression,
     int32_t size_hint_in_dip,
     bool allow_placeholder_icon,
     apps::mojom::Publisher::LoadIconCallback callback) {
-  return LoadIconFromIconKey(GetIconKey(app_id), icon_compression,
-                             size_hint_in_dip, allow_placeholder_icon,
-                             std::move(callback));
+  return LoadIconFromIconKey(app_type, app_id, GetIconKey(app_id),
+                             icon_compression, size_hint_in_dip,
+                             allow_placeholder_icon, std::move(callback));
 }
 
 }  // namespace apps
diff --git a/chrome/services/app_service/public/cpp/icon_loader.h b/chrome/services/app_service/public/cpp/icon_loader.h
index 59f01be..4a1eb6f 100644
--- a/chrome/services/app_service/public/cpp/icon_loader.h
+++ b/chrome/services/app_service/public/cpp/icon_loader.h
@@ -51,6 +51,8 @@
   // This can return nullptr, meaning that the IconLoader does not track when
   // the icon is no longer actively used by the caller.
   virtual std::unique_ptr<Releaser> LoadIconFromIconKey(
+      apps::mojom::AppType app_type,
+      const std::string& app_id,
       apps::mojom::IconKeyPtr icon_key,
       apps::mojom::IconCompression icon_compression,
       int32_t size_hint_in_dip,
@@ -59,6 +61,7 @@
 
   // Convenience method that calls LoadIconFromIconKey(GetIconKey(app_id), etc).
   std::unique_ptr<Releaser> LoadIcon(
+      apps::mojom::AppType app_type,
       const std::string& app_id,
       apps::mojom::IconCompression icon_compression,
       int32_t size_hint_in_dip,
@@ -75,9 +78,9 @@
   // callers, are expected to refer to a Key.
   class Key {
    public:
-    // apps::mojom::IconKey fields.
     apps::mojom::AppType app_type_;
     std::string app_id_;
+    // apps::mojom::IconKey fields.
     uint64_t timeline_;
     int32_t resource_id_;
     uint32_t icon_effects_;
@@ -86,7 +89,9 @@
     int32_t size_hint_in_dip_;
     bool allow_placeholder_icon_;
 
-    Key(const apps::mojom::IconKey& icon_key,
+    Key(apps::mojom::AppType app_type,
+        const std::string& app_id,
+        const apps::mojom::IconKey& icon_key,
         apps::mojom::IconCompression icon_compression,
         int32_t size_hint_in_dip,
         bool allow_placeholder_icon);
diff --git a/chrome/services/app_service/public/mojom/app_service.mojom b/chrome/services/app_service/public/mojom/app_service.mojom
index e1d90893..20bc648 100644
--- a/chrome/services/app_service/public/mojom/app_service.mojom
+++ b/chrome/services/app_service/public/mojom/app_service.mojom
@@ -20,6 +20,8 @@
 
   // App Icon Factory methods.
   LoadIcon(
+      AppType app_type,
+      string app_id,
       IconKey icon_key,
       IconCompression icon_compression,
       int32 size_hint_in_dip,
@@ -53,6 +55,7 @@
 
   // App Icon Factory methods.
   LoadIcon(
+      string app_id,
       IconKey icon_key,
       IconCompression icon_compression,
       int32 size_hint_in_dip,
diff --git a/chrome/services/app_service/public/mojom/types.mojom b/chrome/services/app_service/public/mojom/types.mojom
index a556094..c0c1a2e 100644
--- a/chrome/services/app_service/public/mojom/types.mojom
+++ b/chrome/services/app_service/public/mojom/types.mojom
@@ -90,8 +90,6 @@
 
   const int32 kInvalidResourceId = 0;
 
-  AppType app_type;
-  string app_id;
   // A monotonically increasing number so that, after an icon update, a new
   // IconKey, one that is different in terms of field-by-field equality, can be
   // broadcast by a Publisher.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index ab9fbfe..2dc0e85 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2752,6 +2752,7 @@
     "../browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/use_counter_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/page_load_metrics_util_unittest.cc",
+    "../browser/page_load_metrics/resource_tracker_unittest.cc",
     "../browser/password_manager/chrome_password_manager_client_unittest.cc",
     "../browser/password_manager/password_manager_internals_service_unittest.cc",
     "../browser/password_manager/password_store_mac_unittest.cc",
@@ -3384,6 +3385,7 @@
       "../browser/search/search_suggest/search_suggest_service_unittest.cc",
       "../browser/search/search_unittest.cc",
       "../browser/send_tab_to_self/desktop_notification_handler_unittest.cc",
+      "../browser/send_tab_to_self/send_tab_to_self_client_service_unittest.cc",
       "../browser/send_tab_to_self/send_tab_to_self_util_unittest.cc",
       "../browser/serial/serial_chooser_context_unittest.cc",
       "../browser/sessions/tab_restore_service_unittest.cc",
@@ -3445,7 +3447,6 @@
       "../browser/ui/tabs/tab_switch_event_latency_recorder_unittest.cc",
       "../browser/ui/tabs/test_tab_strip_model_delegate.cc",
       "../browser/ui/tabs/test_tab_strip_model_delegate.h",
-      "../browser/ui/tabs/window_activity_watcher_unittest.cc",
       "../browser/ui/thumbnails/thumbnail_image_unittest.cc",
       "../browser/ui/toolbar/app_menu_model_unittest.cc",
       "../browser/ui/toolbar/back_forward_menu_model_unittest.cc",
@@ -4961,6 +4962,7 @@
       "../browser/renderer_context_menu/render_view_context_menu_browsertest_util.cc",
       "../browser/renderer_context_menu/render_view_context_menu_browsertest_util.h",
       "../browser/renderer_host/site_per_process_text_input_browsertest.cc",
+      "../browser/resource_coordinator/tab_metrics_logger_interactive_uitest.cc",
       "../browser/site_per_process_interactive_browsertest.cc",
       "../browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc",
       "../browser/ui/blocked_content/popup_blocker_browsertest.cc",
@@ -4989,7 +4991,6 @@
       "../browser/ui/signin_view_controller_interactive_uitest.cc",
       "../browser/ui/startup/invalid_user_data_dir_interactive_uitest.cc",
       "../browser/ui/startup/startup_browser_creator_interactive_uitest.cc",
-      "../browser/ui/tabs/window_activity_watcher_interactive_uitest.cc",
       "../browser/ui/translate/translate_bubble_test_utils.h",
       "../browser/ui/views/accessibility/navigation_accessibility_uitest_win.cc",
       "../browser/ui/views/permission_bubble/permission_bubble_views_interactive_uitest_mac.mm",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index d0cb52a5..d23ca2c 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -97,6 +97,7 @@
     "//third_party/android_support_test_runner:rules_java",
     "//third_party/android_support_test_runner:runner_java",
     "//third_party/android_tools:android_test_base_java",
+    "//third_party/gvr-android-sdk:gvr_common_java",
     "//third_party/hamcrest:hamcrest_core_java",
     "//third_party/jsr-305:jsr_305_javalib",
     "//third_party/junit",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java
index beed2b5..7acc69a 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java
@@ -11,24 +11,26 @@
 
 import com.google.android.gms.common.ConnectionResult;
 import com.google.android.gms.common.GoogleApiAvailability;
+import com.google.vr.ndk.base.DaydreamApi;
+import com.google.vr.ndk.base.GvrApi;
 
 import org.junit.rules.TestRule;
 import org.junit.runners.model.InitializationError;
 
 import org.chromium.base.CommandLine;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.StrictModeContext;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseTestResult.PreTestHook;
 import org.chromium.base.test.util.RestrictionSkipCheck;
 import org.chromium.base.test.util.SkipCheck;
 import org.chromium.chrome.browser.ChromeVersionInfo;
-import org.chromium.chrome.browser.vr.VrModuleProvider;
 import org.chromium.chrome.test.util.ChromeRestriction;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner;
 import org.chromium.policy.test.annotations.Policies;
 
 import java.util.List;
-import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 
 /**
@@ -66,22 +68,34 @@
         }
 
         private boolean isDaydreamReady() {
-            return VrModuleProvider.getDelegate().isDaydreamReadyDevice();
+            // We normally check things like this through VrShellDelegate. However, with the
+            // introduction of Dynamic Feature Modules (DFMs), we have tests that expect the VR
+            // DFM to not be loaded. Using the normal approach (VrModuleProvider.getDelegate())
+            // causes the DFM to be loaded, which we don't want done before the test starts. So,
+            // access the Daydream API directly.
+            return DaydreamApi.isDaydreamReadyPlatform(ContextUtils.getApplicationContext());
         }
 
         private boolean isDaydreamViewPaired() {
             if (!isDaydreamReady()) {
                 return false;
             }
-
-            // isDaydreamCurrentViewer() creates a concrete instance of DaydreamApi,
-            // which can only be done on the main thread
+            // We need to ensure that the DaydreamApi instance is created on the main thread.
+            DaydreamApi daydreamApi;
             try {
-                return ThreadUtils.runOnUiThreadBlocking(
-                        VrModuleProvider.getDelegate()::isDaydreamCurrentViewer);
-            } catch (CancellationException | ExecutionException | IllegalArgumentException e) {
+                daydreamApi = ThreadUtils.runOnUiThreadBlocking(
+                        () -> { return DaydreamApi.create(ContextUtils.getApplicationContext()); });
+            } catch (ExecutionException e) {
                 return false;
             }
+            int viewerType;
+            // Getting the current viewer type may result in a disk write in VrCore, so allow that
+            // to prevent StrictMode errors.
+            try (StrictModeContext smc = StrictModeContext.allowDiskWrites()) {
+                viewerType = daydreamApi.getCurrentViewerType();
+            }
+            daydreamApi.close();
+            return viewerType == GvrApi.ViewerType.DAYDREAM;
         }
 
         private boolean isOnStandaloneVrDevice() {
diff --git a/chrome/test/data/webui/settings/add_users_tests.js b/chrome/test/data/webui/settings/add_users_tests.js
new file mode 100644
index 0000000..926fb06a
--- /dev/null
+++ b/chrome/test/data/webui/settings/add_users_tests.js
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+suite('AddPersonDialog', function() {
+  let dialog = null;
+
+  setup(function() {
+    PolymerTest.clearBody();
+
+    dialog = document.createElement('settings-users-add-user-dialog');
+
+    document.body.appendChild(dialog);
+
+    dialog.open();
+  });
+
+  teardown(function() {
+    dialog.remove();
+    dialog = null;
+  });
+
+
+  /**
+   * Test that the dialog reacts to valid and invalid input correctly.
+   */
+  test('Add user', function() {
+    const userInputBox = dialog.$$('#addUserInput');
+    assertTrue(!!userInputBox);
+
+    const addButton = dialog.$$('.action-button');
+    assertTrue(!!addButton);
+    assertTrue(addButton.disabled);
+    assertTrue(!userInputBox.invalid);
+
+    // Try to add a valid username without domain
+    userInputBox.value = 'abcdef';
+    assertTrue(!addButton.disabled);
+    assertTrue(!userInputBox.invalid);
+
+    // Try to add a valid username with domain
+    userInputBox.value = 'abcdef@xyz.com';
+    assertTrue(!addButton.disabled);
+    assertTrue(!userInputBox.invalid);
+
+    // Try to add an invalid username
+    userInputBox.value = 'abcdef@';
+    assertTrue(addButton.disabled);
+    assertTrue(userInputBox.invalid);
+  });
+});
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index a63af80b..759f1efd 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -2442,3 +2442,30 @@
 TEST_F('CrSettingsSiteFaviconTest', 'All', function() {
   mocha.run();
 });
+
+GEN('#if defined(OS_CHROMEOS)');
+
+/**
+ * Test fixture for the chrome://settings/accounts page
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsAddUsersTest() {}
+
+CrSettingsAddUsersTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://settings/accounts.html',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    'add_users_tests.js',
+  ]),
+};
+
+TEST_F('CrSettingsAddUsersTest', 'All', function() {
+  mocha.run();
+});
+
+GEN('#endif  // defined(OS_CHROMEOS)');
diff --git a/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc b/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc
index d5ed9b7..aa829759 100644
--- a/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc
+++ b/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc
@@ -193,8 +193,19 @@
     case ui::AXEventGenerator::Event::STATE_CHANGED:
       return api::automation::EVENT_TYPE_ARIAATTRIBUTECHANGED;
 
+    case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED:
+    case ui::AXEventGenerator::Event::CLASS_NAME_CHANGED:
+    case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
+    case ui::AXEventGenerator::Event::FLOW_TO_CHANGED:
+    case ui::AXEventGenerator::Event::HIERARCHICAL_LEVEL_CHANGED:
+    case ui::AXEventGenerator::Event::KEY_SHORTCUTS_CHANGED:
+    case ui::AXEventGenerator::Event::LABELED_BY_CHANGED:
+    case ui::AXEventGenerator::Event::LANGUAGE_CHANGED:
     case ui::AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED:
+    case ui::AXEventGenerator::Event::PLACEHOLDER_CHANGED:
+    case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
+    case ui::AXEventGenerator::Event::SET_SIZE_CHANGED:
       return api::automation::EVENT_TYPE_NONE;
   }
 
diff --git a/chromeos/dbus/auth_policy/auth_policy_client.cc b/chromeos/dbus/auth_policy/auth_policy_client.cc
index 6656d78..22ef7181 100644
--- a/chromeos/dbus/auth_policy/auth_policy_client.cc
+++ b/chromeos/dbus/auth_policy/auth_policy_client.cc
@@ -10,6 +10,7 @@
 #include "base/location.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "chromeos/dbus/auth_policy/fake_auth_policy_client.h"
 #include "components/account_id/account_id.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
@@ -26,6 +27,8 @@
 // call.
 constexpr int kSlowDbusTimeoutMilliseconds = 630 * 1000;
 
+AuthPolicyClient* g_instance = nullptr;
+
 authpolicy::ErrorType GetErrorFromReader(dbus::MessageReader* reader) {
   int32_t int_error;
   if (!reader->PopInt32(&int_error)) {
@@ -174,8 +177,7 @@
     proxy_->WaitForServiceToBeAvailable(std::move(callback));
   }
 
- protected:
-  void Init(dbus::Bus* bus) override {
+  void Init(dbus::Bus* bus) {
     bus_ = bus;
     proxy_ = bus_->GetObjectProxy(
         authpolicy::kAuthPolicyServiceName,
@@ -232,13 +234,37 @@
 
 }  // namespace
 
-AuthPolicyClient::AuthPolicyClient() = default;
+AuthPolicyClient::AuthPolicyClient() {
+  DCHECK(!g_instance);
+  g_instance = this;
+}
 
-AuthPolicyClient::~AuthPolicyClient() = default;
+AuthPolicyClient::~AuthPolicyClient() {
+  DCHECK_EQ(this, g_instance);
+  g_instance = nullptr;
+}
 
 // static
-AuthPolicyClient* AuthPolicyClient::Create() {
-  return new AuthPolicyClientImpl();
+void AuthPolicyClient::Initialize(dbus::Bus* bus) {
+  DCHECK(bus);
+  (new AuthPolicyClientImpl)->Init(bus);
+}
+
+// static
+void AuthPolicyClient::InitializeFake() {
+  if (!FakeAuthPolicyClient::Get())
+    new FakeAuthPolicyClient();
+}
+
+// static
+void AuthPolicyClient::Shutdown() {
+  DCHECK(g_instance);
+  delete g_instance;
+}
+
+// static
+AuthPolicyClient* AuthPolicyClient::Get() {
+  return g_instance;
 }
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/auth_policy/auth_policy_client.h b/chromeos/dbus/auth_policy/auth_policy_client.h
index 1b4f94b..5b71b0b 100644
--- a/chromeos/dbus/auth_policy/auth_policy_client.h
+++ b/chromeos/dbus/auth_policy/auth_policy_client.h
@@ -10,7 +10,6 @@
 #include "base/callback.h"
 #include "base/component_export.h"
 #include "chromeos/dbus/authpolicy/active_directory_info.pb.h"
-#include "chromeos/dbus/dbus_client.h"
 #include "dbus/object_proxy.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
@@ -21,7 +20,7 @@
 // AuthPolicyClient is used to communicate with the org.chromium.AuthPolicy
 // sevice. All method should be called from the origin thread (UI thread) which
 // initializes the DBusThreadManager instance.
-class COMPONENT_EXPORT(CHROMEOS_DBUS) AuthPolicyClient : public DBusClient {
+class COMPONENT_EXPORT(CHROMEOS_DBUS) AuthPolicyClient {
  public:
   using AuthCallback = base::OnceCallback<void(
       authpolicy::ErrorType error,
@@ -38,11 +37,17 @@
   using RefreshPolicyCallback =
       base::OnceCallback<void(authpolicy::ErrorType error)>;
 
-  ~AuthPolicyClient() override;
+  // Creates and initializes the global instance. |bus| must not be null.
+  static void Initialize(dbus::Bus* bus);
 
-  // Factory function, creates a new instance and returns ownership.
-  // For normal usage, access the singleton via DBusThreadManager::Get().
-  static AuthPolicyClient* Create();
+  // Creates and initializes a fake global instance if not already created.
+  static void InitializeFake();
+
+  // Destroys the global instance which must have been initialized.
+  static void Shutdown();
+
+  // Returns the global instance if initialized. May return null.
+  static AuthPolicyClient* Get();
 
   // Calls JoinADDomain to join a machine/device to an Active Directory domain.
   // Password is read from the |password_fd|. |callback| is called after getting
@@ -91,8 +96,9 @@
       dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) = 0;
 
  protected:
-  // Create() should be used instead.
+  // Initialize/Shutdown should be used instead.
   AuthPolicyClient();
+  virtual ~AuthPolicyClient();
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AuthPolicyClient);
diff --git a/chromeos/dbus/auth_policy/fake_auth_policy_client.cc b/chromeos/dbus/auth_policy/fake_auth_policy_client.cc
index 8554c19..7cd4f1d 100644
--- a/chromeos/dbus/auth_policy/fake_auth_policy_client.cc
+++ b/chromeos/dbus/auth_policy/fake_auth_policy_client.cc
@@ -26,6 +26,8 @@
 
 namespace em = enterprise_management;
 
+namespace chromeos {
+
 namespace {
 
 constexpr size_t kMaxMachineNameLength = 15;
@@ -33,7 +35,9 @@
 constexpr char kDefaultKerberosCreds[] = "credentials";
 constexpr char kDefaultKerberosConf[] = "configuration";
 
-void OnStorePolicy(chromeos::AuthPolicyClient::RefreshPolicyCallback callback,
+FakeAuthPolicyClient* g_instance = nullptr;
+
+void OnStorePolicy(AuthPolicyClient::RefreshPolicyCallback callback,
                    bool success) {
   const authpolicy::ErrorType error =
       success ? authpolicy::ERROR_NONE : authpolicy::ERROR_STORE_POLICY_FAILED;
@@ -57,13 +61,20 @@
 
 }  // namespace
 
-namespace chromeos {
+FakeAuthPolicyClient::FakeAuthPolicyClient() {
+  DCHECK(!g_instance);
+  g_instance = this;
+}
 
-FakeAuthPolicyClient::FakeAuthPolicyClient() = default;
+FakeAuthPolicyClient::~FakeAuthPolicyClient() {
+  DCHECK_EQ(this, g_instance);
+  g_instance = nullptr;
+}
 
-FakeAuthPolicyClient::~FakeAuthPolicyClient() = default;
-
-void FakeAuthPolicyClient::Init(dbus::Bus* bus) {}
+// static
+FakeAuthPolicyClient* FakeAuthPolicyClient::Get() {
+  return g_instance;
+}
 
 void FakeAuthPolicyClient::JoinAdDomain(
     const authpolicy::JoinDomainRequest& request,
@@ -325,8 +336,8 @@
   em::PolicyFetchResponse response;
   response.set_policy_data(policy_data.SerializeAsString());
 
-  chromeos::SessionManagerClient* session_manager_client =
-      chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
+  SessionManagerClient* session_manager_client =
+      DBusThreadManager::Get()->GetSessionManagerClient();
   session_manager_client->StoreDevicePolicy(
       response.SerializeAsString(),
       base::BindOnce(&OnStorePolicy, std::move(callback)));
diff --git a/chromeos/dbus/auth_policy/fake_auth_policy_client.h b/chromeos/dbus/auth_policy/fake_auth_policy_client.h
index f23fb6a2..57986ed 100644
--- a/chromeos/dbus/auth_policy/fake_auth_policy_client.h
+++ b/chromeos/dbus/auth_policy/fake_auth_policy_client.h
@@ -28,8 +28,9 @@
   FakeAuthPolicyClient();
   ~FakeAuthPolicyClient() override;
 
-  // DBusClient overrides.
-  void Init(dbus::Bus* bus) override;
+  // Returns the fake global instance if initialized. May return null.
+  static FakeAuthPolicyClient* Get();
+
   // AuthPolicyClient overrides.
 
   // Performs basic checks on |request.machine_name| and
diff --git a/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc b/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc
index 6d8dab7e..fb524ff 100644
--- a/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc
+++ b/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc
@@ -32,7 +32,9 @@
   FakeAuthPolicyClientTest() = default;
 
  protected:
-  FakeAuthPolicyClient* authpolicy_client() { return auth_policy_client_ptr_; }
+  FakeAuthPolicyClient* authpolicy_client() {
+    return FakeAuthPolicyClient::Get();
+  }
   FakeSessionManagerClient* session_manager_client() {
     return session_manager_client_ptr_;
   }
@@ -41,17 +43,21 @@
     ::testing::Test::SetUp();
     auto session_manager_client = std::make_unique<FakeSessionManagerClient>();
     session_manager_client_ptr_ = session_manager_client.get();
+    // DBusThreadManager::GetSetterForTesting initializes DBusThreadManager.
     DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient(
         std::move(session_manager_client));
     DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
         std::make_unique<FakeCryptohomeClient>());
-    auto auth_policy_client = std::make_unique<FakeAuthPolicyClient>();
-    auth_policy_client_ptr_ = auth_policy_client.get();
-    DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
-        std::move(auth_policy_client));
+
+    AuthPolicyClient::InitializeFake();
     authpolicy_client()->DisableOperationDelayForTesting();
   }
 
+  void TearDown() override {
+    AuthPolicyClient::Shutdown();
+    DBusThreadManager::Shutdown();
+  }
+
   void JoinAdDomain(const std::string& machine_name,
                     const std::string& username,
                     AuthPolicyClient::JoinCallback callback) {
@@ -102,7 +108,6 @@
   int service_is_available_called_num_ = 0;
 
  private:
-  FakeAuthPolicyClient* auth_policy_client_ptr_;          // not owned.
   FakeSessionManagerClient* session_manager_client_ptr_;  // not owned.
   base::MessageLoop loop_;
 
diff --git a/chromeos/dbus/dbus_clients_browser.cc b/chromeos/dbus/dbus_clients_browser.cc
index 5e4f4170..3b5c4a0 100644
--- a/chromeos/dbus/dbus_clients_browser.cc
+++ b/chromeos/dbus/dbus_clients_browser.cc
@@ -9,8 +9,6 @@
 #include "chromeos/dbus/arc_midis_client.h"
 #include "chromeos/dbus/arc_obb_mounter_client.h"
 #include "chromeos/dbus/arc_oemcrypto_client.h"
-#include "chromeos/dbus/auth_policy/auth_policy_client.h"
-#include "chromeos/dbus/auth_policy/fake_auth_policy_client.h"
 #include "chromeos/dbus/cec_service_client.h"
 #include "chromeos/dbus/cicerone_client.h"
 #include "chromeos/dbus/concierge_client.h"
@@ -78,11 +76,6 @@
   else
     arc_oemcrypto_client_.reset(new FakeArcOemCryptoClient);
 
-  if (use_real_clients)
-    auth_policy_client_.reset(AuthPolicyClient::Create());
-  else
-    auth_policy_client_.reset(new FakeAuthPolicyClient);
-
   cec_service_client_ = CecServiceClient::Create(client_impl_type);
 
   cros_disks_client_.reset(CrosDisksClient::Create(client_impl_type));
@@ -169,7 +162,6 @@
   arc_midis_client_->Init(system_bus);
   arc_obb_mounter_client_->Init(system_bus);
   arc_oemcrypto_client_->Init(system_bus);
-  auth_policy_client_->Init(system_bus);
   cec_service_client_->Init(system_bus);
   cicerone_client_->Init(system_bus);
   concierge_client_->Init(system_bus);
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h
index a0fd299..24c86b6 100644
--- a/chromeos/dbus/dbus_clients_browser.h
+++ b/chromeos/dbus/dbus_clients_browser.h
@@ -20,7 +20,6 @@
 class ArcMidisClient;
 class ArcObbMounterClient;
 class ArcOemCryptoClient;
-class AuthPolicyClient;
 class CecServiceClient;
 class CiceroneClient;
 class ConciergeClient;
@@ -58,7 +57,6 @@
   std::unique_ptr<ArcMidisClient> arc_midis_client_;
   std::unique_ptr<ArcObbMounterClient> arc_obb_mounter_client_;
   std::unique_ptr<ArcOemCryptoClient> arc_oemcrypto_client_;
-  std::unique_ptr<AuthPolicyClient> auth_policy_client_;
   std::unique_ptr<CecServiceClient> cec_service_client_;
   std::unique_ptr<CiceroneClient> cicerone_client_;
   std::unique_ptr<ConciergeClient> concierge_client_;
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index 946f48ee9..2efc8ae 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -14,7 +14,6 @@
 #include "chromeos/dbus/arc_midis_client.h"
 #include "chromeos/dbus/arc_obb_mounter_client.h"
 #include "chromeos/dbus/arc_oemcrypto_client.h"
-#include "chromeos/dbus/auth_policy/auth_policy_client.h"
 #include "chromeos/dbus/cec_service_client.h"
 #include "chromeos/dbus/cicerone_client.h"
 #include "chromeos/dbus/concierge_client.h"
@@ -134,11 +133,6 @@
                           : nullptr;
 }
 
-AuthPolicyClient* DBusThreadManager::GetAuthPolicyClient() {
-  return clients_browser_ ? clients_browser_->auth_policy_client_.get()
-                          : nullptr;
-}
-
 CecServiceClient* DBusThreadManager::GetCecServiceClient() {
   return clients_browser_ ? clients_browser_->cec_service_client_.get()
                           : nullptr;
@@ -359,12 +353,6 @@
 
 DBusThreadManagerSetter::~DBusThreadManagerSetter() = default;
 
-void DBusThreadManagerSetter::SetAuthPolicyClient(
-    std::unique_ptr<AuthPolicyClient> client) {
-  DBusThreadManager::Get()->clients_browser_->auth_policy_client_ =
-      std::move(client);
-}
-
 void DBusThreadManagerSetter::SetCiceroneClient(
     std::unique_ptr<CiceroneClient> client) {
   DBusThreadManager::Get()->clients_browser_->cicerone_client_ =
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index 1dfbbcdc..ad843cd 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -28,7 +28,6 @@
 class ArcMidisClient;
 class ArcObbMounterClient;
 class ArcOemCryptoClient;
-class AuthPolicyClient;
 class CecServiceClient;
 class CiceroneClient;
 class ConciergeClient;
@@ -126,7 +125,6 @@
   ArcMidisClient* GetArcMidisClient();
   ArcObbMounterClient* GetArcObbMounterClient();
   ArcOemCryptoClient* GetArcOemCryptoClient();
-  AuthPolicyClient* GetAuthPolicyClient();
   CecServiceClient* GetCecServiceClient();
   CiceroneClient* GetCiceroneClient();
   ConciergeClient* GetConciergeClient();
@@ -191,7 +189,6 @@
  public:
   ~DBusThreadManagerSetter();
 
-  void SetAuthPolicyClient(std::unique_ptr<AuthPolicyClient> client);
   void SetCiceroneClient(std::unique_ptr<CiceroneClient> client);
   void SetConciergeClient(std::unique_ptr<ConciergeClient> client);
   void SetCrasAudioClient(std::unique_ptr<CrasAudioClient> client);
diff --git a/chromeos/dbus/upstart/fake_upstart_client.cc b/chromeos/dbus/upstart/fake_upstart_client.cc
index 1672e4d..1cc6339 100644
--- a/chromeos/dbus/upstart/fake_upstart_client.cc
+++ b/chromeos/dbus/upstart/fake_upstart_client.cc
@@ -46,17 +46,13 @@
 }
 
 void FakeUpstartClient::StartAuthPolicyService() {
-  static_cast<FakeAuthPolicyClient*>(
-      DBusThreadManager::Get()->GetAuthPolicyClient())
-      ->SetStarted(true);
+  FakeAuthPolicyClient::Get()->SetStarted(true);
 }
 
 void FakeUpstartClient::RestartAuthPolicyService() {
-  FakeAuthPolicyClient* authpolicy_client = static_cast<FakeAuthPolicyClient*>(
-      DBusThreadManager::Get()->GetAuthPolicyClient());
-  DLOG_IF(WARNING, !authpolicy_client->started())
+  DLOG_IF(WARNING, !FakeAuthPolicyClient::Get()->started())
       << "Trying to restart authpolicyd which is not started";
-  authpolicy_client->SetStarted(true);
+  FakeAuthPolicyClient::Get()->SetStarted(true);
 }
 
 void FakeUpstartClient::StartMediaAnalytics(
diff --git a/chromeos/login/auth/authpolicy_login_helper.cc b/chromeos/login/auth/authpolicy_login_helper.cc
index 864a8e7..c1175f9 100644
--- a/chromeos/login/auth/authpolicy_login_helper.cc
+++ b/chromeos/login/auth/authpolicy_login_helper.cc
@@ -147,7 +147,7 @@
   authpolicy::AuthenticateUserRequest request;
   request.set_user_principal_name(username);
   request.set_account_id(object_guid);
-  chromeos::DBusThreadManager::Get()->GetAuthPolicyClient()->AuthenticateUser(
+  AuthPolicyClient::Get()->AuthenticateUser(
       request, GetDataReadPipe(password).get(), base::DoNothing());
 }
 
@@ -189,7 +189,7 @@
   DCHECK(!dm_token_.empty());
   request.set_dm_token(dm_token_);
 
-  chromeos::DBusThreadManager::Get()->GetAuthPolicyClient()->JoinAdDomain(
+  AuthPolicyClient::Get()->JoinAdDomain(
       request, GetDataReadPipe(password).get(),
       base::BindOnce(&AuthPolicyLoginHelper::OnJoinCallback,
                      weak_factory_.GetWeakPtr(), std::move(callback)));
@@ -203,7 +203,7 @@
   authpolicy::AuthenticateUserRequest request;
   request.set_user_principal_name(username);
   request.set_account_id(object_guid);
-  chromeos::DBusThreadManager::Get()->GetAuthPolicyClient()->AuthenticateUser(
+  AuthPolicyClient::Get()->AuthenticateUser(
       request, GetDataReadPipe(password).get(),
       base::BindOnce(&AuthPolicyLoginHelper::OnAuthCallback,
                      weak_factory_.GetWeakPtr(), std::move(callback)));
@@ -223,11 +223,9 @@
     std::move(callback).Run(error, machine_domain);
     return;
   }
-  chromeos::DBusThreadManager::Get()
-      ->GetAuthPolicyClient()
-      ->RefreshDevicePolicy(base::BindOnce(
-          &AuthPolicyLoginHelper::OnFirstPolicyRefreshCallback,
-          weak_factory_.GetWeakPtr(), std::move(callback), machine_domain));
+  AuthPolicyClient::Get()->RefreshDevicePolicy(base::BindOnce(
+      &AuthPolicyLoginHelper::OnFirstPolicyRefreshCallback,
+      weak_factory_.GetWeakPtr(), std::move(callback), machine_domain));
 }
 
 void AuthPolicyLoginHelper::OnFirstPolicyRefreshCallback(
diff --git a/chromeos/login/auth/authpolicy_login_helper_unittest.cc b/chromeos/login/auth/authpolicy_login_helper_unittest.cc
index 56d53f58..19cff6e 100644
--- a/chromeos/login/auth/authpolicy_login_helper_unittest.cc
+++ b/chromeos/login/auth/authpolicy_login_helper_unittest.cc
@@ -56,13 +56,11 @@
 
 // Check that helper calls RefreshDevicePolicy after JoinAdDomain.
 TEST(AuthPolicyLoginHelper, JoinFollowedByRefreshDevicePolicy) {
-  std::unique_ptr<MockAuthPolicyClient> mock_client =
-      std::make_unique<MockAuthPolicyClient>();
-  MockAuthPolicyClient* mock_client_ptr = mock_client.get();
-  DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
-      std::move(mock_client));
   DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
       std::make_unique<FakeCryptohomeClient>());
+
+  auto* mock_client = new MockAuthPolicyClient;
+
   AuthPolicyLoginHelper helper;
   helper.set_dm_token(kDMToken);
   helper.JoinAdDomain(std::string(), std::string(),
@@ -73,7 +71,8 @@
                         EXPECT_EQ(authpolicy::ERROR_NONE, error);
                         EXPECT_TRUE(domain.empty());
                       }));
-  mock_client_ptr->CheckExpectations();
+  mock_client->CheckExpectations();
+  AuthPolicyClient::Shutdown();
 }
 
 }  // namespace chromeos
diff --git a/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl_unittest.cc
index e2b1e31..e476d80 100644
--- a/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_v2_enrollment_manager_impl_unittest.cc
@@ -6,6 +6,7 @@
 #include <utility>
 
 #include "base/base64url.h"
+#include "base/no_destructor.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
@@ -51,17 +52,20 @@
 const char kFakeV2PublicKey[] = "public_key_v2";
 const char kFakeV2PrivateKey[] = "private_key_v2";
 
-const base::TimeDelta kFakeRefreshPeriod = base::TimeDelta::FromMilliseconds(
-    cryptauthv2::kTestClientDirectiveCheckinDelayMillis);
-const base::TimeDelta kFakeRetryPeriod = base::TimeDelta::FromMilliseconds(
-    cryptauthv2::kTestClientDirectiveRetryPeriodMillis);
-const base::Time kFakeLastEnrollmentTime = base::Time::UnixEpoch();
-const base::Time kFakeTimeAfterRefreshPeriod = kFakeLastEnrollmentTime +
-                                               kFakeRefreshPeriod +
-                                               base::TimeDelta::FromSeconds(1);
-const base::Time kFakeTimeBeforeRefreshPeriod = kFakeLastEnrollmentTime +
-                                                kFakeRefreshPeriod -
-                                                base::TimeDelta::FromSeconds(1);
+constexpr base::TimeDelta kFakeRefreshPeriod =
+    base::TimeDelta::FromMilliseconds(2592000000);
+constexpr base::TimeDelta kFakeRetryPeriod =
+    base::TimeDelta::FromMilliseconds(43200000);
+
+const cryptauthv2::PolicyReference& GetClientDirectivePolicyReferenceForTest() {
+  static const base::NoDestructor<cryptauthv2::PolicyReference>
+      policy_reference([] {
+        return cryptauthv2::BuildPolicyReference("policy_reference_name",
+                                                 1 /* version */);
+      }());
+
+  return *policy_reference;
+}
 
 // A child of FakeCryptAuthEnrollmentScheduler that sets scheduler parameters
 // based on the latest enrollment result.
@@ -124,6 +128,11 @@
             delegate, clock_);
     instance_ = instance.get();
 
+    // Fix the scheduler's ClientDirective PolicyReference to test that it is
+    // passed to the enroller properly.
+    instance->set_client_directive_policy_reference(
+        GetClientDirectivePolicyReferenceForTest());
+
     if (initial_num_consecutive_failures_) {
       instance->set_num_consecutive_failures(
           *initial_num_consecutive_failures_);
@@ -197,6 +206,8 @@
     NetworkHandler::Initialize();
     base::RunLoop().RunUntilIdle();
 
+    test_clock_.SetNow(base::Time::UnixEpoch());
+
     CryptAuthV2EnrollmentManagerImpl::RegisterPrefs(
         test_pref_service_.registry());
     CryptAuthKeyRegistryImpl::RegisterPrefs(test_pref_service_.registry());
@@ -218,8 +229,8 @@
 
   // testing::Test:
   void TearDown() override {
-    if (enrollment_manager())
-      enrollment_manager()->RemoveObserver(this);
+    if (enrollment_manager_)
+      enrollment_manager_->RemoveObserver(this);
 
     NetworkAwareEnrollmentScheduler::Factory::SetFactoryForTesting(nullptr);
     CryptAuthV2EnrollerImpl::Factory::SetFactoryForTesting(nullptr);
@@ -228,6 +239,14 @@
     DBusThreadManager::Shutdown();
   }
 
+  // CryptAuthEnrollmentManager::Observer:
+  void OnEnrollmentStarted() override {
+    ++num_enrollment_started_notifications_;
+  }
+  void OnEnrollmentFinished(bool success) override {
+    observer_enrollment_finished_success_list_.push_back(success);
+  }
+
   void AddV1UserKeyPairToV1Prefs(const std::string& public_key,
                                  const std::string& private_key) {
     std::string public_key_b64, private_key_b64;
@@ -250,16 +269,6 @@
         num_consecutive_failures);
   }
 
-  // CryptAuthEnrollmentManager::Observer:
-  void OnEnrollmentStarted() override {
-    ++num_enrollment_started_notifications_;
-
-    enrollment_finished_success_ = base::nullopt;
-  }
-  void OnEnrollmentFinished(bool success) override {
-    enrollment_finished_success_ = success;
-  }
-
   void CreateEnrollmentManager() {
     auto mock_timer = std::make_unique<base::MockOneShotTimer>();
     mock_timer_ = mock_timer.get();
@@ -270,7 +279,11 @@
             &mock_client_factory_, &fake_gcm_manager_, &test_pref_service_,
             &test_clock_, std::move(mock_timer));
 
-    enrollment_manager()->AddObserver(this);
+    enrollment_manager_->AddObserver(this);
+  }
+
+  void RequestEnrollmentThroughGcm() {
+    fake_gcm_manager_.PushReenrollMessage();
   }
 
   void VerifyEnrollmentManagerObserversNotifiedOfStart(
@@ -279,6 +292,135 @@
               num_enrollment_started_notifications_);
   }
 
+  void CompleteGcmRegistration(bool success) {
+    EXPECT_TRUE(fake_gcm_manager_.GetRegistrationId().empty());
+
+    if (success) {
+      fake_gcm_manager_.CompleteRegistration(
+          cryptauthv2::kTestGcmRegistrationId);
+    } else {
+      // An empty registration ID is interpreted as an error by
+      // FakeCryptAuthGCMManager.
+      fake_gcm_manager_.CompleteRegistration(std::string());
+    }
+  }
+
+  void HandleGetClientAppMetadataRequest(bool success) {
+    EXPECT_GT(fake_client_app_metadata_provider_.metadata_requests().size(),
+              0u);
+    EXPECT_EQ(cryptauthv2::kTestGcmRegistrationId,
+              fake_client_app_metadata_provider_.metadata_requests()
+                  .back()
+                  .gcm_registration_id);
+
+    if (success) {
+      std::move(fake_client_app_metadata_provider_.metadata_requests()
+                    .back()
+                    .callback)
+          .Run(cryptauthv2::GetClientAppMetadataForTest());
+      return;
+    }
+
+    std::move(
+        fake_client_app_metadata_provider_.metadata_requests().back().callback)
+        .Run(base::nullopt /* client_app_metadata */);
+  }
+
+  void FinishEnrollmentAttempt(
+      size_t expected_enroller_instance_index,
+      const cryptauthv2::ClientMetadata::InvocationReason&
+          expected_invocation_reason,
+      const CryptAuthEnrollmentResult& enrollment_result) {
+    EXPECT_TRUE(enrollment_manager_->IsEnrollmentInProgress());
+
+    // A valid GCM registration ID and valid ClientAppMetadata must exist before
+    // the enroller can be invoked.
+    EXPECT_EQ(cryptauthv2::kTestGcmRegistrationId,
+              fake_gcm_manager_.GetRegistrationId());
+    EXPECT_GT(fake_client_app_metadata_provider_.metadata_requests().size(),
+              0u);
+
+    // Only the most recently created enroller is valid.
+    EXPECT_EQ(fake_enroller_factory_->created_instances().size() - 1,
+              expected_enroller_instance_index);
+    FakeCryptAuthV2Enroller* enroller =
+        fake_enroller_factory_
+            ->created_instances()[expected_enroller_instance_index];
+
+    VerifyEnrollerData(enroller, expected_invocation_reason);
+
+    enroller->FinishAttempt(enrollment_result);
+
+    EXPECT_FALSE(enrollment_manager_->IsEnrollmentInProgress());
+
+    cryptauthv2::ClientMetadata::InvocationReason expected_persisted_reason =
+        enrollment_manager_->IsRecoveringFromFailure()
+            ? expected_invocation_reason
+            : cryptauthv2::ClientMetadata::INVOCATION_REASON_UNSPECIFIED;
+    VerifyPersistedFailureRecoveryInvocationReason(expected_persisted_reason);
+  }
+
+  void VerifyEnrollmentResults(
+      const std::vector<CryptAuthEnrollmentResult>& expected_results) {
+    VerifyResultsSentToEnrollmentManagerObservers(expected_results);
+    VerifyResultsSentToEnrollmentScheduler(expected_results);
+  }
+
+  CryptAuthKeyRegistry* key_registry() { return key_registry_.get(); }
+
+  FakeCryptAuthEnrollmentSchedulerWithResultHandling*
+  fake_enrollment_scheduler() {
+    return fake_enrollment_scheduler_factory_->instance();
+  }
+
+  base::SimpleTestClock* test_clock() { return &test_clock_; }
+
+  base::MockOneShotTimer* mock_timer() { return mock_timer_; }
+
+  CryptAuthEnrollmentManager* enrollment_manager() {
+    return enrollment_manager_.get();
+  }
+
+ private:
+  void VerifyEnrollerData(FakeCryptAuthV2Enroller* enroller,
+                          const cryptauthv2::ClientMetadata::InvocationReason&
+                              expected_invocation_reason) {
+    EXPECT_TRUE(enroller->was_enroll_called());
+
+    EXPECT_EQ(cryptauthv2::BuildClientMetadata(
+                  fake_enrollment_scheduler()
+                      ->GetNumConsecutiveFailures() /* retry_count */,
+                  expected_invocation_reason)
+                  .SerializeAsString(),
+              enroller->client_metadata()->SerializeAsString());
+
+    EXPECT_EQ(cryptauthv2::GetClientAppMetadataForTest().SerializeAsString(),
+              enroller->client_app_metadata()->SerializeAsString());
+
+    EXPECT_EQ(
+        GetClientDirectivePolicyReferenceForTest().SerializeAsString(),
+        (*enroller->client_directive_policy_reference())->SerializeAsString());
+  }
+
+  void VerifyResultsSentToEnrollmentManagerObservers(
+      const std::vector<CryptAuthEnrollmentResult>
+          expected_enrollment_results) {
+    ASSERT_EQ(expected_enrollment_results.size(),
+              observer_enrollment_finished_success_list_.size());
+
+    for (size_t i = 0; i < expected_enrollment_results.size(); ++i) {
+      EXPECT_EQ(expected_enrollment_results[i].IsSuccess(),
+                observer_enrollment_finished_success_list_[i]);
+    }
+  }
+
+  void VerifyResultsSentToEnrollmentScheduler(
+      const std::vector<CryptAuthEnrollmentResult>
+          expected_enrollment_results) {
+    EXPECT_EQ(expected_enrollment_results,
+              fake_enrollment_scheduler()->handled_enrollment_results());
+  }
+
   void VerifyPersistedFailureRecoveryInvocationReason(
       const cryptauthv2::ClientMetadata::InvocationReason&
           expected_failure_recovery_invocation_reason) {
@@ -289,57 +431,11 @@
                 prefs::kCryptAuthEnrollmentFailureRecoveryInvocationReason)));
   }
 
-  void VerifyEnrollmentResult(
-      const CryptAuthEnrollmentResult& expected_result) {
-    VerifyResultSentToEnrollmentManagerObservers(expected_result.IsSuccess());
-    EXPECT_EQ(expected_result,
-              fake_enrollment_scheduler()->handled_enrollment_results().back());
-  }
-
-  TestingPrefServiceSimple* test_pref_service() { return &test_pref_service_; }
-
-  CryptAuthKeyRegistry* key_registry() { return key_registry_.get(); }
-
-  FakeCryptAuthEnrollmentSchedulerWithResultHandling*
-  fake_enrollment_scheduler() {
-    return fake_enrollment_scheduler_factory_->instance();
-  }
-
-  FakeCryptAuthGCMManager* fake_gcm_manager() { return &fake_gcm_manager_; }
-
-  base::SimpleTestClock* test_clock() { return &test_clock_; }
-
-  base::MockOneShotTimer* mock_timer() { return mock_timer_; }
-
-  FakeClientAppMetadataProvider* fake_client_app_metadata_provider() {
-    return &fake_client_app_metadata_provider_;
-  }
-
-  MockCryptAuthClientFactory* mock_client_factory() {
-    return &mock_client_factory_;
-  }
-
-  FakeCryptAuthV2Enroller* fake_enroller(size_t index = 0u) {
-    // Only the most recently created enroller is valid.
-    EXPECT_EQ(fake_enroller_factory_->created_instances().size() - 1, index);
-
-    return fake_enroller_factory_->created_instances()[index];
-  }
-
-  CryptAuthEnrollmentManager* enrollment_manager() {
-    return enrollment_manager_.get();
-  }
-
- private:
-  void VerifyResultSentToEnrollmentManagerObservers(bool success) {
-    EXPECT_EQ(success, enrollment_finished_success_);
-  }
-
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 
   size_t num_enrollment_started_notifications_ = 0;
-  base::Optional<bool> enrollment_finished_success_ = base::nullopt;
   size_t num_consecutive_failures_ = 0;
+  std::vector<bool> observer_enrollment_finished_success_list_;
 
   TestingPrefServiceSimple test_pref_service_;
   FakeClientAppMetadataProvider fake_client_app_metadata_provider_;
@@ -365,52 +461,27 @@
 
   // The user has never enrolled with v1 or v2 and has not registered with GCM.
   EXPECT_TRUE(key_registry()->enrolled_key_bundles().empty());
-  EXPECT_TRUE(fake_gcm_manager()->GetRegistrationId().empty());
   EXPECT_TRUE(enrollment_manager()->GetLastEnrollmentTime().is_null());
   EXPECT_FALSE(enrollment_manager()->IsEnrollmentValid());
 
-  cryptauthv2::PolicyReference expected_policy_reference =
-      cryptauthv2::BuildPolicyReference("expected_policy_reference_name",
-                                        1 /* version */);
-  fake_enrollment_scheduler()->set_client_directive_policy_reference(
-      expected_policy_reference);
   fake_enrollment_scheduler()->RequestEnrollmentNow();
   EXPECT_TRUE(enrollment_manager()->IsEnrollmentInProgress());
   VerifyEnrollmentManagerObserversNotifiedOfStart(
       1 /* expected_num_enrollment_started_notifications */);
 
-  fake_gcm_manager()->CompleteRegistration(cryptauthv2::kTestGcmRegistrationId);
-
-  EXPECT_EQ(1u,
-            fake_client_app_metadata_provider()->metadata_requests().size());
-  EXPECT_EQ(cryptauthv2::kTestGcmRegistrationId,
-            fake_client_app_metadata_provider()
-                ->metadata_requests()[0]
-                .gcm_registration_id);
-  std::move(
-      fake_client_app_metadata_provider()->metadata_requests()[0].callback)
-      .Run(cryptauthv2::GetClientAppMetadataForTest());
-
-  EXPECT_TRUE(fake_enroller()->was_enroll_called());
-  EXPECT_EQ(
-      cryptauthv2::BuildClientMetadata(
-          0 /* retry_count */,
-          cryptauthv2::ClientMetadata::INITIALIZATION /* invocation_reason */)
-          .SerializeAsString(),
-      fake_enroller()->client_metadata()->SerializeAsString());
-  EXPECT_EQ(cryptauthv2::GetClientAppMetadataForTest().SerializeAsString(),
-            fake_enroller()->client_app_metadata()->SerializeAsString());
-  EXPECT_EQ(expected_policy_reference.SerializeAsString(),
-            (*fake_enroller()->client_directive_policy_reference())
-                ->SerializeAsString());
+  CompleteGcmRegistration(true /* success */);
+  HandleGetClientAppMetadataRequest(true /* success */);
 
   CryptAuthEnrollmentResult expected_enrollment_result(
       CryptAuthEnrollmentResult::ResultCode::kSuccessNewKeysEnrolled,
       cryptauthv2::GetClientDirectiveForTest());
-  fake_enroller()->FinishAttempt(expected_enrollment_result);
-  EXPECT_FALSE(enrollment_manager()->IsEnrollmentInProgress());
 
-  VerifyEnrollmentResult(expected_enrollment_result);
+  FinishEnrollmentAttempt(0u /* expected_enroller_instance_index */,
+                          cryptauthv2::ClientMetadata::
+                              INITIALIZATION /* expected_invocation_reason */,
+                          expected_enrollment_result);
+
+  VerifyEnrollmentResults({expected_enrollment_result});
 }
 
 TEST_F(DeviceSyncCryptAuthV2EnrollmentManagerImplTest, GcmRegistrationFailed) {
@@ -418,13 +489,11 @@
   enrollment_manager()->Start();
   fake_enrollment_scheduler()->RequestEnrollmentNow();
 
-  // An empty registration ID is interpreted as an error by
-  // FakeCryptAuthGCMManager.
-  fake_gcm_manager()->CompleteRegistration(std::string() /* registration_id */);
+  CompleteGcmRegistration(false /* success */);
 
-  VerifyEnrollmentResult(CryptAuthEnrollmentResult(
+  VerifyEnrollmentResults({CryptAuthEnrollmentResult(
       CryptAuthEnrollmentResult::ResultCode::kErrorGcmRegistrationFailed,
-      base::nullopt /* client_directive */));
+      base::nullopt /* client_directive */)});
 }
 
 TEST_F(DeviceSyncCryptAuthV2EnrollmentManagerImplTest, GcmRegistrationTimeout) {
@@ -436,10 +505,10 @@
   EXPECT_TRUE(mock_timer()->IsRunning());
   mock_timer()->Fire();
 
-  VerifyEnrollmentResult(
-      CryptAuthEnrollmentResult(CryptAuthEnrollmentResult::ResultCode::
-                                    kErrorTimeoutWaitingForGcmRegistration,
-                                base::nullopt /* client_directive */));
+  VerifyEnrollmentResults(
+      {CryptAuthEnrollmentResult(CryptAuthEnrollmentResult::ResultCode::
+                                     kErrorTimeoutWaitingForGcmRegistration,
+                                 base::nullopt /* client_directive */)});
 }
 
 TEST_F(DeviceSyncCryptAuthV2EnrollmentManagerImplTest,
@@ -447,16 +516,12 @@
   CreateEnrollmentManager();
   enrollment_manager()->Start();
   fake_enrollment_scheduler()->RequestEnrollmentNow();
-  fake_gcm_manager()->CompleteRegistration(cryptauthv2::kTestGcmRegistrationId);
+  CompleteGcmRegistration(true /* success */);
+  HandleGetClientAppMetadataRequest(false /* success */);
 
-  // A failed metadata retrieval will return base::nullopt.
-  std::move(
-      fake_client_app_metadata_provider()->metadata_requests()[0].callback)
-      .Run(base::nullopt /* client_app_metadata */);
-
-  VerifyEnrollmentResult(CryptAuthEnrollmentResult(
+  VerifyEnrollmentResults({CryptAuthEnrollmentResult(
       CryptAuthEnrollmentResult::ResultCode::kErrorClientAppMetadataFetchFailed,
-      base::nullopt /* client_directive */));
+      base::nullopt /* client_directive */)});
 }
 
 TEST_F(DeviceSyncCryptAuthV2EnrollmentManagerImplTest,
@@ -464,16 +529,16 @@
   CreateEnrollmentManager();
   enrollment_manager()->Start();
   fake_enrollment_scheduler()->RequestEnrollmentNow();
-  fake_gcm_manager()->CompleteRegistration(cryptauthv2::kTestGcmRegistrationId);
+  CompleteGcmRegistration(true /* success */);
 
   // Timeout waiting for ClientAppMetadata.
   EXPECT_TRUE(mock_timer()->IsRunning());
   mock_timer()->Fire();
 
-  VerifyEnrollmentResult(
-      CryptAuthEnrollmentResult(CryptAuthEnrollmentResult::ResultCode::
-                                    kErrorTimeoutWaitingForClientAppMetadata,
-                                base::nullopt /* client_directive */));
+  VerifyEnrollmentResults(
+      {CryptAuthEnrollmentResult(CryptAuthEnrollmentResult::ResultCode::
+                                     kErrorTimeoutWaitingForClientAppMetadata,
+                                 base::nullopt /* client_directive */)});
 }
 
 TEST_F(DeviceSyncCryptAuthV2EnrollmentManagerImplTest, ForcedEnrollment) {
@@ -487,15 +552,17 @@
       1 /* expected_num_enrollment_started_notifications */);
 
   // Simulate a failed enrollment attempt due to CryptAuth server overload.
-  fake_gcm_manager()->CompleteRegistration(cryptauthv2::kTestGcmRegistrationId);
-  std::move(
-      fake_client_app_metadata_provider()->metadata_requests()[0].callback)
-      .Run(cryptauthv2::GetClientAppMetadataForTest());
+  CompleteGcmRegistration(true /* success */);
+  HandleGetClientAppMetadataRequest(true /* success */);
   CryptAuthEnrollmentResult expected_enrollment_result(
       CryptAuthEnrollmentResult::ResultCode::kErrorCryptAuthServerOverloaded,
       base::nullopt /* client_directive */);
-  fake_enroller()->FinishAttempt(expected_enrollment_result);
-  VerifyEnrollmentResult(expected_enrollment_result);
+  FinishEnrollmentAttempt(0u /* expected_enroller_instance_index */,
+                          cryptauthv2::ClientMetadata::
+                              FEATURE_TOGGLED /* expected_invocation_reason */,
+                          expected_enrollment_result);
+
+  VerifyEnrollmentResults({expected_enrollment_result});
 }
 
 TEST_F(DeviceSyncCryptAuthV2EnrollmentManagerImplTest,
@@ -504,52 +571,49 @@
   enrollment_manager()->Start();
 
   // The user has already enrolled and is due for a refresh.
-  base::Time expected_last_enrollment_time = kFakeLastEnrollmentTime;
+  base::Time expected_last_enrollment_time = test_clock()->Now();
   fake_enrollment_scheduler()->set_last_successful_enrollment_time(
       expected_last_enrollment_time);
   fake_enrollment_scheduler()->set_refresh_period(kFakeRefreshPeriod);
-  test_clock()->SetNow(kFakeTimeAfterRefreshPeriod);
+
+  // Set clock after refresh period.
+  test_clock()->SetNow(test_clock()->Now() + kFakeRefreshPeriod +
+                       base::TimeDelta::FromSeconds(1));
+
   base::TimeDelta expected_time_to_next_attempt =
       base::TimeDelta::FromSeconds(0);
   fake_enrollment_scheduler()->set_time_to_next_enrollment_request(
       expected_time_to_next_attempt);
-  cryptauthv2::ClientMetadata::InvocationReason expected_invocation_reason =
-      cryptauthv2::ClientMetadata::PERIODIC;
 
   EXPECT_EQ(expected_last_enrollment_time,
             enrollment_manager()->GetLastEnrollmentTime());
   EXPECT_FALSE(enrollment_manager()->IsEnrollmentValid());
   EXPECT_EQ(expected_time_to_next_attempt,
             enrollment_manager()->GetTimeToNextAttempt());
-  EXPECT_FALSE(enrollment_manager()->IsEnrollmentInProgress());
   EXPECT_FALSE(enrollment_manager()->IsRecoveringFromFailure());
 
+  cryptauthv2::ClientMetadata::InvocationReason expected_invocation_reason =
+      cryptauthv2::ClientMetadata::PERIODIC;
+
   // First enrollment attempt fails.
   // Note: User does not yet have a GCM registration ID or ClientAppMetadata.
   fake_enrollment_scheduler()->RequestEnrollmentNow();
   EXPECT_TRUE(enrollment_manager()->IsEnrollmentInProgress());
   VerifyEnrollmentManagerObserversNotifiedOfStart(
       1 /* expected_num_enrollment_started_notifications */);
-  fake_gcm_manager()->CompleteRegistration(cryptauthv2::kTestGcmRegistrationId);
-  std::move(
-      fake_client_app_metadata_provider()->metadata_requests()[0].callback)
-      .Run(cryptauthv2::GetClientAppMetadataForTest());
-  EXPECT_EQ(cryptauthv2::BuildClientMetadata(0 /* retry_count */,
-                                             expected_invocation_reason)
-                .SerializeAsString(),
-            fake_enroller()->client_metadata()->SerializeAsString());
 
-  CryptAuthEnrollmentResult expected_enrollment_result(
+  CompleteGcmRegistration(true /* success */);
+  HandleGetClientAppMetadataRequest(true /* success */);
+
+  CryptAuthEnrollmentResult first_expected_enrollment_result(
       CryptAuthEnrollmentResult::ResultCode::kErrorCryptAuthServerOverloaded,
       base::nullopt /* client_directive */);
-  fake_enroller()->FinishAttempt(expected_enrollment_result);
-  EXPECT_FALSE(enrollment_manager()->IsEnrollmentInProgress());
-  VerifyEnrollmentResult(expected_enrollment_result);
 
-  // The initial invocation reason is persisted for reuse in subsequent failure
-  // recovery attempts.
-  VerifyPersistedFailureRecoveryInvocationReason(
-      cryptauthv2::ClientMetadata::PERIODIC);
+  FinishEnrollmentAttempt(0u /* expected_enroller_instance_index */,
+                          expected_invocation_reason,
+                          first_expected_enrollment_result);
+
+  EXPECT_EQ(kFakeRetryPeriod, enrollment_manager()->GetTimeToNextAttempt());
 
   // Second (successful) enrollment attempt bypasses GCM registration and
   // ClientAppMetadata fetch because they were performed during the failed
@@ -558,27 +622,18 @@
   VerifyEnrollmentManagerObserversNotifiedOfStart(
       2 /* expected_num_enrollment_started_notifications */);
   EXPECT_TRUE(enrollment_manager()->IsRecoveringFromFailure());
-  expected_invocation_reason = cryptauthv2::ClientMetadata::PERIODIC;
-  EXPECT_EQ(cryptauthv2::kTestGcmRegistrationId,
-            fake_gcm_manager()->GetRegistrationId());
-  EXPECT_EQ(1u,
-            fake_client_app_metadata_provider()->metadata_requests().size());
-  EXPECT_EQ(
-      cryptauthv2::BuildClientMetadata(1 /* retry_count */,
-                                       expected_invocation_reason)
-          .SerializeAsString(),
-      fake_enroller(1u /* index */)->client_metadata()->SerializeAsString());
 
-  expected_enrollment_result = CryptAuthEnrollmentResult(
-      CryptAuthEnrollmentResult::ResultCode::kSuccessNoNewKeysNeeded,
-      cryptauthv2::GetClientDirectiveForTest());
-  fake_enroller(1u /* index */)->FinishAttempt(expected_enrollment_result);
-  VerifyEnrollmentResult(expected_enrollment_result);
+  CryptAuthEnrollmentResult second_expected_enrollment_result =
+      CryptAuthEnrollmentResult(
+          CryptAuthEnrollmentResult::ResultCode::kSuccessNoNewKeysNeeded,
+          cryptauthv2::GetClientDirectiveForTest());
 
-  // The persisted invocation reason to be used for failure recovery is cleared
-  // after a successful enrollment attempt.
-  VerifyPersistedFailureRecoveryInvocationReason(
-      cryptauthv2::ClientMetadata::INVOCATION_REASON_UNSPECIFIED);
+  FinishEnrollmentAttempt(1u /* expected_enroller_instance_index */,
+                          expected_invocation_reason,
+                          second_expected_enrollment_result);
+
+  VerifyEnrollmentResults(
+      {first_expected_enrollment_result, second_expected_enrollment_result});
 
   EXPECT_EQ(test_clock()->Now(), enrollment_manager()->GetLastEnrollmentTime());
   EXPECT_TRUE(enrollment_manager()->IsEnrollmentValid());
@@ -591,7 +646,7 @@
   CreateEnrollmentManager();
   enrollment_manager()->Start();
 
-  fake_gcm_manager()->PushReenrollMessage();
+  RequestEnrollmentThroughGcm();
   EXPECT_TRUE(enrollment_manager()->IsEnrollmentInProgress());
 }
 
@@ -633,16 +688,7 @@
                                   CryptAuthKeyBundle::Name::kUserKeyPair));
 
   // A legacy v1 user key pair should overwrite any existing v2 user key pair
-  // when the enrollment manager is constructed. This can happen in the
-  // following rollback-->rollforward scenario:
-  //   - User never enrolled with v1
-  //   - User enrolls with v2, storing v2 user key pair locally in key registry
-  //     and in CryptAuth backend database
-  //   - Chromium rolls back to v1 enrollment flow
-  //   - User enrolls with v1, storing the v1 user key pair in prefs (not key
-  //     registry) and overwriting the v2 key in the CryptAuth backend database
-  //   - Chromium rolls forward to v2 enrollment flow, with different user key
-  //     pairs stored in v1 prefs and the v2 key registry.
+  // when the enrollment manager is constructed.
   CreateEnrollmentManager();
 
   EXPECT_EQ(
@@ -668,6 +714,70 @@
   EXPECT_EQ(kFakeV2PrivateKey, enrollment_manager()->GetUserPrivateKey());
 }
 
+TEST_F(DeviceSyncCryptAuthV2EnrollmentManagerImplTest,
+       MultipleEnrollmentAttempts) {
+  CreateEnrollmentManager();
+  enrollment_manager()->Start();
+
+  std::vector<cryptauthv2::ClientMetadata::InvocationReason>
+      expected_invocation_reasons;
+  std::vector<CryptAuthEnrollmentResult> expected_enrollment_results;
+
+  // Successfully enroll for the first time.
+  expected_invocation_reasons.push_back(
+      cryptauthv2::ClientMetadata::INITIALIZATION);
+  expected_enrollment_results.emplace_back(
+      CryptAuthEnrollmentResult::ResultCode::kSuccessNewKeysEnrolled,
+      cryptauthv2::GetClientDirectiveForTest());
+  fake_enrollment_scheduler()->RequestEnrollmentNow();
+  VerifyEnrollmentManagerObserversNotifiedOfStart(
+      1 /* expected_num_enrollment_started_notifications */);
+  CompleteGcmRegistration(true /* success */);
+  HandleGetClientAppMetadataRequest(true /* success */);
+  FinishEnrollmentAttempt(0u /* expected_enroller_instance_index */,
+                          expected_invocation_reasons.back(),
+                          expected_enrollment_results.back());
+
+  // Fail periodic refresh twice due to overloaded CryptAuth server.
+  test_clock()->SetNow(test_clock()->Now() + kFakeRefreshPeriod +
+                       base::TimeDelta::FromSeconds(1));
+  expected_invocation_reasons.push_back(cryptauthv2::ClientMetadata::PERIODIC);
+  expected_enrollment_results.emplace_back(
+      CryptAuthEnrollmentResult::ResultCode::kErrorCryptAuthServerOverloaded,
+      cryptauthv2::GetClientDirectiveForTest());
+  fake_enrollment_scheduler()->RequestEnrollmentNow();
+  VerifyEnrollmentManagerObserversNotifiedOfStart(
+      2 /* expected_num_enrollment_started_notifications */);
+  FinishEnrollmentAttempt(1u /* expected_enroller_instance_index */,
+                          expected_invocation_reasons.back(),
+                          expected_enrollment_results.back());
+
+  expected_invocation_reasons.push_back(cryptauthv2::ClientMetadata::PERIODIC);
+  expected_enrollment_results.emplace_back(
+      CryptAuthEnrollmentResult::ResultCode::kErrorCryptAuthServerOverloaded,
+      base::nullopt /* client_directive */);
+  fake_enrollment_scheduler()->RequestEnrollmentNow();
+  VerifyEnrollmentManagerObserversNotifiedOfStart(
+      3 /* expected_num_enrollment_started_notifications */);
+  FinishEnrollmentAttempt(2u /* expected_enroller_instance_index */,
+                          expected_invocation_reasons.back(),
+                          expected_enrollment_results.back());
+
+  // While waiting for retry, force a manual enrollment that succeeds.
+  expected_invocation_reasons.push_back(cryptauthv2::ClientMetadata::MANUAL);
+  expected_enrollment_results.emplace_back(
+      CryptAuthEnrollmentResult::ResultCode::kSuccessNoNewKeysNeeded,
+      base::nullopt /* client_directive */);
+  enrollment_manager()->ForceEnrollmentNow(cryptauth::INVOCATION_REASON_MANUAL);
+  VerifyEnrollmentManagerObserversNotifiedOfStart(
+      4 /* expected_num_enrollment_started_notifications */);
+  FinishEnrollmentAttempt(3u /* expected_enroller_instance_index */,
+                          expected_invocation_reasons.back(),
+                          expected_enrollment_results.back());
+
+  VerifyEnrollmentResults(expected_enrollment_results);
+}
+
 }  // namespace device_sync
 
 }  // namespace chromeos
diff --git a/components/autofill/core/browser/suggestion_selection.cc b/components/autofill/core/browser/suggestion_selection.cc
index 1a3f74b8..516899d 100644
--- a/components/autofill/core/browser/suggestion_selection.cc
+++ b/components/autofill/core/browser/suggestion_selection.cc
@@ -105,7 +105,7 @@
       // will be shown rather than 15084880800, 508 488 0800, or +15084880800
       // for US phone numbers.
       if (base::FeatureList::IsEnabled(
-              autofill::features::kAutofillShowFullDisclosureLabel) &&
+              autofill::features::kAutofillUseImprovedLabelDisambiguation) &&
           AutofillType(AutofillType(server_field_type).GetStorableType())
                   .group() == PHONE_HOME) {
         value = base::UTF8ToUTF16(i18n::FormatPhoneNationallyForDisplay(
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 03121ad..73a96419 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -180,10 +180,11 @@
     "AutofillShowAutocompleteConsoleWarnings",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Controls whether suggestions' labels use the full disclosure format to
-// display disambiguation information.
-const base::Feature kAutofillShowFullDisclosureLabel{
-    "AutofillShowFullDisclosureLabel", base::FEATURE_DISABLED_BY_DEFAULT};
+// Controls whether suggestions' labels use the improved label disambiguation
+// format.
+const base::Feature kAutofillUseImprovedLabelDisambiguation{
+    "AutofillUseImprovedLabelDisambiguation",
+    base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Controls attaching the autofill type predictions to their respective
 // element in the DOM.
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 4e7fecf..d58a517 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -54,7 +54,7 @@
 extern const base::Feature kAutofillSettingsCardTypeSplit;
 extern const base::Feature kAutofillShowAllSuggestionsOnPrefilledForms;
 extern const base::Feature kAutofillShowAutocompleteConsoleWarnings;
-extern const base::Feature kAutofillShowFullDisclosureLabel;
+extern const base::Feature kAutofillUseImprovedLabelDisambiguation;
 extern const base::Feature kAutofillShowTypePredictions;
 extern const base::Feature kAutofillSkipComparingInferredLabels;
 extern const base::Feature kAutofillSuppressDisusedAddresses;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
index 6b0f30b3..a74d625f 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
@@ -122,16 +122,21 @@
   RegisterDataReductionProxyFieldTrial();
 }
 
+bool DataReductionProxySettings::IsDataSaverEnabledByUser() const {
+  if (params::ShouldForceEnableDataReductionProxy())
+    return true;
+
+  if (spdy_proxy_auth_enabled_.GetPrefName().empty())
+    return false;
+  return spdy_proxy_auth_enabled_.GetValue();
+}
+
 bool DataReductionProxySettings::IsDataReductionProxyEnabled() const {
   if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
       !params::IsEnabledWithNetworkService()) {
     return false;
   }
-
-  if (spdy_proxy_auth_enabled_.GetPrefName().empty())
-    return false;
-  return spdy_proxy_auth_enabled_.GetValue() ||
-         params::ShouldForceEnableDataReductionProxy();
+  return IsDataSaverEnabledByUser();
 }
 
 bool DataReductionProxySettings::CanUseDataReductionProxy(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
index 16d8252..bff7336 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -98,6 +98,10 @@
       const SyntheticFieldTrialRegistrationCallback&
           on_data_reduction_proxy_enabled);
 
+  // Returns true if DataSaver is enabled by checking only the prefs or forcing
+  // flag. Does not check any holdback experiments.
+  bool IsDataSaverEnabledByUser() const;
+
   // Returns true if the proxy is enabled.
   bool IsDataReductionProxyEnabled() const;
 
diff --git a/components/dom_distiller/standalone/DEPS b/components/dom_distiller/standalone/DEPS
index 5fa91387..ffbd1ead 100644
--- a/components/dom_distiller/standalone/DEPS
+++ b/components/dom_distiller/standalone/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+components/dom_distiller/content",
+  "+components/keyed_service/core",
   "+content/public",
   "+content/shell",
   "+net",
diff --git a/components/dom_distiller/standalone/content_extractor_browsertest.cc b/components/dom_distiller/standalone/content_extractor_browsertest.cc
index 6d7210f..d950b12 100644
--- a/components/dom_distiller/standalone/content_extractor_browsertest.cc
+++ b/components/dom_distiller/standalone/content_extractor_browsertest.cc
@@ -30,6 +30,7 @@
 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
 #include "components/dom_distiller/core/proto/distilled_page.pb.h"
 #include "components/dom_distiller/core/task_tracker.h"
+#include "components/keyed_service/core/simple_factory_key.h"
 #include "components/leveldb_proto/content/proto_database_provider_factory.h"
 #include "components/leveldb_proto/public/proto_database.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
@@ -126,14 +127,19 @@
 
 std::unique_ptr<DomDistillerService> CreateDomDistillerService(
     content::BrowserContext* context,
+    SimpleFactoryKey* key,
     const base::FilePath& db_path,
     const FileToUrlMap& file_to_url_map) {
   scoped_refptr<base::SequencedTaskRunner> background_task_runner =
       base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()});
 
+  // Setting up PrefService for DistilledPagePrefs.
+  sync_preferences::TestingPrefServiceSyncable* pref_service =
+      new sync_preferences::TestingPrefServiceSyncable();
+  DistilledPagePrefs::RegisterProfilePrefs(pref_service->registry());
+
   auto* db_provider =
-      leveldb_proto::ProtoDatabaseProviderFactory::GetForBrowserContext(
-          context);
+      leveldb_proto::ProtoDatabaseProviderFactory::GetForKey(key, pref_service);
 
   // TODO(cjhopman): use an in-memory database instead of an on-disk one with
   // temporary directory.
@@ -177,11 +183,6 @@
       new TestDistillerFactoryImpl(std::move(distiller_url_fetcher_factory),
                                    options, file_to_url_map));
 
-  // Setting up PrefService for DistilledPagePrefs.
-  sync_preferences::TestingPrefServiceSyncable* pref_service =
-      new sync_preferences::TestingPrefServiceSyncable();
-  DistilledPagePrefs::RegisterProfilePrefs(pref_service->registry());
-
   return std::unique_ptr<DomDistillerService>(new DomDistillerService(
       std::move(dom_distiller_store), std::move(distiller_factory),
       std::move(distiller_page_factory),
@@ -359,8 +360,9 @@
         command_line, &file_to_url_map);
     content::BrowserContext* context =
         shell()->web_contents()->GetBrowserContext();
-    service_ =
-        CreateDomDistillerService(context, db_dir_.GetPath(), file_to_url_map);
+    key_ = std::make_unique<SimpleFactoryKey>(context->GetPath());
+    service_ = CreateDomDistillerService(context, key_.get(), db_dir_.GetPath(),
+                                         file_to_url_map);
     PumpQueue();
   }
 
@@ -435,6 +437,8 @@
   size_t max_tasks_;
   size_t next_request_;
 
+  std::unique_ptr<SimpleFactoryKey> key_;
+
   base::ScopedTempDir db_dir_;
   std::unique_ptr<net::ScopedDefaultHostResolverProc>
       mock_host_resolver_override_;
diff --git a/components/leveldb_proto/content/proto_database_provider_factory.cc b/components/leveldb_proto/content/proto_database_provider_factory.cc
index dfdf057d..65c45c36 100644
--- a/components/leveldb_proto/content/proto_database_provider_factory.cc
+++ b/components/leveldb_proto/content/proto_database_provider_factory.cc
@@ -4,38 +4,39 @@
 
 #include "components/leveldb_proto/content/proto_database_provider_factory.h"
 
-#include "base/files/file_path.h"
 #include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "base/no_destructor.h"
+#include "components/keyed_service/core/simple_dependency_manager.h"
+#include "components/keyed_service/core/simple_factory_key.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
-#include "content/public/browser/browser_context.h"
 
 namespace leveldb_proto {
 
 // static
 ProtoDatabaseProviderFactory* ProtoDatabaseProviderFactory::GetInstance() {
-  return base::Singleton<ProtoDatabaseProviderFactory>::get();
+  static base::NoDestructor<ProtoDatabaseProviderFactory> instance;
+  return instance.get();
 }
 
 // static
-leveldb_proto::ProtoDatabaseProvider*
-ProtoDatabaseProviderFactory::GetForBrowserContext(
-    content::BrowserContext* context) {
-  return static_cast<leveldb_proto::ProtoDatabaseProvider*>(
-      GetInstance()->GetServiceForBrowserContext(context, true));
+ProtoDatabaseProvider* ProtoDatabaseProviderFactory::GetForKey(
+    SimpleFactoryKey* key,
+    PrefService* prefs) {
+  return static_cast<ProtoDatabaseProvider*>(
+      GetInstance()->GetServiceForKey(key, prefs, true));
 }
 
 ProtoDatabaseProviderFactory::ProtoDatabaseProviderFactory()
-    : BrowserContextKeyedServiceFactory(
-          "leveldb_proto::ProtoDatabaseProvider",
-          BrowserContextDependencyManager::GetInstance()) {}
+    : SimpleKeyedServiceFactory("leveldb_proto::ProtoDatabaseProvider",
+                                SimpleDependencyManager::GetInstance()) {}
 
 ProtoDatabaseProviderFactory::~ProtoDatabaseProviderFactory() = default;
 
-KeyedService* ProtoDatabaseProviderFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  base::FilePath profile_dir = context->GetPath();
-  return leveldb_proto::ProtoDatabaseProvider::Create(profile_dir);
+std::unique_ptr<KeyedService>
+ProtoDatabaseProviderFactory::BuildServiceInstanceFor(
+    SimpleFactoryKey* key,
+    PrefService* prefs) const {
+  return std::make_unique<ProtoDatabaseProvider>(key->path());
 }
 
 }  // namespace leveldb_proto
diff --git a/components/leveldb_proto/content/proto_database_provider_factory.h b/components/leveldb_proto/content/proto_database_provider_factory.h
index b83e692f..0126a39f 100644
--- a/components/leveldb_proto/content/proto_database_provider_factory.h
+++ b/components/leveldb_proto/content/proto_database_provider_factory.h
@@ -5,12 +5,18 @@
 #ifndef COMPONENTS_LEVELDB_PROTO_CONTENT_PROTO_DATABASE_PROVIDER_FACTORY_H_
 #define COMPONENTS_LEVELDB_PROTO_CONTENT_PROTO_DATABASE_PROVIDER_FACTORY_H_
 
+#include <memory>
+
 #include "base/macros.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "components/keyed_service/core/simple_keyed_service_factory.h"
+
+class KeyedService;
+class PrefService;
+class SimpleFactoryKey;
 
 namespace base {
 template <typename T>
-struct DefaultSingletonTraits;
+class NoDestructor;
 }  // namespace base
 
 namespace leveldb_proto {
@@ -18,25 +24,26 @@
 
 // A factory for ProtoDatabaseProvider, a class that provides proto databases
 // stored in the appropriate directory for the current profile.
-class ProtoDatabaseProviderFactory : public BrowserContextKeyedServiceFactory {
+class ProtoDatabaseProviderFactory : public SimpleKeyedServiceFactory {
  public:
   // Returns singleton instance of ProtoDatabaseProviderFactory.
   static ProtoDatabaseProviderFactory* GetInstance();
 
-  // Returns ProtoDatabaseProvider associated with |context|, so we can
+  // Returns ProtoDatabaseProvider associated with |key|, so we can
   // instantiate ProtoDatabases that use the appropriate profile directory.
-  static ProtoDatabaseProvider* GetForBrowserContext(
-      content::BrowserContext* context);
+  static ProtoDatabaseProvider* GetForKey(SimpleFactoryKey* key,
+                                          PrefService* prefs);
 
  private:
-  friend struct base::DefaultSingletonTraits<ProtoDatabaseProviderFactory>;
+  friend class base::NoDestructor<ProtoDatabaseProviderFactory>;
 
   ProtoDatabaseProviderFactory();
   ~ProtoDatabaseProviderFactory() override;
 
-  // BrowserContextKeyedServiceFactory overrides:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
+  // SimpleKeyedServiceFactory overrides:
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      SimpleFactoryKey* key,
+      PrefService* prefs) const override;
 
   DISALLOW_COPY_AND_ASSIGN(ProtoDatabaseProviderFactory);
 };
diff --git a/components/leveldb_proto/internal/proto_database_impl_unittest.cc b/components/leveldb_proto/internal/proto_database_impl_unittest.cc
index 43571a3..d8b413d 100644
--- a/components/leveldb_proto/internal/proto_database_impl_unittest.cc
+++ b/components/leveldb_proto/internal/proto_database_impl_unittest.cc
@@ -177,8 +177,7 @@
         db_type, db_dir, task_runner, std::move(db_provider));
   }
 
-  void GetDbAndWait(leveldb_proto::ProtoDatabaseProvider* db_provider,
-                    leveldb_proto::ProtoDbType db_type) {
+  void GetDbAndWait(ProtoDatabaseProvider* db_provider, ProtoDbType db_type) {
     base::ScopedTempDir temp_dir;
     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -189,9 +188,9 @@
 
     // Initialize a database, it should succeed.
     db->Init(base::BindOnce(
-        [](base::OnceClosure closure, leveldb_proto::Enums::InitStatus status) {
+        [](base::OnceClosure closure, Enums::InitStatus status) {
           std::move(closure).Run();
-          EXPECT_TRUE(status == leveldb_proto::Enums::InitStatus::kOK);
+          EXPECT_TRUE(status == Enums::InitStatus::kOK);
         },
         run_init.QuitClosure()));
 
@@ -232,8 +231,8 @@
                   const std::string& client_name,
                   bool use_shared_db,
                   Callbacks::InitStatusCallback callback) {
-    db_impl->InitInternal(client_name, leveldb_proto::CreateSimpleOptions(),
-                          use_shared_db, std::move(callback));
+    db_impl->InitInternal(client_name, CreateSimpleOptions(), use_shared_db,
+                          std::move(callback));
   }
 
   void InitDBImplAndWait(ProtoDatabaseImpl<TestProto, T>* db_impl,
@@ -948,7 +947,7 @@
                          this->CreateSharedProvider(db_provider.get()));
 
   base::RunLoop run_init;
-  auto options = leveldb_proto::CreateSimpleOptions();
+  auto options = CreateSimpleOptions();
   options.create_if_missing = false;
 
   // Initialize database with unique DB arguments, it should fail because we
@@ -975,13 +974,13 @@
       {"migrate_TestDatabase1", "false"}, {"migrate_TestDatabase2", "false"}};
   this->SetUpExperimentParams(experiment_params);
 
-  leveldb_proto::ProtoDatabaseProvider* db_provider =
-      leveldb_proto::ProtoDatabaseProvider::Create(temp_dir_profile.GetPath());
+  auto db_provider =
+      std::make_unique<ProtoDatabaseProvider>(temp_dir_profile.GetPath());
 
   // Initialize a database, it should succeed.
-  this->GetDbAndWait(db_provider, leveldb_proto::ProtoDbType::TEST_DATABASE1);
+  this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE1);
   // Initialize a second database, it should also succeed.
-  this->GetDbAndWait(db_provider, leveldb_proto::ProtoDbType::TEST_DATABASE2);
+  this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE2);
 }
 
 TYPED_TEST(ProtoDatabaseImplTest, InitUniqueThenSharedShouldSucceed) {
@@ -993,13 +992,13 @@
       {"migrate_TestDatabase1", "false"}, {"migrate_TestDatabase2", "true"}};
   this->SetUpExperimentParams(experiment_params);
 
-  leveldb_proto::ProtoDatabaseProvider* db_provider =
-      leveldb_proto::ProtoDatabaseProvider::Create(temp_dir_profile.GetPath());
+  auto db_provider =
+      std::make_unique<ProtoDatabaseProvider>(temp_dir_profile.GetPath());
 
   // Initialize a database, it should succeed.
-  this->GetDbAndWait(db_provider, leveldb_proto::ProtoDbType::TEST_DATABASE1);
+  this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE1);
   // Initialize a second database, it should also succeed.
-  this->GetDbAndWait(db_provider, leveldb_proto::ProtoDbType::TEST_DATABASE2);
+  this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE2);
 }
 
 TYPED_TEST(ProtoDatabaseImplTest, InitSharedThenUniqueShouldSucceed) {
@@ -1011,13 +1010,13 @@
       {"migrate_TestDatabase1", "true"}, {"migrate_TestDatabase2", "false"}};
   this->SetUpExperimentParams(experiment_params);
 
-  leveldb_proto::ProtoDatabaseProvider* db_provider =
-      leveldb_proto::ProtoDatabaseProvider::Create(temp_dir_profile.GetPath());
+  auto db_provider =
+      std::make_unique<ProtoDatabaseProvider>(temp_dir_profile.GetPath());
 
   // Initialize a database, it should succeed.
-  this->GetDbAndWait(db_provider, leveldb_proto::ProtoDbType::TEST_DATABASE1);
+  this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE1);
   // Initialize a second database, it should also succeed.
-  this->GetDbAndWait(db_provider, leveldb_proto::ProtoDbType::TEST_DATABASE2);
+  this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE2);
 }
 
 TYPED_TEST(ProtoDatabaseImplTest, InitSharedTwiceShouldSucceed) {
@@ -1029,13 +1028,13 @@
       {"migrate_TestDatabase1", "true"}, {"migrate_TestDatabase2", "true"}};
   this->SetUpExperimentParams(experiment_params);
 
-  leveldb_proto::ProtoDatabaseProvider* db_provider =
-      leveldb_proto::ProtoDatabaseProvider::Create(temp_dir_profile.GetPath());
+  auto db_provider =
+      std::make_unique<ProtoDatabaseProvider>(temp_dir_profile.GetPath());
 
   // Initialize a database, it should succeed.
-  this->GetDbAndWait(db_provider, leveldb_proto::ProtoDbType::TEST_DATABASE1);
+  this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE1);
   // Initialize a second database, it should also succeed.
-  this->GetDbAndWait(db_provider, leveldb_proto::ProtoDbType::TEST_DATABASE2);
+  this->GetDbAndWait(db_provider.get(), ProtoDbType::TEST_DATABASE2);
 }
 
 }  // namespace leveldb_proto
diff --git a/components/leveldb_proto/public/proto_database_provider.cc b/components/leveldb_proto/public/proto_database_provider.cc
index 0ce62bc..c8059f5 100644
--- a/components/leveldb_proto/public/proto_database_provider.cc
+++ b/components/leveldb_proto/public/proto_database_provider.cc
@@ -4,8 +4,11 @@
 
 #include "components/leveldb_proto/public/proto_database_provider.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/files/file_path.h"
+#include "base/memory/ptr_util.h"
 #include "base/sequenced_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/task/post_task.h"
@@ -31,12 +34,6 @@
 
 ProtoDatabaseProvider::~ProtoDatabaseProvider() = default;
 
-// static
-ProtoDatabaseProvider* ProtoDatabaseProvider::Create(
-    const base::FilePath& profile_dir) {
-  return new ProtoDatabaseProvider(profile_dir);
-}
-
 void ProtoDatabaseProvider::GetSharedDBInstance(
     GetSharedDBInstanceCallback callback,
     scoped_refptr<base::SequencedTaskRunner> callback_task_runner) {
diff --git a/components/leveldb_proto/public/proto_database_provider.h b/components/leveldb_proto/public/proto_database_provider.h
index f80a6a6..82e4b04 100644
--- a/components/leveldb_proto/public/proto_database_provider.h
+++ b/components/leveldb_proto/public/proto_database_provider.h
@@ -26,14 +26,16 @@
   using GetSharedDBInstanceCallback =
       base::OnceCallback<void(scoped_refptr<SharedProtoDatabase>)>;
 
-  static ProtoDatabaseProvider* Create(const base::FilePath& profile_dir);
-
   template <typename P, typename T = P>
   static std::unique_ptr<ProtoDatabase<P, T>> CreateUniqueDB(
       const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
     return std::make_unique<ProtoDatabaseImpl<P, T>>(task_runner);
   }
 
+  // Do not create this directly, instead use the ProtoDatabaseProviderFactory
+  // for the embedder to ensure there's only one per context.
+  ProtoDatabaseProvider(const base::FilePath& profile_dir);
+
   // |db_type|: Each database should have a type specified in ProtoDbType enum.
   // This type is used to index data in the shared database. |unique_db_dir|:
   // the subdirectory this database should live in within the profile directory.
@@ -57,8 +59,6 @@
   template <typename T_>
   friend class ProtoDatabaseImplTest;
 
-  ProtoDatabaseProvider(const base::FilePath& profile_dir);
-
   base::FilePath profile_dir_;
   scoped_refptr<SharedProtoDatabase> db_;
   base::Lock get_db_lock_;
diff --git a/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java b/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java
index 6cfb667..fd7a492f 100644
--- a/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java
+++ b/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java
@@ -18,6 +18,7 @@
  * @param <T> The interface of the module/
  */
 public class Module<T> {
+    private static final Set<String> sInstantiatedModuleNames = new HashSet<>();
     private static final Set<String> sModulesUninstalledForTesting = new HashSet<>();
     private final String mName;
     private final Class<T> mInterfaceClass;
@@ -27,8 +28,9 @@
     /** Forces a module to appear uninstalled. */
     @VisibleForTesting
     public static void setForceUninstalled(String moduleName) {
-        // TODO(crbug.com/944223): Make sure that this is not set after the module API has been
-        // used.
+        // We should not be uninstalling anything after the module API has been used for a
+        // particular module.
+        assert !sInstantiatedModuleNames.contains(moduleName);
         sModulesUninstalledForTesting.add(moduleName);
     }
 
@@ -44,6 +46,7 @@
         mName = name;
         mInterfaceClass = interfaceClass;
         mImplClassName = implClassName;
+        sInstantiatedModuleNames.add(name);
     }
 
     /** Returns true if the module is currently installed and can be accessed. */
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index f2b1f56..f8e7987 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -101,18 +101,7 @@
 const char AutocompleteMatch::kEllipsis[] = "... ";
 
 AutocompleteMatch::AutocompleteMatch()
-    : provider(nullptr),
-      relevance(0),
-      typed_count(-1),
-      deletable(false),
-      allowed_to_be_default_match(false),
-      document_type(DocumentType::NONE),
-      swap_contents_and_description(false),
-      transition(ui::PAGE_TRANSITION_GENERATED),
-      type(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED),
-      has_tab_match(false),
-      subtype_identifier(0),
-      from_previous(false) {}
+    : transition(ui::PAGE_TRANSITION_GENERATED) {}
 
 AutocompleteMatch::AutocompleteMatch(AutocompleteProvider* provider,
                                      int relevance,
@@ -120,16 +109,9 @@
                                      Type type)
     : provider(provider),
       relevance(relevance),
-      typed_count(-1),
       deletable(deletable),
-      allowed_to_be_default_match(false),
-      document_type(DocumentType::NONE),
-      swap_contents_and_description(false),
       transition(ui::PAGE_TRANSITION_TYPED),
-      type(type),
-      has_tab_match(false),
-      subtype_identifier(0),
-      from_previous(false) {}
+      type(type) {}
 
 AutocompleteMatch::AutocompleteMatch(const AutocompleteMatch& match)
     : provider(match.provider),
@@ -159,6 +141,7 @@
                              ? new AutocompleteMatch(*match.associated_keyword)
                              : nullptr),
       keyword(match.keyword),
+      from_keyword(match.from_keyword),
       pedal(match.pedal),
       from_previous(match.from_previous),
       search_terms_args(
@@ -207,6 +190,7 @@
           ? new AutocompleteMatch(*match.associated_keyword)
           : nullptr);
   keyword = match.keyword;
+  from_keyword = match.from_keyword;
   pedal = match.pedal;
   from_previous = match.from_previous;
   search_terms_args.reset(
@@ -801,11 +785,11 @@
   res += base::trace_event::EstimateMemoryUsage(stripped_destination_url);
   res += base::trace_event::EstimateMemoryUsage(image_dominant_color);
   res += base::trace_event::EstimateMemoryUsage(image_url);
+  res += base::trace_event::EstimateMemoryUsage(tail_suggest_common_prefix);
   res += base::trace_event::EstimateMemoryUsage(contents);
   res += base::trace_event::EstimateMemoryUsage(contents_class);
   res += base::trace_event::EstimateMemoryUsage(description);
   res += base::trace_event::EstimateMemoryUsage(description_class);
-  res += sizeof(int);
   if (answer)
     res += base::trace_event::EstimateMemoryUsage(answer.value());
   else
@@ -813,6 +797,7 @@
   res += base::trace_event::EstimateMemoryUsage(associated_keyword);
   res += base::trace_event::EstimateMemoryUsage(keyword);
   res += base::trace_event::EstimateMemoryUsage(search_terms_args);
+  res += base::trace_event::EstimateMemoryUsage(post_content);
   res += base::trace_event::EstimateMemoryUsage(additional_info);
   res += base::trace_event::EstimateMemoryUsage(duplicate_matches);
 
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index 587bd2d..2a560d3 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -382,7 +382,7 @@
   // The provider of this match, used to remember which provider the user had
   // selected when the input changes. This may be NULL, in which case there is
   // no provider (or memory of the user's selection).
-  AutocompleteProvider* provider;
+  AutocompleteProvider* provider = nullptr;
 
   // The relevance of this match. See table in autocomplete.h for scores
   // returned by various providers. This is used to rank matches among all
@@ -391,16 +391,16 @@
   //
   // TODO(pkasting): http://b/1111299 This should be calculated algorithmically,
   // rather than being a fairly fixed value defined by the table above.
-  int relevance;
+  int relevance = 0;
 
   // How many times this result was typed in / selected from the omnibox.
   // Only set for some providers and result_types.  If it is not set,
   // its value is -1.  At the time of writing this comment, it is only
   // set for matches from HistoryURL and HistoryQuickProvider.
-  int typed_count;
+  int typed_count = -1;
 
   // True if the user should be able to delete this match.
-  bool deletable;
+  bool deletable = false;
 
   // This string is loaded into the location bar when the item is selected
   // by pressing the arrow keys. This may be different than a URL, for example,
@@ -420,7 +420,7 @@
   // should only set this flag if ".com" will be inline autocompleted;
   // and a navigation to "foo/" (an intranet host) or search for "foo"
   // should set this flag.
-  bool allowed_to_be_default_match;
+  bool allowed_to_be_default_match = false;
 
   // The URL to actually load when the autocomplete item is selected. This URL
   // should be canonical so we can compare URLs with strcmp to avoid dupes.
@@ -438,7 +438,7 @@
   std::string image_url;
 
   // Optional override to use for types that specify an icon sub-type.
-  DocumentType document_type;
+  DocumentType document_type = DocumentType::NONE;
 
   // Holds the common part of tail suggestion.
   base::string16 tail_suggest_common_prefix;
@@ -453,7 +453,7 @@
 
   // If true, UI-level code should swap the contents and description fields
   // before displaying.
-  bool swap_contents_and_description;
+  bool swap_contents_and_description = false;
 
   // A rich-format version of the display for the dropdown.
   base::Optional<SuggestionAnswer> answer;
@@ -461,19 +461,19 @@
   // The transition type to use when the user opens this match.  By default
   // this is TYPED.  Providers whose matches do not look like URLs should set
   // it to GENERATED.
-  ui::PageTransition transition;
+  ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
 
   // Type of this match.
-  Type type;
+  Type type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED;
 
   // True if we saw a tab that matched this suggestion.
-  bool has_tab_match;
+  bool has_tab_match = false;
 
   // Used to identify the specific source / type for suggestions by the
   // suggest server. See |result_subtype_identifier| in omnibox.proto for more
   // details.
   // The identifier 0 is reserved for cases where this specific type is unset.
-  int subtype_identifier;
+  int subtype_identifier = 0;
 
   // Set with a keyword provider match if this match can show a keyword hint.
   // For example, if this is a SearchProvider match for "www.amazon.com",
@@ -499,14 +499,14 @@
   base::string16 keyword;
 
   // Set in matches originating from keyword results.
-  bool from_keyword;
+  bool from_keyword = false;
 
   // Set to a matching pedal if appropriate.  The pedal is not owned, and the
   // owning OmniboxPedalProvider must outlive this.
   OmniboxPedal* pedal = nullptr;
 
   // True if this match is from a previous result.
-  bool from_previous;
+  bool from_previous = false;
 
   // Optional search terms args.  If present,
   // AutocompleteController::UpdateAssistedQueryStats() will incorporate this
diff --git a/components/omnibox/browser/omnibox_view.cc b/components/omnibox/browser/omnibox_view.cc
index a33ce6b..7ea1a21f3 100644
--- a/components/omnibox/browser/omnibox_view.cc
+++ b/components/omnibox/browser/omnibox_view.cc
@@ -281,6 +281,11 @@
     const base::string16& display_text,
     const bool text_is_url,
     const AutocompleteSchemeClassifier& classifier) {
+  if (!text_is_url) {
+    SetEmphasis(true, gfx::Range::InvalidRange());
+    return false;  // Path not eligible for fading if it's not even a URL.
+  }
+
   enum DemphasizeComponents {
     EVERYTHING,
     ALL_BUT_SCHEME,
@@ -292,21 +297,19 @@
   AutocompleteInput::ParseForEmphasizeComponents(display_text, classifier,
                                                  &scheme, &host);
 
-  if (text_is_url) {
-    const base::string16 url_scheme =
-        display_text.substr(scheme.begin, scheme.len);
-    // Extension IDs are not human-readable, so deemphasize everything to draw
-    // attention to the human-readable name in the location icon text.
-    // Data URLs are rarely human-readable and can be used for spoofing, so draw
-    // attention to the scheme to emphasize "this is just a bunch of data".
-    // For normal URLs, the host is the best proxy for "identity".
-    if (url_scheme == base::UTF8ToUTF16(extensions::kExtensionScheme))
-      deemphasize = EVERYTHING;
-    else if (url_scheme == base::UTF8ToUTF16(url::kDataScheme))
-      deemphasize = ALL_BUT_SCHEME;
-    else if (host.is_nonempty())
-      deemphasize = ALL_BUT_HOST;
-  }
+  const base::string16 url_scheme =
+      display_text.substr(scheme.begin, scheme.len);
+  // Extension IDs are not human-readable, so deemphasize everything to draw
+  // attention to the human-readable name in the location icon text.
+  // Data URLs are rarely human-readable and can be used for spoofing, so draw
+  // attention to the scheme to emphasize "this is just a bunch of data".
+  // For normal URLs, the host is the best proxy for "identity".
+  if (url_scheme == base::UTF8ToUTF16(extensions::kExtensionScheme))
+    deemphasize = EVERYTHING;
+  else if (url_scheme == base::UTF8ToUTF16(url::kDataScheme))
+    deemphasize = ALL_BUT_SCHEME;
+  else if (host.is_nonempty())
+    deemphasize = ALL_BUT_HOST;
 
   gfx::Range scheme_range = scheme.is_nonempty()
                                 ? gfx::Range(scheme.begin, scheme.end())
diff --git a/components/policy/core/common/policy_map.cc b/components/policy/core/common/policy_map.cc
index 7e94ec9e..fdd23ba5 100644
--- a/components/policy/core/common/policy_map.cc
+++ b/components/policy/core/common/policy_map.cc
@@ -228,26 +228,33 @@
 
 void PolicyMap::MergeFrom(const PolicyMap& other) {
   for (const auto& it : other) {
-    const Entry* entry = GetUntrusted(it.first);
-    bool same_value = false;
-    if (!entry) {
-      Set(it.first, it.second.DeepCopy());
-    } else {
-      same_value = entry->value && it.second.value->Equals(entry->value.get());
-      if (it.second.has_higher_priority_than(*entry)) {
-        auto new_policy = it.second.DeepCopy();
-        new_policy.AddConflictingPolicy(*entry);
-        Set(it.first, std::move(new_policy));
-      } else {
-        GetMutableUntrusted(it.first)->AddConflictingPolicy(it.second);
-      }
+    Entry* current_policy = GetMutableUntrusted(it.first);
+    auto other_policy = it.second.DeepCopy();
+
+    if (!current_policy) {
+      Set(it.first, std::move(other_policy));
+      continue;
     }
 
-    if (entry) {
-      GetMutableUntrusted(it.first)->AddError(
-          same_value ? IDS_POLICY_CONFLICT_SAME_VALUE
-                     : IDS_POLICY_CONFLICT_DIFF_VALUE);
+    auto& new_policy = other_policy.has_higher_priority_than(*current_policy)
+                           ? other_policy
+                           : *current_policy;
+    auto& conflict =
+        current_policy == &new_policy ? other_policy : *current_policy;
+
+    bool overwriting_default_policy =
+        new_policy.source != conflict.source &&
+        conflict.source == POLICY_SOURCE_ENTERPRISE_DEFAULT;
+    if (!overwriting_default_policy) {
+      new_policy.AddConflictingPolicy(conflict);
+      new_policy.AddError((current_policy->value &&
+                           it.second.value->Equals(current_policy->value.get()))
+                              ? IDS_POLICY_CONFLICT_SAME_VALUE
+                              : IDS_POLICY_CONFLICT_DIFF_VALUE);
     }
+
+    if (current_policy != &new_policy)
+      Set(it.first, std::move(new_policy));
   }
 }
 
@@ -317,7 +324,8 @@
 // static
 bool PolicyMap::MapEntryEquals(const PolicyMap::PolicyMapType::value_type& a,
                                const PolicyMap::PolicyMapType::value_type& b) {
-  return a.first == b.first && a.second.Equals(b.second);
+  bool equals = a.first == b.first && a.second.Equals(b.second);
+  return equals;
 }
 
 void PolicyMap::FilterErase(
diff --git a/components/policy/core/common/policy_map_unittest.cc b/components/policy/core/common/policy_map_unittest.cc
index 62937285..7b72c1a 100644
--- a/components/policy/core/common/policy_map_unittest.cc
+++ b/components/policy/core/common/policy_map_unittest.cc
@@ -242,7 +242,6 @@
   auto conflicted_policy_1 = a.Get(kTestPolicyName1)->DeepCopy();
   auto conflicted_policy_4 = a.Get(kTestPolicyName4)->DeepCopy();
   auto conflicted_policy_5 = a.Get(kTestPolicyName5)->DeepCopy();
-  auto conflicted_policy_7 = a.Get(kTestPolicyName7)->DeepCopy();
   auto conflicted_policy_8 = b.Get(kTestPolicyName8)->DeepCopy();
 
   a.GetMutable(kTestPolicyName7)->SetBlocked();
@@ -287,8 +286,6 @@
   c.Set(kTestPolicyName7, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
         POLICY_SOURCE_ACTIVE_DIRECTORY, std::make_unique<base::Value>(true),
         nullptr);
-  c.GetMutable(kTestPolicyName7)->AddError(IDS_POLICY_CONFLICT_DIFF_VALUE);
-  c.GetMutable(kTestPolicyName7)->AddConflictingPolicy(conflicted_policy_7);
   c.GetMutable(kTestPolicyName7)->SetBlocked();
 
   c.Set(kTestPolicyName8, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
diff --git a/components/previews/core/previews_experiments_unittest.cc b/components/previews/core/previews_experiments_unittest.cc
index 144061e..3274188 100644
--- a/components/previews/core/previews_experiments_unittest.cc
+++ b/components/previews/core/previews_experiments_unittest.cc
@@ -101,20 +101,10 @@
   variations::testing::ClearAllVariationParams();
 }
 
-#if defined(OS_ANDROID)
-
-TEST(PreviewsExperimentsTest, TestClientLoFiEnabledByDefaultOnAndroid) {
-  EXPECT_TRUE(params::IsClientLoFiEnabled());
-}
-
-#else  // !defined(OS_ANDROID)
-
-TEST(PreviewsExperimentsTest, TestClientLoFiDisabledByDefaultOnNonAndroid) {
+TEST(PreviewsExperimentsTest, TestClientLoFiDisabledByDefault) {
   EXPECT_FALSE(params::IsClientLoFiEnabled());
 }
 
-#endif  // defined(OS_ANDROID)
-
 TEST(PreviewsExperimentsTest, TestClientLoFiExplicitlyDisabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(features::kClientLoFi);
diff --git a/components/previews/core/previews_features.cc b/components/previews/core/previews_features.cc
index 8fe59cfa..4514930a 100644
--- a/components/previews/core/previews_features.cc
+++ b/components/previews/core/previews_features.cc
@@ -27,14 +27,8 @@
                                      base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables the Client Lo-Fi previews.
-const base::Feature kClientLoFi {
-  "ClientLoFi",
-#if defined(OS_ANDROID)
-      base::FEATURE_ENABLED_BY_DEFAULT
-#else   // !defined(OS_ANDROID)
-      base::FEATURE_DISABLED_BY_DEFAULT
-#endif  // defined(OS_ANDROID)
-};
+const base::Feature kClientLoFi{"ClientLoFi",
+                                base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Enables the NoScript previews for Android.
 const base::Feature kNoScriptPreviews {
diff --git a/components/renderer_context_menu/views/toolkit_delegate_views.cc b/components/renderer_context_menu/views/toolkit_delegate_views.cc
index a3a1698..2b90b13 100644
--- a/components/renderer_context_menu/views/toolkit_delegate_views.cc
+++ b/components/renderer_context_menu/views/toolkit_delegate_views.cc
@@ -18,11 +18,11 @@
 void ToolkitDelegateViews::RunMenuAt(views::Widget* parent,
                                      const gfx::Point& point,
                                      ui::MenuSourceType type) {
-  views::MenuAnchorPosition anchor_position =
-      (type == ui::MENU_SOURCE_TOUCH ||
-       type == ui::MENU_SOURCE_TOUCH_EDIT_MENU)
-      ? views::MENU_ANCHOR_BOTTOMCENTER
-      : views::MENU_ANCHOR_TOPLEFT;
+  using Position = views::MenuAnchorPosition;
+  Position anchor_position =
+      (type == ui::MENU_SOURCE_TOUCH || type == ui::MENU_SOURCE_TOUCH_EDIT_MENU)
+          ? Position::kBottomCenter
+          : Position::kTopLeft;
   menu_runner_->RunMenuAt(parent, nullptr, gfx::Rect(point, gfx::Size()),
                           anchor_position, type);
 }
diff --git a/components/send_tab_to_self/BUILD.gn b/components/send_tab_to_self/BUILD.gn
index c9da2de7..1569e3b 100644
--- a/components/send_tab_to_self/BUILD.gn
+++ b/components/send_tab_to_self/BUILD.gn
@@ -4,6 +4,8 @@
 
 static_library("send_tab_to_self") {
   sources = [
+    "features.cc",
+    "features.h",
     "send_tab_to_self_bridge.cc",
     "send_tab_to_self_bridge.h",
     "send_tab_to_self_entry.cc",
diff --git a/components/send_tab_to_self/features.cc b/components/send_tab_to_self/features.cc
new file mode 100644
index 0000000..4db29f6
--- /dev/null
+++ b/components/send_tab_to_self/features.cc
@@ -0,0 +1,12 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/send_tab_to_self/features.h"
+
+namespace send_tab_to_self {
+
+const base::Feature kSendTabToSelfReceive{"SendTabToSelfReceive",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
+}  // namespace send_tab_to_self
diff --git a/components/send_tab_to_self/features.h b/components/send_tab_to_self/features.h
new file mode 100644
index 0000000..56c9723
--- /dev/null
+++ b/components/send_tab_to_self/features.h
@@ -0,0 +1,17 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SEND_TAB_TO_SELF_FEATURES_H_
+#define COMPONENTS_SEND_TAB_TO_SELF_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace send_tab_to_self {
+
+// If this feature is enabled, we handle notifying users of sent tabs even if
+// the sync feature is disabled.
+extern const base::Feature kSendTabToSelfReceive;
+}  // namespace send_tab_to_self
+
+#endif  // COMPONENTS_SEND_TAB_TO_SELF_FEATURES_H_
diff --git a/components/signin/core/browser/signin_investigator.cc b/components/signin/core/browser/signin_investigator.cc
index ac8f2d8..7dc1236e 100644
--- a/components/signin/core/browser/signin_investigator.cc
+++ b/components/signin/core/browser/signin_investigator.cc
@@ -17,7 +17,7 @@
 void LogSigninScenario(InvestigatedScenario scenario) {
   UMA_HISTOGRAM_ENUMERATION(
       "Signin.InvestigatedScenario", static_cast<int>(scenario),
-      static_cast<int>(InvestigatedScenario::HISTOGRAM_COUNT));
+      static_cast<int>(InvestigatedScenario::NUM_ENTRIES));
 }
 }  // namespace
 
diff --git a/components/signin/core/browser/signin_investigator.h b/components/signin/core/browser/signin_investigator.h
index a4a8585..ce40682b 100644
--- a/components/signin/core/browser/signin_investigator.h
+++ b/components/signin/core/browser/signin_investigator.h
@@ -26,7 +26,7 @@
   // of local syncable data.
   DIFFERENT_ACCOUNT,
   // Always the last enumerated type.
-  HISTOGRAM_COUNT,
+  NUM_ENTRIES,
 };
 
 // Performs various checks with the current account being used to login in and
diff --git a/components/viz/common/quads/draw_quad.h b/components/viz/common/quads/draw_quad.h
index 01de49e..ecc0ef4 100644
--- a/components/viz/common/quads/draw_quad.h
+++ b/components/viz/common/quads/draw_quad.h
@@ -75,7 +75,8 @@
 
   bool ShouldDrawWithBlending() const {
     return needs_blending || shared_quad_state->opacity < 1.0f ||
-           shared_quad_state->blend_mode != SkBlendMode::kSrcOver;
+           shared_quad_state->blend_mode != SkBlendMode::kSrcOver ||
+           !shared_quad_state->rounded_corner_bounds.IsEmpty();
   }
 
   // Is the left edge of this tile aligned with the originating layer's
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 9e0979a..aedd863 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -186,6 +186,34 @@
   return active_unit;
 }
 
+bool ShouldUseRoundedCornerShader(const DrawQuad* quad) {
+  const SharedQuadState* sqs = quad->shared_quad_state;
+  const gfx::RRectF& rounded_corner_bounds = sqs->rounded_corner_bounds;
+
+  // There is no rounded corner set.
+  if (rounded_corner_bounds.IsEmpty())
+    return false;
+
+  const gfx::RectF target_quad = cc::MathUtil::MapClippedRect(
+      sqs->quad_to_target_transform, gfx::RectF(quad->visible_rect));
+
+  // If the rounded corner rect intersects with the quad, then we should run the
+  // fragment shader.
+  if (rounded_corner_bounds.rect().Intersects(target_quad))
+    return true;
+
+  // If the quad is not within the rounded corner bounds, neither does it
+  // intersect, we do not have to apply any rounded corner on it.
+  if (!rounded_corner_bounds.rect().Contains(target_quad))
+    return false;
+
+  // If the rounded corner bounding rect contains the quad but the rounded
+  // corner rrect does not, it means there is an intersection. Apply rounded
+  // corner on the quad.
+  SkRRect rrect = static_cast<SkRRect>(rounded_corner_bounds);
+  return !rrect.contains(gfx::RectFToSkRect(target_quad));
+}
+
 // Parameters needed to draw a RenderPassDrawQuad.
 struct GLRenderer::DrawRenderPassDrawQuadParams {
   DrawRenderPassDrawQuadParams() {}
@@ -1296,9 +1324,10 @@
 
 void GLRenderer::UpdateRPDQBlendMode(DrawRenderPassDrawQuadParams* params) {
   SkBlendMode blend_mode = params->quad->shared_quad_state->blend_mode;
-  SetBlendEnabled(!params->use_shaders_for_blending &&
-                  (params->quad->ShouldDrawWithBlending() ||
-                   !IsDefaultBlendMode(blend_mode)));
+  SetBlendEnabled((!params->use_shaders_for_blending &&
+                   (params->quad->ShouldDrawWithBlending() ||
+                    !IsDefaultBlendMode(blend_mode))) ||
+                  ShouldUseRoundedCornerShader(params->quad));
   if (!params->use_shaders_for_blending) {
     if (!use_blend_equation_advanced_coherent_ && use_blend_equation_advanced_)
       gl_->BlendBarrierKHR();
@@ -1330,7 +1359,8 @@
       ProgramKey::RenderPass(
           tex_coord_precision, sampler_type, shader_blend_mode,
           params->use_aa ? USE_AA : NO_AA, mask_mode, mask_for_background,
-          params->use_color_matrix, tint_gl_composited_content_),
+          params->use_color_matrix, tint_gl_composited_content_,
+          ShouldUseRoundedCornerShader(params->quad)),
       params->contents_and_bypass_color_space, target_color_space);
 }
 
@@ -1467,6 +1497,8 @@
   }
 
   SetShaderOpacity(params->quad->shared_quad_state->opacity);
+  SetShaderRoundedCorner(params->quad->shared_quad_state->rounded_corner_bounds,
+                         params->window_matrix * params->projection_matrix);
   SetShaderQuadF(params->surface_quad);
 }
 
@@ -1796,10 +1828,14 @@
 
   gfx::ColorSpace quad_color_space = gfx::ColorSpace::CreateSRGB();
   SetUseProgram(ProgramKey::SolidColor(use_aa ? USE_AA : NO_AA,
-                                       tint_gl_composited_content_),
+                                       tint_gl_composited_content_,
+                                       ShouldUseRoundedCornerShader(quad)),
                 quad_color_space,
                 current_frame()->current_render_pass->color_space);
   SetShaderColor(color, opacity);
+  SetShaderRoundedCorner(
+      quad->shared_quad_state->rounded_corner_bounds,
+      current_frame()->window_matrix * current_frame()->projection_matrix);
 
   if (current_program_->tint_color_matrix_location() != -1) {
     auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix();
@@ -1947,7 +1983,8 @@
                        quad->swizzle_contents ? DO_SWIZZLE : NO_SWIZZLE,
                        quad->is_premultiplied ? PREMULTIPLIED_ALPHA
                                               : NON_PREMULTIPLIED_ALPHA,
-                       false, false, tint_gl_composited_content_),
+                       false, false, tint_gl_composited_content_,
+                       ShouldUseRoundedCornerShader(quad)),
       quad_resource_lock.color_space(),
       current_frame()->current_render_pass->color_space);
 
@@ -1969,6 +2006,9 @@
   // Blending is required for antialiasing.
   SetBlendEnabled(true);
   SetShaderOpacity(quad->shared_quad_state->opacity);
+  SetShaderRoundedCorner(
+      quad->shared_quad_state->rounded_corner_bounds,
+      current_frame()->window_matrix * current_frame()->projection_matrix);
   DCHECK(CanApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode));
   ApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode);
 
@@ -2039,7 +2079,8 @@
                        quad->is_premultiplied ? PREMULTIPLIED_ALPHA
                                               : NON_PREMULTIPLIED_ALPHA,
                        !quad->ShouldDrawWithBlending(), has_tex_clamp_rect,
-                       tint_gl_composited_content_),
+                       tint_gl_composited_content_,
+                       ShouldUseRoundedCornerShader(quad)),
       quad_resource_lock.color_space(),
       current_frame()->current_render_pass->color_space);
 
@@ -2062,6 +2103,9 @@
   ApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode);
 
   SetShaderOpacity(quad->shared_quad_state->opacity);
+  SetShaderRoundedCorner(
+      quad->shared_quad_state->rounded_corner_bounds,
+      current_frame()->window_matrix * current_frame()->projection_matrix);
 
   // Pass quad coordinates to the uniform in the same order as GeometryBinding
   // does, then vertices will match the texture mapping in the vertex buffer.
@@ -2171,7 +2215,8 @@
 
   SetUseProgram(
       ProgramKey::YUVVideo(tex_coord_precision, sampler, alpha_texture_mode,
-                           uv_texture_mode, tint_gl_composited_content_),
+                           uv_texture_mode, tint_gl_composited_content_,
+                           ShouldUseRoundedCornerShader(quad)),
       src_color_space, dst_color_space);
 
   if (current_program_->tint_color_matrix_location() != -1) {
@@ -2286,7 +2331,8 @@
   DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_,
                                                  quad->resource_id());
 
-  SetUseProgram(ProgramKey::VideoStream(tex_coord_precision),
+  SetUseProgram(ProgramKey::VideoStream(tex_coord_precision,
+                                        ShouldUseRoundedCornerShader(quad)),
                 lock.color_space(),
                 current_frame()->current_render_pass->color_space);
 
@@ -2441,13 +2487,18 @@
   bool need_tex_clamp_rect = !quad->resource_size_in_pixels().IsEmpty() &&
                              (quad->uv_top_left != gfx::PointF(0, 0) ||
                               quad->uv_bottom_right != gfx::PointF(1, 1));
+
   ProgramKey program_key = ProgramKey::Texture(
       tex_coord_precision, sampler,
       quad->premultiplied_alpha ? PREMULTIPLIED_ALPHA : NON_PREMULTIPLIED_ALPHA,
       quad->background_color != SK_ColorTRANSPARENT, need_tex_clamp_rect,
-      tint_gl_composited_content_);
+      tint_gl_composited_content_, ShouldUseRoundedCornerShader(quad));
   int resource_id = quad->resource_id();
 
+  SetShaderRoundedCorner(
+      quad->shared_quad_state->rounded_corner_bounds,
+      current_frame()->window_matrix * current_frame()->projection_matrix);
+
   size_t max_quads = StaticGeometryBinding::NUM_QUADS;
   if (draw_cache_.is_empty || draw_cache_.program_key != program_key ||
       draw_cache_.resource_id != resource_id ||
@@ -2697,6 +2748,35 @@
   blend_shadow_ = enabled;
 }
 
+void GLRenderer::SetShaderRoundedCorner(
+    const gfx::RRectF& rounded_corner_bounds,
+    const gfx::Transform& screen_transform) {
+  if (!current_program_ ||
+      current_program_->rounded_corner_rect_location() == -1 ||
+      current_program_->rounded_corner_radius_location() == -1 ||
+      rounded_corner_bounds.IsEmpty()) {
+    return;
+  }
+
+  DCHECK(screen_transform.IsScaleOrTranslation());
+  const gfx::Vector2dF& translate = screen_transform.To2dTranslation();
+  const gfx::Vector2dF& scale = screen_transform.Scale2d();
+  gfx::RRectF bounds_in_screen = rounded_corner_bounds;
+  bounds_in_screen.Scale(scale.x(), scale.y());
+  bounds_in_screen.Offset(translate.x(), translate.y());
+
+  gfx::RectF rect = bounds_in_screen.rect();
+
+  gl_->Uniform4f(current_program_->rounded_corner_rect_location(), rect.x(),
+                 rect.y(), rect.width(), rect.height());
+  gl_->Uniform4f(
+      current_program_->rounded_corner_radius_location(),
+      bounds_in_screen.GetCornerRadii(gfx::RRectF::Corner::kUpperLeft).x(),
+      bounds_in_screen.GetCornerRadii(gfx::RRectF::Corner::kUpperRight).x(),
+      bounds_in_screen.GetCornerRadii(gfx::RRectF::Corner::kLowerRight).x(),
+      bounds_in_screen.GetCornerRadii(gfx::RRectF::Corner::kLowerLeft).x());
+}
+
 void GLRenderer::DrawQuadGeometryClippedByQuadF(
     const gfx::Transform& draw_transform,
     const gfx::RectF& quad_rect,
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h
index e1ab3200..40d97137 100644
--- a/components/viz/service/display/gl_renderer.h
+++ b/components/viz/service/display/gl_renderer.h
@@ -261,6 +261,8 @@
   void SetShaderQuadF(const gfx::QuadF& quad);
   void SetShaderMatrix(const gfx::Transform& transform);
   void SetShaderColor(SkColor color, float opacity);
+  void SetShaderRoundedCorner(const gfx::RRectF& rounded_corner_bounds,
+                              const gfx::Transform& screen_transform);
   void DrawQuadGeometryClippedByQuadF(const gfx::Transform& draw_transform,
                                       const gfx::RectF& quad_rect,
                                       const gfx::QuadF& clipping_region_quad,
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index 584ac05..41244c16 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -217,15 +217,18 @@
 
   void TestBasicShaders() {
     TestShader(ProgramKey::DebugBorder());
-    TestShader(ProgramKey::SolidColor(NO_AA, false));
-    TestShader(ProgramKey::SolidColor(USE_AA, false));
+    TestShader(ProgramKey::SolidColor(NO_AA, false, false));
+    TestShader(ProgramKey::SolidColor(USE_AA, false, false));
 
     TestShadersWithOutputColorMatrix(ProgramKey::DebugBorder());
-    TestShadersWithOutputColorMatrix(ProgramKey::SolidColor(NO_AA, false));
-    TestShadersWithOutputColorMatrix(ProgramKey::SolidColor(USE_AA, false));
+    TestShadersWithOutputColorMatrix(
+        ProgramKey::SolidColor(NO_AA, false, false));
+    TestShadersWithOutputColorMatrix(
+        ProgramKey::SolidColor(USE_AA, false, false));
 
-    TestShader(ProgramKey::SolidColor(NO_AA, true));
-    TestShadersWithOutputColorMatrix(ProgramKey::SolidColor(NO_AA, true));
+    TestShader(ProgramKey::SolidColor(NO_AA, true, false));
+    TestShadersWithOutputColorMatrix(
+        ProgramKey::SolidColor(NO_AA, true, false));
   }
 
   void TestColorShaders() {
@@ -254,8 +257,8 @@
           gfx::ColorSpace::CreateCustom(primaries, transfer_fns[i]);
 
       renderer()->SetCurrentFrameForTesting(GLRenderer::DrawingFrame());
-      renderer()->SetUseProgram(ProgramKey::SolidColor(NO_AA, false), src,
-                                gfx::ColorSpace::CreateXYZD50());
+      renderer()->SetUseProgram(ProgramKey::SolidColor(NO_AA, false, false),
+                                src, gfx::ColorSpace::CreateXYZD50());
       EXPECT_TRUE(renderer()->current_program_->initialized());
     }
   }
@@ -264,77 +267,97 @@
     // This program uses external textures and sampler, so it won't compile
     // everywhere.
     if (context_provider()->ContextCapabilities().egl_image_external) {
-      TestShader(ProgramKey::VideoStream(precision));
+      TestShader(ProgramKey::VideoStream(precision, false));
     }
   }
 
   void TestShadersWithPrecisionAndBlend(TexCoordPrecision precision,
                                         BlendMode blend_mode) {
     TestShader(ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode,
-                                      NO_AA, NO_MASK, false, false, false));
+                                      NO_AA, NO_MASK, false, false, false,
+                                      false));
     TestShader(ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode,
-                                      USE_AA, NO_MASK, false, false, false));
+                                      USE_AA, NO_MASK, false, false, false,
+                                      false));
   }
 
   void TestShadersWithPrecisionAndSampler(TexCoordPrecision precision,
                                           SamplerType sampler) {
     TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
-                                   false, true, false));
+                                   false, true, false, false));
     TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
-                                   false, false, false));
+                                   false, false, false, false));
     TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
-                                   true, true, false));
+                                   true, true, false, false));
     TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
-                                   true, false, false));
+                                   true, false, false, false));
     TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
-                                   false, true, false));
+                                   false, true, false, false));
     TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
-                                   false, false, false));
+                                   false, false, false, false));
     TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
-                                   true, true, false));
+                                   true, true, false, false));
     TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
-                                   true, false, false));
+                                   true, false, false, false));
 
     TestShader(ProgramKey::Tile(precision, sampler, USE_AA, NO_SWIZZLE,
-                                PREMULTIPLIED_ALPHA, false, false, false));
+                                PREMULTIPLIED_ALPHA, false, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, USE_AA, DO_SWIZZLE,
-                                PREMULTIPLIED_ALPHA, false, false, false));
+                                PREMULTIPLIED_ALPHA, false, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE,
-                                PREMULTIPLIED_ALPHA, false, false, false));
+                                PREMULTIPLIED_ALPHA, false, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE,
-                                PREMULTIPLIED_ALPHA, false, false, false));
+                                PREMULTIPLIED_ALPHA, false, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE,
-                                PREMULTIPLIED_ALPHA, true, false, false));
+                                PREMULTIPLIED_ALPHA, true, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE,
-                                PREMULTIPLIED_ALPHA, true, false, false));
+                                PREMULTIPLIED_ALPHA, true, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE,
-                                PREMULTIPLIED_ALPHA, false, true, false));
+                                PREMULTIPLIED_ALPHA, false, true, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE,
-                                PREMULTIPLIED_ALPHA, false, true, false));
+                                PREMULTIPLIED_ALPHA, false, true, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE,
-                                PREMULTIPLIED_ALPHA, true, true, false));
+                                PREMULTIPLIED_ALPHA, true, true, false, false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE,
-                                PREMULTIPLIED_ALPHA, true, true, false));
+                                PREMULTIPLIED_ALPHA, true, true, false, false));
     TestShader(ProgramKey::Tile(precision, sampler, USE_AA, NO_SWIZZLE,
-                                NON_PREMULTIPLIED_ALPHA, false, false, false));
+                                NON_PREMULTIPLIED_ALPHA, false, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, USE_AA, DO_SWIZZLE,
-                                NON_PREMULTIPLIED_ALPHA, false, false, false));
+                                NON_PREMULTIPLIED_ALPHA, false, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE,
-                                NON_PREMULTIPLIED_ALPHA, false, false, false));
+                                NON_PREMULTIPLIED_ALPHA, false, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE,
-                                NON_PREMULTIPLIED_ALPHA, false, false, false));
+                                NON_PREMULTIPLIED_ALPHA, false, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE,
-                                NON_PREMULTIPLIED_ALPHA, true, false, false));
+                                NON_PREMULTIPLIED_ALPHA, true, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE,
-                                NON_PREMULTIPLIED_ALPHA, true, false, false));
+                                NON_PREMULTIPLIED_ALPHA, true, false, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE,
-                                NON_PREMULTIPLIED_ALPHA, false, true, false));
+                                NON_PREMULTIPLIED_ALPHA, false, true, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE,
-                                NON_PREMULTIPLIED_ALPHA, false, true, false));
+                                NON_PREMULTIPLIED_ALPHA, false, true, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE,
-                                NON_PREMULTIPLIED_ALPHA, true, true, false));
+                                NON_PREMULTIPLIED_ALPHA, true, true, false,
+                                false));
     TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE,
-                                NON_PREMULTIPLIED_ALPHA, true, true, false));
+                                NON_PREMULTIPLIED_ALPHA, true, true, false,
+                                false));
 
     // Iterate over alpha plane, nv12, and color_lut parameters.
     UVTextureMode uv_modes[2] = {UV_TEXTURE_MODE_UV, UV_TEXTURE_MODE_U_V};
@@ -343,7 +366,7 @@
     for (int j = 0; j < 2; j++) {
       for (int k = 0; k < 2; k++) {
         TestShader(ProgramKey::YUVVideo(precision, sampler, a_modes[j],
-                                        uv_modes[k], false));
+                                        uv_modes[k], false, false));
       }
     }
   }
@@ -354,16 +377,16 @@
                             bool mask_for_background) {
     TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA,
                                       HAS_MASK, mask_for_background, false,
-                                      false));
+                                      false, false));
     TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA,
                                       HAS_MASK, mask_for_background, true,
-                                      false));
+                                      false, false));
     TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA,
                                       HAS_MASK, mask_for_background, false,
-                                      false));
+                                      false, false));
     TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA,
                                       HAS_MASK, mask_for_background, true,
-                                      false));
+                                      false, false));
   }
 };
 
@@ -542,7 +565,7 @@
                              BlendMode blend_mode) {
     const Program* program = renderer_->GetProgramIfInitialized(
         ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, NO_AA,
-                               NO_MASK, false, false, false));
+                               NO_MASK, false, false, false, false));
     EXPECT_PROGRAM_VALID(program);
     EXPECT_EQ(program, renderer_->current_program_);
   }
@@ -551,7 +574,7 @@
                                         BlendMode blend_mode) {
     const Program* program = renderer_->GetProgramIfInitialized(
         ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, NO_AA,
-                               NO_MASK, false, true, false));
+                               NO_MASK, false, true, false, false));
     EXPECT_PROGRAM_VALID(program);
     EXPECT_EQ(program, renderer_->current_program_);
   }
@@ -561,7 +584,7 @@
                                  BlendMode blend_mode) {
     const Program* program = renderer_->GetProgramIfInitialized(
         ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA, HAS_MASK,
-                               false, false, false));
+                               false, false, false, false));
     EXPECT_PROGRAM_VALID(program);
     EXPECT_EQ(program, renderer_->current_program_);
   }
@@ -571,7 +594,7 @@
                                             BlendMode blend_mode) {
     const Program* program = renderer_->GetProgramIfInitialized(
         ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA, HAS_MASK,
-                               false, true, false));
+                               false, true, false, false));
     EXPECT_PROGRAM_VALID(program);
     EXPECT_EQ(program, renderer_->current_program_);
   }
@@ -580,7 +603,7 @@
                                BlendMode blend_mode) {
     const Program* program = renderer_->GetProgramIfInitialized(
         ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, USE_AA,
-                               NO_MASK, false, false, false));
+                               NO_MASK, false, false, false, false));
     EXPECT_PROGRAM_VALID(program);
     EXPECT_EQ(program, renderer_->current_program_);
   }
@@ -589,7 +612,7 @@
                                           BlendMode blend_mode) {
     const Program* program = renderer_->GetProgramIfInitialized(
         ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, USE_AA,
-                               NO_MASK, false, true, false));
+                               NO_MASK, false, true, false, false));
     EXPECT_PROGRAM_VALID(program);
     EXPECT_EQ(program, renderer_->current_program_);
   }
@@ -599,7 +622,7 @@
                                    BlendMode blend_mode) {
     const Program* program = renderer_->GetProgramIfInitialized(
         ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA, HAS_MASK,
-                               false, false, false));
+                               false, false, false, false));
     EXPECT_PROGRAM_VALID(program);
     EXPECT_EQ(program, renderer_->current_program_);
   }
@@ -609,14 +632,14 @@
                                               BlendMode blend_mode) {
     const Program* program = renderer_->GetProgramIfInitialized(
         ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA, HAS_MASK,
-                               false, true, false));
+                               false, true, false, false));
     EXPECT_PROGRAM_VALID(program);
     EXPECT_EQ(program, renderer_->current_program_);
   }
 
   void TestSolidColorProgramAA() {
     const Program* program = renderer_->GetProgramIfInitialized(
-        ProgramKey::SolidColor(USE_AA, false));
+        ProgramKey::SolidColor(USE_AA, false, false));
     EXPECT_PROGRAM_VALID(program);
     EXPECT_EQ(program, renderer_->current_program_);
   }
diff --git a/components/viz/service/display/program_binding.cc b/components/viz/service/display/program_binding.cc
index 9436dc3..e676be18 100644
--- a/components/viz/service/display/program_binding.cc
+++ b/components/viz/service/display/program_binding.cc
@@ -35,7 +35,8 @@
          uv_texture_mode_ == other.uv_texture_mode_ &&
          color_conversion_mode_ == other.color_conversion_mode_ &&
          color_transform_ == other.color_transform_ &&
-         has_output_color_matrix_ == other.has_output_color_matrix_;
+         has_output_color_matrix_ == other.has_output_color_matrix_ &&
+         has_rounded_corner_ == other.has_rounded_corner_;
 }
 
 bool ProgramKey::operator!=(const ProgramKey& other) const {
@@ -50,11 +51,14 @@
 }
 
 // static
-ProgramKey ProgramKey::SolidColor(AAMode aa_mode, bool tint_color) {
+ProgramKey ProgramKey::SolidColor(AAMode aa_mode,
+                                  bool tint_color,
+                                  bool rounded_corner) {
   ProgramKey result;
   result.type_ = PROGRAM_TYPE_SOLID_COLOR;
   result.aa_mode_ = aa_mode;
   result.has_tint_color_matrix_ = tint_color;
+  result.has_rounded_corner_ = rounded_corner;
   return result;
 }
 
@@ -66,7 +70,8 @@
                             PremultipliedAlphaMode premultiplied_alpha,
                             bool is_opaque,
                             bool has_tex_clamp_rect,
-                            bool tint_color) {
+                            bool tint_color,
+                            bool rounded_corner) {
   ProgramKey result;
   result.type_ = PROGRAM_TYPE_TILE;
   result.precision_ = precision;
@@ -77,6 +82,7 @@
   result.has_tex_clamp_rect_ = has_tex_clamp_rect;
   result.has_tint_color_matrix_ = tint_color;
   result.premultiplied_alpha_ = premultiplied_alpha;
+  result.has_rounded_corner_ = rounded_corner;
   return result;
 }
 
@@ -86,7 +92,8 @@
                                PremultipliedAlphaMode premultiplied_alpha,
                                bool has_background_color,
                                bool has_tex_clamp_rect,
-                               bool tint_color) {
+                               bool tint_color,
+                               bool rounded_corner) {
   ProgramKey result;
   result.type_ = PROGRAM_TYPE_TEXTURE;
   result.precision_ = precision;
@@ -95,6 +102,7 @@
   result.has_background_color_ = has_background_color;
   result.has_tex_clamp_rect_ = has_tex_clamp_rect;
   result.has_tint_color_matrix_ = tint_color;
+  result.has_rounded_corner_ = rounded_corner;
   return result;
 }
 
@@ -106,7 +114,8 @@
                                   MaskMode mask_mode,
                                   bool mask_for_background,
                                   bool has_color_matrix,
-                                  bool tint_color) {
+                                  bool tint_color,
+                                  bool rounded_corner) {
   ProgramKey result;
   result.type_ = PROGRAM_TYPE_RENDER_PASS;
   result.precision_ = precision;
@@ -117,15 +126,18 @@
   result.mask_for_background_ = mask_for_background;
   result.has_color_matrix_ = has_color_matrix;
   result.has_tint_color_matrix_ = tint_color;
+  result.has_rounded_corner_ = rounded_corner;
   return result;
 }
 
 // static
-ProgramKey ProgramKey::VideoStream(TexCoordPrecision precision) {
+ProgramKey ProgramKey::VideoStream(TexCoordPrecision precision,
+                                   bool rounded_corner) {
   ProgramKey result;
   result.type_ = PROGRAM_TYPE_VIDEO_STREAM;
   result.precision_ = precision;
   result.sampler_ = SAMPLER_TYPE_EXTERNAL_OES;
+  result.has_rounded_corner_ = rounded_corner;
   return result;
 }
 
@@ -134,7 +146,8 @@
                                 SamplerType sampler,
                                 YUVAlphaTextureMode yuv_alpha_texture_mode,
                                 UVTextureMode uv_texture_mode,
-                                bool tint_color) {
+                                bool tint_color,
+                                bool rounded_corner) {
   ProgramKey result;
   result.type_ = PROGRAM_TYPE_YUV_VIDEO;
   result.precision_ = precision;
@@ -146,6 +159,7 @@
   DCHECK(uv_texture_mode == UV_TEXTURE_MODE_UV ||
          uv_texture_mode == UV_TEXTURE_MODE_U_V);
   result.has_tint_color_matrix_ = tint_color;
+  result.has_rounded_corner_ = rounded_corner;
   return result;
 }
 
diff --git a/components/viz/service/display/program_binding.h b/components/viz/service/display/program_binding.h
index 2a8fb9f..d222e145 100644
--- a/components/viz/service/display/program_binding.h
+++ b/components/viz/service/display/program_binding.h
@@ -77,7 +77,9 @@
   ~ProgramKey();
 
   static ProgramKey DebugBorder();
-  static ProgramKey SolidColor(AAMode aa_mode, bool tint_color);
+  static ProgramKey SolidColor(AAMode aa_mode,
+                               bool tint_color,
+                               bool rounded_corner);
   static ProgramKey Tile(TexCoordPrecision precision,
                          SamplerType sampler,
                          AAMode aa_mode,
@@ -85,13 +87,15 @@
                          PremultipliedAlphaMode premultiplied_alpha,
                          bool is_opaque,
                          bool has_tex_clamp_rect,
-                         bool tint_color);
+                         bool tint_color,
+                         bool rounded_corner);
   static ProgramKey Texture(TexCoordPrecision precision,
                             SamplerType sampler,
                             PremultipliedAlphaMode premultiplied_alpha,
                             bool has_background_color,
                             bool has_tex_clamp_rect,
-                            bool tint_color);
+                            bool tint_color,
+                            bool rounded_corner);
 
   // TODO(ccameron): Merge |mask_for_background| into MaskMode.
   static ProgramKey RenderPass(TexCoordPrecision precision,
@@ -101,13 +105,16 @@
                                MaskMode mask_mode,
                                bool mask_for_background,
                                bool has_color_matrix,
-                               bool tint_color);
-  static ProgramKey VideoStream(TexCoordPrecision precision);
+                               bool tint_color,
+                               bool rounded_corner);
+  static ProgramKey VideoStream(TexCoordPrecision precision,
+                                bool rounded_corner);
   static ProgramKey YUVVideo(TexCoordPrecision precision,
                              SamplerType sampler,
                              YUVAlphaTextureMode yuv_alpha_texture_mode,
                              UVTextureMode uv_texture_mode,
-                             bool tint_color);
+                             bool tint_color,
+                             bool rounded_corner);
 
   bool operator==(const ProgramKey& other) const;
   bool operator!=(const ProgramKey& other) const;
@@ -149,6 +156,7 @@
 
   bool has_output_color_matrix_ = false;
   bool has_tint_color_matrix_ = false;
+  bool has_rounded_corner_ = false;
 };
 
 struct ProgramKeyHash {
@@ -170,7 +178,8 @@
            (static_cast<size_t>(key.color_conversion_mode_) << 26) ^
            (static_cast<size_t>(key.has_tex_clamp_rect_) << 28) ^
            (static_cast<size_t>(key.has_output_color_matrix_) << 29) ^
-           (static_cast<size_t>(key.has_tint_color_matrix_) << 30);
+           (static_cast<size_t>(key.has_tint_color_matrix_) << 30) ^
+           (static_cast<size_t>(key.has_rounded_corner_) << 31);
   }
 };
 
@@ -193,6 +202,7 @@
     fragment_shader_.color_transform_ = key.color_transform_;
     fragment_shader_.has_output_color_matrix_ = key.has_output_color_matrix_;
     fragment_shader_.has_tint_color_matrix_ = key.has_tint_color_matrix_;
+    fragment_shader_.has_rounded_corner_ = key.has_rounded_corner_;
 
     switch (key.type_) {
       case PROGRAM_TYPE_DEBUG_BORDER:
@@ -321,6 +331,12 @@
   int tint_color_matrix_location() const {
     return fragment_shader_.tint_color_matrix_location_;
   }
+  int rounded_corner_rect_location() const {
+    return fragment_shader_.rounded_corner_rect_location_;
+  }
+  int rounded_corner_radius_location() const {
+    return fragment_shader_.rounded_corner_radius_location_;
+  }
 
  private:
   void InitializeDebugBorderProgram() {
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc
index 4c9232c3..00ba3b4 100644
--- a/components/viz/service/display/renderer_pixeltest.cc
+++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -133,19 +133,21 @@
 SharedQuadState* CreateTestSharedQuadState(
     gfx::Transform quad_to_target_transform,
     const gfx::Rect& rect,
-    RenderPass* render_pass) {
+    RenderPass* render_pass,
+    const gfx::RRectF& rrect) {
   const gfx::Rect layer_rect = rect;
   const gfx::Rect visible_layer_rect = rect;
   const gfx::Rect clip_rect = rect;
   const bool is_clipped = false;
   const bool are_contents_opaque = false;
   const float opacity = 1.0f;
+  const gfx::RRectF rounded_corner_bounds = rrect;
   const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
   int sorting_context_id = 0;
   SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
-                       /*rounded_corner_bounds=*/gfx::RRectF(), clip_rect,
-                       is_clipped, are_contents_opaque, opacity, blend_mode,
+                       rounded_corner_bounds, clip_rect, is_clipped,
+                       are_contents_opaque, opacity, blend_mode,
                        sorting_context_id);
   return shared_state;
 }
@@ -937,8 +939,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   color_quad->SetNew(shared_state, rect, rect, SK_ColorGREEN, false);
@@ -959,8 +961,8 @@
   std::unique_ptr<RenderPass> child_pass =
       CreateTestRenderPass(child_id, small_rect, gfx::Transform());
 
-  SharedQuadState* child_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), small_rect, child_pass.get());
+  SharedQuadState* child_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), small_rect, child_pass.get(), gfx::RRectF());
 
   auto* color_quad = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   color_quad->SetNew(child_shared_state, rect, rect, SK_ColorGREEN, false);
@@ -969,8 +971,8 @@
   std::unique_ptr<RenderPass> root_pass =
       CreateTestRenderPass(root_id, rect, gfx::Transform());
 
-  SharedQuadState* root_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, root_pass.get());
+  SharedQuadState* root_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, root_pass.get(), gfx::RRectF());
 
   CreateTestRenderPassDrawQuad(root_shared_state, small_rect, child_id,
                                root_pass.get());
@@ -993,8 +995,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   CreateTestTextureDrawQuad(
       this->use_gpu(), gfx::Rect(this->device_viewport_size_),
@@ -1022,8 +1024,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* texture_quad_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* texture_quad_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
   texture_quad_state->opacity = 0.8f;
 
   CreateTestTextureDrawQuad(
@@ -1035,8 +1037,8 @@
       this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
       this->child_context_provider_, pass.get());
 
-  SharedQuadState* color_quad_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* color_quad_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
   auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
 
@@ -1054,16 +1056,16 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
   shared_state->opacity = 1 - 16.0f / 255;
   shared_state->blend_mode = SkBlendMode::kDstOut;
 
   auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   color_quad->SetNew(shared_state, rect, rect, SK_ColorRED, false);
 
-  SharedQuadState* shared_state_background =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state_background = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   SkColor background_color = SkColorSetRGB(0xff, 0xff * 14 / 16, 0xff);
   auto* color_quad_background =
@@ -1086,8 +1088,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   color_quad->SetNew(shared_state, rect, rect, SK_ColorYELLOW, false);
@@ -1129,8 +1131,8 @@
       gfx::Transform(), cc::FilterOperations());
   cc::AddQuad(root_pass, root_rect, SK_ColorYELLOW);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), viewport_rect, root_pass);
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), viewport_rect, root_pass, gfx::RRectF());
   CreateTestRenderPassDrawQuad(pass_shared_state, viewport_rect, child_pass_id,
                                root_pass);
 
@@ -1155,8 +1157,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* texture_quad_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* texture_quad_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
   texture_quad_state->opacity = 0.8f;
 
   float vertex_opacity[4] = {1.f, 1.f, 0.f, 0.f};
@@ -1170,8 +1172,8 @@
       this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
       this->child_context_provider_, pass.get());
 
-  SharedQuadState* color_quad_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* color_quad_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
   auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
 
@@ -1207,8 +1209,8 @@
     trans.Translate3d(0, 0, 0.707 * this->device_viewport_size_.width() / 2.0);
     trans.RotateAboutZAxis(45.0);
     trans.RotateAboutYAxis(45.0);
-    front_quad_state_ =
-        CreateTestSharedQuadState(trans, viewport_rect_, render_pass_.get());
+    front_quad_state_ = CreateTestSharedQuadState(
+        trans, viewport_rect_, render_pass_.get(), gfx::RRectF());
     front_quad_state_->clip_rect = quad_rect_;
     // Make sure they end up in a 3d sorting context.
     front_quad_state_->sorting_context_id = 1;
@@ -1218,15 +1220,15 @@
     trans = gfx::Transform();
     trans.Translate3d(0, 0, -0.707 * this->device_viewport_size_.width() / 2.0);
     trans.RotateAboutYAxis(-45.0);
-    back_quad_state_ =
-        CreateTestSharedQuadState(trans, viewport_rect_, render_pass_.get());
+    back_quad_state_ = CreateTestSharedQuadState(
+        trans, viewport_rect_, render_pass_.get(), gfx::RRectF());
     back_quad_state_->sorting_context_id = 1;
     back_quad_state_->clip_rect = quad_rect_;
   }
   void AppendBackgroundAndRunTest(const cc::PixelComparator& comparator,
                                   const base::FilePath::CharType* ref_file) {
     SharedQuadState* background_quad_state = CreateTestSharedQuadState(
-        gfx::Transform(), viewport_rect_, render_pass_.get());
+        gfx::Transform(), viewport_rect_, render_pass_.get(), gfx::RRectF());
     auto* background_quad =
         render_pass_->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
     background_quad->SetNew(background_quad_state, viewport_rect_,
@@ -1466,11 +1468,11 @@
   std::unique_ptr<RenderPass> child_pass1 =
       CreateTestRenderPass(child_pass_id1, this->quad_rect_, gfx::Transform());
   SharedQuadState* child1_quad_state = CreateTestSharedQuadState(
-      gfx::Transform(), this->quad_rect_, child_pass1.get());
+      gfx::Transform(), this->quad_rect_, child_pass1.get(), gfx::RRectF());
   std::unique_ptr<RenderPass> child_pass2 =
       CreateTestRenderPass(child_pass_id2, this->quad_rect_, gfx::Transform());
   SharedQuadState* child2_quad_state = CreateTestSharedQuadState(
-      gfx::Transform(), this->quad_rect_, child_pass2.get());
+      gfx::Transform(), this->quad_rect_, child_pass2.get(), gfx::RRectF());
   CreateTestTwoColoredTextureDrawQuad(
       this->use_gpu(), this->quad_rect_,
       GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)),
@@ -1564,8 +1566,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   CreateTestTextureDrawQuad(
       this->use_gpu(), gfx::Rect(this->device_viewport_size_),
@@ -1594,8 +1596,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* texture_quad_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* texture_quad_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
   texture_quad_state->opacity = 0.8f;
 
   CreateTestTextureDrawQuad(
@@ -1607,8 +1609,8 @@
       this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
       this->child_context_provider_, pass.get());
 
-  SharedQuadState* color_quad_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* color_quad_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
   auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
 
@@ -1641,8 +1643,8 @@
     gfx::Transform scale_by_2;
     scale_by_2.Scale(2.f, 2.f);
     gfx::Rect half_rect(100, 100);
-    SharedQuadState* shared_state =
-        CreateTestSharedQuadState(scale_by_2, half_rect, pass.get());
+    SharedQuadState* shared_state = CreateTestSharedQuadState(
+        scale_by_2, half_rect, pass.get(), gfx::RRectF());
 
     gfx::Size background_size(200, 200);
     gfx::Rect green_rect(16, 20, 100, 100);
@@ -1706,8 +1708,8 @@
     pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M,
                                         gfx::ColorSpace::TransferID::SMPTE170M);
 
-    SharedQuadState* shared_state =
-        CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+    SharedQuadState* shared_state = CreateTestSharedQuadState(
+        gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
     CreateTestYUVVideoDrawQuad_Striped(
         shared_state, media::PIXEL_FORMAT_I420, gfx::ColorSpace::CreateREC601(),
@@ -1734,8 +1736,8 @@
     pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M,
                                         gfx::ColorSpace::TransferID::SMPTE170M);
 
-    SharedQuadState* shared_state =
-        CreateTestSharedQuadState(gfx::Transform(), viewport, pass.get());
+    SharedQuadState* shared_state = CreateTestSharedQuadState(
+        gfx::Transform(), viewport, pass.get(), gfx::RRectF());
 
     CreateTestYUVVideoDrawQuad_Striped(
         shared_state, media::PIXEL_FORMAT_I420, gfx::ColorSpace::CreateREC601(),
@@ -1783,8 +1785,8 @@
   pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M,
                                       gfx::ColorSpace::TransferID::SMPTE170M);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   // Intentionally sets frame format to I420 for testing coverage.
   CreateTestYUVVideoDrawQuad_Striped(
@@ -1811,8 +1813,8 @@
   pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M,
                                       gfx::ColorSpace::TransferID::SMPTE170M);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   // In MPEG color range YUV values of (15,128,128) should produce black.
   CreateTestYUVVideoDrawQuad_Solid(
@@ -1842,8 +1844,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   // YUV of (149,43,21) should be green (0,255,0) in RGB.
   CreateTestYUVVideoDrawQuad_Solid(
@@ -1867,8 +1869,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   // YUV of (149,43,21) should be green (0,255,0) in RGB.
   CreateTestYUVVideoDrawQuad_NV12(
@@ -1920,8 +1922,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   // Dark grey in JPEG color range (in MPEG, this is black).
   CreateTestYUVVideoDrawQuad_Solid(
@@ -1950,8 +1952,8 @@
   pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M,
                                       gfx::ColorSpace::TransferID::SMPTE170M);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   CreateTestYUVVideoDrawQuad_Striped(
       shared_state, media::PIXEL_FORMAT_I420A, gfx::ColorSpace::CreateREC601(),
@@ -1980,8 +1982,8 @@
   pass->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M,
                                       gfx::ColorSpace::TransferID::SMPTE170M);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   CreateTestYUVVideoDrawQuad_Striped(
       shared_state, media::PIXEL_FORMAT_I420A, gfx::ColorSpace::CreateREC601(),
@@ -2007,8 +2009,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   gfx::Rect upper_rect(rect.x(), rect.y(), rect.width(), rect.height() / 2);
   CreateTestY16TextureDrawQuad_TwoColor(
@@ -2063,7 +2065,7 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
   shared_state->opacity = 0.5f;
 
   gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
@@ -2077,14 +2079,14 @@
   yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
 
   SharedQuadState* blank_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
 
   auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE,
                 false);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get());
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
 
   auto* render_pass_quad =
       root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
@@ -2123,7 +2125,7 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
   shared_state->opacity = 0.5f;
 
   gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
@@ -2137,14 +2139,14 @@
   yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
 
   SharedQuadState* blank_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
 
   auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE,
                 false);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get());
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
 
   auto* render_pass_quad =
       root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
@@ -2184,7 +2186,7 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
   shared_state->opacity = 0.5f;
 
   gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
@@ -2198,14 +2200,14 @@
   yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
 
   SharedQuadState* blank_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
 
   auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE,
                 false);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get());
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
 
   auto* render_pass_quad =
       root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
@@ -2266,7 +2268,7 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
   shared_state->opacity = 0.5f;
 
   gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
@@ -2280,14 +2282,14 @@
   yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
 
   SharedQuadState* blank_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
 
   auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE,
                 false);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get());
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
 
   auto* render_pass_quad =
       root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
@@ -2324,7 +2326,7 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
 
   gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
                       this->device_viewport_size_.height() / 2);
@@ -2336,8 +2338,8 @@
   auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get());
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
   CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
                                root_pass.get());
 
@@ -2367,7 +2369,7 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
 
   gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
                       this->device_viewport_size_.height() / 2);
@@ -2382,13 +2384,13 @@
   gfx::Transform aa_transform;
   aa_transform.Translate(0.5, 0.0);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(aa_transform, pass_rect, root_pass.get());
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      aa_transform, pass_rect, root_pass.get(), gfx::RRectF());
   CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
                                root_pass.get());
 
   SharedQuadState* root_shared_state = CreateTestSharedQuadState(
-      gfx::Transform(), viewport_rect, root_pass.get());
+      gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
   auto* background = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   background->SetNew(root_shared_state, gfx::Rect(this->device_viewport_size_),
                      gfx::Rect(this->device_viewport_size_), SK_ColorWHITE,
@@ -2415,14 +2417,14 @@
   std::unique_ptr<RenderPass> root_pass =
       CreateTestRootRenderPass(root_pass_id, viewport_rect);
   SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState(
-      gfx::Transform(), viewport_rect, root_pass.get());
+      gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
 
   int child_pass_id = 2;
   gfx::Transform transform_to_root;
   std::unique_ptr<RenderPass> child_pass =
       CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root);
   SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
-      gfx::Transform(), viewport_rect, child_pass.get());
+      gfx::Transform(), viewport_rect, child_pass.get(), gfx::RRectF());
 
   // The child render pass is just a green box.
   static const SkColor kCSSGreen = 0xff008000;
@@ -2512,14 +2514,14 @@
   std::unique_ptr<RenderPass> root_pass =
       CreateTestRootRenderPass(root_pass_id, viewport_rect);
   SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState(
-      gfx::Transform(), viewport_rect, root_pass.get());
+      gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
 
   int child_pass_id = 2;
   gfx::Transform transform_to_root;
   std::unique_ptr<RenderPass> child_pass =
       CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root);
   SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
-      gfx::Transform(), viewport_rect, child_pass.get());
+      gfx::Transform(), viewport_rect, child_pass.get(), gfx::RRectF());
 
   // The child render pass is just a green box.
   static const SkColor kCSSGreen = 0xff008000;
@@ -2600,6 +2602,196 @@
       cc::ExactPixelComparator(true)));
 }
 
+TYPED_TEST(RendererPixelTest, RenderPassAndMaskForRoundedCorner) {
+  gfx::Rect viewport_rect(this->device_viewport_size_);
+  constexpr int kInset = 20;
+  constexpr int kCornerRadius = 20;
+
+  int root_pass_id = 1;
+  std::unique_ptr<RenderPass> root_pass =
+      CreateTestRootRenderPass(root_pass_id, viewport_rect);
+  SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
+
+  int child_pass_id = 2;
+  gfx::Transform transform_to_root;
+  std::unique_ptr<RenderPass> child_pass =
+      CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root);
+  SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), viewport_rect, child_pass.get(), gfx::RRectF());
+
+  // The child render pass is just a blue box.
+  auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  blue->SetNew(child_pass_shared_state, viewport_rect, viewport_rect,
+               SK_ColorBLUE, false);
+
+  // Make a mask.
+  gfx::Rect mask_rect = viewport_rect;
+  SkBitmap bitmap;
+  bitmap.allocPixels(
+      SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height()));
+  cc::SkiaPaintCanvas canvas(bitmap);
+  cc::PaintFlags flags;
+  flags.setStyle(cc::PaintFlags::kFill_Style);
+  flags.setColor(SK_ColorWHITE);
+  flags.setAntiAlias(true);
+  canvas.clear(SK_ColorTRANSPARENT);
+  gfx::Rect rounded_corner_rect = mask_rect;
+  rounded_corner_rect.Inset(kInset, kInset);
+  SkRRect rounded_corner = SkRRect::MakeRectXY(
+      gfx::RectToSkRect(rounded_corner_rect), kCornerRadius, kCornerRadius);
+  canvas.drawRRect(rounded_corner, flags);
+
+  ResourceId mask_resource_id;
+  if (this->use_gpu()) {
+    mask_resource_id = CreateGpuResource(
+        this->child_context_provider_, this->child_resource_provider_.get(),
+        mask_rect.size(), RGBA_8888, gfx::ColorSpace(), MakePixelSpan(bitmap));
+  } else {
+    mask_resource_id =
+        this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap);
+  }
+
+  // Return the mapped resource id.
+  std::unordered_map<ResourceId, ResourceId> resource_map =
+      cc::SendResourceAndGetChildToParentMap(
+          {mask_resource_id}, this->resource_provider_.get(),
+          this->child_resource_provider_.get(),
+          this->child_context_provider_.get());
+  ResourceId mapped_mask_resource_id = resource_map[mask_resource_id];
+
+  // Set up a mask on the RenderPassDrawQuad.
+  auto* mask_quad = root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
+  mask_quad->SetNew(
+      root_pass_shared_state, viewport_rect, viewport_rect, child_pass_id,
+      mapped_mask_resource_id,
+      gfx::ScaleRect(gfx::RectF(viewport_rect), 1.f / mask_rect.width(),
+                     1.f / mask_rect.height()),  // mask_uv_rect
+      gfx::Size(mask_rect.size()),               // mask_texture_size
+      gfx::Vector2dF(),                          // filters scale
+      gfx::PointF(),                             // filter origin
+      gfx::RectF(viewport_rect),                 // tex_coord_rect
+      false,                                     // force_anti_aliasing_off
+      1.0f);                                     // backdrop_filter_quality
+  // White background behind the masked render pass.
+  auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  white->SetNew(root_pass_shared_state, viewport_rect, viewport_rect,
+                SK_ColorWHITE, false);
+
+  RenderPassList pass_list;
+  pass_list.push_back(std::move(child_pass));
+  pass_list.push_back(std::move(root_pass));
+
+  // The rounded corners generated by masks should be very close to the rounded
+  // corners generated by the fragment shader approach. The percentage of pixel
+  // mismatch is around 0.52%.
+  EXPECT_TRUE(this->RunPixelTest(
+      &pass_list,
+      base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
+      cc::FuzzyPixelComparator(true, 0.6f, 0.f, 255.f, 255, 0)));
+}
+
+TYPED_TEST(RendererPixelTest, RenderPassAndMaskForRoundedCornerMultiRadii) {
+  gfx::Rect viewport_rect(this->device_viewport_size_);
+  constexpr int kInset = 20;
+  const SkVector kCornerRadii[4] = {
+      SkVector::Make(5.0, 5.0),
+      SkVector::Make(15.0, 15.0),
+      SkVector::Make(25.0, 25.0),
+      SkVector::Make(35.0, 35.0),
+  };
+
+  int root_pass_id = 1;
+  std::unique_ptr<RenderPass> root_pass =
+      CreateTestRootRenderPass(root_pass_id, viewport_rect);
+  SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
+
+  int child_pass_id = 2;
+  gfx::Transform transform_to_root;
+  std::unique_ptr<RenderPass> child_pass =
+      CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root);
+  SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), viewport_rect, child_pass.get(), gfx::RRectF());
+
+  // The child render pass is half a blue box and other half yellow box.
+  gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
+                      this->device_viewport_size_.height() / 2);
+  auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  blue->SetNew(child_pass_shared_state, blue_rect, blue_rect, SK_ColorBLUE,
+               false);
+
+  gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2,
+                        this->device_viewport_size_.width(),
+                        this->device_viewport_size_.height() / 2);
+  auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  yellow->SetNew(child_pass_shared_state, yellow_rect, yellow_rect,
+                 SK_ColorYELLOW, false);
+
+  // Make a mask.
+  gfx::Rect mask_rect = viewport_rect;
+  SkBitmap bitmap;
+  bitmap.allocPixels(
+      SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height()));
+  cc::SkiaPaintCanvas canvas(bitmap);
+  cc::PaintFlags flags;
+  flags.setStyle(cc::PaintFlags::kFill_Style);
+  flags.setColor(SK_ColorWHITE);
+  flags.setAntiAlias(true);
+  canvas.clear(SK_ColorTRANSPARENT);
+  gfx::Rect rounded_corner_rect = mask_rect;
+  rounded_corner_rect.Inset(kInset, kInset);
+  SkRRect rounded_corner =
+      SkRRect::MakeRect(gfx::RectToSkRect(rounded_corner_rect));
+  rounded_corner.setRectRadii(rounded_corner.rect(), kCornerRadii);
+  canvas.drawRRect(rounded_corner, flags);
+
+  ResourceId mask_resource_id;
+  if (this->use_gpu()) {
+    mask_resource_id = CreateGpuResource(
+        this->child_context_provider_, this->child_resource_provider_.get(),
+        mask_rect.size(), RGBA_8888, gfx::ColorSpace(), MakePixelSpan(bitmap));
+  } else {
+    mask_resource_id =
+        this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap);
+  }
+
+  // Return the mapped resource id.
+  std::unordered_map<ResourceId, ResourceId> resource_map =
+      cc::SendResourceAndGetChildToParentMap(
+          {mask_resource_id}, this->resource_provider_.get(),
+          this->child_resource_provider_.get(),
+          this->child_context_provider_.get());
+  ResourceId mapped_mask_resource_id = resource_map[mask_resource_id];
+
+  // Set up a mask on the RenderPassDrawQuad.
+  auto* mask_quad = root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
+  mask_quad->SetNew(
+      root_pass_shared_state, viewport_rect, viewport_rect, child_pass_id,
+      mapped_mask_resource_id,
+      gfx::ScaleRect(gfx::RectF(viewport_rect), 1.f / mask_rect.width(),
+                     1.f / mask_rect.height()),  // mask_uv_rect
+      gfx::Size(mask_rect.size()),               // mask_texture_size
+      gfx::Vector2dF(),                          // filters scale
+      gfx::PointF(),                             // filter origin
+      gfx::RectF(viewport_rect),                 // tex_coord_rect
+      false,                                     // force_anti_aliasing_off
+      1.0f);                                     // backdrop_filter_quality
+  // White background behind the masked render pass.
+  auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  white->SetNew(root_pass_shared_state, viewport_rect, viewport_rect,
+                SK_ColorWHITE, false);
+
+  RenderPassList pass_list;
+  pass_list.push_back(std::move(child_pass));
+  pass_list.push_back(std::move(root_pass));
+
+  EXPECT_TRUE(this->RunPixelTest(
+      &pass_list,
+      base::FilePath(FILE_PATH_LITERAL("rounded_corner_multi_radii.png")),
+      cc::FuzzyPixelComparator(true, 0.6f, 0.f, 255.f, 255, 0)));
+}
+
 template <typename RendererType>
 class RendererPixelTestWithBackgroundFilter
     : public RendererPixelTest<RendererType> {
@@ -2623,9 +2815,9 @@
 
     // A non-visible quad in the filtering render pass.
     {
-      SharedQuadState* shared_state =
-          CreateTestSharedQuadState(identity_quad_to_target_transform,
-                                    filter_pass_layer_rect_, filter_pass.get());
+      SharedQuadState* shared_state = CreateTestSharedQuadState(
+          identity_quad_to_target_transform, filter_pass_layer_rect_,
+          filter_pass.get(), gfx::RRectF());
       auto* color_quad =
           filter_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
       color_quad->SetNew(shared_state, filter_pass_layer_rect_,
@@ -2633,9 +2825,9 @@
     }
 
     {
-      SharedQuadState* shared_state =
-          CreateTestSharedQuadState(filter_pass_to_target_transform_,
-                                    filter_pass_layer_rect_, filter_pass.get());
+      SharedQuadState* shared_state = CreateTestSharedQuadState(
+          filter_pass_to_target_transform_, filter_pass_layer_rect_,
+          filter_pass.get(), gfx::RRectF());
       auto* filter_pass_quad =
           root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
       filter_pass_quad->SetNew(shared_state, filter_pass_layer_rect_,
@@ -2654,8 +2846,9 @@
 
     gfx::Rect left_rect = gfx::Rect(0, 0, kColumnWidth, 20);
     for (int i = 0; left_rect.y() < device_viewport_rect.height(); ++i) {
-      SharedQuadState* shared_state = CreateTestSharedQuadState(
-          identity_quad_to_target_transform, left_rect, root_pass.get());
+      SharedQuadState* shared_state =
+          CreateTestSharedQuadState(identity_quad_to_target_transform,
+                                    left_rect, root_pass.get(), gfx::RRectF());
       auto* color_quad =
           root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
       color_quad->SetNew(shared_state, left_rect, left_rect, SK_ColorGREEN,
@@ -2666,7 +2859,8 @@
     gfx::Rect middle_rect = gfx::Rect(kColumnWidth + 1, 0, kColumnWidth, 20);
     for (int i = 0; middle_rect.y() < device_viewport_rect.height(); ++i) {
       SharedQuadState* shared_state = CreateTestSharedQuadState(
-          identity_quad_to_target_transform, middle_rect, root_pass.get());
+          identity_quad_to_target_transform, middle_rect, root_pass.get(),
+          gfx::RRectF());
       auto* color_quad =
           root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
       color_quad->SetNew(shared_state, middle_rect, middle_rect, SK_ColorRED,
@@ -2677,8 +2871,9 @@
     gfx::Rect right_rect =
         gfx::Rect((kColumnWidth + 1) * 2, 0, kColumnWidth, 20);
     for (int i = 0; right_rect.y() < device_viewport_rect.height(); ++i) {
-      SharedQuadState* shared_state = CreateTestSharedQuadState(
-          identity_quad_to_target_transform, right_rect, root_pass.get());
+      SharedQuadState* shared_state =
+          CreateTestSharedQuadState(identity_quad_to_target_transform,
+                                    right_rect, root_pass.get(), gfx::RRectF());
       auto* color_quad =
           root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
       color_quad->SetNew(shared_state, right_rect, right_rect, SK_ColorBLUE,
@@ -2686,9 +2881,9 @@
       right_rect += gfx::Vector2d(0, right_rect.height() + 1);
     }
 
-    SharedQuadState* shared_state =
-        CreateTestSharedQuadState(identity_quad_to_target_transform,
-                                  device_viewport_rect, root_pass.get());
+    SharedQuadState* shared_state = CreateTestSharedQuadState(
+        identity_quad_to_target_transform, device_viewport_rect,
+        root_pass.get(), gfx::RRectF());
     auto* background_quad =
         root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
     background_quad->SetNew(shared_state, device_viewport_rect,
@@ -2776,8 +2971,8 @@
   gfx::Rect rect(this->device_viewport_size_);
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
-  SharedQuadState* blue_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
   auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
   pass->has_transparent_background = false;
@@ -2798,8 +2993,8 @@
   gfx::Rect rect(this->device_viewport_size_);
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
-  SharedQuadState* green_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* green_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
   auto* green = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false);
   RenderPassList pass_list;
@@ -2831,15 +3026,15 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
 
   gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
                       this->device_viewport_size_.height());
   auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get());
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
   CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
                                root_pass.get());
   RenderPassList pass_list;
@@ -2861,8 +3056,8 @@
 
   gfx::Transform red_quad_to_target_transform;
   red_quad_to_target_transform.Rotate(10);
-  SharedQuadState* red_shared_state =
-      CreateTestSharedQuadState(red_quad_to_target_transform, rect, pass.get());
+  SharedQuadState* red_shared_state = CreateTestSharedQuadState(
+      red_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* red = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   red->SetNew(red_shared_state, rect, rect, SK_ColorRED, false);
@@ -2870,14 +3065,14 @@
   gfx::Transform yellow_quad_to_target_transform;
   yellow_quad_to_target_transform.Rotate(5);
   SharedQuadState* yellow_shared_state = CreateTestSharedQuadState(
-      yellow_quad_to_target_transform, rect, pass.get());
+      yellow_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* yellow = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   yellow->SetNew(yellow_shared_state, rect, rect, SK_ColorYELLOW, false);
 
   gfx::Transform blue_quad_to_target_transform;
   SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
-      blue_quad_to_target_transform, rect, pass.get());
+      blue_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
@@ -2904,8 +3099,8 @@
   red_quad_to_target_transform.Translate(50, 50);
   red_quad_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f),
                                      0.5f + 1.0f / (rect.height() * 2.0f));
-  SharedQuadState* red_shared_state =
-      CreateTestSharedQuadState(red_quad_to_target_transform, rect, pass.get());
+  SharedQuadState* red_shared_state = CreateTestSharedQuadState(
+      red_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* red = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   red->SetNew(red_shared_state, rect, rect, SK_ColorRED, false);
@@ -2914,14 +3109,14 @@
   yellow_quad_to_target_transform.Translate(25.5f, 25.5f);
   yellow_quad_to_target_transform.Scale(0.5f, 0.5f);
   SharedQuadState* yellow_shared_state = CreateTestSharedQuadState(
-      yellow_quad_to_target_transform, rect, pass.get());
+      yellow_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* yellow = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   yellow->SetNew(yellow_shared_state, rect, rect, SK_ColorYELLOW, false);
 
   gfx::Transform blue_quad_to_target_transform;
   SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
-      blue_quad_to_target_transform, rect, pass.get());
+      blue_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
@@ -2950,14 +3145,14 @@
   hole_quad_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f),
                                       0.5f + 1.0f / (rect.height() * 2.0f));
   SharedQuadState* hole_shared_state = CreateTestSharedQuadState(
-      hole_quad_to_target_transform, rect, pass.get());
+      hole_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* hole = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   hole->SetAll(hole_shared_state, rect, rect, false, SK_ColorTRANSPARENT, true);
 
   gfx::Transform green_quad_to_target_transform;
   SharedQuadState* green_shared_state = CreateTestSharedQuadState(
-      green_quad_to_target_transform, rect, pass.get());
+      green_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* green = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false);
@@ -2989,7 +3184,7 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* hole_shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, rect, child_pass.get());
+      quad_to_target_transform, rect, child_pass.get(), gfx::RRectF());
   SolidColorDrawQuad* hole =
       child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   hole->SetAll(hole_shared_state, rect, rect, false, SK_ColorTRANSPARENT,
@@ -3003,7 +3198,7 @@
   hole_pass_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f),
                                       0.5f + 1.0f / (rect.height() * 2.0f));
   SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
-      hole_pass_to_target_transform, rect, root_pass.get());
+      hole_pass_to_target_transform, rect, root_pass.get(), gfx::RRectF());
   RenderPassDrawQuad* pass_quad =
       root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
   pass_quad->SetAll(pass_shared_state, rect, rect, needs_blending,
@@ -3013,7 +3208,7 @@
 
   gfx::Transform green_quad_to_target_transform;
   SharedQuadState* green_shared_state = CreateTestSharedQuadState(
-      green_quad_to_target_transform, rect, root_pass.get());
+      green_quad_to_target_transform, rect, root_pass.get(), gfx::RRectF());
 
   SolidColorDrawQuad* green =
       root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -3073,7 +3268,7 @@
   hole_quad_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f),
                                       0.5f + 1.0f / (rect.height() * 2.0f));
   SharedQuadState* hole_shared_state = CreateTestSharedQuadState(
-      hole_quad_to_target_transform, rect, pass.get());
+      hole_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
   TileDrawQuad* hole = pass->CreateAndAppendDrawQuad<TileDrawQuad>();
   hole->SetNew(hole_shared_state, rect, rect, needs_blending, mapped_resource,
                gfx::RectF(gfx::Rect(tile_size)), tile_size, swizzle_contents,
@@ -3082,7 +3277,7 @@
 
   gfx::Transform green_quad_to_target_transform;
   SharedQuadState* green_shared_state = CreateTestSharedQuadState(
-      green_quad_to_target_transform, rect, pass.get());
+      green_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   SolidColorDrawQuad* green =
       pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -3107,19 +3302,19 @@
       1.0f, 2.4520f, 10.6206f, 19.0f, 0.0f, 0.3528f, 5.9737f, 9.5f, 0.0f,
       -0.2250f, -0.9744f, 0.0f, 0.0f, 0.0225f, 0.0974f, 1.0f);
   SharedQuadState* red_shared_state = CreateTestSharedQuadState(
-      red_quad_to_target_transform, red_rect, pass.get());
+      red_quad_to_target_transform, red_rect, pass.get(), gfx::RRectF());
   auto* red = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   red->SetNew(red_shared_state, red_rect, red_rect, SK_ColorRED, false);
 
   gfx::Rect green_rect(19, 7, 180, 10);
-  SharedQuadState* green_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), green_rect, pass.get());
+  SharedQuadState* green_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), green_rect, pass.get(), gfx::RRectF());
   auto* green = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   green->SetNew(green_shared_state, green_rect, green_rect, SK_ColorGREEN,
                 false);
 
-  SharedQuadState* blue_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
   auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
 
@@ -3156,13 +3351,13 @@
   // Small enough red rect that linear filtering will miss it but large enough
   // that it makes a meaningful contribution when using trilinear filtering.
   red_rect.ClampToCenteredSize(gfx::Size(2, child_pass_rect.height()));
-  SharedQuadState* red_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), red_rect, child_pass.get());
+  SharedQuadState* red_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), red_rect, child_pass.get(), gfx::RRectF());
   auto* red = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   red->SetNew(red_shared_state, red_rect, red_rect, SK_ColorRED, false);
 
   SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
-      gfx::Transform(), child_pass_rect, child_pass.get());
+      gfx::Transform(), child_pass_rect, child_pass.get(), gfx::RRectF());
   auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   blue->SetNew(blue_shared_state, child_pass_rect, child_pass_rect,
                SK_ColorBLUE, false);
@@ -3171,7 +3366,7 @@
       RectToSkRect(child_pass_rect), RectToSkRect(viewport_rect),
       SkMatrix::kFill_ScaleToFit));
   SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
-      child_to_root_transform, child_pass_rect, root_pass.get());
+      child_to_root_transform, child_pass_rect, root_pass.get(), gfx::RRectF());
   auto* child_pass_quad =
       root_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
   child_pass_quad->SetNew(child_pass_shared_state, child_pass_rect,
@@ -3247,7 +3442,7 @@
 
   gfx::Transform green_quad_to_target_transform;
   SharedQuadState* green_shared_state = CreateTestSharedQuadState(
-      green_quad_to_target_transform, viewport, pass.get());
+      green_quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
 
   auto* green_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
   green_quad->SetNew(green_shared_state, viewport, viewport, needs_blending,
@@ -3288,7 +3483,7 @@
 
   gfx::Transform green_quad_to_target_transform;
   SharedQuadState* green_shared_state = CreateTestSharedQuadState(
-      green_quad_to_target_transform, viewport, pass.get());
+      green_quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
   green_shared_state->opacity = 0.5f;
 
   auto* green_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
@@ -3309,7 +3504,7 @@
 
   gfx::Transform white_quad_to_target_transform;
   SharedQuadState* white_shared_state = CreateTestSharedQuadState(
-      white_quad_to_target_transform, viewport, pass.get());
+      white_quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
 
   auto* white_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
   white_quad->SetNew(white_shared_state, viewport, viewport, needs_blending,
@@ -3383,8 +3578,8 @@
       recording->CreateRasterSource();
 
   gfx::Transform quad_to_target_transform;
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(quad_to_target_transform, viewport, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
 
   auto* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
   quad->SetNew(shared_state, viewport, viewport, needs_blending,
@@ -3435,8 +3630,8 @@
       recording->CreateRasterSource();
 
   gfx::Transform quad_to_target_transform;
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(quad_to_target_transform, viewport, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
 
   auto* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
   quad->SetNew(shared_state, viewport, viewport, needs_blending,
@@ -3495,8 +3690,8 @@
       CreateTestRenderPass(id, viewport, transform_to_root);
 
   gfx::Transform quad_to_target_transform;
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(quad_to_target_transform, viewport, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
 
   auto* quad = pass->CreateAndAppendDrawQuad<TileDrawQuad>();
   quad->SetNew(shared_state, viewport, viewport, needs_blending,
@@ -3546,8 +3741,8 @@
       CreateTestRenderPass(id, viewport, transform_to_root);
 
   gfx::Transform quad_to_target_transform;
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(quad_to_target_transform, viewport, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
 
   float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
   auto* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -3600,8 +3795,8 @@
       CreateTestRenderPass(id, viewport, transform_to_root);
 
   gfx::Transform quad_to_target_transform;
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(quad_to_target_transform, viewport, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
 
   float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
   auto* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -3657,7 +3852,7 @@
 
   SharedQuadState* top_right_green_shared_quad_state =
       CreateTestSharedQuadState(green_quad_to_target_transform, viewport,
-                                pass.get());
+                                pass.get(), gfx::RRectF());
 
   auto* green_quad1 = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
   green_quad1->SetNew(
@@ -3729,7 +3924,7 @@
   quad_to_target_transform.Scale(10.0, 10.0);
   gfx::Rect quad_content_rect(gfx::Size(20, 20));
   SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, quad_content_rect, pass.get());
+      quad_to_target_transform, quad_content_rect, pass.get(), gfx::RRectF());
 
   auto* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
   blue_quad->SetNew(blue_shared_state, quad_content_rect, quad_content_rect,
@@ -3741,8 +3936,9 @@
   // Fill left half of viewport with green.
   gfx::Transform half_green_quad_to_target_transform;
   gfx::Rect half_green_rect(gfx::Size(viewport.width() / 2, viewport.height()));
-  SharedQuadState* half_green_shared_state = CreateTestSharedQuadState(
-      half_green_quad_to_target_transform, half_green_rect, pass.get());
+  SharedQuadState* half_green_shared_state =
+      CreateTestSharedQuadState(half_green_quad_to_target_transform,
+                                half_green_rect, pass.get(), gfx::RRectF());
   auto* half_color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   half_color_quad->SetNew(half_green_shared_state, half_green_rect,
                           half_green_rect, SK_ColorGREEN, false);
@@ -3783,7 +3979,7 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
 
   gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
                       this->device_viewport_size_.height() / 2);
@@ -3795,8 +3991,8 @@
   auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get());
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
   CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
                                root_pass.get());
 
@@ -3828,7 +4024,7 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
 
   gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
                       this->device_viewport_size_.height() / 2);
@@ -3840,8 +4036,8 @@
   auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get());
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
   CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
                                root_pass.get());
 
@@ -3871,7 +4067,7 @@
 
   gfx::Transform quad_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
-      quad_to_target_transform, viewport_rect, child_pass.get());
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
 
   // Draw a green quad full-size with a blue quad in the lower-right corner.
   gfx::Rect blue_rect(this->device_viewport_size_.width() * 3 / 4,
@@ -3885,8 +4081,8 @@
   auto* green = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   green->SetNew(shared_state, green_rect, green_rect, SK_ColorGREEN, false);
 
-  SharedQuadState* pass_shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), pass_rect, root_pass.get());
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
   CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
                                root_pass.get());
 
@@ -3916,8 +4112,8 @@
   int id = 1;
   std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
 
-  SharedQuadState* shared_state =
-      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
   // Make a mask.
   gfx::Rect mask_rect = rect;
@@ -4041,8 +4237,8 @@
   // tex coord rect.
   gfx::Transform transform;
   transform.Scale(40, 40);
-  SharedQuadState* quad_shared =
-      CreateTestSharedQuadState(transform, gfx::Rect(layer_size), pass.get());
+  SharedQuadState* quad_shared = CreateTestSharedQuadState(
+      transform, gfx::Rect(layer_size), pass.get(), gfx::RRectF());
   auto* quad = pass->CreateAndAppendDrawQuad<TileDrawQuad>();
   quad->SetNew(quad_shared, gfx::Rect(layer_size), gfx::Rect(layer_size),
                needs_blending, mapped_resource, tex_coord_rect, tile_size,
@@ -4050,8 +4246,8 @@
                use_aa);
 
   // Green background.
-  SharedQuadState* background_shared =
-      CreateTestSharedQuadState(gfx::Transform(), viewport, pass.get());
+  SharedQuadState* background_shared = CreateTestSharedQuadState(
+      gfx::Transform(), viewport, pass.get(), gfx::RRectF());
   auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   color_quad->SetNew(background_shared, viewport, viewport, SK_ColorGREEN,
                      false);
@@ -4064,6 +4260,149 @@
                                  cc::ExactPixelComparator(true)));
 }
 
+TYPED_TEST(GLOnlyRendererPixelTest, RoundedCornerSimple) {
+  gfx::Rect viewport_rect(this->device_viewport_size_);
+  constexpr int kInset = 20;
+  constexpr int kCornerRadius = 20;
+
+  int root_pass_id = 1;
+  std::unique_ptr<RenderPass> root_pass =
+      CreateTestRootRenderPass(root_pass_id, viewport_rect);
+
+  gfx::Transform quad_to_target_transform;
+  gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
+                      this->device_viewport_size_.height());
+  gfx::Rect red_rect = blue_rect;
+  blue_rect.Inset(kInset, kInset);
+
+  gfx::RRectF rounded_corner_rrect(gfx::RectF(blue_rect), kCornerRadius);
+  SharedQuadState* shared_state_rounded =
+      CreateTestSharedQuadState(quad_to_target_transform, viewport_rect,
+                                root_pass.get(), rounded_corner_rrect);
+
+  auto* blue = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  blue->SetNew(shared_state_rounded, blue_rect, blue_rect, SK_ColorBLUE, false);
+
+  SharedQuadState* shared_state_normal = CreateTestSharedQuadState(
+      quad_to_target_transform, viewport_rect, root_pass.get(), gfx::RRectF());
+
+  auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  white->SetNew(shared_state_normal, red_rect, red_rect, SK_ColorWHITE, false);
+
+  RenderPassList pass_list;
+  pass_list.push_back(std::move(root_pass));
+
+  EXPECT_TRUE(this->RunPixelTest(
+      &pass_list,
+      base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
+      cc::ExactPixelComparator(true)));
+}
+
+// This draws a render pass with 2 solid color quads one of which has a rounded
+// corner. The render pass itself also has a rounded corner.
+TYPED_TEST(GLOnlyRendererPixelTest, RoundedCornerOnRenderPass) {
+  gfx::Rect viewport_rect(this->device_viewport_size_);
+  constexpr int kInset = 20;
+  constexpr int kCornerRadius = 20;
+  constexpr int kBlueCornerRadius = 10;
+
+  int root_pass_id = 1;
+  std::unique_ptr<RenderPass> root_pass =
+      CreateTestRootRenderPass(root_pass_id, viewport_rect);
+
+  int child_pass_id = 2;
+  gfx::Rect pass_rect(this->device_viewport_size_);
+  pass_rect.Inset(kInset, kInset);
+  gfx::Transform transform_to_root;
+  std::unique_ptr<RenderPass> child_pass =
+      CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
+
+  gfx::Rect blue_rect = pass_rect;
+  blue_rect.Offset(-30, 40);
+  gfx::RRectF blue_rrect(gfx::RectF(blue_rect), kBlueCornerRadius);
+  gfx::Transform quad_to_target_transform;
+  SharedQuadState* shared_state_with_rrect = CreateTestSharedQuadState(
+      quad_to_target_transform, viewport_rect, child_pass.get(), blue_rrect);
+  auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  blue->SetNew(shared_state_with_rrect, blue_rect, blue_rect, SK_ColorBLUE,
+               false);
+
+  SharedQuadState* shared_state_without_rrect = CreateTestSharedQuadState(
+      quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
+  gfx::Rect yellow_rect = pass_rect;
+  yellow_rect.Offset(30, -60);
+  auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  yellow->SetNew(shared_state_without_rrect, yellow_rect, yellow_rect,
+                 SK_ColorYELLOW, false);
+
+  gfx::Rect white_rect = pass_rect;
+  auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  white->SetNew(shared_state_without_rrect, white_rect, white_rect,
+                SK_ColorWHITE, false);
+
+  gfx::RRectF rounded_corner_bounds(gfx::RectF(pass_rect), kCornerRadius);
+  SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
+      gfx::Transform(), pass_rect, root_pass.get(), rounded_corner_bounds);
+  CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
+                               root_pass.get());
+
+  RenderPassList pass_list;
+  pass_list.push_back(std::move(child_pass));
+  pass_list.push_back(std::move(root_pass));
+
+  EXPECT_TRUE(this->RunPixelTest(
+      &pass_list,
+      base::FilePath(FILE_PATH_LITERAL("rounded_corner_render_pass.png")),
+      cc::ExactPixelComparator(true)));
+}
+
+TYPED_TEST(GLOnlyRendererPixelTest, RoundedCornerMultiRadii) {
+  gfx::Rect viewport_rect(this->device_viewport_size_);
+  constexpr std::array<uint32_t, 4> kCornerRadii = {5, 15, 25, 35};
+  constexpr int kInset = 20;
+
+  int root_pass_id = 1;
+  std::unique_ptr<RenderPass> root_pass =
+      CreateTestRootRenderPass(root_pass_id, viewport_rect);
+
+  gfx::Rect pass_rect(this->device_viewport_size_);
+  pass_rect.Inset(kInset, kInset);
+  gfx::RRectF rounded_corner_bounds(
+      gfx::RectF(pass_rect), kCornerRadii[0], kCornerRadii[0], kCornerRadii[1],
+      kCornerRadii[1], kCornerRadii[2], kCornerRadii[2], kCornerRadii[3],
+      kCornerRadii[3]);
+  gfx::Rect blue_rect = pass_rect;
+  blue_rect.set_height(blue_rect.height() / 2);
+
+  gfx::Transform quad_to_target_transform;
+  SharedQuadState* shared_state_normal =
+      CreateTestSharedQuadState(quad_to_target_transform, pass_rect,
+                                root_pass.get(), rounded_corner_bounds);
+  auto* blue = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  blue->SetNew(shared_state_normal, blue_rect, blue_rect, SK_ColorBLUE, false);
+
+  gfx::Rect yellow_rect = blue_rect;
+  yellow_rect.Offset(0, blue_rect.height());
+
+  auto* yellow = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  yellow->SetNew(shared_state_normal, yellow_rect, yellow_rect, SK_ColorYELLOW,
+                 false);
+
+  SharedQuadState* sqs_white = CreateTestSharedQuadState(
+      quad_to_target_transform, viewport_rect, root_pass.get(), gfx::RRectF());
+  gfx::Rect white_rect = gfx::Rect(this->device_viewport_size_);
+  auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  white->SetNew(sqs_white, white_rect, white_rect, SK_ColorWHITE, false);
+
+  RenderPassList pass_list;
+  pass_list.push_back(std::move(root_pass));
+
+  EXPECT_TRUE(this->RunPixelTest(
+      &pass_list,
+      base::FilePath(FILE_PATH_LITERAL("rounded_corner_multi_radii.png")),
+      cc::ExactPixelComparator(true)));
+}
+
 template <typename RendererType>
 class RendererPixelTestWithOverdrawFeedback
     : public RendererPixelTest<RendererType> {
@@ -4092,7 +4431,7 @@
       0.5f + 1.0f / (rect.width() * 2.0f),
       0.5f + 1.0f / (rect.height() * 2.0f));
   SharedQuadState* dark_gray_shared_state = CreateTestSharedQuadState(
-      dark_gray_quad_to_target_transform, rect, pass.get());
+      dark_gray_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* dark_gray = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   dark_gray->SetNew(dark_gray_shared_state, rect, rect, 0x10444444, false);
@@ -4101,14 +4440,14 @@
   light_gray_quad_to_target_transform.Translate(25.5f, 25.5f);
   light_gray_quad_to_target_transform.Scale(0.5f, 0.5f);
   SharedQuadState* light_gray_shared_state = CreateTestSharedQuadState(
-      light_gray_quad_to_target_transform, rect, pass.get());
+      light_gray_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* light_gray = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   light_gray->SetNew(light_gray_shared_state, rect, rect, 0x10CCCCCC, false);
 
   gfx::Transform bg_quad_to_target_transform;
-  SharedQuadState* bg_shared_state =
-      CreateTestSharedQuadState(bg_quad_to_target_transform, rect, pass.get());
+  SharedQuadState* bg_shared_state = CreateTestSharedQuadState(
+      bg_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* bg = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   bg->SetNew(bg_shared_state, rect, rect, SK_ColorBLACK, false);
@@ -4150,7 +4489,7 @@
       0.5f + 1.0f / (rect.width() * 2.0f),
       0.5f + 1.0f / (rect.height() * 2.0f));
   SharedQuadState* dark_gray_shared_state = CreateTestSharedQuadState(
-      dark_gray_quad_to_target_transform, rect, pass.get());
+      dark_gray_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* dark_gray = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   dark_gray->SetNew(dark_gray_shared_state, rect, rect, 0x10444444, false);
@@ -4159,14 +4498,14 @@
   light_gray_quad_to_target_transform.Translate(25.5f, 25.5f);
   light_gray_quad_to_target_transform.Scale(0.5f, 0.5f);
   SharedQuadState* light_gray_shared_state = CreateTestSharedQuadState(
-      light_gray_quad_to_target_transform, rect, pass.get());
+      light_gray_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* light_gray = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   light_gray->SetNew(light_gray_shared_state, rect, rect, 0x10CCCCCC, false);
 
   gfx::Transform bg_quad_to_target_transform;
-  SharedQuadState* bg_shared_state =
-      CreateTestSharedQuadState(bg_quad_to_target_transform, rect, pass.get());
+  SharedQuadState* bg_shared_state = CreateTestSharedQuadState(
+      bg_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
 
   auto* bg = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   bg->SetNew(bg_shared_state, rect, rect, SK_ColorBLACK, false);
@@ -4270,8 +4609,8 @@
 
     // Append a quad to execute the transform.
     {
-      SharedQuadState* shared_state =
-          CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+      SharedQuadState* shared_state = CreateTestSharedQuadState(
+          gfx::Transform(), rect, pass.get(), gfx::RRectF());
 
       ResourceId resource = CreateGpuResource(
           this->child_context_provider_, this->child_resource_provider_.get(),
diff --git a/components/viz/service/display/shader.cc b/components/viz/service/display/shader.cc
index 62bab35..25ed944 100644
--- a/components/viz/service/display/shader.cc
+++ b/components/viz/service/display/shader.cc
@@ -394,6 +394,7 @@
     precision = TEX_COORD_PRECISION_MEDIUM;
   std::string shader = GetShaderSource();
   SetBlendModeFunctions(&shader);
+  SetRoundedCornerFunctions(&shader);
   SetFragmentSamplerType(sampler_type_, &shader);
   SetFragmentTexCoordPrecision(precision, &shader);
   return shader;
@@ -459,6 +460,11 @@
   if (has_tint_color_matrix_)
     uniforms.emplace_back("tint_color_matrix");
 
+  if (has_rounded_corner_) {
+    uniforms.emplace_back("roundedCornerRect");
+    uniforms.emplace_back("roundedCornerRadius");
+  }
+
   locations.resize(uniforms.size());
 
   GetProgramUniformLocations(context, program, uniforms.size(), uniforms.data(),
@@ -521,9 +527,123 @@
   if (has_tint_color_matrix_)
     tint_color_matrix_location_ = locations[index++];
 
+  if (has_rounded_corner_) {
+    rounded_corner_rect_location_ = locations[index++];
+    rounded_corner_radius_location_ = locations[index++];
+  }
+
   DCHECK_EQ(index, locations.size());
 }
 
+void FragmentShader::SetRoundedCornerFunctions(
+    std::string* shader_string) const {
+  if (!has_rounded_corner_)
+    return;
+
+  static constexpr base::StringPiece kUniforms = SHADER0([]() {
+    uniform vec4 roundedCornerRect;
+    uniform vec4 roundedCornerRadius;
+  });
+
+  static constexpr base::StringPiece kFunctionRcUtility = SHADER0([]() {
+    // Returns a vector of size 4. Each component of a vector is set to 1 or 0
+    // representing whether |rcCoord| is a part of the respective corner or
+    // not.
+    // The component ordering is:
+    //     [Top left, Top right, Bottom right, Bottom left]
+    vec4 IsCorner(vec2 rcCoord) {
+      // Top left corner
+      if (rcCoord.x < roundedCornerRadius.x &&
+          rcCoord.y < roundedCornerRadius.x) {
+        return vec4(1.0, 0.0, 0.0, 0.0);
+      }
+
+      // Top right corner
+      if (rcCoord.x > roundedCornerRect.z - roundedCornerRadius.y &&
+          rcCoord.y < roundedCornerRadius.y) {
+        return vec4(0.0, 1.0, 0.0, 0.0);
+      }
+
+      // Bottom right corner
+      if (rcCoord.x > roundedCornerRect.z - roundedCornerRadius.z &&
+          rcCoord.y > roundedCornerRect.w - roundedCornerRadius.z) {
+        return vec4(0.0, 0.0, 1.0, 0.0);
+      }
+
+      // Bottom left corner
+      if (rcCoord.x < roundedCornerRadius.w &&
+          rcCoord.y > roundedCornerRect.w - roundedCornerRadius.w) {
+        return vec4(0.0, 0.0, 0.0, 1.0);
+      }
+      return vec4(0.0, 0.0, 0.0, 0.0);
+    }
+
+    // Returns the center of the rounded corner. |corner| holds the info on
+    // which corner the center is requested for.
+    vec2 GetCenter(vec4 corner, float radius) {
+      if (corner.x == 1.0) {
+        // Top left corner
+        return vec2(radius, radius);
+      } else if (corner.y == 1.0) {
+        // Top right corner
+        return vec2(roundedCornerRect.z - radius, radius);
+      } else if (corner.z == 1.0) {
+        // Bottom right corner
+        return vec2(roundedCornerRect.z - radius, roundedCornerRect.w - radius);
+      } else {
+        // Bottom left corner
+        return vec2(radius, roundedCornerRect.w - radius);
+      }
+    }
+  });
+
+  static constexpr base::StringPiece kFunctionApplyRoundedCorner =
+      SHADER0([]() {
+        vec4 ApplyRoundedCorner(vec4 src) {
+          vec2 rcCoord = gl_FragCoord.xy - roundedCornerRect.xy;
+
+          // If outside bounds, then just clip everything.
+          if (rcCoord.x < 0.0 || rcCoord.y < 0.0 ||
+              rcCoord.x > roundedCornerRect.z ||
+              rcCoord.y > roundedCornerRect.w) {
+            return vec4(0.0);
+          }
+
+          vec4 isCorner = IsCorner(rcCoord);
+
+          // Get the radius to use based on the corner this fragment lies in.
+          float r = dot(isCorner, roundedCornerRadius);
+
+          // If the radius is 0, then there is no rounded corner here. We can do
+          // an early return.
+          if (r == 0.0)
+            return src;
+
+          // Vector to the corner's center this frag is in.
+          vec2 cornerCenter = GetCenter(isCorner, r);
+
+          // Vector from the center of the corner to the current fragment center
+          vec2 cxy = rcCoord - cornerCenter;
+
+          // Compute the distance of the fragment's center from the corner's
+          // center.
+          float fragDst = length(cxy);
+
+          float alpha = smoothstep(r - 1.0, r + 1.0, fragDst);
+          return vec4(0.0) * alpha + src * (1.0 - alpha);
+        }
+      });
+
+  std::string shader;
+  shader.reserve(shader_string->size() + 2048);
+  shader += "precision mediump float;";
+  kUniforms.AppendToString(&shader);
+  kFunctionRcUtility.AppendToString(&shader);
+  kFunctionApplyRoundedCorner.AppendToString(&shader);
+  shader += *shader_string;
+  *shader_string = std::move(shader);
+}
+
 void FragmentShader::SetBlendModeFunctions(std::string* shader_string) const {
   if (!has_blend_mode()) {
     return;
@@ -1070,6 +1190,10 @@
       }
       break;
   }
+
+  if (has_rounded_corner_)
+    SRC("gl_FragColor = ApplyRoundedCorner(gl_FragColor);");
+
   source += "}\n";
 
   return header + source;
diff --git a/components/viz/service/display/shader.h b/components/viz/service/display/shader.h
index 7ab139c..10b45af5 100644
--- a/components/viz/service/display/shader.h
+++ b/components/viz/service/display/shader.h
@@ -234,6 +234,7 @@
   bool has_blend_mode() const { return blend_mode_ != BLEND_MODE_NONE; }
 
   void SetBlendModeFunctions(std::string* shader_string) const;
+  void SetRoundedCornerFunctions(std::string* shader_string) const;
 
   // Settings that are modified by sub-classes.
   AAMode aa_mode_ = NO_AA;
@@ -308,6 +309,11 @@
   int ya_clamp_rect_location_ = -1;
   int uv_clamp_rect_location_ = -1;
 
+  // Rounded corner locations
+  bool has_rounded_corner_ = false;
+  int rounded_corner_rect_location_ = -1;
+  int rounded_corner_radius_location_ = -1;
+
   // The resource offset and multiplier to adjust for bit depth.
   int resource_multiplier_location_ = -1;
   int resource_offset_location_ = -1;
diff --git a/components/viz/test/data/rounded_corner_multi_radii.png b/components/viz/test/data/rounded_corner_multi_radii.png
new file mode 100644
index 0000000..38e3fcf
--- /dev/null
+++ b/components/viz/test/data/rounded_corner_multi_radii.png
Binary files differ
diff --git a/components/viz/test/data/rounded_corner_render_pass.png b/components/viz/test/data/rounded_corner_render_pass.png
new file mode 100644
index 0000000..49f930b8
--- /dev/null
+++ b/components/viz/test/data/rounded_corner_render_pass.png
Binary files differ
diff --git a/components/viz/test/data/rounded_corner_simple.png b/components/viz/test/data/rounded_corner_simple.png
new file mode 100644
index 0000000..257c2a3
--- /dev/null
+++ b/components/viz/test/data/rounded_corner_simple.png
Binary files differ
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index a420ebfd..49ab076 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1343,6 +1343,8 @@
     "renderer_host/cursor_manager.h",
     "renderer_host/dip_util.cc",
     "renderer_host/dip_util.h",
+    "renderer_host/direct_manipulation_win.cc",
+    "renderer_host/direct_manipulation_win.h",
     "renderer_host/display_util.cc",
     "renderer_host/display_util.h",
     "renderer_host/dwrite_font_file_util_win.cc",
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index 98dba09..5e3c314e 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -195,26 +195,37 @@
         wcax->HandleSliderChanged(android_node->unique_id());
       }
       break;
+    case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED:
     case ui::AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED:
     case ui::AXEventGenerator::Event::AUTO_COMPLETE_CHANGED:
     case ui::AXEventGenerator::Event::CHILDREN_CHANGED:
+    case ui::AXEventGenerator::Event::CLASS_NAME_CHANGED:
     case ui::AXEventGenerator::Event::COLLAPSED:
+    case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
     case ui::AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED:
     case ui::AXEventGenerator::Event::EXPANDED:
+    case ui::AXEventGenerator::Event::FLOW_TO_CHANGED:
+    case ui::AXEventGenerator::Event::HIERARCHICAL_LEVEL_CHANGED:
     case ui::AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED:
     case ui::AXEventGenerator::Event::INVALID_STATUS_CHANGED:
+    case ui::AXEventGenerator::Event::KEY_SHORTCUTS_CHANGED:
+    case ui::AXEventGenerator::Event::LABELED_BY_CHANGED:
+    case ui::AXEventGenerator::Event::LANGUAGE_CHANGED:
     case ui::AXEventGenerator::Event::LIVE_REGION_CHANGED:
     case ui::AXEventGenerator::Event::LIVE_REGION_CREATED:
     case ui::AXEventGenerator::Event::LOAD_START:
     case ui::AXEventGenerator::Event::MENU_ITEM_SELECTED:
     case ui::AXEventGenerator::Event::NAME_CHANGED:
     case ui::AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED:
+    case ui::AXEventGenerator::Event::PLACEHOLDER_CHANGED:
+    case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
     case ui::AXEventGenerator::Event::RELATED_NODE_CHANGED:
     case ui::AXEventGenerator::Event::ROLE_CHANGED:
     case ui::AXEventGenerator::Event::ROW_COUNT_CHANGED:
     case ui::AXEventGenerator::Event::SELECTED_CHANGED:
     case ui::AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED:
+    case ui::AXEventGenerator::Event::SET_SIZE_CHANGED:
     case ui::AXEventGenerator::Event::STATE_CHANGED:
       // There are some notifications that aren't meaningful on Android.
       // It's okay to skip them.
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 4752532..3ed0d0d3 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -371,19 +371,30 @@
     case ui::AXEventGenerator::Event::MENU_ITEM_SELECTED:
       mac_notification = NSAccessibilityMenuItemSelectedNotification;
       break;
+    case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED:
     case ui::AXEventGenerator::Event::AUTO_COMPLETE_CHANGED:
     case ui::AXEventGenerator::Event::CHILDREN_CHANGED:
+    case ui::AXEventGenerator::Event::CLASS_NAME_CHANGED:
+    case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
     case ui::AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED:
+    case ui::AXEventGenerator::Event::FLOW_TO_CHANGED:
+    case ui::AXEventGenerator::Event::HIERARCHICAL_LEVEL_CHANGED:
     case ui::AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED:
+    case ui::AXEventGenerator::Event::KEY_SHORTCUTS_CHANGED:
+    case ui::AXEventGenerator::Event::LABELED_BY_CHANGED:
+    case ui::AXEventGenerator::Event::LANGUAGE_CHANGED:
     case ui::AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED:
     case ui::AXEventGenerator::Event::LOAD_START:
     case ui::AXEventGenerator::Event::NAME_CHANGED:
     case ui::AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED:
+    case ui::AXEventGenerator::Event::PLACEHOLDER_CHANGED:
+    case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
     case ui::AXEventGenerator::Event::RELATED_NODE_CHANGED:
     case ui::AXEventGenerator::Event::ROLE_CHANGED:
     case ui::AXEventGenerator::Event::SCROLL_POSITION_CHANGED:
     case ui::AXEventGenerator::Event::SELECTED_CHANGED:
+    case ui::AXEventGenerator::Event::SET_SIZE_CHANGED:
     case ui::AXEventGenerator::Event::STATE_CHANGED:
       // There are some notifications that aren't meaningful on Mac.
       // It's okay to skip them.
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index 7350db70..1180f70 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -145,6 +145,9 @@
   }
 
   switch (event_type) {
+    case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_AccessKeyPropertyId, node);
+      break;
     case ui::AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED:
       FireWinAccessibilityEvent(IA2_EVENT_ACTIVE_DESCENDANT_CHANGED, node);
       break;
@@ -152,12 +155,58 @@
       FireWinAccessibilityEvent(EVENT_SYSTEM_ALERT, node);
       FireUiaAccessibilityEvent(UIA_SystemAlertEventId, node);
       break;
+    case ui::AXEventGenerator::Event::CHECKED_STATE_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_ToggleToggleStatePropertyId, node);
+      break;
     case ui::AXEventGenerator::Event::CHILDREN_CHANGED:
       FireWinAccessibilityEvent(EVENT_OBJECT_REORDER, node);
       break;
+    case ui::AXEventGenerator::Event::CLASS_NAME_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_ClassNamePropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::COLLAPSED:
+    case ui::AXEventGenerator::Event::EXPANDED:
+      FireUiaPropertyChangedEvent(
+          UIA_ExpandCollapseExpandCollapseStatePropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_DescribedByPropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_FullDescriptionPropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: {
+      // Fire the event on the object where the focus of the selection is.
+      int32_t focus_id = GetTreeData().sel_focus_object_id;
+      BrowserAccessibility* focus_object = GetFromID(focus_id);
+      if (focus_object && focus_object->HasVisibleCaretOrSelection())
+        FireWinAccessibilityEvent(IA2_EVENT_TEXT_CARET_MOVED, focus_object);
+      break;
+    }
+    case ui::AXEventGenerator::Event::FLOW_TO_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_FlowsToPropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::HIERARCHICAL_LEVEL_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_LevelPropertyId, node);
+      break;
     case ui::AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED:
       FireWinAccessibilityEvent(EVENT_OBJECT_NAMECHANGE, node);
       break;
+    case ui::AXEventGenerator::Event::INVALID_STATUS_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_IsDataValidForFormPropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::KEY_SHORTCUTS_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_AcceleratorKeyPropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::LABELED_BY_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_LabeledByPropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::LANGUAGE_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_CulturePropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::LIVE_REGION_CREATED:
+      FireUiaPropertyChangedEvent(UIA_LiveSettingPropertyId, node);
+      break;
     case ui::AXEventGenerator::Event::LIVE_REGION_CHANGED:
       // This event is redundant with the IA2_EVENT_TEXT_INSERTED events;
       // however, JAWS 2018 and earlier do not process the text inserted
@@ -175,50 +224,43 @@
     case ui::AXEventGenerator::Event::LOAD_COMPLETE:
       FireWinAccessibilityEvent(IA2_EVENT_DOCUMENT_LOAD_COMPLETE, node);
       break;
+    case ui::AXEventGenerator::Event::NAME_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_NamePropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::PLACEHOLDER_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_HelpTextPropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_PositionInSetPropertyId, node);
+      break;
+    case ui::AXEventGenerator::Event::ROLE_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_AriaRolePropertyId, node);
+      break;
     case ui::AXEventGenerator::Event::SCROLL_POSITION_CHANGED:
       FireWinAccessibilityEvent(EVENT_SYSTEM_SCROLLINGEND, node);
       break;
+    case ui::AXEventGenerator::Event::SELECTED_CHANGED:
+      HandleSelectedStateChanged(node);
+      break;
     case ui::AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED:
       FireWinAccessibilityEvent(EVENT_OBJECT_SELECTIONWITHIN, node);
       break;
-    case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: {
-      // Fire the event on the object where the focus of the selection is.
-      int32_t focus_id = GetTreeData().sel_focus_object_id;
-      BrowserAccessibility* focus_object = GetFromID(focus_id);
-      if (focus_object && focus_object->HasVisibleCaretOrSelection())
-        FireWinAccessibilityEvent(IA2_EVENT_TEXT_CARET_MOVED, focus_object);
+    case ui::AXEventGenerator::Event::SET_SIZE_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_SizeOfSetPropertyId, node);
       break;
-    }
-    case ui::AXEventGenerator::Event::SELECTED_CHANGED:
-      HandleSelectedStateChanged(node);
+    case ui::AXEventGenerator::Event::VALUE_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_ValueValuePropertyId, node);
       break;
-    case ui::AXEventGenerator::Event::CHECKED_STATE_CHANGED:
-      FireUiaPropertyChangedEvent(UIA_ToggleToggleStatePropertyId, node);
-      break;
-    case ui::AXEventGenerator::Event::EXPANDED:
-    case ui::AXEventGenerator::Event::COLLAPSED:
-      FireUiaPropertyChangedEvent(
-          UIA_ExpandCollapseExpandCollapseStatePropertyId, node);
-      break;
-    case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
-      FireUiaPropertyChangedEvent(UIA_FullDescriptionPropertyId, node);
-      break;
-    case ui::AXEventGenerator::Event::INVALID_STATUS_CHANGED:
-      FireUiaPropertyChangedEvent(UIA_IsDataValidForFormPropertyId, node);
-      break;
+
     case ui::AXEventGenerator::Event::AUTO_COMPLETE_CHANGED:
     case ui::AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED:
-    case ui::AXEventGenerator::Event::LIVE_REGION_CREATED:
     case ui::AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED:
     case ui::AXEventGenerator::Event::LOAD_START:
     case ui::AXEventGenerator::Event::MENU_ITEM_SELECTED:
-    case ui::AXEventGenerator::Event::NAME_CHANGED:
     case ui::AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED:
     case ui::AXEventGenerator::Event::RELATED_NODE_CHANGED:
-    case ui::AXEventGenerator::Event::ROLE_CHANGED:
     case ui::AXEventGenerator::Event::ROW_COUNT_CHANGED:
     case ui::AXEventGenerator::Event::STATE_CHANGED:
-    case ui::AXEventGenerator::Event::VALUE_CHANGED:
       // There are some notifications that aren't meaningful on Windows.
       // It's okay to skip them.
       break;
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 697dc4929..f843a47 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -1378,8 +1378,14 @@
 
   DCHECK(render_frame_host_);
 
-  NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(render_frame_host_,
-                                                           common_params_.url);
+  // The check for WebUI should be performed only if error page isolation is
+  // enabled for this failed navigation. It is possible for subframe error page
+  // to be committed in a WebUI process as shown in https://crbug.com/944086.
+  if (SiteIsolationPolicy::IsErrorPageIsolationEnabled(
+          frame_tree_node_->IsMainFrame())) {
+    NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(
+        render_frame_host_, common_params_.url);
+  }
 
   has_stale_copy_in_cache_ = status.exists_in_cache;
 
diff --git a/content/browser/frame_host/webui_navigation_browsertest.cc b/content/browser/frame_host/webui_navigation_browsertest.cc
index aa8fedce..1dc739e 100644
--- a/content/browser/frame_host/webui_navigation_browsertest.cc
+++ b/content/browser/frame_host/webui_navigation_browsertest.cc
@@ -147,9 +147,11 @@
 
   // TODO(nasko): Replace this URL with one with a custom WebUI object that
   // doesn't have restrictive CSP, so the test can successfully add an
-  // iframe and test the actual throttle blocking. Currently the CSP policy
-  // will just block the navigation prior to the throttle being even
-  // invoked. See http://crbug.com/776900.
+  // iframe and test the actual throttle blocking. The default CSP policy
+  // on WebUI objects will just block the navigation prior to the throttle
+  // being even invoked. For now use the blob-internals URL, which is not
+  // backed by WebUI and does not have CSP policy attached to it.
+  // See http://crbug.com/776900.
   GURL chrome_url = GURL(std::string(kChromeUIScheme) + "://" +
                          std::string(kChromeUIBlobInternalsHost));
   EXPECT_TRUE(NavigateToURL(shell(), chrome_url));
@@ -206,6 +208,34 @@
   }
 }
 
+// Verify that a chrome: scheme document cannot add iframes with web content
+// and does not crash if the navigation is blocked by CSP.
+// See https://crbug.com/944086.
+IN_PROC_BROWSER_TEST_F(WebUINavigationBrowserTest,
+                       WebFrameInChromeSchemeDisallowedByCSP) {
+  // Use the chrome://gpu WebUI, which has a restrictive CSP disallowing
+  // subframes. This will cause the navigation to fail due to the CSP check
+  // and ensure this behaves the same way as the repros steps in
+  // https://crbug.com/944086.
+  GURL chrome_url = GURL(std::string(kChromeUIScheme) + "://" +
+                         std::string(kChromeUIGpuHost));
+  EXPECT_TRUE(NavigateToURL(shell(), chrome_url));
+  EXPECT_EQ(chrome_url, shell()->web_contents()->GetLastCommittedURL());
+
+  {
+    GURL web_url(embedded_test_server()->GetURL("/title2.html"));
+    TestNavigationObserver navigation_observer(shell()->web_contents());
+    EXPECT_TRUE(ExecJs(
+        shell(), JsReplace("var frame = document.createElement('iframe');\n"
+                           "frame.src = $1;\n"
+                           "document.body.appendChild(frame);\n",
+                           web_url)));
+    navigation_observer.Wait();
+
+    EXPECT_FALSE(navigation_observer.last_navigation_succeeded());
+  }
+}
+
 // Verify that a WebUI document in the main frame is allowed to navigate to
 // web content and it properly does cross-process navigation.
 IN_PROC_BROWSER_TEST_F(WebUINavigationBrowserTest, WebUIMainFrameToWebAllowed) {
diff --git a/content/browser/media/capture/screen_capture_device_android_unittest.cc b/content/browser/media/capture/screen_capture_device_android_unittest.cc
index ef59073..ca204dd 100644
--- a/content/browser/media/capture/screen_capture_device_android_unittest.cc
+++ b/content/browser/media/capture/screen_capture_device_android_unittest.cc
@@ -63,6 +63,7 @@
   void OnIncomingCapturedBufferExt(
       Buffer buffer,
       const media::VideoCaptureFormat& format,
+      const gfx::ColorSpace& color_space,
       base::TimeTicks reference_time,
       base::TimeDelta timestamp,
       gfx::Rect visible_rect,
diff --git a/ui/base/win/direct_manipulation.cc b/content/browser/renderer_host/direct_manipulation_win.cc
similarity index 95%
rename from ui/base/win/direct_manipulation.cc
rename to content/browser/renderer_host/direct_manipulation_win.cc
index f38da1c..fca09cb6 100644
--- a/ui/base/win/direct_manipulation.cc
+++ b/content/browser/renderer_host/direct_manipulation_win.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/base/win/direct_manipulation.h"
+#include "content/browser/renderer_host/direct_manipulation_win.h"
 
 #include <objbase.h>
 #include <cmath>
@@ -15,8 +15,7 @@
 #include "ui/display/win/screen_win.h"
 #include "ui/gfx/geometry/rect.h"
 
-namespace ui {
-namespace win {
+namespace content {
 
 namespace {
 
@@ -42,7 +41,7 @@
 // static
 std::unique_ptr<DirectManipulationHelper>
 DirectManipulationHelper::CreateInstance(HWND window,
-                                         WindowEventTarget* event_target) {
+                                         ui::WindowEventTarget* event_target) {
   if (!::IsWindow(window))
     return nullptr;
 
@@ -66,7 +65,7 @@
 // static
 std::unique_ptr<DirectManipulationHelper>
 DirectManipulationHelper::CreateInstanceForTesting(
-    WindowEventTarget* event_target,
+    ui::WindowEventTarget* event_target,
     Microsoft::WRL::ComPtr<IDirectManipulationViewport> viewport) {
   if (!base::FeatureList::IsEnabled(features::kPrecisionTouchpad))
     return nullptr;
@@ -78,8 +77,9 @@
   std::unique_ptr<DirectManipulationHelper> instance =
       base::WrapUnique(new DirectManipulationHelper());
 
-  instance->event_handler_ = Microsoft::WRL::Make<DirectManipulationHandler>(
-      instance.get(), event_target);
+  instance->event_handler_ =
+      Microsoft::WRL::Make<DirectManipulationHandler>(instance.get());
+  instance->event_handler_->SetWindowEventTarget(event_target);
 
   instance->viewport_ = viewport;
 
@@ -93,7 +93,7 @@
 
 DirectManipulationHelper::DirectManipulationHelper() {}
 
-bool DirectManipulationHelper::Initialize(WindowEventTarget* event_target) {
+bool DirectManipulationHelper::Initialize(ui::WindowEventTarget* event_target) {
   // IDirectManipulationUpdateManager is the first COM object created by the
   // application to retrieve other objects in the Direct Manipulation API.
   // It also serves to activate and deactivate Direct Manipulation functionality
@@ -144,8 +144,8 @@
     return false;
   }
 
-  event_handler_ =
-      Microsoft::WRL::Make<DirectManipulationHandler>(this, event_target);
+  event_handler_ = Microsoft::WRL::Make<DirectManipulationHandler>(this);
+  event_handler_->SetWindowEventTarget(event_target);
 
   // We got Direct Manipulation transform from
   // IDirectManipulationViewportEventHandler.
@@ -230,7 +230,7 @@
 
 bool DirectManipulationHelper::OnPointerHitTest(
     WPARAM w_param,
-    WindowEventTarget* event_target) {
+    ui::WindowEventTarget* event_target) {
   // Update the device scale factor.
   event_handler_->SetDeviceScaleFactor(
       display::win::ScreenWin::GetScaleFactorForHWND(window_));
@@ -296,9 +296,8 @@
 }
 
 DirectManipulationHandler::DirectManipulationHandler(
-    DirectManipulationHelper* helper,
-    WindowEventTarget* event_target)
-    : helper_(helper), event_target_(event_target) {}
+    DirectManipulationHelper* helper)
+    : helper_(helper) {}
 
 DirectManipulationHandler::~DirectManipulationHandler() {}
 
@@ -565,7 +564,7 @@
 }
 
 void DirectManipulationHandler::SetWindowEventTarget(
-    WindowEventTarget* event_target) {
+    ui::WindowEventTarget* event_target) {
   if (!event_target && LoggingEnabled()) {
     DebugLogging("Event target is null.", S_OK);
     if (event_target_) {
@@ -582,5 +581,4 @@
   device_scale_factor_ = device_scale_factor;
 }
 
-}  // namespace win
-}  // namespace ui
+}  // namespace content
diff --git a/ui/base/win/direct_manipulation.h b/content/browser/renderer_host/direct_manipulation_win.h
similarity index 87%
rename from ui/base/win/direct_manipulation.h
rename to content/browser/renderer_host/direct_manipulation_win.h
index 2f709b2..1f759a8 100644
--- a/ui/base/win/direct_manipulation.h
+++ b/content/browser/renderer_host/direct_manipulation_win.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_WIN_DIRECT_MANIPULATION_H_
-#define UI_WIN_DIRECT_MANIPULATION_H_
+#ifndef CONTENT_BROWSER_RENDERER_HOST_DIRECT_MANIPULATION_WIN_H_
+#define CONTENT_BROWSER_RENDERER_HOST_DIRECT_MANIPULATION_WIN_H_
 
 #include <windows.h>
 
@@ -13,20 +13,15 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "ui/base/ui_base_export.h"
+#include "content/common/content_export.h"
 #include "ui/base/win/window_event_target.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace content {
+
 class DirectManipulationBrowserTest;
-}  // namespace content
-
-namespace ui {
-namespace win {
-
-class DirectManipulationUnitTest;
-
 class DirectManipulationHelper;
+class DirectManipulationUnitTest;
 
 // DirectManipulationHandler receives status update and gesture events from
 // Direct Manipulation API.
@@ -40,12 +35,11 @@
               Microsoft::WRL::FtmBase,
               IDirectManipulationViewportEventHandler>> {
  public:
-  explicit DirectManipulationHandler(DirectManipulationHelper* helper,
-                                     WindowEventTarget* event_target);
+  explicit DirectManipulationHandler(DirectManipulationHelper* helper);
 
   // WindowEventTarget updates for every DM_POINTERHITTEST in case window
   // hierarchy changed.
-  void SetWindowEventTarget(WindowEventTarget* event_target);
+  void SetWindowEventTarget(ui::WindowEventTarget* event_target);
 
   void SetDeviceScaleFactor(float device_scale_factor);
 
@@ -72,7 +66,7 @@
                    _In_ IDirectManipulationContent* content) override;
 
   DirectManipulationHelper* helper_ = nullptr;
-  WindowEventTarget* event_target_ = nullptr;
+  ui::WindowEventTarget* event_target_ = nullptr;
   float device_scale_factor_ = 1.0f;
   float last_scale_ = 1.0f;
   int last_x_offset_ = 0;
@@ -95,18 +89,18 @@
 //    when DM_POINTERHITTEST.
 // 3. OnViewportStatusChanged will be called when the gesture phase change.
 //    OnContentUpdated will be called when the gesture update.
-class UI_BASE_EXPORT DirectManipulationHelper {
+class CONTENT_EXPORT DirectManipulationHelper {
  public:
   // Creates and initializes an instance of this class if Direct Manipulation is
   // enabled on the platform. Returns nullptr if it disabled or failed on
   // initialization.
   static std::unique_ptr<DirectManipulationHelper> CreateInstance(
       HWND window,
-      WindowEventTarget* event_target);
+      ui::WindowEventTarget* event_target);
 
   // Creates and initializes an instance for testing.
   static std::unique_ptr<DirectManipulationHelper> CreateInstanceForTesting(
-      WindowEventTarget* event_target,
+      ui::WindowEventTarget* event_target,
       Microsoft::WRL::ComPtr<IDirectManipulationViewport> viewport);
 
   ~DirectManipulationHelper();
@@ -126,7 +120,7 @@
 
   // Pass the pointer hit test to Direct Manipulation. Return true indicated we
   // need poll for new events every frame from here.
-  bool OnPointerHitTest(WPARAM w_param, WindowEventTarget* event_target);
+  bool OnPointerHitTest(WPARAM w_param, ui::WindowEventTarget* event_target);
 
   // On each frame poll new Direct Manipulation events. Return true if we still
   // need poll for new events on next frame, otherwise stop request need begin
@@ -141,7 +135,7 @@
 
   // This function instantiates Direct Manipulation and creates a viewport for
   // the passed in |window|. Return false if initialize failed.
-  bool Initialize(WindowEventTarget* event_target);
+  bool Initialize(ui::WindowEventTarget* event_target);
 
   void SetDeviceScaleFactorForTesting(float factor);
 
@@ -157,7 +151,6 @@
   DISALLOW_COPY_AND_ASSIGN(DirectManipulationHelper);
 };
 
-}  // namespace win
-}  // namespace ui
+}  // namespace content
 
-#endif  // UI_WIN_DIRECT_MANIPULATION_H_
+#endif  // CONTENT_BROWSER_RENDERER_HOST_DIRECT_MANIPULATION_WIN_H_
diff --git a/content/browser/renderer_host/direct_manipulation_browsertest.cc b/content/browser/renderer_host/direct_manipulation_win_browsertest.cc
similarity index 99%
rename from content/browser/renderer_host/direct_manipulation_browsertest.cc
rename to content/browser/renderer_host/direct_manipulation_win_browsertest.cc
index 07b0aa2..b6855d4 100644
--- a/content/browser/renderer_host/direct_manipulation_browsertest.cc
+++ b/content/browser/renderer_host/direct_manipulation_win_browsertest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/base/win/direct_manipulation.h"
+#include "content/browser/renderer_host/direct_manipulation_win.h"
 
 #include <windows.h>
 
diff --git a/ui/base/win/direct_manipulation_unittest.cc b/content/browser/renderer_host/direct_manipulation_win_unittest.cc
similarity index 98%
rename from ui/base/win/direct_manipulation_unittest.cc
rename to content/browser/renderer_host/direct_manipulation_win_unittest.cc
index 79d4bb77..5483889 100644
--- a/ui/base/win/direct_manipulation_unittest.cc
+++ b/content/browser/renderer_host/direct_manipulation_win_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/base/win/direct_manipulation.h"
+#include "content/browser/renderer_host/direct_manipulation_win.h"
 
 #include <objbase.h>
 
@@ -12,9 +12,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ui_base_features.h"
 
-namespace ui {
-
-namespace win {
+namespace content {
 
 namespace {
 
@@ -265,7 +263,7 @@
   float scroll_y_ = 0;
 };
 
-class MockWindowEventTarget : public WindowEventTarget {
+class MockWindowEventTarget : public ui::WindowEventTarget {
  public:
   MockWindowEventTarget() {}
 
@@ -751,6 +749,4 @@
   EXPECT_EQ(5, events[0].scroll_x_);
 }
 
-}  //  namespace win
-
-}  //  namespace ui
\ No newline at end of file
+}  //  namespace content
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc
index 2467b4b..492bbaaffa 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.cc
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -14,6 +14,7 @@
 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/accessibility/browser_accessibility_win.h"
+#include "content/browser/renderer_host/direct_manipulation_win.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
 #include "content/public/common/content_switches.h"
@@ -24,7 +25,6 @@
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/base/view_prop.h"
-#include "ui/base/win/direct_manipulation.h"
 #include "ui/base/win/internal_constants.h"
 #include "ui/base/win/window_event_target.h"
 #include "ui/compositor/compositor.h"
@@ -214,9 +214,8 @@
 
   // Direct Manipulation is enabled on Windows 10+. The CreateInstance function
   // returns NULL if Direct Manipulation is not available.
-  direct_manipulation_helper_ =
-      ui::win::DirectManipulationHelper::CreateInstance(
-          hwnd(), GetWindowEventTarget(GetParent()));
+  direct_manipulation_helper_ = DirectManipulationHelper::CreateInstance(
+      hwnd(), GetWindowEventTarget(GetParent()));
 
   // Disable pen flicks (http://crbug.com/506977)
   base::win::DisableFlicks(hwnd());
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.h b/content/browser/renderer_host/legacy_render_widget_host_win.h
index ec2ec68..1f7e1f0 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.h
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.h
@@ -21,17 +21,14 @@
 namespace ui {
 class AXFragmentRootWin;
 class AXSystemCaretWin;
-class DirectManipulationHelper;
 class WindowEventTarget;
-namespace win {
-class DirectManipulationHelper;
-}  // namespace win
 }  // namespace ui
 
 namespace content {
-class RenderWidgetHostViewAura;
 
 class DirectManipulationBrowserTest;
+class DirectManipulationHelper;
+class RenderWidgetHostViewAura;
 
 // Reasons for the existence of this class outlined below:-
 // 1. Some screen readers expect every tab / every unique web content container
@@ -188,8 +185,7 @@
   // This class provides functionality to register the legacy window as a
   // Direct Manipulation consumer. This allows us to support smooth scroll
   // in Chrome on Windows 10.
-  std::unique_ptr<ui::win::DirectManipulationHelper>
-      direct_manipulation_helper_;
+  std::unique_ptr<DirectManipulationHelper> direct_manipulation_helper_;
 
   std::unique_ptr<ui::CompositorAnimationObserver>
       compositor_animation_observer_;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index b2edd8c..8ec3d837 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -528,11 +528,11 @@
     "//services/video_capture/public/mojom",
     "//services/viz/public/interfaces",
     "//services/ws/public/mojom",
-    "//services/ws/public/mojom/ime",
     "//skia/public/interfaces",
     "//third_party/blink/public:mojo_bindings",
     "//third_party/blink/public/mojom:mojom_core",
     "//third_party/blink/public/mojom:web_feature_mojo_bindings",
+    "//ui/base/ime/mojo",
     "//ui/base/mojo",
     "//ui/events/mojo:interfaces",
     "//ui/gfx/geometry/mojo",
diff --git a/content/common/content_param_traits_macros.h b/content/common/content_param_traits_macros.h
index e5663ef..a840303 100644
--- a/content/common/content_param_traits_macros.h
+++ b/content/common/content_param_traits_macros.h
@@ -42,8 +42,8 @@
                               blink::WebInputEvent::kTypeLast)
 IPC_ENUM_TRAITS_MAX_VALUE(blink::WebImeTextSpan::Type,
                           blink::WebImeTextSpan::Type::kMisspellingSuggestion)
-IPC_ENUM_TRAITS_MAX_VALUE(ws::mojom::ImeTextSpanThickness,
-                          ws::mojom::ImeTextSpanThickness::kThick)
+IPC_ENUM_TRAITS_MAX_VALUE(ui::mojom::ImeTextSpanThickness,
+                          ui::mojom::ImeTextSpanThickness::kThick)
 
 IPC_STRUCT_TRAITS_BEGIN(viz::Selection<gfx::SelectionBound>)
   IPC_STRUCT_TRAITS_MEMBER(start)
diff --git a/content/common/input/ime_text_span_conversions.cc b/content/common/input/ime_text_span_conversions.cc
index 0898ec4..be91d760 100644
--- a/content/common/input/ime_text_span_conversions.cc
+++ b/content/common/input/ime_text_span_conversions.cc
@@ -38,29 +38,29 @@
   return ui::ImeTextSpan::Type::kComposition;
 }
 
-ws::mojom::ImeTextSpanThickness ConvertUiThicknessToUiImeTextSpanThickness(
+ui::mojom::ImeTextSpanThickness ConvertUiThicknessToUiImeTextSpanThickness(
     ui::ImeTextSpan::Thickness thickness) {
   switch (thickness) {
     case ui::ImeTextSpan::Thickness::kNone:
-      return ws::mojom::ImeTextSpanThickness::kNone;
+      return ui::mojom::ImeTextSpanThickness::kNone;
     case ui::ImeTextSpan::Thickness::kThin:
-      return ws::mojom::ImeTextSpanThickness::kThin;
+      return ui::mojom::ImeTextSpanThickness::kThin;
     case ui::ImeTextSpan::Thickness::kThick:
-      return ws::mojom::ImeTextSpanThickness::kThick;
+      return ui::mojom::ImeTextSpanThickness::kThick;
   }
 
   NOTREACHED();
-  return ws::mojom::ImeTextSpanThickness::kThin;
+  return ui::mojom::ImeTextSpanThickness::kThin;
 }
 
 ui::ImeTextSpan::Thickness ConvertUiImeTextSpanThicknessToUiThickness(
-    ws::mojom::ImeTextSpanThickness thickness) {
+    ui::mojom::ImeTextSpanThickness thickness) {
   switch (thickness) {
-    case ws::mojom::ImeTextSpanThickness::kNone:
+    case ui::mojom::ImeTextSpanThickness::kNone:
       return ui::ImeTextSpan::Thickness::kNone;
-    case ws::mojom::ImeTextSpanThickness::kThin:
+    case ui::mojom::ImeTextSpanThickness::kThin:
       return ui::ImeTextSpan::Thickness::kThin;
-    case ws::mojom::ImeTextSpanThickness::kThick:
+    case ui::mojom::ImeTextSpanThickness::kThick:
       return ui::ImeTextSpan::Thickness::kThick;
   }
 
diff --git a/content/common/input/ime_text_span_conversions.h b/content/common/input/ime_text_span_conversions.h
index 846a550fa..18353d30 100644
--- a/content/common/input/ime_text_span_conversions.h
+++ b/content/common/input/ime_text_span_conversions.h
@@ -14,10 +14,10 @@
     ui::ImeTextSpan::Type type);
 ui::ImeTextSpan::Type ConvertWebImeTextSpanTypeToUiType(
     blink::WebImeTextSpan::Type type);
-ws::mojom::ImeTextSpanThickness ConvertUiThicknessToUiImeTextSpanThickness(
+ui::mojom::ImeTextSpanThickness ConvertUiThicknessToUiImeTextSpanThickness(
     ui::ImeTextSpan::Thickness thickness);
 ui::ImeTextSpan::Thickness ConvertUiImeTextSpanThicknessToUiThickness(
-    ws::mojom::ImeTextSpanThickness thickness);
+    ui::mojom::ImeTextSpanThickness thickness);
 blink::WebImeTextSpan ConvertUiImeTextSpanToBlinkImeTextSpan(
     const ui::ImeTextSpan&);
 ui::ImeTextSpan ConvertBlinkImeTextSpanToUiImeTextSpan(
diff --git a/content/common/input/input_handler.mojom b/content/common/input/input_handler.mojom
index 5ffd883..484d0ca 100644
--- a/content/common/input/input_handler.mojom
+++ b/content/common/input/input_handler.mojom
@@ -8,8 +8,8 @@
 import "content/common/native_types.mojom";
 import "mojo/public/mojom/base/string16.mojom";
 import "mojo/public/mojom/base/time.mojom";
-import "services/ws/public/mojom/ime/ime.mojom";
 import "third_party/blink/public/mojom/selection_menu/selection_menu_behavior.mojom";
+import "ui/base/ime/mojo/ime_types.mojom";
 import "ui/events/mojo/event.mojom";
 import "ui/events/mojo/event_constants.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
@@ -228,13 +228,13 @@
 
   // This message sends a string being composed with an input method.
   ImeSetComposition(mojo_base.mojom.String16 text,
-                    array<ws.mojom.ImeTextSpan> ime_text_spans,
+                    array<ui.mojom.ImeTextSpan> ime_text_spans,
                     gfx.mojom.Range range, int32 start, int32 end);
 
   // This message deletes the current composition, inserts specified text, and
   // moves the cursor.
   ImeCommitText(mojo_base.mojom.String16 text,
-                array<ws.mojom.ImeTextSpan> ime_text_spans,
+                array<ui.mojom.ImeTextSpan> ime_text_spans,
                 gfx.mojom.Range range, int32 relative_cursor_position) => ();
 
   // This message inserts the ongoing composition.
@@ -290,7 +290,7 @@
   // Sets the text composition to be between the given start and end offsets in
   // the currently focused editable field.
   SetCompositionFromExistingText(
-      int32 start, int32 end, array<ws.mojom.ImeTextSpan> ime_text_spans);
+      int32 start, int32 end, array<ui.mojom.ImeTextSpan> ime_text_spans);
 
   // Deletes the current selection plus the specified number of characters
   // before and after the selection or caret.
diff --git a/content/common/render_widget_host_ns_view.mojom b/content/common/render_widget_host_ns_view.mojom
index 0dbe014..797404e 100644
--- a/content/common/render_widget_host_ns_view.mojom
+++ b/content/common/render_widget_host_ns_view.mojom
@@ -7,7 +7,6 @@
 import "content/common/native_types.mojom";
 import "content/common/input/input_handler.mojom";
 import "mojo/public/mojom/base/string16.mojom";
-import "services/ws/public/mojom/ime/ime.mojom";
 import "ui/base/ime/mojo/ime_types.mojom";
 import "ui/display/mojo/display.mojom";
 import "ui/events/mojo/event.mojom";
@@ -168,7 +167,7 @@
   // it is the result of GetActiveWidget.
   ImeSetComposition(
       mojo_base.mojom.String16 text,
-      array<ws.mojom.ImeTextSpan> ime_text_spans,
+      array<ui.mojom.ImeTextSpan> ime_text_spans,
       gfx.mojom.Range replacement_range,
       int32 selection_start,
       int32 selection_end);
diff --git a/content/common/sandbox_init_mac.cc b/content/common/sandbox_init_mac.cc
index 0a4a263..398a3454 100644
--- a/content/common/sandbox_init_mac.cc
+++ b/content/common/sandbox_init_mac.cc
@@ -15,7 +15,7 @@
 #include "gpu/config/gpu_switches.h"
 #include "gpu/config/gpu_switching.h"
 #include "gpu/config/gpu_util.h"
-#include "media/gpu/vt_video_decode_accelerator_mac.h"
+#include "media/gpu/mac/vt_video_decode_accelerator_mac.h"
 #include "sandbox/mac/seatbelt.h"
 #include "sandbox/mac/seatbelt_exec.h"
 #include "services/service_manager/sandbox/mac/sandbox_mac.h"
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
index 21575052..e938cae 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
@@ -488,9 +488,6 @@
                 case ChildProcessImportance.IMPORTANT:
                     connection.addStrongBinding();
                     break;
-                case ChildProcessImportance.COUNT:
-                    assert false;
-                    break;
                 default:
                     assert false;
             }
@@ -513,9 +510,6 @@
                 case ChildProcessImportance.IMPORTANT:
                     connection.removeStrongBinding();
                     break;
-                case ChildProcessImportance.COUNT:
-                    assert false;
-                    break;
                 default:
                     assert false;
             }
diff --git a/content/public/browser/android/child_process_importance.h b/content/public/browser/android/child_process_importance.h
index 45b3afa..4e2baea 100644
--- a/content/public/browser/android/child_process_importance.h
+++ b/content/public/browser/android/child_process_importance.h
@@ -17,8 +17,6 @@
   NORMAL = 0,
   MODERATE,
   IMPORTANT,
-  // Place holder to represent number of values.
-  COUNT,
 };
 
 }  // namespace content
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index a820de5..c2ebfd7 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1917,6 +1917,12 @@
   return false;
 }
 
+void WaitForAccessibilityTreeToChange(WebContents* web_contents) {
+  AccessibilityNotificationWaiter accessibility_waiter(
+      web_contents, ui::AXMode(), ax::mojom::Event::kNone);
+  accessibility_waiter.WaitForNotification();
+}
+
 void WaitForAccessibilityTreeToContainNodeWithName(WebContents* web_contents,
                                                    const std::string& name) {
   WebContentsImpl* web_contents_impl = static_cast<WebContentsImpl*>(
@@ -1927,9 +1933,7 @@
       main_frame->browser_accessibility_manager();
   while (!main_frame_manager || !AccessibilityTreeContainsNodeWithName(
              main_frame_manager->GetRoot(), name)) {
-    AccessibilityNotificationWaiter accessibility_waiter(
-        web_contents, ui::AXMode(), ax::mojom::Event::kNone);
-    accessibility_waiter.WaitForNotification();
+    WaitForAccessibilityTreeToChange(web_contents);
     main_frame_manager = main_frame->browser_accessibility_manager();
   }
 }
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 6c71c90..37f3a16 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -848,13 +848,14 @@
 
 // This is intended to be a robust way to assert that the accessibility
 // tree eventually gets into the correct state, without worrying about
-// the exact ordering of events received while getting there.
-//
+// the exact ordering of events received while getting there. Blocks
+// until any change happens to the accessibility tree.
+void WaitForAccessibilityTreeToChange(WebContents* web_contents);
+
 // Searches the accessibility tree to see if any node's accessible name
-// is equal to the given name. If not, sets up a notification waiter
-// that listens for any accessibility event in any frame, and checks again
-// after each event. Keeps looping until the text is found (or the
-// test times out).
+// is equal to the given name. If not, repeatedly calls
+// WaitForAccessibilityTreeToChange, above, and then checks again.
+// Keeps looping until the text is found (or the test times out).
 void WaitForAccessibilityTreeToContainNodeWithName(WebContents* web_contents,
                                                    const std::string& name);
 
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index 0379d1d..dfc2a8d8 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -452,6 +452,9 @@
           &VideoCaptureImpl::OnAllClientsFinishedConsumingFrame,
           weak_factory_.GetWeakPtr(), buffer_id, std::move(buffer_context)))));
 
+  if (info->color_space.has_value() && info->color_space->IsValid())
+    frame->set_color_space(info->color_space.value());
+
   frame->metadata()->MergeInternalValuesFrom(info->metadata);
 
   // TODO(qiangchen): Dive into the full code path to let frame metadata hold
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 02dd519..2f635880 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -1011,7 +1011,7 @@
   // Set the composition target.
   for (size_t i = 0; i < ime_text_spans.size(); ++i) {
     if (ime_text_spans[i].thickness ==
-        ws::mojom::ImeTextSpanThickness::kThick) {
+        ui::mojom::ImeTextSpanThickness::kThick) {
       auto it = std::find(event.composition_segment_offsets.begin(),
                           event.composition_segment_offsets.end(),
                           utf8_offsets[2 * i + 2]);
@@ -2393,7 +2393,7 @@
     ime_text_span.start_offset = offsets[i];
     ime_text_span.end_offset = offsets[i + 1];
     if (input_event.composition_target_segment == static_cast<int32_t>(i - 2))
-      ime_text_span.thickness = ws::mojom::ImeTextSpanThickness::kThick;
+      ime_text_span.thickness = ui::mojom::ImeTextSpanThickness::kThick;
     ime_text_spans.push_back(ime_text_span);
   }
 
diff --git a/content/shell/browser/shell_web_contents_view_delegate_views.cc b/content/shell/browser/shell_web_contents_view_delegate_views.cc
index 937639f..9289cdb9 100644
--- a/content/shell/browser/shell_web_contents_view_delegate_views.cc
+++ b/content/shell/browser/shell_web_contents_view_delegate_views.cc
@@ -93,7 +93,7 @@
       web_contents_->GetTopLevelNativeWindow());
   context_menu_runner_->RunMenuAt(
       widget, nullptr, gfx::Rect(screen_point, gfx::Size()),
-      views::MENU_ANCHOR_TOPRIGHT, ui::MENU_SOURCE_NONE);
+      views::MenuAnchorPosition::kTopRight, ui::MENU_SOURCE_NONE);
 }
 
 }  // namespace content
diff --git a/content/shell/test_runner/text_input_controller.cc b/content/shell/test_runner/text_input_controller.cc
index 74b6018f..a2681bc5 100644
--- a/content/shell/test_runner/text_input_controller.cc
+++ b/content/shell/test_runner/text_input_controller.cc
@@ -273,12 +273,12 @@
     ime_text_span.start_offset = start;
     ime_text_span.end_offset = start + length;
   }
-  ime_text_span.thickness = ws::mojom::ImeTextSpanThickness::kThick;
+  ime_text_span.thickness = ui::mojom::ImeTextSpanThickness::kThick;
   ime_text_spans.push_back(ime_text_span);
   if (start + length < static_cast<int>(web_text.length())) {
     ime_text_span.start_offset = ime_text_span.end_offset;
     ime_text_span.end_offset = web_text.length();
-    ime_text_span.thickness = ws::mojom::ImeTextSpanThickness::kThin;
+    ime_text_span.thickness = ui::mojom::ImeTextSpanThickness::kThin;
     ime_text_spans.push_back(ime_text_span);
   }
 
@@ -385,7 +385,7 @@
   std::vector<blink::WebImeTextSpan> ime_text_spans;
   ime_text_spans.push_back(blink::WebImeTextSpan(
       blink::WebImeTextSpan::Type::kComposition, 0, textLength,
-      ws::mojom::ImeTextSpanThickness::kThin, SK_ColorTRANSPARENT));
+      ui::mojom::ImeTextSpanThickness::kThin, SK_ColorTRANSPARENT));
   if (auto* controller = GetInputMethodController()) {
     controller->SetComposition(
         newText, blink::WebVector<blink::WebImeTextSpan>(ime_text_spans),
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 2e60501c..212e7766 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1145,7 +1145,7 @@
       "../browser/accessibility/accessibility_win_browsertest.cc",
       "../browser/accessibility/ax_platform_node_win_browsertest.cc",
       "../browser/renderer_host/accessibility_tree_linkage_win_browsertest.cc",
-      "../browser/renderer_host/direct_manipulation_browsertest.cc",
+      "../browser/renderer_host/direct_manipulation_win_browsertest.cc",
     ]
 
     deps += [
@@ -1581,6 +1581,7 @@
     "../browser/presentation/presentation_service_impl_unittest.cc",
     "../browser/renderer_host/clipboard_host_impl_unittest.cc",
     "../browser/renderer_host/cursor_manager_unittest.cc",
+    "../browser/renderer_host/direct_manipulation_win_unittest.cc",
     "../browser/renderer_host/dwrite_font_lookup_table_builder_win_unittest.cc",
     "../browser/renderer_host/dwrite_font_proxy_impl_win_unittest.cc",
     "../browser/renderer_host/embedded_frame_sink_provider_impl_unittest.cc",
diff --git a/content/test/data/accessibility/event/description-change-expected-uia-win.txt b/content/test/data/accessibility/event/description-change-expected-uia-win.txt
index 367dbfc..bf611803 100644
--- a/content/test/data/accessibility/event/description-change-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/description-change-expected-uia-win.txt
@@ -1 +1,2 @@
+DescribedBy changed on role=heading, name=Before
 FullDescription changed on role=heading, name=Before
diff --git a/content/test/data/accessibility/event/description-change-expected-uia-win7.txt b/content/test/data/accessibility/event/description-change-expected-uia-win7.txt
index e69de29..8a4ad677 100644
--- a/content/test/data/accessibility/event/description-change-expected-uia-win7.txt
+++ b/content/test/data/accessibility/event/description-change-expected-uia-win7.txt
@@ -0,0 +1 @@
+DescribedBy changed on role=heading, name=Before
diff --git a/content/test/data/accessibility/event/description-change-indirect-expected-uia-win.txt b/content/test/data/accessibility/event/description-change-indirect-expected-uia-win.txt
index 4ba19bd..f2d9c8f 100644
--- a/content/test/data/accessibility/event/description-change-indirect-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/description-change-indirect-expected-uia-win.txt
@@ -1 +1,2 @@
 FullDescription changed on role=main
+Name changed on role=heading, name=oranges
diff --git a/content/test/data/accessibility/event/description-change-indirect-expected-uia-win7.txt b/content/test/data/accessibility/event/description-change-indirect-expected-uia-win7.txt
index e69de29..297423e 100644
--- a/content/test/data/accessibility/event/description-change-indirect-expected-uia-win7.txt
+++ b/content/test/data/accessibility/event/description-change-indirect-expected-uia-win7.txt
@@ -0,0 +1 @@
+Name changed on role=heading, name=oranges
diff --git a/content/test/data/accessibility/event/live-region-change-expected-uia-win.txt b/content/test/data/accessibility/event/live-region-change-expected-uia-win.txt
new file mode 100644
index 0000000..6dc8b6a
--- /dev/null
+++ b/content/test/data/accessibility/event/live-region-change-expected-uia-win.txt
@@ -0,0 +1 @@
+Name changed on role=description, name=After
diff --git a/content/test/data/accessibility/event/live-region-create-expected-uia-win.txt b/content/test/data/accessibility/event/live-region-create-expected-uia-win.txt
new file mode 100644
index 0000000..bedabc06
--- /dev/null
+++ b/content/test/data/accessibility/event/live-region-create-expected-uia-win.txt
@@ -0,0 +1 @@
+LiveSetting changed on role=group
diff --git a/content/test/data/accessibility/event/menulist-collapse-expected-uia-win.txt b/content/test/data/accessibility/event/menulist-collapse-expected-uia-win.txt
new file mode 100644
index 0000000..7dff0a6
--- /dev/null
+++ b/content/test/data/accessibility/event/menulist-collapse-expected-uia-win.txt
@@ -0,0 +1 @@
+ValueValue changed on role=combobox
diff --git a/content/test/data/accessibility/event/menulist-collapse-next-expected-uia-win.txt b/content/test/data/accessibility/event/menulist-collapse-next-expected-uia-win.txt
new file mode 100644
index 0000000..9521fe9
--- /dev/null
+++ b/content/test/data/accessibility/event/menulist-collapse-next-expected-uia-win.txt
@@ -0,0 +1,2 @@
+SelectionItem_ElementSelected on role=listitem, name=Orange
+ValueValue changed on role=combobox
diff --git a/content/test/data/accessibility/event/name-change-expected-uia-win.txt b/content/test/data/accessibility/event/name-change-expected-uia-win.txt
new file mode 100644
index 0000000..d42f91db
--- /dev/null
+++ b/content/test/data/accessibility/event/name-change-expected-uia-win.txt
@@ -0,0 +1 @@
+Name changed on role=heading, name=After
diff --git a/content/test/data/accessibility/event/name-change-indirect-expected-uia-win.txt b/content/test/data/accessibility/event/name-change-indirect-expected-uia-win.txt
new file mode 100644
index 0000000..46c8c92
--- /dev/null
+++ b/content/test/data/accessibility/event/name-change-indirect-expected-uia-win.txt
@@ -0,0 +1,2 @@
+Name changed on role=heading, name=oranges
+Name changed on role=main, name=oranges
diff --git a/content/test/data/accessibility/event/text-changed-expected-uia-win.txt b/content/test/data/accessibility/event/text-changed-expected-uia-win.txt
new file mode 100644
index 0000000..abbec0f
--- /dev/null
+++ b/content/test/data/accessibility/event/text-changed-expected-uia-win.txt
@@ -0,0 +1,2 @@
+Name changed on role=description, name=Text modified
+Name changed on role=heading, name=Heading
diff --git a/device/gamepad/xbox_data_fetcher_mac.cc b/device/gamepad/xbox_data_fetcher_mac.cc
index 4fddce07..097e07d0 100644
--- a/device/gamepad/xbox_data_fetcher_mac.cc
+++ b/device/gamepad/xbox_data_fetcher_mac.cc
@@ -144,12 +144,9 @@
     PendingController* pending) {
   // Destroying the PendingController object unregisters our interest
   // notification.
-  for (auto it = pending_controllers_.begin(); it != pending_controllers_.end();
-       ++it) {
-    if (pending == it->get()) {
-      pending_controllers_.erase(it);
-      break;
-    }
+  auto it = pending_controllers_.find(pending);
+  if (it != pending_controllers_.end()) {
+    pending_controllers_.erase(it);
   }
   TryOpenDevice(service);
 }
diff --git a/device/gamepad/xbox_data_fetcher_mac.h b/device/gamepad/xbox_data_fetcher_mac.h
index 46c5e06..c6e59fa 100644
--- a/device/gamepad/xbox_data_fetcher_mac.h
+++ b/device/gamepad/xbox_data_fetcher_mac.h
@@ -12,6 +12,7 @@
 
 #include <IOKit/IOMessage.h>
 
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/mac/scoped_ionotificationportref.h"
 #include "base/mac/scoped_ioobject.h"
 #include "base/macros.h"
@@ -95,7 +96,8 @@
   // The set of enumerated controllers that received an exclusive access error
   // on opening the device. The data fetcher is notified when these devices
   // become available so we can try opening them again.
-  std::set<std::unique_ptr<PendingController>> pending_controllers_;
+  std::set<std::unique_ptr<PendingController>, base::UniquePtrComparator>
+      pending_controllers_;
 
   bool listening_ = false;
 
diff --git a/fuchsia/base/agent_impl.cc b/fuchsia/base/agent_impl.cc
index 4c9623a..c01a749 100644
--- a/fuchsia/base/agent_impl.cc
+++ b/fuchsia/base/agent_impl.cc
@@ -46,8 +46,6 @@
     : create_component_state_callback_(
           std::move(create_component_state_callback)),
       agent_binding_(service_directory, this) {
-  agent_binding_.SetOnLastClientCallback(base::BindOnce(
-      &AgentImpl::MaybeRunOnLastClientCallback, base::Unretained(this)));
 }
 
 AgentImpl::~AgentImpl() {
@@ -80,15 +78,6 @@
 void AgentImpl::DeleteComponentState(base::StringPiece component_id) {
   size_t removed_components = active_components_.erase(component_id);
   DCHECK_EQ(removed_components, 1u);
-  MaybeRunOnLastClientCallback();
-}
-
-void AgentImpl::MaybeRunOnLastClientCallback() {
-  if (!on_last_client_callback_)
-    return;
-  if (!active_components_.empty() || agent_binding_.has_clients())
-    return;
-  std::move(on_last_client_callback_).Run();
 }
 
 }  // namespace cr_fuchsia
diff --git a/fuchsia/base/agent_impl.h b/fuchsia/base/agent_impl.h
index 4bea609..e6b7e78 100644
--- a/fuchsia/base/agent_impl.h
+++ b/fuchsia/base/agent_impl.h
@@ -106,12 +106,6 @@
             CreateComponentStateCallback create_component_state_callback);
   ~AgentImpl() override;
 
-  // Configures a Closure that will be run when no component instances, nor
-  // connections to the Agent interface, remain.
-  void set_on_last_client_callback(base::OnceClosure on_last_client_callback) {
-    on_last_client_callback_ = std::move(on_last_client_callback);
-  }
-
   // fuchsia::modular::Agent implementation.
   void Connect(std::string requester_url,
                fidl::InterfaceRequest<::fuchsia::sys::ServiceProvider> services)
@@ -134,9 +128,6 @@
   base::flat_map<std::string, std::unique_ptr<ComponentStateBase>>
       active_components_;
 
-  // Run when no active components, nor Agent clients, remain.
-  base::OnceClosure on_last_client_callback_;
-
   DISALLOW_COPY_AND_ASSIGN(AgentImpl);
 };
 
diff --git a/fuchsia/base/agent_impl_unittests.cc b/fuchsia/base/agent_impl_unittests.cc
index 6e97672..dee70fa 100644
--- a/fuchsia/base/agent_impl_unittests.cc
+++ b/fuchsia/base/agent_impl_unittests.cc
@@ -109,10 +109,6 @@
   DISALLOW_COPY_AND_ASSIGN(AgentImplTest);
 };
 
-void SetBoolToTrue(bool* bool_value) {
-  *bool_value = true;
-}
-
 }  // namespace
 
 // Verify that the Agent can publish and unpublish itself.
@@ -142,56 +138,6 @@
   EXPECT_EQ(*client_disconnect_status2, ZX_ERR_PEER_CLOSED);
 }
 
-// Verify that the on-last-client callback is not invoked if the Agent channel
-// is closed, until the last component is gone.
-TEST_F(AgentImplTest, OnLastClientCallbackAfterComponentOutlivesAgent) {
-  fuchsia::modular::AgentPtr agent = CreateAgentAndConnect();
-
-  // Register an on-last-client callback.
-  bool on_last_client_called = false;
-  agent_impl_->set_on_last_client_callback(
-      base::BindOnce(&SetBoolToTrue, base::Unretained(&on_last_client_called)));
-
-  // Connect a component to the Agent.
-  fuchsia::sys::ServiceProviderPtr component_services;
-  agent->Connect(kNoServicesComponentId, component_services.NewRequest());
-
-  // Disconnect from the Agent API.
-  agent.Unbind();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(on_last_client_called);
-
-  // Disconnect the component.
-  component_services.Unbind();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(on_last_client_called);
-}
-
-// Verify that the on-last-client callback is not invoked when the last
-// component disconnects, until the Agent channel is also closed.
-TEST_F(AgentImplTest, OnLastClientCallbackAfterAgentOutlivesComponent) {
-  fuchsia::modular::AgentPtr agent = CreateAgentAndConnect();
-
-  // Register an on-last-client callback.
-  bool on_last_client_called = false;
-  agent_impl_->set_on_last_client_callback(
-      base::BindOnce(&SetBoolToTrue, base::Unretained(&on_last_client_called)));
-
-  // Connect a component to the Agent.
-  fuchsia::sys::ServiceProviderPtr component_services;
-  agent->Connect(kNoServicesComponentId, component_services.NewRequest());
-
-  // Disconnect the component.
-  component_services.Unbind();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(on_last_client_called);
-
-  // Disconnect from the Agent API.
-  agent.Unbind();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(on_last_client_called);
-}
-
 // Verify that multiple connection attempts with the different component Ids
 // to the same service get different instances.
 TEST_F(AgentImplTest, DifferentComponentIdSameService) {
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index 6864224..c1a90a6b 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -180,20 +180,15 @@
   name: "android-gpu-fyi-ci"
   dimensions: "os:Ubuntu-14.04"
   mixins: "gpu-fyi-ci"
-}
-
-builder_mixins {
-  name: "android-gpu-manual-try"
-  mixins: "android-optional-gpu-try"
-  # Increase timeout to allow tryjobs against small number of phones.
   mixins: "gpu-slow-bot"
 }
 
 builder_mixins {
   name: "android-optional-gpu-try"
   dimensions: "os:Ubuntu-14.04"
-  mixins: "gpu-optional-try"
   mixins: "android-try"
+  mixins: "gpu-optional-try"
+  mixins: "gpu-slow-bot"
 }
 
 builder_mixins {
@@ -366,11 +361,9 @@
 
 builder_mixins {
   name: "linux-optional-gpu-try"
-  mixins: "linux"
+  mixins: "linux-try"
   mixins: "gpu-optional-try"
-  recipe {
-    properties: "mastername:tryserver.chromium.linux"
-  }
+  mixins: "gpu-slow-bot"
 }
 
 builder_mixins {
@@ -410,6 +403,7 @@
   name: "linux-gpu-fyi-ci"
   mixins: "linux"
   mixins: "gpu-fyi-ci"
+  mixins: "gpu-slow-bot"
 }
 
 builder_mixins {
@@ -442,11 +436,8 @@
 
 builder_mixins {
   name: "mac-optional-gpu-try"
-  mixins: "mac"
+  mixins: "mac-try"
   mixins: "gpu-optional-try"
-  recipe {
-    properties: "mastername:tryserver.chromium.mac"
-  }
 }
 
 builder_mixins {
@@ -536,11 +527,9 @@
 
 builder_mixins {
   name: "win-optional-gpu-try"
-  mixins: "win"
+  mixins: "win-try"
   mixins: "gpu-optional-try"
-  recipe {
-    properties: "mastername:tryserver.chromium.win"
-  }
+  mixins: "gpu-slow-bot"
 }
 
 builder_mixins {
@@ -669,15 +658,11 @@
     builders {
       name: "Android FYI 32 dEQP Vk Release (Pixel 2)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
       name: "Android FYI 32 dEQP Vk Release (Pixel XL)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
@@ -688,15 +673,11 @@
     builders {
       name: "Android FYI 32 Vk Release (Pixel 2)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
       name: "Android FYI 32 Vk Release (Pixel XL)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
@@ -707,15 +688,11 @@
     builders {
       name: "Android FYI 64 dEQP Vk Release (Pixel 2)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
       name: "Android FYI 64 dEQP Vk Release (Pixel XL)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
@@ -726,15 +703,11 @@
     builders {
       name: "Android FYI 64 Vk Release (Pixel 2)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
       name: "Android FYI 64 Vk Release (Pixel XL)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
@@ -745,8 +718,6 @@
     builders {
       name: "Android FYI Release (Nexus 5)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
@@ -757,36 +728,26 @@
     builders {
       name: "Android FYI Release (Nexus 6)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
       name: "Android FYI Release (Nexus 6P)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
       name: "Android FYI Release (Nexus 9)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
       name: "Android FYI Release (NVIDIA Shield TV)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
       name: "Android FYI Release (Pixel 2)"
       mixins: "android-gpu-fyi-ci"
-      # Increase timeout to allow tryjobs against small number of phones.
-      mixins: "gpu-slow-bot"
     }
 
     builders {
@@ -1324,7 +1285,6 @@
 
     builders {
       name: "Linux FYI Experimental Release (Intel HD 630)"
-      mixins: "gpu-slow-bot"
       mixins: "linux-gpu-fyi-ci"
     }
 
@@ -1366,7 +1326,6 @@
     builders {
       name: "Linux FYI Release (AMD R7 240)"
       mixins: "linux-gpu-fyi-ci"
-      mixins: "gpu-slow-bot"
     }
 
     builders {
@@ -3161,59 +3120,59 @@
       dimensions: "os:Ubuntu-14.04"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-l-nexus-5-32"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-l-nexus-6-32"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-m-nexus-6p-64"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-m-nexus-9-64"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-n-nvidia-shield-tv-64"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-p-pixel-2-32"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-p-pixel-2-32-vk"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-p-pixel-2-32-deqp-vk"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-p-pixel-2-64-vk"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-p-pixel-2-64-deqp-vk"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-p-pixel-xl-32-vk"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-p-pixel-xl-32-deqp-vk"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-p-pixel-xl-64-vk"
     }
     builders {
-      mixins: "android-gpu-manual-try"
+      mixins: "android-optional-gpu-try"
       name: "gpu-manual-try-android-p-pixel-xl-64-deqp-vk"
     }
     builders {
@@ -3246,12 +3205,6 @@
       name: "linux-chromeos-rel"
     }
 
-    builders { mixins: "linux-angle-try" name: "linux_angle_compile_dbg_ng" }
-    builders { mixins: "linux-angle-try" name: "linux_angle_dbg_ng" }
-    builders { mixins: "linux-angle-try" name: "linux_angle_deqp_rel_ng" }
-    builders { mixins: "linux-angle-try" name: "linux_angle_ozone_rel_ng" }
-    builders { mixins: "linux-angle-try" name: "linux_angle_rel_ng" }
-
     builders { mixins: "linux-try" name: "cast_shell_audio_linux" }
     builders { mixins: "linux-try" name: "cast_shell_linux" }
     builders { mixins: "linux-try" name: "chromium_devtools" }
@@ -3278,7 +3231,52 @@
     builders { mixins: "linux-try" name: "fuchsia-fyi-x64-rel" }
     builders { mixins: "linux-try" name: "fuchsia_x64" }
     builders { mixins: "linux-try" name: "fuchsia-x64-cast" }
+    builders {
+      mixins: "linux-optional-gpu-try"
+      name: "gpu-manual-try-linux-amd-rel"
+    }
+    builders {
+      mixins: "linux-optional-gpu-try"
+      name: "gpu-manual-try-linux-intel-dqp"
+    }
+    builders {
+      mixins: "linux-optional-gpu-try"
+      name: "gpu-manual-try-linux-intel-exp"
+    }
+    builders {
+      mixins: "linux-optional-gpu-try"
+      name: "gpu-manual-try-linux-intel-ozn"
+    }
+    builders {
+      mixins: "linux-optional-gpu-try"
+      name: "gpu-manual-try-linux-intel-rel"
+    }
+    builders {
+      mixins: "linux-optional-gpu-try"
+      name: "gpu-manual-try-linux-nvidia-dbg"
+    }
+    builders {
+      mixins: "linux-optional-gpu-try"
+      name: "gpu-manual-try-linux-nvidia-dqp"
+    }
+    builders {
+      mixins: "linux-optional-gpu-try"
+      name: "gpu-manual-try-linux-nvidia-exp"
+    }
+    builders {
+      mixins: "linux-optional-gpu-try"
+      name: "gpu-manual-try-linux-nvidia-rel"
+    }
+    builders {
+      mixins: "linux-optional-gpu-try"
+      name: "gpu-manual-try-linux-nvidia-tsn"
+    }
     builders { mixins: "linux-try" name: "leak_detection_linux" }
+    builders { mixins: "linux-angle-try" name: "linux_angle_compile_dbg_ng" }
+    builders { mixins: "linux-angle-try" name: "linux_angle_dbg_ng" }
+    builders { mixins: "linux-angle-try" name: "linux_angle_deqp_rel_ng" }
+    builders { mixins: "linux-angle-try" name: "linux_angle_ozone_rel_ng" }
+    builders { mixins: "linux-angle-try" name: "linux_angle_rel_ng" }
     builders { mixins: "linux-try" name: "linux-blink-heap-incremental-marking" }
     builders { mixins: "linux-try" name: "linux-blink-heap-verification-try" }
     builders { mixins: "linux-try" name: "linux-dcheck-off-rel" }
@@ -3437,8 +3435,55 @@
 
     builders {
       mixins: "win-optional-gpu-try"
-      name: "gpu_manual_try_win7_nvidia_rel"
-      execution_timeout_secs: 10800  # 3h
+      name: "gpu-manual-try-win7-amd-dbg"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win7-amd-dqp"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win7-amd-rel"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win7-nvidia-dqp-64"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win7-nvidia-rel"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win7-nvidia-rel-64"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win10-intel-dqp"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win10-intel-exp"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win10-intel-rel"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win10-nvidia-dbg"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win10-nvidia-dqp"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win10-nvidia-exp"
+    }
+    builders {
+      mixins: "win-optional-gpu-try"
+      name: "gpu-manual-try-win10-nvidia-rel"
     }
     builders { mixins: "win-try" name: "win10_chromium_x64_dbg_ng" }
     builders {
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index 65c6f98..44e08ea 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -4020,6 +4020,36 @@
     name: "buildbucket/luci.chromium.try/fuchsia-x64-cast"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-amd-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-intel-dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-intel-exp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-intel-ozn"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-intel-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-nvidia-dbg"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-nvidia-dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-nvidia-exp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-nvidia-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-nvidia-tsn"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/layout_test_leak_detection"
   }
   builders {
@@ -4240,7 +4270,43 @@
   refs: "refs/heads/master"
   manifest_name: "REVISION"
   builders {
-    name: "buildbucket/luci.chromium.try/gpu_manual_try_win7_nvidia_rel"
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-amd-dbg"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-amd-dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-amd-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-nvidia-dqp-64"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-nvidia-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-nvidia-rel-64"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-intel-dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-intel-exp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-intel-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-nvidia-dbg"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-nvidia-dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-nvidia-exp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-nvidia-rel"
   }
   builders {
     name: "buildbucket/luci.chromium.try/win-libfuzzer-asan-rel"
@@ -4534,7 +4600,73 @@
     name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-64-deqp-vk"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu_manual_try_win7_nvidia_rel"
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-amd-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-intel-dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-intel-exp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-intel-ozn"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-intel-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-nvidia-dbg"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-nvidia-dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-nvidia-exp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-nvidia-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-linux-nvidia-tsn"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-amd-dbg"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-amd-dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-amd-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-nvidia-dqp-64"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-nvidia-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win7-nvidia-rel-64"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-intel-dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-intel-exp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-intel-rel"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-nvidia-dbg"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-nvidia-dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-nvidia-exp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-win10-nvidia-rel"
   }
   builders {
     name: "buildbucket/luci.chromium.try/linux-blink-heap-incremental-marking"
diff --git a/ios/chrome/browser/leveldb_proto/proto_database_provider_factory.mm b/ios/chrome/browser/leveldb_proto/proto_database_provider_factory.mm
index 29bfeac..420eec2 100644
--- a/ios/chrome/browser/leveldb_proto/proto_database_provider_factory.mm
+++ b/ios/chrome/browser/leveldb_proto/proto_database_provider_factory.mm
@@ -22,10 +22,9 @@
 }
 
 // static
-leveldb_proto::ProtoDatabaseProvider*
-ProtoDatabaseProviderFactory::GetForBrowserState(
+ProtoDatabaseProvider* ProtoDatabaseProviderFactory::GetForBrowserState(
     ios::ChromeBrowserState* browser_state) {
-  return static_cast<leveldb_proto::ProtoDatabaseProvider*>(
+  return static_cast<ProtoDatabaseProvider*>(
       GetInstance()->GetServiceForBrowserState(browser_state, true));
 }
 
@@ -39,9 +38,7 @@
 std::unique_ptr<KeyedService>
 ProtoDatabaseProviderFactory::BuildServiceInstanceFor(
     web::BrowserState* context) const {
-  base::FilePath profile_dir = context->GetStatePath();
-  return base::WrapUnique(
-      leveldb_proto::ProtoDatabaseProvider::Create(profile_dir));
+  return std::make_unique<ProtoDatabaseProvider>(context->GetStatePath());
 }
 
 }  // namespace leveldb_proto
\ No newline at end of file
diff --git a/ios/chrome/browser/overscroll_actions/overscroll_actions_tab_helper_unittest.mm b/ios/chrome/browser/overscroll_actions/overscroll_actions_tab_helper_unittest.mm
index 8fd7642..4183eeca 100644
--- a/ios/chrome/browser/overscroll_actions/overscroll_actions_tab_helper_unittest.mm
+++ b/ios/chrome/browser/overscroll_actions/overscroll_actions_tab_helper_unittest.mm
@@ -80,7 +80,13 @@
 
 // Tests that OverscrollActionsControllerDelegate is set correctly and triggered
 // When there is a view pull.
-TEST_F(OverscrollActionsTabHelperTest, TestDelegateTrigger) {
+// TODO(crbug.com/944599): Fails on device.
+#if TARGET_IPHONE_SIMULATOR
+#define MAYBE_TestDelegateTrigger TestDelegateTrigger
+#else
+#define MAYBE_TestDelegateTrigger DISABLED_TestDelegateTrigger
+#endif
+TEST_F(OverscrollActionsTabHelperTest, MAYBE_TestDelegateTrigger) {
   web_state_.SetBrowserState(browser_state_.get());
   overscroll_tab_helper()->SetDelegate(overscroll_delegate_);
   // Start pull for page refresh action.
@@ -96,7 +102,13 @@
 
 // Tests that overscrolls actions view style is set correctly, for regular
 // browsing browser state.
-TEST_F(OverscrollActionsTabHelperTest, TestRegularBrowserStateStyle) {
+// TODO(crbug.com/944599): Fails on device.
+#if TARGET_IPHONE_SIMULATOR
+#define MAYBE_TestRegularBrowserStateStyle TestRegularBrowserStateStyle
+#else
+#define MAYBE_TestRegularBrowserStateStyle DISABLED_TestRegularBrowserStateStyle
+#endif
+TEST_F(OverscrollActionsTabHelperTest, MAYBE_TestRegularBrowserStateStyle) {
   web_state_.SetBrowserState(browser_state_.get());
   overscroll_tab_helper()->SetDelegate(overscroll_delegate_);
   SimulatePullForRefreshAction();
@@ -109,7 +121,16 @@
 
 // Tests that overscrolls actions view style is set correctly, for off the
 // record browser state.
-TEST_F(OverscrollActionsTabHelperTest, TestOffTheRecordBrowserStateStyle) {
+// TODO(crbug.com/944599): Fails on device.
+#if TARGET_IPHONE_SIMULATOR
+#define MAYBE_TestOffTheRecordBrowserStateStyle \
+  TestOffTheRecordBrowserStateStyle
+#else
+#define MAYBE_TestOffTheRecordBrowserStateStyle \
+  DISABLED_TestOffTheRecordBrowserStateStyle
+#endif
+TEST_F(OverscrollActionsTabHelperTest,
+       MAYBE_TestOffTheRecordBrowserStateStyle) {
   web_state_.SetBrowserState(
       browser_state_->GetOffTheRecordChromeBrowserState());
   overscroll_tab_helper()->SetDelegate(overscroll_delegate_);
diff --git a/ios/web/find_in_page/find_in_page_constants.h b/ios/web/find_in_page/find_in_page_constants.h
index 4ae2c52..8d23f4d0 100644
--- a/ios/web/find_in_page/find_in_page_constants.h
+++ b/ios/web/find_in_page/find_in_page_constants.h
@@ -11,6 +11,8 @@
 extern const char kFindInPageSearch[];
 // The name of JavaScript function which continues an unfinished find.
 extern const char kFindInPagePump[];
+// The name of JavaScript function which highlights a match.
+extern const char kFindInPageHighlightMatch[];
 
 }  // namespace web
 
diff --git a/ios/web/find_in_page/find_in_page_constants.mm b/ios/web/find_in_page/find_in_page_constants.mm
index af4792f..05fd1f8 100644
--- a/ios/web/find_in_page/find_in_page_constants.mm
+++ b/ios/web/find_in_page/find_in_page_constants.mm
@@ -14,4 +14,6 @@
 
 const char kFindInPagePump[] = "findInPage.pumpSearch";
 
+const char kFindInPageHighlightMatch[] = "findInPage.highlightMatch";
+
 }  // namespace web
diff --git a/ios/web/web_state/js/find_in_page_js_unittest.mm b/ios/web/web_state/js/find_in_page_js_unittest.mm
index a1bd7837..748a096e 100644
--- a/ios/web/web_state/js/find_in_page_js_unittest.mm
+++ b/ios/web/web_state/js/find_in_page_js_unittest.mm
@@ -4,12 +4,14 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/run_loop.h"
 #import "base/test/ios/wait_util.h"
 #import "ios/web/find_in_page/find_in_page_constants.h"
 #import "ios/web/public/test/web_test_with_web_state.h"
 #import "ios/web/public/web_state/web_frame.h"
 #import "ios/web/public/web_state/web_frame_util.h"
 #import "ios/web/public/web_state/web_frames_manager.h"
+#include "testing/gtest_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -26,9 +28,6 @@
 
 // Pump search timeout in milliseconds.
 const double kPumpSearchTimeout = 100.0;
-
-// Timeout for frame javascript execution, in seconds.
-const double kCallJavascriptFunctionTimeout = 3.0;
 }
 
 namespace web {
@@ -49,23 +48,25 @@
 // with 1 match.
 TEST_F(FindInPageJsTest, FindText) {
   ASSERT_TRUE(LoadHtml("<span>foo</span>"));
-  WaitForCondition(^{
+  base::TimeDelta kCallJavascriptFunctionTimeout =
+      base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
     return frames_manager()->GetAllWebFrames().size() == 1;
-  });
+  }));
 
   __block bool message_received = false;
   std::vector<base::Value> params;
   params.push_back(base::Value(kFindStringFoo));
   params.push_back(base::Value(kPumpSearchTimeout));
   main_web_frame()->CallJavaScriptFunction(
-      kFindInPageSearch, params, base::BindOnce(^(const base::Value* res) {
-        ASSERT_TRUE(res);
-        ASSERT_TRUE(res->is_double());
-        int count = static_cast<int>(res->GetDouble());
-        ASSERT_TRUE(count == 1);
+      kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) {
+        ASSERT_TRUE(result);
+        ASSERT_TRUE(result->is_double());
+        double count = result->GetDouble();
+        ASSERT_EQ(1.0, count);
         message_received = true;
       }),
-      base::TimeDelta::FromSeconds(kCallJavascriptFunctionTimeout));
+      kCallJavascriptFunctionTimeout);
 
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
     return message_received;
@@ -76,22 +77,24 @@
 // hidden and responds with 0 matches.
 TEST_F(FindInPageJsTest, FindTextNoResults) {
   ASSERT_TRUE(LoadHtml("<span style='display:none'>foo</span>"));
-  WaitForCondition(^{
+  base::TimeDelta kCallJavascriptFunctionTimeout =
+      base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
     return frames_manager()->GetAllWebFrames().size() == 1;
-  });
+  }));
   __block bool message_received = false;
   std::vector<base::Value> params;
   params.push_back(base::Value(kFindStringFoo));
   params.push_back(base::Value(kPumpSearchTimeout));
   main_web_frame()->CallJavaScriptFunction(
-      kFindInPageSearch, params, base::BindOnce(^(const base::Value* res) {
-        ASSERT_TRUE(res);
-        ASSERT_TRUE(res->is_double());
-        int count = static_cast<int>(res->GetDouble());
-        ASSERT_TRUE(count == 0);
+      kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) {
+        ASSERT_TRUE(result);
+        ASSERT_TRUE(result->is_double());
+        double count = result->GetDouble();
+        ASSERT_EQ(0.0, count);
         message_received = true;
       }),
-      base::TimeDelta::FromSeconds(kCallJavascriptFunctionTimeout));
+      kCallJavascriptFunctionTimeout);
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
     return message_received;
   }));
@@ -106,9 +109,11 @@
     ASSERT_TRUE(LoadHtml(
         "<iframe "
         "srcdoc='<html><body><span>foo</span></body></html>'></iframe>"));
-    WaitForCondition(^{
+    base::TimeDelta kCallJavascriptFunctionTimeout =
+        base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout);
+    ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
       return frames_manager()->GetAllWebFrames().size() == 2;
-    });
+    }));
     std::set<WebFrame*> all_frames = frames_manager()->GetAllWebFrames();
     __block bool message_received = false;
     WebFrame* child_frame = nullptr;
@@ -123,14 +128,14 @@
     params.push_back(base::Value(kFindStringFoo));
     params.push_back(base::Value(kPumpSearchTimeout));
     child_frame->CallJavaScriptFunction(
-        kFindInPageSearch, params, base::BindOnce(^(const base::Value* res) {
-          ASSERT_TRUE(res);
-          ASSERT_TRUE(res->is_double());
-          int count = static_cast<int>(res->GetDouble());
-          ASSERT_TRUE(count == 1);
+        kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) {
+          ASSERT_TRUE(result);
+          ASSERT_TRUE(result->is_double());
+          double count = result->GetDouble();
+          ASSERT_EQ(1.0, count);
           message_received = true;
         }),
-        base::TimeDelta::FromSeconds(kCallJavascriptFunctionTimeout));
+        kCallJavascriptFunctionTimeout);
     ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
       return message_received;
     }));
@@ -140,22 +145,24 @@
 // Tests that FindInPage works when searching for white space.
 TEST_F(FindInPageJsTest, FindWhiteSpace) {
   ASSERT_TRUE(LoadHtml("<span> </span>"));
-  WaitForCondition(^{
+  base::TimeDelta kCallJavascriptFunctionTimeout =
+      base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
     return frames_manager()->GetAllWebFrames().size() == 1;
-  });
+  }));
   __block bool message_received = false;
   std::vector<base::Value> params;
   params.push_back(base::Value(" "));
   params.push_back(base::Value(kPumpSearchTimeout));
   main_web_frame()->CallJavaScriptFunction(
-      kFindInPageSearch, params, base::BindOnce(^(const base::Value* res) {
-        ASSERT_TRUE(res);
-        ASSERT_TRUE(res->is_double());
-        int count = static_cast<int>(res->GetDouble());
-        ASSERT_TRUE(count == 1);
+      kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) {
+        ASSERT_TRUE(result);
+        ASSERT_TRUE(result->is_double());
+        double count = result->GetDouble();
+        ASSERT_EQ(1.0, count);
         message_received = true;
       }),
-      base::TimeDelta::FromSeconds(kCallJavascriptFunctionTimeout));
+      kCallJavascriptFunctionTimeout);
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
     return message_received;
   }));
@@ -165,25 +172,182 @@
 TEST_F(FindInPageJsTest, FindAcrossMultipleNodes) {
   ASSERT_TRUE(
       LoadHtml("<p>xx1<span>2</span>3<a>4512345xxx12</a>34<a>5xxx12345xx</p>"));
-  WaitForCondition(^{
+  base::TimeDelta kCallJavascriptFunctionTimeout =
+      base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
     return frames_manager()->GetAllWebFrames().size() == 1;
-  });
+  }));
   __block bool message_received = false;
   std::vector<base::Value> params;
   params.push_back(base::Value(kFindString12345));
   params.push_back(base::Value(kPumpSearchTimeout));
   main_web_frame()->CallJavaScriptFunction(
-      kFindInPageSearch, params, base::BindOnce(^(const base::Value* res) {
-        ASSERT_TRUE(res);
-        ASSERT_TRUE(res->is_double());
-        int count = static_cast<int>(res->GetDouble());
-        ASSERT_TRUE(count == 4);
+      kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) {
+        ASSERT_TRUE(result);
+        ASSERT_TRUE(result->is_double());
+        double count = result->GetDouble();
+        ASSERT_EQ(4.0, count);
         message_received = true;
       }),
-      base::TimeDelta::FromSeconds(kCallJavascriptFunctionTimeout));
+      kCallJavascriptFunctionTimeout);
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
     return message_received;
   }));
 }
 
+// Tests that a FindInPage match can be highlighted.
+TEST_F(FindInPageJsTest, FindHighlightMatch) {
+  ASSERT_TRUE(LoadHtml("<span>foo</span>"));
+  base::TimeDelta kCallJavascriptFunctionTimeout =
+      base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return frames_manager()->GetAllWebFrames().size() == 1;
+  }));
+
+  __block bool message_received = false;
+  std::vector<base::Value> params;
+  params.push_back(base::Value(kFindStringFoo));
+  params.push_back(base::Value(kPumpSearchTimeout));
+  main_web_frame()->CallJavaScriptFunction(
+      kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) {
+        ASSERT_TRUE(result);
+        ASSERT_TRUE(result->is_double());
+        double count = result->GetDouble();
+        ASSERT_EQ(1.0, count);
+        message_received = true;
+      }),
+      kCallJavascriptFunctionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return message_received;
+  }));
+
+  __block bool highlight_done = false;
+  std::vector<base::Value> highlight_params;
+  highlight_params.push_back(base::Value(0));
+  main_web_frame()->CallJavaScriptFunction(
+      kFindInPageHighlightMatch, highlight_params,
+      base::BindOnce(^(const base::Value* result) {
+        highlight_done = true;
+      }),
+      kCallJavascriptFunctionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return highlight_done;
+  }));
+
+  EXPECT_NSEQ(@1,
+              ExecuteJavaScript(
+                  @"document.getElementsByClassName('find_selected').length"));
+}
+
+// Tests that a FindInPage match can be highlighted and that a previous
+// highlight is removed when another match is highlighted.
+TEST_F(FindInPageJsTest, FindHighlightSeparateMatches) {
+  ASSERT_TRUE(LoadHtml("<span>foo foo</span>"));
+  base::TimeDelta kCallJavascriptFunctionTimeout =
+      base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return frames_manager()->GetAllWebFrames().size() == 1;
+  }));
+
+  __block bool message_received = false;
+  std::vector<base::Value> params;
+  params.push_back(base::Value(kFindStringFoo));
+  params.push_back(base::Value(kPumpSearchTimeout));
+  main_web_frame()->CallJavaScriptFunction(
+      kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) {
+        ASSERT_TRUE(result);
+        ASSERT_TRUE(result->is_double());
+        double count = result->GetDouble();
+        ASSERT_EQ(2.0, count);
+        message_received = true;
+      }),
+      kCallJavascriptFunctionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return message_received;
+  }));
+
+  __block bool highlight_done = false;
+  std::vector<base::Value> highlight_params;
+  highlight_params.push_back(base::Value(0));
+  main_web_frame()->CallJavaScriptFunction(
+      kFindInPageHighlightMatch, highlight_params,
+      base::BindOnce(^(const base::Value* result) {
+        highlight_done = true;
+      }),
+      kCallJavascriptFunctionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return highlight_done;
+  }));
+
+  EXPECT_NSEQ(@1,
+              ExecuteJavaScript(
+                  @"document.getElementsByClassName('find_selected').length"));
+
+  highlight_done = false;
+  std::vector<base::Value> highlight_second_params;
+  highlight_second_params.push_back(base::Value(1));
+  main_web_frame()->CallJavaScriptFunction(
+      kFindInPageHighlightMatch, highlight_second_params,
+      base::BindOnce(^(const base::Value* result) {
+        highlight_done = true;
+      }),
+      kCallJavascriptFunctionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return highlight_done;
+  }));
+
+  id inner_html = ExecuteJavaScript(@"document.body.innerHTML");
+  ASSERT_TRUE([inner_html isKindOfClass:[NSString class]]);
+  EXPECT_TRUE([inner_html
+      containsString:@"<chrome_find class=\"find_in_page\">foo</chrome_find> "
+                     @"<chrome_find class=\"find_in_page "
+                     @"find_selected\">foo</chrome_find>"]);
+  EXPECT_TRUE(
+      [inner_html containsString:@"find_selected{background-color:#ff9632"]);
+}
+
+// Tests that FindInPage does not highlight any matches given an invalid index.
+TEST_F(FindInPageJsTest, FindHighlightMatchAtInvalidIndex) {
+  ASSERT_TRUE(LoadHtml("<span>invalid </span>"));
+  base::TimeDelta kCallJavascriptFunctionTimeout =
+      base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return frames_manager()->GetAllWebFrames().size() == 1;
+  }));
+
+  __block bool message_received = false;
+  std::vector<base::Value> params;
+  params.push_back(base::Value(kFindStringFoo));
+  params.push_back(base::Value(kPumpSearchTimeout));
+  main_web_frame()->CallJavaScriptFunction(
+      kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) {
+        ASSERT_TRUE(result);
+        ASSERT_TRUE(result->is_double());
+        double count = result->GetDouble();
+        ASSERT_TRUE(count == 0.0);
+        message_received = true;
+      }),
+      kCallJavascriptFunctionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return message_received;
+  }));
+
+  __block bool highlight_done = false;
+  std::vector<base::Value> highlight_params;
+  highlight_params.push_back(base::Value(0));
+  main_web_frame()->CallJavaScriptFunction(
+      kFindInPageHighlightMatch, highlight_params,
+      base::BindOnce(^(const base::Value* result) {
+        highlight_done = true;
+      }),
+      kCallJavascriptFunctionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return highlight_done;
+  }));
+
+  EXPECT_NSEQ(@0,
+              ExecuteJavaScript(
+                  @"document.getElementsByClassName('find_selected').length"));
+}
+
 }  // namespace web
diff --git a/ios/web/web_state/js/resources/find_in_page.js b/ios/web/web_state/js/resources/find_in_page.js
index c5a00f2..b558ed2 100644
--- a/ios/web/web_state/js/resources/find_in_page.js
+++ b/ios/web/web_state/js/resources/find_in_page.js
@@ -112,7 +112,7 @@
    */
   addSelectHighlight() {
     for (let i = 0; i < this.nodes.length; ++i) {
-      this.nodes[i].className = (this.nodes[i].className || '') + ' findysel';
+      this.nodes[i].classList.add(CSS_CLASS_NAME_SELECT);
     }
   }
 
@@ -122,8 +122,7 @@
    */
   removeSelectHighlight() {
     for (let i = 0; i < this.nodes.length; ++i) {
-      this.nodes[i].className =
-          (this.nodes[i].className || '').replace(/\sfindysel/g, '');
+      this.nodes[i].classList.remove(CSS_CLASS_NAME_SELECT);
     }
   }
 }
@@ -138,7 +137,7 @@
  * Index of the current highlighted choice.  -1 means none.
  * @type {number}
  */
-__gCrWeb.findInPage.selectedMatchIndex = -1;
+let selectedMatchIndex_ = -1;
 
 /**
  * The ID for the next Match found in |allText_|. This ID is used for
@@ -318,12 +317,18 @@
   'OBJECT', 'SELECT', 'TEXTAREA', 'IFRAME']);
 
 /**
- * Class name of CSS element.
+ * Class name of CSS element that highlights matches with yellow.
  * @type {string}
  */
 const CSS_CLASS_NAME = 'find_in_page';
 
 /**
+ * Class name of CSS element that selects a highlighted match with orange.
+ * @type {string}
+ */
+const CSS_CLASS_NAME_SELECT = 'find_selected';
+
+/**
  * ID of CSS style.
  * @type {string}
  */
@@ -342,10 +347,14 @@
 const REGEX_ESCAPER = /([.?*+^$[\]\\(){}|-])/g;
 
 /**
- * @return {Match} The currently selected Match.
+ * @return {Match} The currently selected Match. Returns null if no
+ * currently selected match.
  */
 function getCurrentSelectedMatch_() {
-  return __gCrWeb.findInPage.matches[__gCrWeb.findInPage.selectedMatchIndex];
+   if (selectedMatchIndex_ < 0) {
+    return null;
+   }
+  return __gCrWeb.findInPage.matches[selectedMatchIndex_];
 };
 
 /**
@@ -566,7 +575,7 @@
   sectionsIndex_ = 0;
 
   __gCrWeb.findInPage.matches = [];
-  __gCrWeb.findInPage.selectedMatchIndex = -1;
+  selectedMatchIndex_ = -1;
   matchId_ = 0;
   partialMatches_ = [];
 
@@ -575,92 +584,25 @@
 };
 
 /**
- * Increments the index of the current selected Match or, if the index is
- * already at the end, sets it to the index of the first Match in the page.
+ * Highlights the match at |index|. Clears currently highlighted match if
+ * one exists.
+ * @param {Number} index of match to highlight.
  */
-__gCrWeb.findInPage.incrementIndex = function() {
-  if (__gCrWeb.findInPage.selectedMatchIndex >=
-      __gCrWeb.findInPage.matches.length - 1) {
-    __gCrWeb.findInPage.selectedMatchIndex = 0;
-  } else {
-    __gCrWeb.findInPage.selectedMatchIndex++;
-  }
-};
-
-/**
- * Switches to the next result, animating a little highlight in the process.
- * @return {string} JSON encoded array of coordinates to scroll to, or blank if
- *     nothing happened.
- */
-__gCrWeb.findInPage.goNext = function() {
-  if (!__gCrWeb.findInPage.matches || __gCrWeb.findInPage.matches.length == 0) {
-    return '';
-  }
-  if (__gCrWeb.findInPage.selectedMatchIndex >= 0) {
-    // Remove previous highlight.
-    getCurrentSelectedMatch_().removeSelectHighlight();
-  }
-  // Iterate through to the next index, but because they might not be visible,
-  // keep trying until you find one that is.  Make sure we don't loop forever by
-  // stopping on what we are currently highlighting.
-  let oldIndex = __gCrWeb.findInPage.selectedMatchIndex;
-  __gCrWeb.findInPage.incrementIndex();
-  while (!getCurrentSelectedMatch_().visible()) {
-    if (oldIndex === __gCrWeb.findInPage.selectedMatchIndex) {
-      // Checked all matches but didn't find anything else visible.
-      return '';
-    }
-    __gCrWeb.findInPage.incrementIndex();
-    if (0 === __gCrWeb.findInPage.selectedMatchIndex && oldIndex < 0) {
-      // Didn't find anything visible and haven't highlighted anything yet.
-      return '';
-    }
-  }
-  // Return scroll dimensions.
-  return findScrollDimensions_();
-};
-
-/**
- * Decrements the index of the current selected Match or, if the index is
- * already at the beginning, sets it to the index of the last Match in the page.
- */
-__gCrWeb.findInPage.decrementIndex = function() {
-  if (__gCrWeb.findInPage.selectedMatchIndex <= 0) {
-    __gCrWeb.findInPage.selectedMatchIndex =
-        __gCrWeb.findInPage.matches.length - 1;
-  } else {
-    __gCrWeb.findInPage.selectedMatchIndex--;
-  }
-};
-
-/**
- * Switches to the previous result, animating a little highlight in the process.
- * @return {string} JSON encoded array of coordinates to scroll to, or blank if
- *     nothing happened.
- */
-__gCrWeb.findInPage.goPrev = function() {
-  if (!__gCrWeb.findInPage.matches || __gCrWeb.findInPage.matches.length == 0) {
-    return '';
-  }
-  if (__gCrWeb.findInPage.selectedMatchIndex >= 0) {
-    // Remove previous highlight.
-    getCurrentSelectedMatch_().removeSelectHighlight();
-  }
-  // Iterate through to the next index, but because they might not be visible,
-  // keep trying until you find one that is.  Make sure we don't loop forever by
-  // stopping on what we are currently highlighting.
-  let old = __gCrWeb.findInPage.selectedMatchIndex;
-  __gCrWeb.findInPage.decrementIndex();
-  while (!getCurrentSelectedMatch_().visible()) {
-    __gCrWeb.findInPage.decrementIndex();
-    if (old == __gCrWeb.findInPage.selectedMatchIndex) {
-      // Checked all matches but didn't find anything.
-      return '';
-    }
+__gCrWeb.findInPage.highlightMatch = function(index) {
+  if (index >= __gCrWeb.findInPage.matches.length || index < 0) {
+    // Do nothing if invalid index is passed.
+    return;
   }
 
-  // Return scroll dimensions.
-  return findScrollDimensions_();
+  // Remove previous highlight.
+  let match = getCurrentSelectedMatch_();
+  if (match) {
+    match.removeSelectHighlight();
+  }
+
+  selectedMatchIndex_ = index;
+
+  getCurrentSelectedMatch_().addSelectHighlight()
 };
 
 /**
@@ -751,7 +693,7 @@
           'padding:0px;margin:0px;' +
           'overflow:visible !important;');
   addCSSRule(
-      '.findysel',
+      '.' + CSS_CLASS_NAME_SELECT,
       'background-color:#ff9632 !important;' +
           'padding:0px;margin:0px;' +
           'overflow:visible !important;');
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 66906e8..3770e35e 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -129,14 +129,14 @@
 using web::WebState;
 using web::WebStateImpl;
 
-namespace {
-
 using web::wk_navigation_util::IsPlaceholderUrl;
 using web::wk_navigation_util::CreatePlaceholderUrlForUrl;
 using web::wk_navigation_util::ExtractUrlFromPlaceholderUrl;
 using web::wk_navigation_util::IsRestoreSessionUrl;
 using web::wk_navigation_util::IsWKInternalUrl;
 
+namespace {
+
 // Struct to capture data about a user interaction. Records the time of the
 // interaction and the main document URL at that time.
 struct UserInteractionEvent {
@@ -161,6 +161,12 @@
 // Message command sent when a frame is unloading.
 NSString* const kFrameBecameUnavailableMessageName = @"FrameBecameUnavailable";
 
+NSString* const kReferrerHeaderName = @"Referer";  // [sic]
+
+// The duration of the period following a screen touch during which the user is
+// still considered to be interacting with the page.
+const NSTimeInterval kMaximumDelayForUserInteractionInSeconds = 2;
+
 // Values for the histogram that counts slow/fast back/forward navigations.
 enum class BackForwardNavigationType {
   // Fast back navigation through WKWebView back-forward list.
@@ -194,6 +200,17 @@
 // stored errors is not expected to be high.
 const CertVerificationErrorsCacheType::size_type kMaxCertErrorsCount = 100;
 
+// URLs that are fed into UIWebView as history push/replace get escaped,
+// potentially changing their format. Code that attempts to determine whether a
+// URL hasn't changed can be confused by those differences though, so method
+// will round-trip a URL through the escaping process so that it can be adjusted
+// pre-storing, to allow later comparisons to work as expected.
+GURL URLEscapedForHistory(const GURL& url) {
+  // TODO(stuartmorgan): This is a very large hammer; see if limited unicode
+  // escaping would be sufficient.
+  return net::GURLWithNSURL(net::NSURLWithGURL(url));
+}
+
 }  // namespace
 
 #pragma mark -
@@ -608,26 +625,6 @@
 
 @end
 
-namespace {
-
-NSString* const kReferrerHeaderName = @"Referer";  // [sic]
-
-// The duration of the period following a screen touch during which the user is
-// still considered to be interacting with the page.
-const NSTimeInterval kMaximumDelayForUserInteractionInSeconds = 2;
-
-// URLs that are fed into UIWebView as history push/replace get escaped,
-// potentially changing their format. Code that attempts to determine whether a
-// URL hasn't changed can be confused by those differences though, so method
-// will round-trip a URL through the escaping process so that it can be adjusted
-// pre-storing, to allow later comparisons to work as expected.
-GURL URLEscapedForHistory(const GURL& url) {
-  // TODO(stuartmorgan): This is a very large hammer; see if limited unicode
-  // escaping would be sufficient.
-  return net::GURLWithNSURL(net::NSURLWithGURL(url));
-}
-}  // namespace
-
 @implementation CRWWebController
 
 // Synthesize as it is readonly.
@@ -844,10 +841,6 @@
   }
 }
 
-- (id<CRWNativeContent>)nativeController {
-  return [_containerView nativeController];
-}
-
 - (void)setNativeController:(id<CRWNativeContent>)nativeController {
   // Check for pointer equality.
   if (self.nativeController == nativeController)
@@ -962,7 +955,7 @@
   return _touchTrackingRecognizer;
 }
 
-#pragma mark Session Information
+#pragma mark Navigation and Session Information
 
 - (CRWSessionController*)sessionController {
   NavigationManagerImpl* navigationManager = self.navigationManagerImpl;
@@ -1452,6 +1445,10 @@
   }
 }
 
+- (id<CRWNativeContent>)nativeController {
+  return [_containerView nativeController];
+}
+
 - (void)didFinishGoToIndexSameDocumentNavigationWithType:
             (web::NavigationInitiationType)type
                                           hasUserGesture:(BOOL)hasUserGesture {
@@ -1758,7 +1755,7 @@
   }
 }
 
-#pragma mark - Load helpers
+#pragma mark - Navigation Helpers
 
 // Registers load request with empty referrer and link or client redirect
 // transition based on user interaction state. Returns navigation context for
@@ -1915,7 +1912,7 @@
   return context;
 }
 
-// Load the current URL in a web view, first ensuring the web view is visible.
+// Loads the current URL in a web view, first ensuring the web view is visible.
 - (void)loadCurrentURLInWebView {
   web::NavigationItem* item = self.currentNavItem;
   GURL targetURL = item ? item->GetVirtualURL() : GURL::EmptyGURL();
@@ -2352,7 +2349,7 @@
   self.webStateImpl->OnPageLoaded(currentURL, YES);
 }
 
-#pragma mark - Error helpers
+#pragma mark - Error Helpers
 
 - (void)loadErrorPageForNavigationItem:(web::NavigationItemImpl*)item
                      navigationContext:(web::NavigationContextImpl*)context {
@@ -2714,7 +2711,7 @@
   return [self.nativeProvider nativeContentInsetForWebState:self.webState];
 }
 
-#pragma mark - CRWJSInjectionEvaluator helper methods (Private)
+#pragma mark - JavaScript message Helpers (Private)
 
 - (BOOL)respondToMessage:(base::DictionaryValue*)message
        userIsInteracting:(BOOL)userIsInteracting
@@ -3199,7 +3196,7 @@
   return YES;
 }
 
-#pragma mark - JavaScript message helpers
+#pragma mark - Navigation Helpers
 
 // Adds a new NavigationItem with the given URL and state object to the history
 // stack. A state object is a serialized generic JavaScript object that contains
@@ -3594,7 +3591,7 @@
   }
 }
 
-#pragma mark - WebDelegate Calls
+#pragma mark - WKNavigationDelegate Helpers
 
 - (BOOL)isMainFrameNavigationAction:(WKNavigationAction*)action {
   if (action.targetFrame) {
@@ -3606,6 +3603,8 @@
   return action.sourceFrame.mainFrame;
 }
 
+#pragma mark - Security Helpers
+
 - (void)updateSSLStatusForCurrentNavigationItem {
   if (_isBeingDestroyed) {
     return;
@@ -3739,7 +3738,7 @@
   [self loadCancelled];
 }
 
-#pragma mark - WebView helpers
+#pragma mark - WebView Helpers
 
 // Creates a container view if it's not yet created.
 - (void)ensureContainerViewCreated {
@@ -4036,7 +4035,7 @@
       previewingViewController);
 }
 
-#pragma mark - WKUIDelegate helper methods
+#pragma mark - WKUIDelegate Helpers
 
 // Helper to respond to |webView:runJavaScript...| delegate methods.
 // |completionHandler| must not be nil.
@@ -5909,7 +5908,7 @@
   }
 }
 
-#pragma mark - KVO helper methods
+#pragma mark - KVO Helpers
 
 // Returns YES if a KVO change to |newURL| could be a 'navigation' within the
 // document (hash change, pushState/replaceState, etc.). This should only be
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
index f116052..4ff4574 100644
--- a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
@@ -19,14 +19,13 @@
 import org.chromium.media.MediaDrmSessionManager.SessionId;
 import org.chromium.media.MediaDrmSessionManager.SessionInfo;
 
-import java.io.IOException;
+import java.lang.reflect.Method;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Queue;
-import java.util.Scanner;
 import java.util.UUID;
 
 // Implementation Notes of MediaDrmBridge:
@@ -412,18 +411,13 @@
     @CalledByNative
     private static int getFirstApiLevel() {
         int firstApiLevel = 0;
-        Scanner scanner = null;
-        // If first_api_level property is set, return it.
         try {
-            Process process = new ProcessBuilder("getprop", FIRST_API_LEVEL).start();
-            scanner = new Scanner(process.getInputStream());
-            firstApiLevel = Integer.parseInt(scanner.nextLine().trim());
-        } catch (IOException | NumberFormatException e) {
+            final Class<?> systemProperties = Class.forName("android.os.SystemProperties");
+            final Method getInt = systemProperties.getMethod("getInt", String.class, int.class);
+            firstApiLevel = (Integer) getInt.invoke(null, FIRST_API_LEVEL, 0);
+        } catch (Exception e) {
+            Log.e("Exception while getting system property %s. Using default.", FIRST_API_LEVEL, e);
             firstApiLevel = 0;
-        } finally {
-            if (scanner != null) {
-                scanner.close();
-            }
         }
         return firstApiLevel;
     }
@@ -527,7 +521,7 @@
         assert !securityLevel.isEmpty();
 
         String currentSecurityLevel = mMediaDrm.getPropertyString(SECURITY_LEVEL);
-        Log.e(TAG, "Security level: current %s, new %s", currentSecurityLevel, securityLevel);
+        Log.i(TAG, "Security level: current %s, new %s", currentSecurityLevel, securityLevel);
         if (securityLevel.equals(currentSecurityLevel)) {
             // No need to set the same security level again. This is not just
             // a shortcut! Setting the same security level actually causes an
@@ -1113,7 +1107,7 @@
             Log.e(TAG, "getSecurityLevel(): MediaDrm is null or security level is not supported.");
             return "";
         }
-        return mMediaDrm.getPropertyString("securityLevel");
+        return mMediaDrm.getPropertyString(SECURITY_LEVEL);
     }
 
     private void startProvisioning() {
@@ -1317,7 +1311,7 @@
         public void onEvent(
                 MediaDrm mediaDrm, byte[] drmSessionId, int event, int extra, byte[] data) {
             if (drmSessionId == null) {
-                Log.e(TAG, "EventListener: Null session.");
+                Log.e(TAG, "EventListener: No session for event %d.", event);
                 return;
             }
             SessionId sessionId = getSessionIdByDrmId(drmSessionId);
diff --git a/media/capture/content/android/thread_safe_capture_oracle.cc b/media/capture/content/android/thread_safe_capture_oracle.cc
index e80f233..13d4a30 100644
--- a/media/capture/content/android/thread_safe_capture_oracle.cc
+++ b/media/capture/content/android/thread_safe_capture_oracle.cc
@@ -237,8 +237,8 @@
                                    params_.requested_format.frame_rate,
                                    frame->format());
   client_->OnIncomingCapturedBufferExt(
-      std::move(capture->buffer), format, reference_time, frame->timestamp(),
-      frame->visible_rect(), *frame->metadata());
+      std::move(capture->buffer), format, frame->ColorSpace(), reference_time,
+      frame->timestamp(), frame->visible_rect(), *frame->metadata());
 }
 
 void ThreadSafeCaptureOracle::OnConsumerReportingUtilization(
diff --git a/media/capture/mojom/video_capture_types.mojom b/media/capture/mojom/video_capture_types.mojom
index 233d135..ee201ab12 100644
--- a/media/capture/mojom/video_capture_types.mojom
+++ b/media/capture/mojom/video_capture_types.mojom
@@ -274,7 +274,7 @@
   // This field is only optional to work around the issue of native enums
   // not being usable for non-Chromium Mojo clients.
   // TODO(chfremer): Make this non-optional once gfx.mojom.ColorSpace has been
-  // migrated to a full Mojo struct.
+  // migrated to a full Mojo struct. See https://crbug.com/893203.
   gfx.mojom.ColorSpace? color_space;
   // Optionally, stride information can be provided.
   // If not provided, it is assumed that frame data is tightly packed.
diff --git a/media/capture/video/chromeos/mock_video_capture_client.cc b/media/capture/video/chromeos/mock_video_capture_client.cc
index 2d90502f..04e26a48 100644
--- a/media/capture/video/chromeos/mock_video_capture_client.cc
+++ b/media/capture/video/chromeos/mock_video_capture_client.cc
@@ -90,6 +90,7 @@
 void MockVideoCaptureClient::OnIncomingCapturedBufferExt(
     Buffer buffer,
     const VideoCaptureFormat& format,
+    const gfx::ColorSpace& color_space,
     base::TimeTicks reference_time,
     base::TimeDelta timestamp,
     gfx::Rect visible_rect,
diff --git a/media/capture/video/chromeos/mock_video_capture_client.h b/media/capture/video/chromeos/mock_video_capture_client.h
index 88039c7..7ab44a08 100644
--- a/media/capture/video/chromeos/mock_video_capture_client.h
+++ b/media/capture/video/chromeos/mock_video_capture_client.h
@@ -64,6 +64,7 @@
   void OnIncomingCapturedBufferExt(
       Buffer buffer,
       const VideoCaptureFormat& format,
+      const gfx::ColorSpace& color_space,
       base::TimeTicks reference_time,
       base::TimeDelta timestamp,
       gfx::Rect visible_rect,
diff --git a/media/capture/video/fake_video_capture_device_unittest.cc b/media/capture/video/fake_video_capture_device_unittest.cc
index df0723b..c5b3d806 100644
--- a/media/capture/video/fake_video_capture_device_unittest.cc
+++ b/media/capture/video/fake_video_capture_device_unittest.cc
@@ -175,12 +175,12 @@
                           const media::VideoCaptureFormat& frame_format,
                           base::TimeTicks,
                           base::TimeDelta) { OnFrameCaptured(frame_format); }));
-    ON_CALL(*result, DoOnIncomingCapturedBufferExt(_, _, _, _, _, _))
-        .WillByDefault(
-            Invoke([this](media::VideoCaptureDevice::Client::Buffer&,
-                          const media::VideoCaptureFormat& frame_format,
-                          base::TimeTicks, base::TimeDelta, gfx::Rect,
-                          const media::VideoFrameMetadata&) {
+    ON_CALL(*result, DoOnIncomingCapturedBufferExt(_, _, _, _, _, _, _))
+        .WillByDefault(Invoke(
+            [this](media::VideoCaptureDevice::Client::Buffer&,
+                   const media::VideoCaptureFormat& frame_format,
+                   const gfx::ColorSpace&, base::TimeTicks, base::TimeDelta,
+                   gfx::Rect, const media::VideoFrameMetadata&) {
               OnFrameCaptured(frame_format);
             }));
     return result;
diff --git a/media/capture/video/mock_video_capture_device_client.cc b/media/capture/video/mock_video_capture_device_client.cc
index 74e1fda..b113c6a 100644
--- a/media/capture/video/mock_video_capture_device_client.cc
+++ b/media/capture/video/mock_video_capture_device_client.cc
@@ -19,12 +19,13 @@
 void MockVideoCaptureDeviceClient::OnIncomingCapturedBufferExt(
     Buffer buffer,
     const media::VideoCaptureFormat& format,
+    const gfx::ColorSpace& color_space,
     base::TimeTicks reference_time,
     base::TimeDelta timestamp,
     gfx::Rect visible_rect,
     const media::VideoFrameMetadata& additional_metadata) {
-  DoOnIncomingCapturedBufferExt(buffer, format, reference_time, timestamp,
-                                visible_rect, additional_metadata);
+  DoOnIncomingCapturedBufferExt(buffer, format, color_space, reference_time,
+                                timestamp, visible_rect, additional_metadata);
 }
 
 }  // namespace media
diff --git a/media/capture/video/mock_video_capture_device_client.h b/media/capture/video/mock_video_capture_device_client.h
index a7f83a3d..b0e2d76f 100644
--- a/media/capture/video/mock_video_capture_device_client.h
+++ b/media/capture/video/mock_video_capture_device_client.h
@@ -47,6 +47,7 @@
   void OnIncomingCapturedBufferExt(
       Buffer buffer,
       const media::VideoCaptureFormat& format,
+      const gfx::ColorSpace& color_space,
       base::TimeTicks reference_time,
       base::TimeDelta timestamp,
       gfx::Rect visible_rect,
@@ -57,9 +58,10 @@
                     const media::VideoCaptureFormat&,
                     base::TimeTicks,
                     base::TimeDelta));
-  MOCK_METHOD6(DoOnIncomingCapturedBufferExt,
+  MOCK_METHOD7(DoOnIncomingCapturedBufferExt,
                void(Buffer& buffer,
                     const media::VideoCaptureFormat& format,
+                    const gfx::ColorSpace& color_space,
                     base::TimeTicks reference_time,
                     base::TimeDelta timestamp,
                     gfx::Rect visible_rect,
diff --git a/media/capture/video/video_capture_device.h b/media/capture/video/video_capture_device.h
index d4ad22b..3cef019 100644
--- a/media/capture/video/video_capture_device.h
+++ b/media/capture/video/video_capture_device.h
@@ -199,6 +199,7 @@
     virtual void OnIncomingCapturedBufferExt(
         Buffer buffer,
         const VideoCaptureFormat& format,
+        const gfx::ColorSpace& color_space,
         base::TimeTicks reference_time,
         base::TimeDelta timestamp,
         gfx::Rect visible_rect,
diff --git a/media/capture/video/video_capture_device_client.cc b/media/capture/video/video_capture_device_client.cc
index ef84b21..6c7cf02e 100644
--- a/media/capture/video/video_capture_device_client.cc
+++ b/media/capture/video/video_capture_device_client.cc
@@ -202,7 +202,8 @@
 
   int crop_x = 0;
   int crop_y = 0;
-  libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY;
+  libyuv::FourCC fourcc_format = libyuv::FOURCC_ANY;
+  gfx::ColorSpace color_space;
 
   bool flip = false;
   switch (format.pixel_format) {
@@ -210,27 +211,27 @@
       break;
     case PIXEL_FORMAT_I420:
       DCHECK(!chopped_width && !chopped_height);
-      origin_colorspace = libyuv::FOURCC_I420;
+      fourcc_format = libyuv::FOURCC_I420;
       break;
     case PIXEL_FORMAT_YV12:
       DCHECK(!chopped_width && !chopped_height);
-      origin_colorspace = libyuv::FOURCC_YV12;
+      fourcc_format = libyuv::FOURCC_YV12;
       break;
     case PIXEL_FORMAT_NV12:
       DCHECK(!chopped_width && !chopped_height);
-      origin_colorspace = libyuv::FOURCC_NV12;
+      fourcc_format = libyuv::FOURCC_NV12;
       break;
     case PIXEL_FORMAT_NV21:
       DCHECK(!chopped_width && !chopped_height);
-      origin_colorspace = libyuv::FOURCC_NV21;
+      fourcc_format = libyuv::FOURCC_NV21;
       break;
     case PIXEL_FORMAT_YUY2:
       DCHECK(!chopped_width && !chopped_height);
-      origin_colorspace = libyuv::FOURCC_YUY2;
+      fourcc_format = libyuv::FOURCC_YUY2;
       break;
     case PIXEL_FORMAT_UYVY:
       DCHECK(!chopped_width && !chopped_height);
-      origin_colorspace = libyuv::FOURCC_UYVY;
+      fourcc_format = libyuv::FOURCC_UYVY;
       break;
     case PIXEL_FORMAT_RGB24:
 // Linux RGB24 defines red at lowest byte address,
@@ -238,9 +239,9 @@
 // Windows RGB24 defines blue at lowest byte,
 // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd407253
 #if defined(OS_LINUX)
-      origin_colorspace = libyuv::FOURCC_RAW;
+      fourcc_format = libyuv::FOURCC_RAW;
 #elif defined(OS_WIN)
-      origin_colorspace = libyuv::FOURCC_24BG;
+      fourcc_format = libyuv::FOURCC_24BG;
 #else
       NOTREACHED() << "RGB24 is only available in Linux and Windows platforms";
 #endif
@@ -251,6 +252,11 @@
       // that vertical flipping is needed.
       flip = true;
 #endif
+      // We don't actually know, for sure, what the source color space is. It's
+      // probably safe to assume its sRGB, though, and so it would be valid to
+      // assume libyuv::ConvertToI420() is going to produce results in Rec601
+      // (or very close to it).
+      color_space = gfx::ColorSpace::CreateREC601();
       break;
     case PIXEL_FORMAT_RGB32:
 // Fallback to PIXEL_FORMAT_ARGB setting |flip| in Windows
@@ -260,10 +266,11 @@
       FALLTHROUGH;
 #endif
     case PIXEL_FORMAT_ARGB:
-      origin_colorspace = libyuv::FOURCC_ARGB;
+      fourcc_format = libyuv::FOURCC_ARGB;
+      color_space = gfx::ColorSpace::CreateREC601();
       break;
     case PIXEL_FORMAT_MJPEG:
-      origin_colorspace = libyuv::FOURCC_MJPG;
+      fourcc_format = libyuv::FOURCC_MJPG;
       break;
     default:
       NOTREACHED();
@@ -289,12 +296,13 @@
     }
   }
 
+  // libyuv::ConvertToI420 use Rec601 to convert RGB to YUV.
   if (libyuv::ConvertToI420(
           data, length, y_plane_data, yplane_stride, u_plane_data,
           uv_plane_stride, v_plane_data, uv_plane_stride, crop_x, crop_y,
           format.frame_size.width(),
           (flip ? -1 : 1) * format.frame_size.height(), new_unrotated_width,
-          new_unrotated_height, rotation_mode, origin_colorspace) != 0) {
+          new_unrotated_height, rotation_mode, fourcc_format) != 0) {
     DLOG(WARNING) << "Failed to convert buffer's pixel format to I420 from "
                   << VideoPixelFormatToString(format.pixel_format);
     receiver_->OnFrameDropped(
@@ -304,8 +312,9 @@
 
   const VideoCaptureFormat output_format =
       VideoCaptureFormat(dimensions, format.frame_rate, PIXEL_FORMAT_I420);
-  OnIncomingCapturedBuffer(std::move(buffer), output_format, reference_time,
-                           timestamp);
+  OnIncomingCapturedBufferExt(std::move(buffer), output_format, color_space,
+                              reference_time, timestamp, gfx::Rect(dimensions),
+                              VideoFrameMetadata());
 }
 
 void VideoCaptureDeviceClient::OnIncomingCapturedGfxBuffer(
@@ -443,14 +452,15 @@
     base::TimeTicks reference_time,
     base::TimeDelta timestamp) {
   DFAKE_SCOPED_RECURSIVE_LOCK(call_from_producer_);
-  OnIncomingCapturedBufferExt(std::move(buffer), format, reference_time,
-                              timestamp, gfx::Rect(format.frame_size),
-                              VideoFrameMetadata());
+  OnIncomingCapturedBufferExt(
+      std::move(buffer), format, gfx::ColorSpace(), reference_time, timestamp,
+      gfx::Rect(format.frame_size), VideoFrameMetadata());
 }
 
 void VideoCaptureDeviceClient::OnIncomingCapturedBufferExt(
     Buffer buffer,
     const VideoCaptureFormat& format,
+    const gfx::ColorSpace& color_space,
     base::TimeTicks reference_time,
     base::TimeDelta timestamp,
     gfx::Rect visible_rect,
@@ -465,6 +475,7 @@
   mojom::VideoFrameInfoPtr info = mojom::VideoFrameInfo::New();
   info->timestamp = timestamp;
   info->pixel_format = format.pixel_format;
+  info->color_space = color_space;
   info->coded_size = format.frame_size;
   info->visible_rect = visible_rect;
   info->metadata = metadata.GetInternalValues().Clone();
diff --git a/media/capture/video/video_capture_device_client.h b/media/capture/video/video_capture_device_client.h
index f93e44b..dfea6ac 100644
--- a/media/capture/video/video_capture_device_client.h
+++ b/media/capture/video/video_capture_device_client.h
@@ -80,6 +80,7 @@
   void OnIncomingCapturedBufferExt(
       Buffer buffer,
       const VideoCaptureFormat& format,
+      const gfx::ColorSpace& color_space,
       base::TimeTicks reference_time,
       base::TimeDelta timestamp,
       gfx::Rect visible_rect,
diff --git a/media/capture/video/video_capture_device_unittest.cc b/media/capture/video/video_capture_device_unittest.cc
index fb39e510..73859b55 100644
--- a/media/capture/video/video_capture_device_unittest.cc
+++ b/media/capture/video/video_capture_device_unittest.cc
@@ -309,7 +309,7 @@
     ON_CALL(*result, OnError(_, _, _)).WillByDefault(Invoke(DumpError));
     EXPECT_CALL(*result, ReserveOutputBuffer(_, _, _, _)).Times(0);
     EXPECT_CALL(*result, DoOnIncomingCapturedBuffer(_, _, _, _)).Times(0);
-    EXPECT_CALL(*result, DoOnIncomingCapturedBufferExt(_, _, _, _, _, _))
+    EXPECT_CALL(*result, DoOnIncomingCapturedBufferExt(_, _, _, _, _, _, _))
         .Times(0);
     ON_CALL(*result, OnIncomingCapturedData(_, _, _, _, _, _, _))
         .WillByDefault(
diff --git a/media/capture/video/win/video_capture_device_mf_win_unittest.cc b/media/capture/video/win/video_capture_device_mf_win_unittest.cc
index 8ad8f3fa..f8c252f 100644
--- a/media/capture/video/win/video_capture_device_mf_win_unittest.cc
+++ b/media/capture/video/win/video_capture_device_mf_win_unittest.cc
@@ -53,6 +53,7 @@
   void OnIncomingCapturedBufferExt(
       Buffer buffer,
       const VideoCaptureFormat& format,
+      const gfx::ColorSpace& color_space,
       base::TimeTicks reference_time,
       base::TimeDelta timestamp,
       gfx::Rect visible_rect,
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 72803b2..b1750d5 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -69,8 +69,6 @@
     "command_buffer_helper.h",
     "fake_jpeg_decode_accelerator.cc",
     "fake_jpeg_decode_accelerator.h",
-    "fake_video_decode_accelerator.cc",
-    "fake_video_decode_accelerator.h",
     "gles2_decoder_helper.cc",
     "gles2_decoder_helper.h",
     "gpu_jpeg_decode_accelerator_factory.cc",
@@ -122,10 +120,10 @@
 
   if (is_mac) {
     sources += [
-      "vt_video_decode_accelerator_mac.cc",
-      "vt_video_decode_accelerator_mac.h",
-      "vt_video_encode_accelerator_mac.cc",
-      "vt_video_encode_accelerator_mac.h",
+      "mac/vt_video_decode_accelerator_mac.cc",
+      "mac/vt_video_decode_accelerator_mac.h",
+      "mac/vt_video_encode_accelerator_mac.cc",
+      "mac/vt_video_encode_accelerator_mac.h",
     ]
     public_deps += [ "//third_party/webrtc/common_video" ]
     libs += [
@@ -395,6 +393,8 @@
 
     if (is_win || is_chromeos || use_v4l2_codec) {
       sources = [
+        "test/fake_video_decode_accelerator.cc",
+        "test/fake_video_decode_accelerator.h",
         "video_decode_accelerator_unittest.cc",
       ]
       deps += [
@@ -589,8 +589,8 @@
   visibility = [ "//media:test_support" ]
   testonly = true
   sources = [
-    "fake_command_buffer_helper.cc",
-    "fake_command_buffer_helper.h",
+    "test/fake_command_buffer_helper.cc",
+    "test/fake_command_buffer_helper.h",
   ]
   configs += [ "//media:media_config" ]
   deps = [
diff --git a/media/gpu/android/texture_pool_unittest.cc b/media/gpu/android/texture_pool_unittest.cc
index b294ff2..cc21988f 100644
--- a/media/gpu/android/texture_pool_unittest.cc
+++ b/media/gpu/android/texture_pool_unittest.cc
@@ -15,7 +15,7 @@
 #include "gpu/command_buffer/service/sequence_id.h"
 #include "gpu/ipc/common/gpu_messages.h"
 #include "media/gpu/android/mock_abstract_texture.h"
-#include "media/gpu/fake_command_buffer_helper.h"
+#include "media/gpu/test/fake_command_buffer_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/media/gpu/gpu_video_decode_accelerator_factory.cc b/media/gpu/gpu_video_decode_accelerator_factory.cc
index 27b3fe4e..dc9ff3f 100644
--- a/media/gpu/gpu_video_decode_accelerator_factory.cc
+++ b/media/gpu/gpu_video_decode_accelerator_factory.cc
@@ -20,7 +20,7 @@
 #include "media/gpu/windows/dxva_video_decode_accelerator_win.h"
 #endif
 #if defined(OS_MACOSX)
-#include "media/gpu/vt_video_decode_accelerator_mac.h"
+#include "media/gpu/mac/vt_video_decode_accelerator_mac.h"
 #endif
 #if BUILDFLAG(USE_V4L2_CODEC)
 #include "media/gpu/v4l2/v4l2_device.h"
diff --git a/media/gpu/gpu_video_encode_accelerator_factory.cc b/media/gpu/gpu_video_encode_accelerator_factory.cc
index 2945abf..7e77b69 100644
--- a/media/gpu/gpu_video_encode_accelerator_factory.cc
+++ b/media/gpu/gpu_video_encode_accelerator_factory.cc
@@ -17,7 +17,7 @@
 #include "media/gpu/android/android_video_encode_accelerator.h"
 #endif
 #if defined(OS_MACOSX)
-#include "media/gpu/vt_video_encode_accelerator_mac.h"
+#include "media/gpu/mac/vt_video_encode_accelerator_mac.h"
 #endif
 #if defined(OS_WIN)
 #include "base/feature_list.h"
diff --git a/media/gpu/ipc/service/picture_buffer_manager_unittest.cc b/media/gpu/ipc/service/picture_buffer_manager_unittest.cc
index fcf2475..2d3e284 100644
--- a/media/gpu/ipc/service/picture_buffer_manager_unittest.cc
+++ b/media/gpu/ipc/service/picture_buffer_manager_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
 #include "media/base/simple_sync_token_client.h"
-#include "media/gpu/fake_command_buffer_helper.h"
+#include "media/gpu/test/fake_command_buffer_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace media {
diff --git a/media/gpu/ipc/service/vda_video_decoder_unittest.cc b/media/gpu/ipc/service/vda_video_decoder_unittest.cc
index 0264cf9..c7c79fe 100644
--- a/media/gpu/ipc/service/vda_video_decoder_unittest.cc
+++ b/media/gpu/ipc/service/vda_video_decoder_unittest.cc
@@ -25,8 +25,8 @@
 #include "media/base/video_frame.h"
 #include "media/base/video_rotation.h"
 #include "media/base/video_types.h"
-#include "media/gpu/fake_command_buffer_helper.h"
 #include "media/gpu/ipc/service/picture_buffer_manager.h"
+#include "media/gpu/test/fake_command_buffer_helper.h"
 #include "media/video/mock_video_decode_accelerator.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/media/gpu/vt_video_decode_accelerator_mac.cc b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
similarity index 99%
rename from media/gpu/vt_video_decode_accelerator_mac.cc
rename to media/gpu/mac/vt_video_decode_accelerator_mac.cc
index f9a834a0..f01a29b0 100644
--- a/media/gpu/vt_video_decode_accelerator_mac.cc
+++ b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/vt_video_decode_accelerator_mac.h"
+#include "media/gpu/mac/vt_video_decode_accelerator_mac.h"
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <CoreVideo/CoreVideo.h>
diff --git a/media/gpu/vt_video_decode_accelerator_mac.h b/media/gpu/mac/vt_video_decode_accelerator_mac.h
similarity index 97%
rename from media/gpu/vt_video_decode_accelerator_mac.h
rename to media/gpu/mac/vt_video_decode_accelerator_mac.h
index 3f01a8b..5ecad5a8 100644
--- a/media/gpu/vt_video_decode_accelerator_mac.h
+++ b/media/gpu/mac/vt_video_decode_accelerator_mac.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_GPU_VT_VIDEO_DECODE_ACCELERATOR_MAC_H_
-#define MEDIA_GPU_VT_VIDEO_DECODE_ACCELERATOR_MAC_H_
+#ifndef MEDIA_GPU_MAC_VT_VIDEO_DECODE_ACCELERATOR_MAC_H_
+#define MEDIA_GPU_MAC_VT_VIDEO_DECODE_ACCELERATOR_MAC_H_
 
 #include <stdint.h>
 
@@ -288,4 +288,4 @@
 
 }  // namespace media
 
-#endif  // MEDIA_GPU_VT_VIDEO_DECODE_ACCELERATOR_MAC_H_
+#endif  // MEDIA_GPU_MAC_VT_VIDEO_DECODE_ACCELERATOR_MAC_H_
diff --git a/media/gpu/vt_video_encode_accelerator_mac.cc b/media/gpu/mac/vt_video_encode_accelerator_mac.cc
similarity index 99%
rename from media/gpu/vt_video_encode_accelerator_mac.cc
rename to media/gpu/mac/vt_video_encode_accelerator_mac.cc
index d3fce17..243bf4b 100644
--- a/media/gpu/vt_video_encode_accelerator_mac.cc
+++ b/media/gpu/mac/vt_video_encode_accelerator_mac.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/vt_video_encode_accelerator_mac.h"
+#include "media/gpu/mac/vt_video_encode_accelerator_mac.h"
 
 #include <memory>
 
diff --git a/media/gpu/vt_video_encode_accelerator_mac.h b/media/gpu/mac/vt_video_encode_accelerator_mac.h
similarity index 96%
rename from media/gpu/vt_video_encode_accelerator_mac.h
rename to media/gpu/mac/vt_video_encode_accelerator_mac.h
index 391e14c..255bd5dd 100644
--- a/media/gpu/vt_video_encode_accelerator_mac.h
+++ b/media/gpu/mac/vt_video_encode_accelerator_mac.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_GPU_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_
-#define MEDIA_GPU_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_
+#ifndef MEDIA_GPU_MAC_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_
+#define MEDIA_GPU_MAC_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_
 
 #include <memory>
 
@@ -142,4 +142,4 @@
 
 }  // namespace media
 
-#endif  // MEDIA_GPU_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_
+#endif  // MEDIA_GPU_MAC_VT_VIDEO_ENCODE_ACCELERATOR_MAC_H_
diff --git a/media/gpu/fake_command_buffer_helper.cc b/media/gpu/test/fake_command_buffer_helper.cc
similarity index 98%
rename from media/gpu/fake_command_buffer_helper.cc
rename to media/gpu/test/fake_command_buffer_helper.cc
index 5e061a6..4e7a92cb 100644
--- a/media/gpu/fake_command_buffer_helper.cc
+++ b/media/gpu/test/fake_command_buffer_helper.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/fake_command_buffer_helper.h"
+#include "media/gpu/test/fake_command_buffer_helper.h"
 
 #include "base/logging.h"
 
diff --git a/media/gpu/fake_command_buffer_helper.h b/media/gpu/test/fake_command_buffer_helper.h
similarity index 93%
rename from media/gpu/fake_command_buffer_helper.h
rename to media/gpu/test/fake_command_buffer_helper.h
index e99f114f..e136974 100644
--- a/media/gpu/fake_command_buffer_helper.h
+++ b/media/gpu/test/fake_command_buffer_helper.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_GPU_FAKE_COMMAND_BUFFER_HELPER_H_
-#define MEDIA_GPU_FAKE_COMMAND_BUFFER_HELPER_H_
+#ifndef MEDIA_GPU_TEST_FAKE_COMMAND_BUFFER_HELPER_H_
+#define MEDIA_GPU_TEST_FAKE_COMMAND_BUFFER_HELPER_H_
 
 #include <map>
 #include <set>
@@ -78,4 +78,4 @@
 
 }  // namespace media
 
-#endif  // MEDIA_GPU_FAKE_COMMAND_BUFFER_HELPER_H_
+#endif  // MEDIA_GPU_TEST_FAKE_COMMAND_BUFFER_HELPER_H_
diff --git a/media/gpu/fake_video_decode_accelerator.cc b/media/gpu/test/fake_video_decode_accelerator.cc
similarity index 98%
rename from media/gpu/fake_video_decode_accelerator.cc
rename to media/gpu/test/fake_video_decode_accelerator.cc
index 41c4962..935917a 100644
--- a/media/gpu/fake_video_decode_accelerator.cc
+++ b/media/gpu/test/fake_video_decode_accelerator.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/fake_video_decode_accelerator.h"
+#include "media/gpu/test/fake_video_decode_accelerator.h"
 
 #include <stddef.h>
 #include <string.h>
diff --git a/media/gpu/fake_video_decode_accelerator.h b/media/gpu/test/fake_video_decode_accelerator.h
similarity index 92%
rename from media/gpu/fake_video_decode_accelerator.h
rename to media/gpu/test/fake_video_decode_accelerator.h
index 24c48976..609bb0bd 100644
--- a/media/gpu/fake_video_decode_accelerator.h
+++ b/media/gpu/test/fake_video_decode_accelerator.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_GPU_FAKE_VIDEO_DECODE_ACCELERATOR_H_
-#define MEDIA_GPU_FAKE_VIDEO_DECODE_ACCELERATOR_H_
+#ifndef MEDIA_GPU_TEST_FAKE_VIDEO_DECODE_ACCELERATOR_H_
+#define MEDIA_GPU_TEST_FAKE_VIDEO_DECODE_ACCELERATOR_H_
 
 #include <stdint.h>
 
@@ -71,4 +71,4 @@
 
 }  // namespace media
 
-#endif  // MEDIA_GPU_FAKE_VIDEO_DECODE_ACCELERATOR_H_
+#endif  // MEDIA_GPU_TEST_FAKE_VIDEO_DECODE_ACCELERATOR_H_
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc
index 09289b9..41a06c83 100644
--- a/media/gpu/video_decode_accelerator_unittest.cc
+++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -61,9 +61,9 @@
 #include "media/base/test_data_util.h"
 #include "media/base/video_frame.h"
 #include "media/gpu/buildflags.h"
-#include "media/gpu/fake_video_decode_accelerator.h"
 #include "media/gpu/format_utils.h"
 #include "media/gpu/gpu_video_decode_accelerator_factory.h"
+#include "media/gpu/test/fake_video_decode_accelerator.h"
 #include "media/gpu/test/rendering_helper.h"
 #include "media/gpu/test/texture_ref.h"
 #include "media/gpu/test/video_accelerator_unittest_helpers.h"
diff --git a/mojo/core/channel_posix.cc b/mojo/core/channel_posix.cc
index 2ef2a5f..9348a93 100644
--- a/mojo/core/channel_posix.cc
+++ b/mojo/core/channel_posix.cc
@@ -53,12 +53,7 @@
 
   MessageView(MessageView&& other) { *this = std::move(other); }
 
-  MessageView& operator=(MessageView&& other) {
-    message_ = std::move(other.message_);
-    offset_ = other.offset_;
-    handles_ = std::move(other.handles_);
-    return *this;
-  }
+  MessageView& operator=(MessageView&& other) = default;
 
   ~MessageView() {}
 
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 71eb22dc..531044e1 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -6053,6 +6053,50 @@
   ]
 }
 
+fuzzer_test("net_cert_ocsp_parse_ocsp_cert_id_fuzzer") {
+  sources = [
+    "cert/internal/ocsp_parse_ocsp_cert_id_fuzzer.cc",
+  ]
+  seed_corpus = "data/fuzzer_data/parse_ocsp_cert_id_fuzzer"
+  deps = [
+    "//base",
+    "//net",
+  ]
+}
+
+fuzzer_test("net_cert_ocsp_parse_ocsp_single_response_fuzzer") {
+  sources = [
+    "cert/internal/ocsp_parse_ocsp_single_response_fuzzer.cc",
+  ]
+  seed_corpus = "data/fuzzer_data/parse_ocsp_single_response_fuzzer"
+  deps = [
+    "//base",
+    "//net",
+  ]
+}
+
+fuzzer_test("net_cert_ocsp_parse_ocsp_response_data_fuzzer") {
+  sources = [
+    "cert/internal/ocsp_parse_ocsp_response_data_fuzzer.cc",
+  ]
+  seed_corpus = "data/fuzzer_data/parse_ocsp_response_data_fuzzer"
+  deps = [
+    "//base",
+    "//net",
+  ]
+}
+
+fuzzer_test("net_cert_ocsp_parse_ocsp_response_fuzzer") {
+  sources = [
+    "cert/internal/ocsp_parse_ocsp_response_fuzzer.cc",
+  ]
+  seed_corpus = "data/fuzzer_data/parse_ocsp_response_fuzzer"
+  deps = [
+    "//base",
+    "//net",
+  ]
+}
+
 fuzzer_test("net_cert_parse_certificate_fuzzer") {
   sources = [
     "cert/internal/parse_certificate_fuzzer.cc",
diff --git a/net/cert/internal/ocsp.h b/net/cert/internal/ocsp.h
index 53f5b19d..c530e5b 100644
--- a/net/cert/internal/ocsp.h
+++ b/net/cert/internal/ocsp.h
@@ -39,7 +39,7 @@
 //    issuerKeyHash           OCTET STRING, -- Hash of issuer's public key
 //    serialNumber            CertificateSerialNumber
 // }
-struct OCSPCertID {
+struct NET_EXPORT_PRIVATE OCSPCertID {
   OCSPCertID();
   ~OCSPCertID();
 
diff --git a/net/cert/internal/ocsp_parse_ocsp_cert_id_fuzzer.cc b/net/cert/internal/ocsp_parse_ocsp_cert_id_fuzzer.cc
new file mode 100644
index 0000000..855908d
--- /dev/null
+++ b/net/cert/internal/ocsp_parse_ocsp_cert_id_fuzzer.cc
@@ -0,0 +1,17 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "net/cert/internal/ocsp.h"
+#include "net/der/input.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  net::der::Input cert_id_der(data, size);
+  net::OCSPCertID cert_id;
+  net::ParseOCSPCertID(cert_id_der, &cert_id);
+
+  return 0;
+}
diff --git a/net/cert/internal/ocsp_parse_ocsp_response_data_fuzzer.cc b/net/cert/internal/ocsp_parse_ocsp_response_data_fuzzer.cc
new file mode 100644
index 0000000..4d7ca75
--- /dev/null
+++ b/net/cert/internal/ocsp_parse_ocsp_response_data_fuzzer.cc
@@ -0,0 +1,17 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "net/cert/internal/ocsp.h"
+#include "net/der/input.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  net::der::Input response_data_der(data, size);
+  net::OCSPResponseData response_data;
+  net::ParseOCSPResponseData(response_data_der, &response_data);
+
+  return 0;
+}
diff --git a/net/cert/internal/ocsp_parse_ocsp_response_fuzzer.cc b/net/cert/internal/ocsp_parse_ocsp_response_fuzzer.cc
new file mode 100644
index 0000000..f5dae65
--- /dev/null
+++ b/net/cert/internal/ocsp_parse_ocsp_response_fuzzer.cc
@@ -0,0 +1,17 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "net/cert/internal/ocsp.h"
+#include "net/der/input.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  net::der::Input response_der(data, size);
+  net::OCSPResponse response;
+  net::ParseOCSPResponse(response_der, &response);
+
+  return 0;
+}
diff --git a/net/cert/internal/ocsp_parse_ocsp_single_response_fuzzer.cc b/net/cert/internal/ocsp_parse_ocsp_single_response_fuzzer.cc
new file mode 100644
index 0000000..9eddfec4
--- /dev/null
+++ b/net/cert/internal/ocsp_parse_ocsp_single_response_fuzzer.cc
@@ -0,0 +1,17 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "net/cert/internal/ocsp.h"
+#include "net/der/input.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  net::der::Input single_response_der(data, size);
+  net::OCSPSingleResponse single_response;
+  net::ParseOCSPSingleResponse(single_response_der, &single_response);
+
+  return 0;
+}
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 0e3e8a5a..d786360 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -119,10 +119,7 @@
                                             const CookieOptions& options) {
     DCHECK(cm);
     GetCookieListCallback callback;
-    cm->GetCookieListWithOptionsAsync(
-        url, options,
-        base::BindOnce(&GetCookieListCallback::Run,
-                       base::Unretained(&callback)));
+    cm->GetCookieListWithOptionsAsync(url, options, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.cookies();
   }
@@ -133,10 +130,7 @@
       const CookieOptions& options) {
     DCHECK(cm);
     GetCookieListCallback callback;
-    cm->GetCookieListWithOptionsAsync(
-        url, options,
-        base::BindOnce(&GetCookieListCallback::Run,
-                       base::Unretained(&callback)));
+    cm->GetCookieListWithOptionsAsync(url, options, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.excluded_cookies();
   }
@@ -144,10 +138,7 @@
   bool SetAllCookies(CookieMonster* cm, const CookieList& list) {
     DCHECK(cm);
     ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback;
-    cm->SetAllCookiesAsync(
-        list, base::BindOnce(&ResultSavingCookieCallback<
-                                 CanonicalCookie::CookieInclusionStatus>::Run,
-                             base::Unretained(&callback)));
+    cm->SetAllCookiesAsync(list, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result() == CanonicalCookie::CookieInclusionStatus::INCLUDE;
   }
@@ -162,10 +153,7 @@
     cm->SetCanonicalCookieAsync(
         CanonicalCookie::Create(url, cookie_line, creation_time,
                                 CookieOptions()),
-        url.scheme(), CookieOptions(),
-        base::BindOnce(&ResultSavingCookieCallback<
-                           CanonicalCookie::CookieInclusionStatus>::Run,
-                       base::Unretained(&callback)));
+        url.scheme(), CookieOptions(), callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result() == CanonicalCookie::CookieInclusionStatus::INCLUDE;
   }
@@ -174,10 +162,8 @@
                                        const TimeRange& creation_range) {
     DCHECK(cm);
     ResultSavingCookieCallback<uint32_t> callback;
-    cm->DeleteAllCreatedInTimeRangeAsync(
-        creation_range,
-        base::BindRepeating(&ResultSavingCookieCallback<uint32_t>::Run,
-                            base::Unretained(&callback)));
+    cm->DeleteAllCreatedInTimeRangeAsync(creation_range,
+                                         callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result();
   }
@@ -186,10 +172,8 @@
                                  CookieDeletionInfo delete_info) {
     DCHECK(cm);
     ResultSavingCookieCallback<uint32_t> callback;
-    cm->DeleteAllMatchingInfoAsync(
-        std::move(delete_info),
-        base::BindOnce(&ResultSavingCookieCallback<uint32_t>::Run,
-                       base::Unretained(&callback)));
+    cm->DeleteAllMatchingInfoAsync(std::move(delete_info),
+                                   callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result();
   }
@@ -2198,16 +2182,11 @@
   // Get all cookies task that queues a task to set a cookie when executed.
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
       set_cookie_callback;
-  cm->SetCookieWithOptionsAsync(
-      kUrl, "a=b", CookieOptions(),
-      base::BindOnce(&ResultSavingCookieCallback<
-                         CanonicalCookie::CookieInclusionStatus>::Run,
-                     base::Unretained(&set_cookie_callback)));
+  cm->SetCookieWithOptionsAsync(kUrl, "a=b", CookieOptions(),
+                                set_cookie_callback.MakeCallback());
 
   GetCookieListCallback get_cookie_list_callback1;
-  cm->GetAllCookiesAsync(
-      base::BindOnce(&GetCookieListCallback::Run,
-                     base::Unretained(&get_cookie_list_callback1)));
+  cm->GetAllCookiesAsync(get_cookie_list_callback1.MakeCallback());
 
   // Two load events should have been queued.
   ASSERT_EQ(2u, store->commands().size());
@@ -2235,9 +2214,7 @@
 
   // The just set cookie should still be in the store.
   GetCookieListCallback get_cookie_list_callback2;
-  cm->GetAllCookiesAsync(
-      base::BindOnce(&GetCookieListCallback::Run,
-                     base::Unretained(&get_cookie_list_callback2)));
+  cm->GetAllCookiesAsync(get_cookie_list_callback2.MakeCallback());
   get_cookie_list_callback2.WaitUntilDone();
   EXPECT_EQ(1u, get_cookie_list_callback2.cookies().size());
 }
@@ -2253,14 +2230,11 @@
   std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   ResultSavingCookieCallback<uint32_t> delete_callback;
-  cm->DeleteAllAsync(base::BindOnce(&ResultSavingCookieCallback<uint32_t>::Run,
-                                    base::Unretained(&delete_callback)));
+  cm->DeleteAllAsync(delete_callback.MakeCallback());
 
   GetCookieListCallback get_cookie_list_callback;
-  cm->GetCookieListWithOptionsAsync(
-      kUrl, CookieOptions(),
-      base::BindOnce(&GetCookieListCallback::Run,
-                     base::Unretained(&get_cookie_list_callback)));
+  cm->GetCookieListWithOptionsAsync(kUrl, CookieOptions(),
+                                    get_cookie_list_callback.MakeCallback());
 
   // Only the main load should have been queued.
   ASSERT_EQ(1u, store->commands().size());
@@ -2293,22 +2267,15 @@
   std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   GetCookieListCallback get_cookie_list_callback1;
-  cm->GetAllCookiesAsync(
-      base::BindOnce(&GetCookieListCallback::Run,
-                     base::Unretained(&get_cookie_list_callback1)));
+  cm->GetAllCookiesAsync(get_cookie_list_callback1.MakeCallback());
 
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
       set_cookie_callback;
-  cm->SetCookieWithOptionsAsync(
-      kUrl, "a=b", CookieOptions(),
-      base::BindOnce(&ResultSavingCookieCallback<
-                         CanonicalCookie::CookieInclusionStatus>::Run,
-                     base::Unretained(&set_cookie_callback)));
+  cm->SetCookieWithOptionsAsync(kUrl, "a=b", CookieOptions(),
+                                set_cookie_callback.MakeCallback());
 
   GetCookieListCallback get_cookie_list_callback2;
-  cm->GetAllCookiesAsync(
-      base::BindOnce(&GetCookieListCallback::Run,
-                     base::Unretained(&get_cookie_list_callback2)));
+  cm->GetAllCookiesAsync(get_cookie_list_callback2.MakeCallback());
 
   // Only the main load should have been queued.
   ASSERT_EQ(1u, store->commands().size());
@@ -2354,19 +2321,14 @@
       set_cookie_callback;
   cm->GetAllCookiesAsync(base::BindOnce(
       &RunClosureOnCookieListReceived,
-      base::BindOnce(
-          &CookieStore::SetCookieWithOptionsAsync, base::Unretained(cm.get()),
-          kUrl, "a=b", CookieOptions(),
-          base::BindOnce(&ResultSavingCookieCallback<
-                             CanonicalCookie::CookieInclusionStatus>::Run,
-                         base::Unretained(&set_cookie_callback)))));
+      base::BindOnce(&CookieStore::SetCookieWithOptionsAsync,
+                     base::Unretained(cm.get()), kUrl, "a=b", CookieOptions(),
+                     set_cookie_callback.MakeCallback())));
 
   // Get cookie task. Queued before the delete task is executed, so should not
   // see the set cookie.
   GetCookieListCallback get_cookie_list_callback1;
-  cm->GetAllCookiesAsync(
-      base::BindOnce(&GetCookieListCallback::Run,
-                     base::Unretained(&get_cookie_list_callback1)));
+  cm->GetAllCookiesAsync(get_cookie_list_callback1.MakeCallback());
 
   // Only the main load should have been queued.
   ASSERT_EQ(1u, store->commands().size());
@@ -2386,9 +2348,7 @@
 
   // A subsequent get cookies call should see the new cookie.
   GetCookieListCallback get_cookie_list_callback2;
-  cm->GetAllCookiesAsync(
-      base::BindOnce(&GetCookieListCallback::Run,
-                     base::Unretained(&get_cookie_list_callback2)));
+  cm->GetAllCookiesAsync(get_cookie_list_callback2.MakeCallback());
   get_cookie_list_callback2.WaitUntilDone();
   EXPECT_EQ(1u, get_cookie_list_callback2.cookies().size());
 }
@@ -3163,17 +3123,12 @@
   cm.SetCanonicalCookieAsync(
       CanonicalCookie::Create(GURL("http://a.com/"), "A=B", base::Time::Now(),
                               CookieOptions()),
-      "http", CookieOptions(),
-      base::BindOnce(&ResultSavingCookieCallback<
-                         CanonicalCookie::CookieInclusionStatus>::Run,
-                     base::Unretained(&callback_set)));
+      "http", CookieOptions(), callback_set.MakeCallback());
 
   // Get cookies for a different URL.
   GetCookieListCallback callback_get;
-  cm.GetCookieListWithOptionsAsync(
-      GURL("http://b.com/"), CookieOptions(),
-      base::BindOnce(&GetCookieListCallback::Run,
-                     base::Unretained(&callback_get)));
+  cm.GetCookieListWithOptionsAsync(GURL("http://b.com/"), CookieOptions(),
+                                   callback_get.MakeCallback());
 
   // Now go through the store commands, and execute individual loads.
   for (const CookieStoreCommand& command : persistent_store->commands()) {
@@ -3246,31 +3201,23 @@
   auto cookie = CanonicalCookie::Create(url, cookie_line, t1, options);
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
       set_callback_1;
-  cm.SetCanonicalCookieAsync(
-      std::move(cookie), url.scheme(), options,
-      base::BindOnce(&ResultSavingCookieCallback<
-                         CanonicalCookie::CookieInclusionStatus>::Run,
-                     base::Unretained(&set_callback_1)));
+  cm.SetCanonicalCookieAsync(std::move(cookie), url.scheme(), options,
+                             set_callback_1.MakeCallback());
   set_callback_1.WaitUntilDone();
 
   // Overwrite the cookie at |t2|.
   cookie = CanonicalCookie::Create(url, cookie_line, t2, options);
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
       set_callback_2;
-  cm.SetCanonicalCookieAsync(
-      std::move(cookie), url.scheme(), options,
-      base::BindOnce(&ResultSavingCookieCallback<
-                         CanonicalCookie::CookieInclusionStatus>::Run,
-                     base::Unretained(&set_callback_2)));
+  cm.SetCanonicalCookieAsync(std::move(cookie), url.scheme(), options,
+                             set_callback_2.MakeCallback());
   set_callback_2.WaitUntilDone();
 
   // The second cookie overwrites the first one but it will inherit the creation
   // timestamp |t1|. Test that deleting the new cookie still works.
   cookie = CanonicalCookie::Create(url, cookie_line, t2, options);
   ResultSavingCookieCallback<unsigned int> delete_callback;
-  cm.DeleteCanonicalCookieAsync(
-      *cookie, base::BindOnce(&ResultSavingCookieCallback<unsigned int>::Run,
-                              base::Unretained(&delete_callback)));
+  cm.DeleteCanonicalCookieAsync(*cookie, delete_callback.MakeCallback());
   delete_callback.WaitUntilDone();
   EXPECT_EQ(1U, delete_callback.result());
 }
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 682823e..b8fd108 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -141,9 +141,7 @@
                                     const CookieOptions& options) {
     DCHECK(cs);
     GetCookieListCallback callback;
-    cs->GetCookieListWithOptionsAsync(
-        url, options,
-        base::Bind(&GetCookieListCallback::Run, base::Unretained(&callback)));
+    cs->GetCookieListWithOptionsAsync(url, options, callback.MakeCallback());
     callback.WaitUntilDone();
     return CanonicalCookie::BuildCookieLine(callback.cookies());
   }
@@ -153,9 +151,7 @@
                                       const CookieOptions& options) {
     DCHECK(cs);
     GetCookieListCallback callback;
-    cs->GetCookieListWithOptionsAsync(
-        url, options,
-        base::Bind(&GetCookieListCallback::Run, base::Unretained(&callback)));
+    cs->GetCookieListWithOptionsAsync(url, options, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.cookies();
   }
@@ -163,8 +159,7 @@
   CookieList GetAllCookiesForURL(CookieStore* cs, const GURL& url) {
     DCHECK(cs);
     GetCookieListCallback callback;
-    cs->GetAllCookiesForURLAsync(url, base::Bind(&GetCookieListCallback::Run,
-                                                 base::Unretained(&callback)));
+    cs->GetAllCookiesForURLAsync(url, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.cookies();
   }
@@ -177,10 +172,7 @@
     options.set_same_site_cookie_context(
         CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
     options.set_return_excluded_cookies();
-    cs->GetCookieListWithOptionsAsync(
-        url, options,
-        base::BindOnce(&GetCookieListCallback::Run,
-                       base::Unretained(&callback)));
+    cs->GetCookieListWithOptionsAsync(url, options, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.excluded_cookies();
   }
@@ -188,8 +180,7 @@
   CookieList GetAllCookies(CookieStore* cs) {
     DCHECK(cs);
     GetCookieListCallback callback;
-    cs->GetAllCookiesAsync(
-        base::Bind(&GetCookieListCallback::Run, base::Unretained(&callback)));
+    cs->GetAllCookiesAsync(callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.cookies();
   }
@@ -200,11 +191,8 @@
                             const CookieOptions& options) {
     DCHECK(cs);
     ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback;
-    cs->SetCookieWithOptionsAsync(
-        url, cookie_line, options,
-        base::BindOnce(&ResultSavingCookieCallback<
-                           CanonicalCookie::CookieInclusionStatus>::Run,
-                       base::Unretained(&callback)));
+    cs->SetCookieWithOptionsAsync(url, cookie_line, options,
+                                  callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result() == CanonicalCookie::CookieInclusionStatus::INCLUDE;
   }
@@ -218,11 +206,8 @@
     CookieOptions options;
     if (can_modify_httponly)
       options.set_include_httponly();
-    cs->SetCanonicalCookieAsync(
-        std::move(cookie), std::move(source_scheme), options,
-        base::BindOnce(&ResultSavingCookieCallback<
-                           CanonicalCookie::CookieInclusionStatus>::Run,
-                       base::Unretained(&callback)));
+    cs->SetCanonicalCookieAsync(std::move(cookie), std::move(source_scheme),
+                                options, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result() == CanonicalCookie::CookieInclusionStatus::INCLUDE;
   }
@@ -257,11 +242,8 @@
 
     DCHECK(cs);
     ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback;
-    cs->SetCookieWithOptionsAsync(
-        url, cookie_line, options,
-        base::BindOnce(&ResultSavingCookieCallback<
-                           CanonicalCookie::CookieInclusionStatus>::Run,
-                       base::Unretained(&callback)));
+    cs->SetCookieWithOptionsAsync(url, cookie_line, options,
+                                  callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result();
   }
@@ -276,11 +258,8 @@
     CookieOptions options;
     if (can_modify_httponly)
       options.set_include_httponly();
-    cs->SetCanonicalCookieAsync(
-        std::move(cookie), std::move(source_scheme), options,
-        base::BindOnce(&ResultSavingCookieCallback<
-                           CanonicalCookie::CookieInclusionStatus>::Run,
-                       base::Unretained(&callback)));
+    cs->SetCanonicalCookieAsync(std::move(cookie), std::move(source_scheme),
+                                options, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result();
   }
@@ -289,9 +268,7 @@
                                  const CanonicalCookie& cookie) {
     DCHECK(cs);
     ResultSavingCookieCallback<uint32_t> callback;
-    cs->DeleteCanonicalCookieAsync(
-        cookie, base::Bind(&ResultSavingCookieCallback<uint32_t>::Run,
-                           base::Unretained(&callback)));
+    cs->DeleteCanonicalCookieAsync(cookie, callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result();
   }
@@ -300,10 +277,8 @@
                                     const TimeRange& creation_range) {
     DCHECK(cs);
     ResultSavingCookieCallback<uint32_t> callback;
-    cs->DeleteAllCreatedInTimeRangeAsync(
-        creation_range,
-        base::BindRepeating(&ResultSavingCookieCallback<uint32_t>::Run,
-                            base::Unretained(&callback)));
+    cs->DeleteAllCreatedInTimeRangeAsync(creation_range,
+                                         callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result();
   }
@@ -312,10 +287,8 @@
                                        CookieDeletionInfo delete_info) {
     DCHECK(cs);
     ResultSavingCookieCallback<uint32_t> callback;
-    cs->DeleteAllMatchingInfoAsync(
-        std::move(delete_info),
-        base::Bind(&ResultSavingCookieCallback<uint32_t>::Run,
-                   base::Unretained(&callback)));
+    cs->DeleteAllMatchingInfoAsync(std::move(delete_info),
+                                   callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result();
   }
@@ -323,9 +296,7 @@
   uint32_t DeleteSessionCookies(CookieStore* cs) {
     DCHECK(cs);
     ResultSavingCookieCallback<uint32_t> callback;
-    cs->DeleteSessionCookiesAsync(
-        base::Bind(&ResultSavingCookieCallback<uint32_t>::Run,
-                   base::Unretained(&callback)));
+    cs->DeleteSessionCookiesAsync(callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result();
   }
@@ -333,8 +304,7 @@
   uint32_t DeleteAll(CookieStore* cs) {
     DCHECK(cs);
     ResultSavingCookieCallback<uint32_t> callback;
-    cs->DeleteAllAsync(base::Bind(&ResultSavingCookieCallback<uint32_t>::Run,
-                                  base::Unretained(&callback)));
+    cs->DeleteAllAsync(callback.MakeCallback());
     callback.WaitUntilDone();
     return callback.result();
   }
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_issuer_key_hash_type b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_issuer_key_hash_type
new file mode 100644
index 0000000..8b001aa
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_issuer_key_hash_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_name_hash_type b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_name_hash_type
new file mode 100644
index 0000000..63084c2
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_name_hash_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_params b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_params
new file mode 100644
index 0000000..059120ed
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_params
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_serial_number_type b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_serial_number_type
new file mode 100644
index 0000000..29224ffd
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/bad_serial_number_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_hash b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_hash
new file mode 100644
index 0000000..595db6b
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_hash
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_hash_oid b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_hash_oid
new file mode 100644
index 0000000..282dbb1
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_hash_oid
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_sequence b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_sequence
new file mode 100644
index 0000000..def7fcb
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_sequence
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_serial_number b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_serial_number
new file mode 100644
index 0000000..6296a22
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/empty_serial_number
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/good b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/good
new file mode 100644
index 0000000..788cbf0
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/good
@@ -0,0 +1,2 @@
+0;0
+*ÏUƒuÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/hash_as_integer b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/hash_as_integer
new file mode 100644
index 0000000..7b407db
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/hash_as_integer
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/hash_oid_as_integer b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/hash_oid_as_integer
new file mode 100644
index 0000000..f2234fb
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/hash_oid_as_integer
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/md4_params b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/md4_params
new file mode 100644
index 0000000..8448edb
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/md4_params
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/negative_serial b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/negative_serial
new file mode 100644
index 0000000..009e7f4
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/negative_serial
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/non_minimal_serial b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/non_minimal_serial
new file mode 100644
index 0000000..32bd979
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/non_minimal_serial
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/not_sequence b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/not_sequence
new file mode 100644
index 0000000..cfcc2fe
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/not_sequence
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/null_params b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/null_params
new file mode 100644
index 0000000..2bc8fb5
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/null_params
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/overlong_serial b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/overlong_serial
new file mode 100644
index 0000000..ee0e2b6
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/overlong_serial
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/trailing_data b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/trailing_data
new file mode 100644
index 0000000..8507597
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/trailing_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/trailing_inner_data b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/trailing_inner_data
new file mode 100644
index 0000000..13f1aec4
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/trailing_inner_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/unknown_hash_oid b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/unknown_hash_oid
new file mode 100644
index 0000000..c11ffee
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/unknown_hash_oid
@@ -0,0 +1 @@
+0	0+
\ No newline at end of file
diff --git a/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/zero_serial b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/zero_serial
new file mode 100644
index 0000000..cb9c66422
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_cert_id_fuzzer/zero_serial
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_produced_at_type b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_produced_at_type
new file mode 100644
index 0000000..033c54b
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_produced_at_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responder_id_key_hash_length b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responder_id_key_hash_length
new file mode 100644
index 0000000..302c64b
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responder_id_key_hash_length
@@ -0,0 +1 @@
+0¢ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responder_id_key_hash_trailing_data b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responder_id_key_hash_trailing_data
new file mode 100644
index 0000000..42906d0
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responder_id_key_hash_trailing_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responder_id_key_hash_type b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responder_id_key_hash_type
new file mode 100644
index 0000000..5b667cc
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responder_id_key_hash_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responses_data b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responses_data
new file mode 100644
index 0000000..6638cbfc
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responses_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responses_type b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responses_type
new file mode 100644
index 0000000..4b09b3c
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/bad_responses_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_extensions b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_extensions
new file mode 100644
index 0000000..c46e843
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_extensions
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_responder_id_name b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_responder_id_name
new file mode 100644
index 0000000..7cb619dc
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_responder_id_name
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_responses b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_responses
new file mode 100644
index 0000000..62840b94
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_responses
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_version b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_version
new file mode 100644
index 0000000..fa20e44
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/empty_version
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/null_responses_data b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/null_responses_data
new file mode 100644
index 0000000..29bbc444
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/null_responses_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/trailing_junk b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/trailing_junk
new file mode 100644
index 0000000..d69f701a
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/trailing_junk
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/trailing_outer_data b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/trailing_outer_data
new file mode 100644
index 0000000..3b73587
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/trailing_outer_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_explicit_default b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_explicit_default
new file mode 100644
index 0000000..15c89fbb5
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_explicit_default
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_too_large b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_too_large
new file mode 100644
index 0000000..4c5e703
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_too_large
@@ -0,0 +1 @@
+0 
\ No newline at end of file
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_too_new b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_too_new
new file mode 100644
index 0000000..6dfd6ad
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_too_new
@@ -0,0 +1 @@
+0 
\ No newline at end of file
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_trailing_data b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_trailing_data
new file mode 100644
index 0000000..75412ad
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/version_trailing_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/wrong_outer_type b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/wrong_outer_type
new file mode 100644
index 0000000..19b3e94
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/wrong_outer_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/wrong_responder_id_type b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/wrong_responder_id_type
new file mode 100644
index 0000000..df0dd6d
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_data_fuzzer/wrong_responder_id_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/baisc_response_bad_data b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/baisc_response_bad_data
new file mode 100644
index 0000000..418147d1
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/baisc_response_bad_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/baisc_response_trailing_data b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/baisc_response_trailing_data
new file mode 100644
index 0000000..6e5c0fe3
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/baisc_response_trailing_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs
new file mode 100644
index 0000000..0460e1af
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs_inner_data b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs_inner_data
new file mode 100644
index 0000000..eb4dd03a
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs_inner_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs_trailing_data b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs_trailing_data
new file mode 100644
index 0000000..9c322c4
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs_trailing_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs_type b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs_type
new file mode 100644
index 0000000..61fd3a2
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_certs_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg
new file mode 100644
index 0000000..2b501de
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_bad_params b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_bad_params
new file mode 100644
index 0000000..cb855ef
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_bad_params
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_bad_sha1_non_empty_params b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_bad_sha1_non_empty_params
new file mode 100644
index 0000000..8a593e7
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_bad_sha1_non_empty_params
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_bad_sha1_params b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_bad_sha1_params
new file mode 100644
index 0000000..497e993
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_bad_sha1_params
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_data_trailing_params b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_data_trailing_params
new file mode 100644
index 0000000..c6ce25e
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_data_trailing_params
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_empty_oid b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_empty_oid
new file mode 100644
index 0000000..b27581b
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_empty_oid
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_oid_type b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_oid_type
new file mode 100644
index 0000000..2a2db0a
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_oid_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_type b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_type
new file mode 100644
index 0000000..cef9501
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_alg_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_type b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_type
new file mode 100644
index 0000000..a0d9616
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_bad_sig_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_empty_certs b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_empty_certs
new file mode 100644
index 0000000..6da3aa0
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_empty_certs
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_empty_sig b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_empty_sig
new file mode 100644
index 0000000..97ef6a9a
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_empty_sig
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_null_certs b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_null_certs
new file mode 100644
index 0000000..73ff9c0
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_null_certs
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_trailing_inner_junk b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_trailing_inner_junk
new file mode 100644
index 0000000..169dbea
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_trailing_inner_junk
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_trailing_junk b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_trailing_junk
new file mode 100644
index 0000000..3ce548d
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_trailing_junk
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_trailing_outer_junk b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_trailing_outer_junk
new file mode 100644
index 0000000..52eb0f86
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/basic_response_trailing_outer_junk
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_bad_oid_type b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_bad_oid_type
new file mode 100644
index 0000000..a821342c
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_bad_oid_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_bad_response_type b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_bad_response_type
new file mode 100644
index 0000000..cd6df83
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_bad_response_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_empty_oid b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_empty_oid
new file mode 100644
index 0000000..63152f7
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_empty_oid
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_empty_response b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_empty_response
new file mode 100644
index 0000000..8c42956
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_empty_response
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_trailing_data b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_trailing_data
new file mode 100644
index 0000000..ffdf181
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_bytes_trailing_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_status_type_out_of_range b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_status_type_out_of_range
new file mode 100644
index 0000000..e96966e
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_status_type_out_of_range
@@ -0,0 +1,2 @@
+0
+
\ No newline at end of file
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_status_type_too_large b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_status_type_too_large
new file mode 100644
index 0000000..a071026
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/response_status_type_too_large
@@ -0,0 +1,2 @@
+0
+
\ No newline at end of file
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/trailing_inner_data b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/trailing_inner_data
new file mode 100644
index 0000000..d3fa1b40
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/trailing_inner_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/trailing_outer_data b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/trailing_outer_data
new file mode 100644
index 0000000..3b73587
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/trailing_outer_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/try_later b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/try_later
new file mode 100644
index 0000000..39e09cf
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/try_later
@@ -0,0 +1,2 @@
+0
+
\ No newline at end of file
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/unused b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/unused
new file mode 100644
index 0000000..38383937
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/unused
@@ -0,0 +1,2 @@
+0
+
\ No newline at end of file
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_basic_response_type b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_basic_response_type
new file mode 100644
index 0000000..7966443
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_basic_response_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_outer_type b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_outer_type
new file mode 100644
index 0000000..bbfb76b
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_outer_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_response_bytes b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_response_bytes
new file mode 100644
index 0000000..0b7768bc
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_response_bytes
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_response_bytes_type b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_response_bytes_type
new file mode 100644
index 0000000..5bd1e98
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_response_bytes_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_response_status_type b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_response_status_type
new file mode 100644
index 0000000..7b407db
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_response_fuzzer/wrong_response_status_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_cert_status_context b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_cert_status_context
new file mode 100644
index 0000000..610d533
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_cert_status_context
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_cert_status_type b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_cert_status_type
new file mode 100644
index 0000000..f3ca9af89
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_cert_status_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_extensions b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_extensions
new file mode 100644
index 0000000..e654d41
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_extensions
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_next_update b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_next_update
new file mode 100644
index 0000000..b04f3adc
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_next_update
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_next_update_trailing_data b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_next_update_trailing_data
new file mode 100644
index 0000000..d228524
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_next_update_trailing_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_next_update_type b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_next_update_type
new file mode 100644
index 0000000..f0d1489
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_next_update_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_outer_type b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_outer_type
new file mode 100644
index 0000000..bbfb76b
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_outer_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_date_offset b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_date_offset
new file mode 100644
index 0000000..85b7ccf
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_date_offset
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_date_type b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_date_type
new file mode 100644
index 0000000..e890edb6
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_date_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_date_value b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_date_value
new file mode 100644
index 0000000..65e3709
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_date_value
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_integer b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_integer
new file mode 100644
index 0000000..03c66fe
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_integer
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_primitive b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_primitive
new file mode 100644
index 0000000..5a849848
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_primitive
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_out_of_range b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_out_of_range
new file mode 100644
index 0000000..a31531c
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_out_of_range
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_too_large b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_too_large
new file mode 100644
index 0000000..bec5172
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_too_large
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_trailing_data b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_trailing_data
new file mode 100644
index 0000000..778630f
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_trailing_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_type b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_type
new file mode 100644
index 0000000..144078b
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_unused b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_unused
new file mode 100644
index 0000000..0bade04
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_reason_value_unused
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_trailing_data b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_trailing_data
new file mode 100644
index 0000000..5e5bcbc
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_revoked_info_trailing_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_this_update_type b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_this_update_type
new file mode 100644
index 0000000..0d82e23
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/bad_this_update_type
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/empty_extensions b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/empty_extensions
new file mode 100644
index 0000000..457a329
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/empty_extensions
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/empty_next_update b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/empty_next_update
new file mode 100644
index 0000000..d401d935
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/empty_next_update
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/no_extensions b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/no_extensions
new file mode 100644
index 0000000..d026ebb
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/no_extensions
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/trailing_inner_data b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/trailing_inner_data
new file mode 100644
index 0000000..5f58d17
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/trailing_inner_data
Binary files differ
diff --git a/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/trailing_outer_data b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/trailing_outer_data
new file mode 100644
index 0000000..8507597
--- /dev/null
+++ b/net/data/fuzzer_data/parse_ocsp_single_response_fuzzer/trailing_outer_data
Binary files differ
diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc
index ab4168da..6eded7b5 100644
--- a/net/http/http_stream_factory.cc
+++ b/net/http/http_stream_factory.cc
@@ -217,14 +217,12 @@
 }
 
 void HttpStreamFactory::OnJobControllerComplete(JobController* controller) {
-  for (auto it = job_controller_set_.begin(); it != job_controller_set_.end();
-       ++it) {
-    if (it->get() == controller) {
-      job_controller_set_.erase(it);
-      return;
-    }
+  auto it = job_controller_set_.find(controller);
+  if (it != job_controller_set_.end()) {
+    job_controller_set_.erase(it);
+  } else {
+    NOTREACHED();
   }
-  NOTREACHED();
 }
 
 HttpStreamFactory::PreconnectingProxyServer::PreconnectingProxyServer(
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index 45a0657..ffffb93 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -13,6 +13,7 @@
 #include <set>
 #include <string>
 
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -123,7 +124,8 @@
 
   friend class HttpStreamFactoryPeer;
 
-  using JobControllerSet = std::set<std::unique_ptr<JobController>>;
+  using JobControllerSet =
+      std::set<std::unique_ptr<JobController>, base::UniquePtrComparator>;
 
   url::SchemeHostPort RewriteHost(const url::SchemeHostPort& server);
 
diff --git a/services/network/p2p/socket_manager.cc b/services/network/p2p/socket_manager.cc
index 475c27ff..071c13e 100644
--- a/services/network/p2p/socket_manager.cc
+++ b/services/network/p2p/socket_manager.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 
-#include <algorithm>
 #include <utility>
 
 #include "base/bind.h"
@@ -374,11 +373,7 @@
     const net::IPAddressList& addresses) {
   std::move(callback).Run(addresses);
 
-  dns_requests_.erase(
-      std::find_if(dns_requests_.begin(), dns_requests_.end(),
-                   [request](const std::unique_ptr<DnsRequest>& ptr) {
-                     return ptr.get() == request;
-                   }));
+  dns_requests_.erase(dns_requests_.find(request));
 }
 
 void P2PSocketManager::OnConnectionError() {
diff --git a/services/network/p2p/socket_manager.h b/services/network/p2p/socket_manager.h
index 191fe96f..4ba2788 100644
--- a/services/network/p2p/socket_manager.h
+++ b/services/network/p2p/socket_manager.h
@@ -14,6 +14,7 @@
 
 #include "base/callback.h"
 #include "base/containers/flat_map.h"
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -121,7 +122,8 @@
 
   base::flat_map<P2PSocket*, std::unique_ptr<P2PSocket>> sockets_;
 
-  std::set<std::unique_ptr<DnsRequest>> dns_requests_;
+  std::set<std::unique_ptr<DnsRequest>, base::UniquePtrComparator>
+      dns_requests_;
   P2PMessageThrottler throttler_;
 
   bool dump_incoming_rtp_packet_ = false;
diff --git a/services/ws/public/mojom/ime/ime.mojom b/services/ws/public/mojom/ime/ime.mojom
index 5548b31..04ca6de 100644
--- a/services/ws/public/mojom/ime/ime.mojom
+++ b/services/ws/public/mojom/ime/ime.mojom
@@ -59,47 +59,6 @@
   mojo_base.mojom.String16 description_body;
 };
 
-// See comments for ui::ImeTextSpan::Type for more details.
-enum ImeTextSpanType {
-  kComposition,
-  kSuggestion,
-  kMisspellingSuggestion,
-};
-
-// This enum represents the thickness of an underline segment of text,
-// the thickness of a ui::ImeTextSpan element.
-// The possible values are:
-// * kNone: When you don't want to paint the underline.
-// * kThin: For regular size.
-// * kThick: For thick underlines.
-enum ImeTextSpanThickness {
-  kNone,
-  kThin,
-  kThick,
-};
-
-// Represents an underlined segment of text currently composed by IME.
-// Corresponds to ui::ImeTextSpan.
-struct ImeTextSpan {
-  ImeTextSpanType type;
-  uint32 start_offset;
-  uint32 end_offset;
-  uint32 underline_color;
-  ImeTextSpanThickness thickness;
-  uint32 background_color;
-  uint32 suggestion_highlight_color;
-  bool remove_on_finish_composing;
-  array<string> suggestions;
-};
-
-// Represents a text currently being composed by IME. Corresponds to
-// ui::CompositionText.
-struct CompositionText {
-  mojo_base.mojom.String16 text;
-  array<ImeTextSpan> ime_text_spans;
-  gfx.mojom.Range selection;
-};
-
 // Represents the text input state of a client.
 struct TextInputState {
   ui.mojom.TextInputType text_input_type;
@@ -123,16 +82,6 @@
   array<bool>? edit_command_enabled;
 };
 
-// Represents how a text client gets focused. Corresponds to
-// ui::TextInputClient::FocusReason.
-enum FocusReason {
-  kNone,   // Not focused.
-  kMouse,  // User initiated with mouse.
-  kTouch,  // User initiated with touch.
-  kPen,    // User initiated with pen.
-  kOther,  // All other reasons (e.g. system initiated, mouse)
-};
-
 // Detailed data of an IME session.
 struct SessionDetails {
   // State of the text input client.
@@ -145,7 +94,7 @@
   TextInputClientData data;
 
   // How the text input client was focused.
-  FocusReason focus_reason;
+  ui.mojom.FocusReason focus_reason;
 
   // ukm::SourceId for identifying the text input client.
   int64 client_source_for_metrics;
@@ -205,7 +154,7 @@
 
   // Sets composition text and attributes. See comments for
   // ui::TextInputClient::SetCompositionText() for more details.
-  SetCompositionText(CompositionText composition);
+  SetCompositionText(ui.mojom.CompositionText composition);
 
   // Converts current composition text into final content.
   ConfirmCompositionText();
diff --git a/services/ws/public/mojom/ime/ime.typemap b/services/ws/public/mojom/ime/ime.typemap
index 325e7354..e1492ceb 100644
--- a/services/ws/public/mojom/ime/ime.typemap
+++ b/services/ws/public/mojom/ime/ime.typemap
@@ -3,31 +3,16 @@
 # found in the LICENSE file.
 
 mojom = "//services/ws/public/mojom/ime/ime.mojom"
-public_headers = [
-  "//ui/base/ime/candidate_window.h",
-  "//ui/base/ime/composition_text.h",
-  "//ui/base/ime/ime_text_span.h",
-  "//ui/base/ime/text_input_client.h",
-  "//ui/base/ime/text_input_mode.h",
-  "//ui/base/ime/text_input_type.h",
-]
+public_headers = [ "//ui/base/ime/candidate_window.h" ]
 traits_headers = [ "//services/ws/public/mojom/ime/ime_struct_traits.h" ]
 sources = [
   "//services/ws/public/mojom/ime/ime_struct_traits.cc",
 ]
 public_deps = [
-  "//ui/base/ime",
-]
-deps = [
-  "//ui/gfx/range",
-  "//ui/gfx/range/mojo:struct_traits",
+  "//ui/base/ime:ime_types",
 ]
 
 type_mappings = [
   "ws.mojom.CandidateWindowEntry=ui::CandidateWindow::Entry",
   "ws.mojom.CandidateWindowProperties=ui::CandidateWindow::CandidateWindowProperty",
-  "ws.mojom.CompositionText=ui::CompositionText",
-  "ws.mojom.FocusReason=ui::TextInputClient::FocusReason",
-  "ws.mojom.ImeTextSpan=ui::ImeTextSpan",
-  "ws.mojom.ImeTextSpanThickness=ui::ImeTextSpan::Thickness",
 ]
diff --git a/services/ws/public/mojom/ime/ime_struct_traits.cc b/services/ws/public/mojom/ime/ime_struct_traits.cc
index 156d7b7..a5bc13b 100644
--- a/services/ws/public/mojom/ime/ime_struct_traits.cc
+++ b/services/ws/public/mojom/ime/ime_struct_traits.cc
@@ -5,7 +5,6 @@
 #include "services/ws/public/mojom/ime/ime_struct_traits.h"
 
 #include "mojo/public/cpp/base/string16_mojom_traits.h"
-#include "ui/gfx/range/mojo/range_struct_traits.h"
 
 namespace mojo {
 
@@ -40,154 +39,4 @@
          data.ReadDescriptionBody(&out->description_body);
 }
 
-// static
-bool StructTraits<ws::mojom::ImeTextSpanDataView, ui::ImeTextSpan>::Read(
-    ws::mojom::ImeTextSpanDataView data,
-    ui::ImeTextSpan* out) {
-  if (data.is_null())
-    return false;
-  if (!data.ReadType(&out->type))
-    return false;
-  out->start_offset = data.start_offset();
-  out->end_offset = data.end_offset();
-  out->underline_color = data.underline_color();
-  if (!data.ReadThickness(&out->thickness))
-    return false;
-  out->background_color = data.background_color();
-  out->suggestion_highlight_color = data.suggestion_highlight_color();
-  out->remove_on_finish_composing = data.remove_on_finish_composing();
-  if (!data.ReadSuggestions(&out->suggestions))
-    return false;
-  return true;
-}
-
-// static
-bool StructTraits<ws::mojom::CompositionTextDataView, ui::CompositionText>::
-    Read(ws::mojom::CompositionTextDataView data, ui::CompositionText* out) {
-  return !data.is_null() && data.ReadText(&out->text) &&
-         data.ReadImeTextSpans(&out->ime_text_spans) &&
-         data.ReadSelection(&out->selection);
-}
-
-// static
-ws::mojom::FocusReason
-EnumTraits<ws::mojom::FocusReason, ui::TextInputClient::FocusReason>::ToMojom(
-    ui::TextInputClient::FocusReason input) {
-  switch (input) {
-    case ui::TextInputClient::FOCUS_REASON_NONE:
-      return ws::mojom::FocusReason::kNone;
-    case ui::TextInputClient::FOCUS_REASON_MOUSE:
-      return ws::mojom::FocusReason::kMouse;
-    case ui::TextInputClient::FOCUS_REASON_TOUCH:
-      return ws::mojom::FocusReason::kTouch;
-    case ui::TextInputClient::FOCUS_REASON_PEN:
-      return ws::mojom::FocusReason::kPen;
-    case ui::TextInputClient::FOCUS_REASON_OTHER:
-      return ws::mojom::FocusReason::kOther;
-  }
-
-  NOTREACHED();
-  return ws::mojom::FocusReason::kNone;
-}
-
-// static
-bool EnumTraits<ws::mojom::FocusReason, ui::TextInputClient::FocusReason>::
-    FromMojom(ws::mojom::FocusReason input,
-              ui::TextInputClient::FocusReason* out) {
-  switch (input) {
-    case ws::mojom::FocusReason::kNone:
-      *out = ui::TextInputClient::FOCUS_REASON_NONE;
-      return true;
-    case ws::mojom::FocusReason::kMouse:
-      *out = ui::TextInputClient::FOCUS_REASON_MOUSE;
-      return true;
-    case ws::mojom::FocusReason::kTouch:
-      *out = ui::TextInputClient::FOCUS_REASON_TOUCH;
-      return true;
-    case ws::mojom::FocusReason::kPen:
-      *out = ui::TextInputClient::FOCUS_REASON_PEN;
-      return true;
-    case ws::mojom::FocusReason::kOther:
-      *out = ui::TextInputClient::FOCUS_REASON_OTHER;
-      return true;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
-// static
-ws::mojom::ImeTextSpanType
-EnumTraits<ws::mojom::ImeTextSpanType, ui::ImeTextSpan::Type>::ToMojom(
-    ui::ImeTextSpan::Type ime_text_span_type) {
-  switch (ime_text_span_type) {
-    case ui::ImeTextSpan::Type::kComposition:
-      return ws::mojom::ImeTextSpanType::kComposition;
-    case ui::ImeTextSpan::Type::kSuggestion:
-      return ws::mojom::ImeTextSpanType::kSuggestion;
-    case ui::ImeTextSpan::Type::kMisspellingSuggestion:
-      return ws::mojom::ImeTextSpanType::kMisspellingSuggestion;
-  }
-
-  NOTREACHED();
-  return ws::mojom::ImeTextSpanType::kComposition;
-}
-
-// static
-bool EnumTraits<ws::mojom::ImeTextSpanType, ui::ImeTextSpan::Type>::FromMojom(
-    ws::mojom::ImeTextSpanType type,
-    ui::ImeTextSpan::Type* out) {
-  switch (type) {
-    case ws::mojom::ImeTextSpanType::kComposition:
-      *out = ui::ImeTextSpan::Type::kComposition;
-      return true;
-    case ws::mojom::ImeTextSpanType::kSuggestion:
-      *out = ui::ImeTextSpan::Type::kSuggestion;
-      return true;
-    case ws::mojom::ImeTextSpanType::kMisspellingSuggestion:
-      *out = ui::ImeTextSpan::Type::kMisspellingSuggestion;
-      return true;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
-// static
-ws::mojom::ImeTextSpanThickness EnumTraits<
-    ws::mojom::ImeTextSpanThickness,
-    ui::ImeTextSpan::Thickness>::ToMojom(ui::ImeTextSpan::Thickness thickness) {
-  switch (thickness) {
-    case ui::ImeTextSpan::Thickness::kNone:
-      return ws::mojom::ImeTextSpanThickness::kNone;
-    case ui::ImeTextSpan::Thickness::kThin:
-      return ws::mojom::ImeTextSpanThickness::kThin;
-    case ui::ImeTextSpan::Thickness::kThick:
-      return ws::mojom::ImeTextSpanThickness::kThick;
-  }
-
-  NOTREACHED();
-  return ws::mojom::ImeTextSpanThickness::kThin;
-}
-
-// static
-bool EnumTraits<ws::mojom::ImeTextSpanThickness, ui::ImeTextSpan::Thickness>::
-    FromMojom(ws::mojom::ImeTextSpanThickness input,
-              ui::ImeTextSpan::Thickness* out) {
-  switch (input) {
-    case ws::mojom::ImeTextSpanThickness::kNone:
-      *out = ui::ImeTextSpan::Thickness::kNone;
-      return true;
-    case ws::mojom::ImeTextSpanThickness::kThin:
-      *out = ui::ImeTextSpan::Thickness::kThin;
-      return true;
-    case ws::mojom::ImeTextSpanThickness::kThick:
-      *out = ui::ImeTextSpan::Thickness::kThick;
-      return true;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
 }  // namespace mojo
diff --git a/services/ws/public/mojom/ime/ime_struct_traits.h b/services/ws/public/mojom/ime/ime_struct_traits.h
index b0974f2..0d7e959 100644
--- a/services/ws/public/mojom/ime/ime_struct_traits.h
+++ b/services/ws/public/mojom/ime/ime_struct_traits.h
@@ -7,11 +7,6 @@
 
 #include "services/ws/public/mojom/ime/ime.mojom-shared.h"
 #include "ui/base/ime/candidate_window.h"
-#include "ui/base/ime/composition_text.h"
-#include "ui/base/ime/ime_text_span.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/base/ime/text_input_mode.h"
-#include "ui/base/ime/text_input_type.h"
 
 namespace mojo {
 
@@ -73,70 +68,6 @@
                    ui::CandidateWindow::Entry* out);
 };
 
-template <>
-struct StructTraits<ws::mojom::CompositionTextDataView, ui::CompositionText> {
-  static base::string16 text(const ui::CompositionText& c) { return c.text; }
-  static ui::ImeTextSpans ime_text_spans(const ui::CompositionText& c) {
-    return c.ime_text_spans;
-  }
-  static gfx::Range selection(const ui::CompositionText& c) {
-    return c.selection;
-  }
-  static bool Read(ws::mojom::CompositionTextDataView data,
-                   ui::CompositionText* out);
-};
-
-template <>
-struct EnumTraits<ws::mojom::FocusReason, ui::TextInputClient::FocusReason> {
-  static ws::mojom::FocusReason ToMojom(ui::TextInputClient::FocusReason input);
-  static bool FromMojom(ws::mojom::FocusReason input,
-                        ui::TextInputClient::FocusReason* out);
-};
-
-template <>
-struct StructTraits<ws::mojom::ImeTextSpanDataView, ui::ImeTextSpan> {
-  static ui::ImeTextSpan::Type type(const ui::ImeTextSpan& c) { return c.type; }
-  static uint32_t start_offset(const ui::ImeTextSpan& c) {
-    return c.start_offset;
-  }
-  static uint32_t end_offset(const ui::ImeTextSpan& c) { return c.end_offset; }
-  static uint32_t underline_color(const ui::ImeTextSpan& c) {
-    return c.underline_color;
-  }
-  static ui::ImeTextSpan::Thickness thickness(const ui::ImeTextSpan& i) {
-    return i.thickness;
-  }
-  static uint32_t background_color(const ui::ImeTextSpan& c) {
-    return c.background_color;
-  }
-  static uint32_t suggestion_highlight_color(const ui::ImeTextSpan& c) {
-    return c.suggestion_highlight_color;
-  }
-  static bool remove_on_finish_composing(const ui::ImeTextSpan& c) {
-    return c.remove_on_finish_composing;
-  }
-  static std::vector<std::string> suggestions(const ui::ImeTextSpan& c) {
-    return c.suggestions;
-  }
-  static bool Read(ws::mojom::ImeTextSpanDataView data, ui::ImeTextSpan* out);
-};
-
-template <>
-struct EnumTraits<ws::mojom::ImeTextSpanType, ui::ImeTextSpan::Type> {
-  static ws::mojom::ImeTextSpanType ToMojom(
-      ui::ImeTextSpan::Type ime_text_span_type);
-  static bool FromMojom(ws::mojom::ImeTextSpanType input,
-                        ui::ImeTextSpan::Type* out);
-};
-
-template <>
-struct EnumTraits<ws::mojom::ImeTextSpanThickness, ui::ImeTextSpan::Thickness> {
-  static ws::mojom::ImeTextSpanThickness ToMojom(
-      ui::ImeTextSpan::Thickness thickness);
-  static bool FromMojom(ws::mojom::ImeTextSpanThickness input,
-                        ui::ImeTextSpan::Thickness* out);
-};
-
 }  // namespace mojo
 
 #endif  // SERVICES_WS_PUBLIC_MOJOM_IME_IME_STRUCT_TRAITS_H_
diff --git a/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc b/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc
index f122553..ad28ee1f 100644
--- a/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc
+++ b/services/ws/public/mojom/ime/ime_struct_traits_unittest.cc
@@ -12,9 +12,6 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/ws/public/mojom/ime/ime.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/ime/composition_text.h"
-#include "ui/base/ime/ime_text_span.h"
-#include "ui/gfx/range/mojo/range_struct_traits.h"
 
 namespace ws {
 
@@ -87,24 +84,4 @@
   EXPECT_EQ(input.description_body, output.description_body);
 }
 
-TEST_F(IMEStructTraitsTest, CompositionText) {
-  ui::CompositionText input;
-  input.text = base::UTF8ToUTF16("abcdefghij");
-  ui::ImeTextSpan ime_text_span_1(0, 2, ui::ImeTextSpan::Thickness::kThin);
-  ime_text_span_1.underline_color = SK_ColorGRAY;
-  input.ime_text_spans.push_back(ime_text_span_1);
-  ui::ImeTextSpan ime_text_span_2(ui::ImeTextSpan::Type::kComposition, 3, 6,
-                                  ui::ImeTextSpan::Thickness::kThick,
-                                  SK_ColorGREEN);
-  ime_text_span_2.underline_color = SK_ColorRED;
-  input.ime_text_spans.push_back(ime_text_span_2);
-  input.selection = gfx::Range(1, 7);
-
-  ui::CompositionText output;
-  EXPECT_TRUE(mojom::CompositionText::Deserialize(
-      mojom::CompositionText::Serialize(&input), &output));
-
-  EXPECT_EQ(input, output);
-}
-
 }  // namespace ws
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index e08bf46..15f65a1 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2976,6 +2976,28 @@
             ]
         }
     ],
+    "NetUnusedIdleSocketTimeout": [
+        {
+            "platforms": [
+                "android",
+                "windows",
+                "mac",
+                "chromeos",
+                "linux"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_300_seconds_20190314",
+                    "params": {
+                        "unused_idle_socket_timeout_seconds": "300"
+                    },
+                    "enable_features": [
+                        "NetUnusedIdleSocketTimeout"
+                    ]
+                }
+            ]
+        }
+    ],
     "NetworkQualityEstimator": [
         {
             "platforms": [
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index e9778e6..5364917 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -538,10 +538,10 @@
   public_deps = [
     "//net",
     "//services/service_manager/public/cpp",
-    "//services/ws/public/mojom/ime",
     "//skia",
     "//third_party/blink/public/common",
     "//ui/accessibility:ax_enums_mojo",
+    "//ui/base/ime/mojo",
     "//url",
   ]
 
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 343118e..e3e5c000 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2239,7 +2239,6 @@
   kRTCStatsRelativePacketArrivalDelay = 2827,
 
   // The above items are available in M74 branch.
-  kFlexboxWithOverflowFlexItemIntrinsicSize = 2828,
   kCSSSelectorHostContextInSnapshotProfile = 2829,
   kCSSSelectorHostContextInLiveProfile = 2830,
   kImportMap = 2831,
diff --git a/third_party/blink/public/web/DEPS b/third_party/blink/public/web/DEPS
index 6489048..38d6dc41 100644
--- a/third_party/blink/public/web/DEPS
+++ b/third_party/blink/public/web/DEPS
@@ -22,10 +22,10 @@
     "+services/service_manager/public",
     # Enforce to use mojom-shared.h in blink/public so that it can compile
     # inside and outside Blink.
-    "+services/ws/public/mojom/ime/ime.mojom-shared.h",
     "+third_party/blink/public/platform",
     "+third_party/blink/public/web",
     "+ui/accessibility/ax_enums.mojom-shared.h",
+    "+ui/base/ime/mojo/ime_types.mojom-shared.h",
 
     # Allowed only inside INSIDE_BLINK
     "+third_party/blink/renderer/core",
diff --git a/third_party/blink/public/web/web_ime_text_span.h b/third_party/blink/public/web/web_ime_text_span.h
index 94fa241..9fb26aae 100644
--- a/third_party/blink/public/web/web_ime_text_span.h
+++ b/third_party/blink/public/web/web_ime_text_span.h
@@ -34,8 +34,8 @@
 #include <string>
 #include <vector>
 
-#include "services/ws/public/mojom/ime/ime.mojom-shared.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/ime/mojo/ime_types.mojom-shared.h"
 
 namespace blink {
 
@@ -58,7 +58,7 @@
       : type(Type::kComposition),
         start_offset(0),
         end_offset(0),
-        thickness(ws::mojom::ImeTextSpanThickness::kThin),
+        thickness(ui::mojom::ImeTextSpanThickness::kThin),
         background_color(0),
         suggestion_highlight_color(0),
         suggestions(std::vector<std::string>()) {}
@@ -67,7 +67,7 @@
       Type ty,
       unsigned s,
       unsigned e,
-      ws::mojom::ImeTextSpanThickness th,
+      ui::mojom::ImeTextSpanThickness th,
       SkColor bc,
       SkColor shc = 0,
       const std::vector<std::string>& su = std::vector<std::string>())
@@ -91,7 +91,7 @@
   unsigned start_offset;
   unsigned end_offset;
   SkColor underline_color = SK_ColorTRANSPARENT;
-  ws::mojom::ImeTextSpanThickness thickness;
+  ui::mojom::ImeTextSpanThickness thickness;
   SkColor background_color;
   SkColor suggestion_highlight_color;
   bool remove_on_finish_composing;
diff --git a/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl
index 137742a..ae2d194 100644
--- a/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/origin_trials.cc.tmpl
@@ -52,11 +52,10 @@
 bool origin_trials::{{feature.name}}Enabled(const ExecutionContext* executionContext) {
   if (RuntimeEnabledFeatures::{{feature.name}}EnabledByRuntimeFlag())
     return true;
-{%- for depends_on in feature.depends_on %}
+{% for depends_on in feature.depends_on %}
   if (!RuntimeEnabledFeatures::{{depends_on}}Enabled())
     return false;
-{%- endfor %}
-
+{% endfor %}
   const OriginTrialContext* context = OriginTrialContext::From(executionContext);
   if (!context) return false;
   if (context->IsFeatureEnabled(OriginTrialFeature::k{{feature.name}}))
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index e1ab9cd..7fe3498 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -102,7 +102,6 @@
   public_deps = [
     "//services/network/public/cpp:cpp",
     "//services/service_manager/public/cpp",
-    "//services/ws/public/mojom/ime",
     "//skia",
     "//third_party/angle:translator",
     "//third_party/blink/public:core_mojo_bindings_blink",
@@ -118,6 +117,7 @@
     "//third_party/ots",
     "//third_party/snappy",
     "//third_party/zlib",
+    "//ui/base/ime/mojo",
     "//ui/events:dom_keycode_converter",
     "//ui/gfx/geometry",
     "//ui/native_theme",
diff --git a/third_party/blink/renderer/core/DEPS b/third_party/blink/renderer/core/DEPS
index 43985918..41da7a6 100644
--- a/third_party/blink/renderer/core/DEPS
+++ b/third_party/blink/renderer/core/DEPS
@@ -55,7 +55,6 @@
     "+services/resource_coordinator/public/cpp/resource_coordinator_features.h",
     "+services/resource_coordinator/public/mojom/coordination_unit.mojom-blink.h",
     "+services/service_manager/public",
-    "+services/ws/public/mojom/ime/ime.mojom-shared.h",
     "+skia/public/interfaces/bitmap_skbitmap_struct_traits.h",
     "+skia/ext/image_operations.h",
     "+skia/ext/skia_utils_mac.h",
@@ -68,6 +67,7 @@
     "+third_party/blink/renderer/core",
     "-third_party/blink/renderer/modules",
     "+third_party/skia/include",
+    "+ui/base/ime/mojo/ime_types.mojom-shared.h",
     "+ui/gfx/geometry",
     "+ui/gfx/skia_util.h",
     "-web",
diff --git a/third_party/blink/renderer/core/editing/ime/ime_text_span.cc b/third_party/blink/renderer/core/editing/ime/ime_text_span.cc
index 9295aab..8463319c 100644
--- a/third_party/blink/renderer/core/editing/ime/ime_text_span.cc
+++ b/third_party/blink/renderer/core/editing/ime/ime_text_span.cc
@@ -13,7 +13,7 @@
                          unsigned start_offset,
                          unsigned end_offset,
                          const Color& underline_color,
-                         ws::mojom::ImeTextSpanThickness thickness,
+                         ui::mojom::ImeTextSpanThickness thickness,
                          const Color& background_color,
                          const Color& suggestion_highlight_color,
                          bool remove_on_finish_composing,
diff --git a/third_party/blink/renderer/core/editing/ime/ime_text_span.h b/third_party/blink/renderer/core/editing/ime/ime_text_span.h
index 8a317d5..6215e623 100644
--- a/third_party/blink/renderer/core/editing/ime/ime_text_span.h
+++ b/third_party/blink/renderer/core/editing/ime/ime_text_span.h
@@ -26,12 +26,12 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_IME_IME_TEXT_SPAN_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_IME_IME_TEXT_SPAN_H_
 
-#include "services/ws/public/mojom/ime/ime.mojom-shared.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "ui/base/ime/mojo/ime_types.mojom-shared.h"
 
 namespace blink {
 
@@ -47,7 +47,7 @@
               unsigned start_offset,
               unsigned end_offset,
               const Color& underline_color,
-              ws::mojom::ImeTextSpanThickness,
+              ui::mojom::ImeTextSpanThickness,
               const Color& background_color,
               const Color& suggestion_highlight_color = Color::kTransparent,
               bool remove_on_finish_composing = false,
@@ -59,7 +59,7 @@
   unsigned StartOffset() const { return start_offset_; }
   unsigned EndOffset() const { return end_offset_; }
   const Color& UnderlineColor() const { return underline_color_; }
-  ws::mojom::ImeTextSpanThickness Thickness() const { return thickness_; }
+  ui::mojom::ImeTextSpanThickness Thickness() const { return thickness_; }
   const Color& BackgroundColor() const { return background_color_; }
   const Color& SuggestionHighlightColor() const {
     return suggestion_highlight_color_;
@@ -74,7 +74,7 @@
   unsigned start_offset_;
   unsigned end_offset_;
   Color underline_color_;
-  ws::mojom::ImeTextSpanThickness thickness_;
+  ui::mojom::ImeTextSpanThickness thickness_;
   Color background_color_;
   Color suggestion_highlight_color_;
   bool remove_on_finish_composing_;
diff --git a/third_party/blink/renderer/core/editing/ime/ime_text_span_test.cc b/third_party/blink/renderer/core/editing/ime/ime_text_span_test.cc
index d8e1764..6118240 100644
--- a/third_party/blink/renderer/core/editing/ime/ime_text_span_test.cc
+++ b/third_party/blink/renderer/core/editing/ime/ime_text_span_test.cc
@@ -12,7 +12,7 @@
 ImeTextSpan CreateImeTextSpan(unsigned start_offset, unsigned end_offset) {
   return ImeTextSpan(ImeTextSpan::Type::kComposition, start_offset, end_offset,
                      Color::kTransparent,
-                     ws::mojom::ImeTextSpanThickness::kNone,
+                     ui::mojom::ImeTextSpanThickness::kNone,
                      Color::kTransparent);
 }
 
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
index 930f404..07874c0 100644
--- a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
+++ b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
@@ -912,7 +912,7 @@
   if (ime_text_spans.IsEmpty()) {
     GetDocument().Markers().AddCompositionMarker(
         CompositionEphemeralRange(), Color::kTransparent,
-        ws::mojom::ImeTextSpanThickness::kThin,
+        ui::mojom::ImeTextSpanThickness::kThin,
         LayoutTheme::GetTheme().PlatformDefaultCompositionBackgroundColor());
     return;
   }
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
index a015b21..5177fdf9 100644
--- a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
+++ b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
@@ -23,7 +23,7 @@
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
 
-using ws::mojom::ImeTextSpanThickness;
+using ui::mojom::ImeTextSpanThickness;
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/editing/markers/active_suggestion_marker.cc b/third_party/blink/renderer/core/editing/markers/active_suggestion_marker.cc
index 0c410be..926d2c85 100644
--- a/third_party/blink/renderer/core/editing/markers/active_suggestion_marker.cc
+++ b/third_party/blink/renderer/core/editing/markers/active_suggestion_marker.cc
@@ -10,7 +10,7 @@
     unsigned start_offset,
     unsigned end_offset,
     Color underline_color,
-    ws::mojom::ImeTextSpanThickness thickness,
+    ui::mojom::ImeTextSpanThickness thickness,
     Color background_color)
     : StyleableMarker(start_offset,
                       end_offset,
diff --git a/third_party/blink/renderer/core/editing/markers/active_suggestion_marker.h b/third_party/blink/renderer/core/editing/markers/active_suggestion_marker.h
index 1f14b3a7..4c559c2 100644
--- a/third_party/blink/renderer/core/editing/markers/active_suggestion_marker.h
+++ b/third_party/blink/renderer/core/editing/markers/active_suggestion_marker.h
@@ -17,7 +17,7 @@
   ActiveSuggestionMarker(unsigned start_offset,
                          unsigned end_offset,
                          Color underline_color,
-                         ws::mojom::ImeTextSpanThickness,
+                         ui::mojom::ImeTextSpanThickness,
                          Color background_color);
 
   // DocumentMarker implementations
diff --git a/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_list_impl_test.cc b/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_list_impl_test.cc
index fa085a4..3278806 100644
--- a/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_list_impl_test.cc
+++ b/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_list_impl_test.cc
@@ -17,7 +17,7 @@
   DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) {
     return MakeGarbageCollected<ActiveSuggestionMarker>(
         start_offset, end_offset, Color::kTransparent,
-        ws::mojom::ImeTextSpanThickness::kThin, Color::kBlack);
+        ui::mojom::ImeTextSpanThickness::kThin, Color::kBlack);
   }
 
   Persistent<ActiveSuggestionMarkerListImpl> marker_list_;
diff --git a/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_test.cc b/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_test.cc
index d4921c61..1e3872b 100644
--- a/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_test.cc
+++ b/third_party/blink/renderer/core/editing/markers/active_suggestion_marker_test.cc
@@ -6,7 +6,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
-using ws::mojom::ImeTextSpanThickness;
+using ui::mojom::ImeTextSpanThickness;
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/editing/markers/composition_marker.cc b/third_party/blink/renderer/core/editing/markers/composition_marker.cc
index b0c2616..954fa2a 100644
--- a/third_party/blink/renderer/core/editing/markers/composition_marker.cc
+++ b/third_party/blink/renderer/core/editing/markers/composition_marker.cc
@@ -9,7 +9,7 @@
 CompositionMarker::CompositionMarker(unsigned start_offset,
                                      unsigned end_offset,
                                      Color underline_color,
-                                     ws::mojom::ImeTextSpanThickness thickness,
+                                     ui::mojom::ImeTextSpanThickness thickness,
                                      Color background_color)
     : StyleableMarker(start_offset,
                       end_offset,
diff --git a/third_party/blink/renderer/core/editing/markers/composition_marker.h b/third_party/blink/renderer/core/editing/markers/composition_marker.h
index 3db0263..ba5af65c 100644
--- a/third_party/blink/renderer/core/editing/markers/composition_marker.h
+++ b/third_party/blink/renderer/core/editing/markers/composition_marker.h
@@ -19,7 +19,7 @@
   CompositionMarker(unsigned start_offset,
                     unsigned end_offset,
                     Color underline_color,
-                    ws::mojom::ImeTextSpanThickness,
+                    ui::mojom::ImeTextSpanThickness,
                     Color background_color);
 
   // DocumentMarker implementations
diff --git a/third_party/blink/renderer/core/editing/markers/composition_marker_list_impl_test.cc b/third_party/blink/renderer/core/editing/markers/composition_marker_list_impl_test.cc
index fc7fd27..d1d3b40 100644
--- a/third_party/blink/renderer/core/editing/markers/composition_marker_list_impl_test.cc
+++ b/third_party/blink/renderer/core/editing/markers/composition_marker_list_impl_test.cc
@@ -18,7 +18,7 @@
   DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) {
     return MakeGarbageCollected<CompositionMarker>(
         start_offset, end_offset, Color::kTransparent,
-        ws::mojom::ImeTextSpanThickness::kThin, Color::kBlack);
+        ui::mojom::ImeTextSpanThickness::kThin, Color::kBlack);
   }
 
   Persistent<CompositionMarkerListImpl> marker_list_;
diff --git a/third_party/blink/renderer/core/editing/markers/composition_marker_test.cc b/third_party/blink/renderer/core/editing/markers/composition_marker_test.cc
index 7414cfa6..5bf0d80 100644
--- a/third_party/blink/renderer/core/editing/markers/composition_marker_test.cc
+++ b/third_party/blink/renderer/core/editing/markers/composition_marker_test.cc
@@ -6,7 +6,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
-using ws::mojom::ImeTextSpanThickness;
+using ui::mojom::ImeTextSpanThickness;
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc b/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
index f7dc533..99d9bea 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
@@ -182,7 +182,7 @@
 void DocumentMarkerController::AddCompositionMarker(
     const EphemeralRange& range,
     Color underline_color,
-    ws::mojom::ImeTextSpanThickness thickness,
+    ui::mojom::ImeTextSpanThickness thickness,
     Color background_color) {
   DCHECK(!document_->NeedsLayoutTreeUpdate());
   AddMarkerInternal(range, [underline_color, thickness, background_color](
@@ -195,7 +195,7 @@
 void DocumentMarkerController::AddActiveSuggestionMarker(
     const EphemeralRange& range,
     Color underline_color,
-    ws::mojom::ImeTextSpanThickness thickness,
+    ui::mojom::ImeTextSpanThickness thickness,
     Color background_color) {
   DCHECK(!document_->NeedsLayoutTreeUpdate());
   AddMarkerInternal(range, [underline_color, thickness, background_color](
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller.h b/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
index b16ee42..e0a51ae 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
@@ -66,11 +66,11 @@
   void AddTextMatchMarker(const EphemeralRange&, TextMatchMarker::MatchStatus);
   void AddCompositionMarker(const EphemeralRange&,
                             Color underline_color,
-                            ws::mojom::ImeTextSpanThickness,
+                            ui::mojom::ImeTextSpanThickness,
                             Color background_color);
   void AddActiveSuggestionMarker(const EphemeralRange&,
                                  Color underline_color,
-                                 ws::mojom::ImeTextSpanThickness,
+                                 ui::mojom::ImeTextSpanThickness,
                                  Color background_color);
   void AddSuggestionMarker(const EphemeralRange&,
                            const SuggestionMarkerProperties&);
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc b/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
index 498146a..871086e 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
@@ -240,10 +240,10 @@
   Node* text = GetDocument().body()->firstChild()->firstChild();
   MarkerController().AddCompositionMarker(
       EphemeralRange(Position(text, 0), Position(text, 1)), Color::kTransparent,
-      ws::mojom::ImeTextSpanThickness::kThin, Color::kBlack);
+      ui::mojom::ImeTextSpanThickness::kThin, Color::kBlack);
   MarkerController().AddCompositionMarker(
       EphemeralRange(Position(text, 1), Position(text, 3)), Color::kTransparent,
-      ws::mojom::ImeTextSpanThickness::kThick, Color::kBlack);
+      ui::mojom::ImeTextSpanThickness::kThick, Color::kBlack);
 
   EXPECT_EQ(2u, MarkerController().Markers().size());
 }
diff --git a/third_party/blink/renderer/core/editing/markers/styleable_marker.cc b/third_party/blink/renderer/core/editing/markers/styleable_marker.cc
index 15826e6e..51691b29 100644
--- a/third_party/blink/renderer/core/editing/markers/styleable_marker.cc
+++ b/third_party/blink/renderer/core/editing/markers/styleable_marker.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/core/editing/markers/styleable_marker.h"
 
-using ws::mojom::ImeTextSpanThickness;
+using ui::mojom::ImeTextSpanThickness;
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/editing/markers/styleable_marker.h b/third_party/blink/renderer/core/editing/markers/styleable_marker.h
index 0074660..d58e82fd 100644
--- a/third_party/blink/renderer/core/editing/markers/styleable_marker.h
+++ b/third_party/blink/renderer/core/editing/markers/styleable_marker.h
@@ -5,8 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_STYLEABLE_MARKER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_STYLEABLE_MARKER_H_
 
-#include "services/ws/public/mojom/ime/ime.mojom-shared.h"
 #include "third_party/blink/renderer/core/editing/markers/document_marker.h"
+#include "ui/base/ime/mojo/ime_types.mojom-shared.h"
 
 namespace blink {
 
@@ -17,7 +17,7 @@
   StyleableMarker(unsigned start_offset,
                   unsigned end_offset,
                   Color underline_color,
-                  ws::mojom::ImeTextSpanThickness,
+                  ui::mojom::ImeTextSpanThickness,
                   Color background_color);
 
   // StyleableMarker-specific
@@ -31,7 +31,7 @@
  private:
   const Color underline_color_;
   const Color background_color_;
-  const ws::mojom::ImeTextSpanThickness thickness_;
+  const ui::mojom::ImeTextSpanThickness thickness_;
 
   DISALLOW_COPY_AND_ASSIGN(StyleableMarker);
 };
diff --git a/third_party/blink/renderer/core/editing/markers/suggestion_marker_properties.cc b/third_party/blink/renderer/core/editing/markers/suggestion_marker_properties.cc
index 414c696..4e446603 100644
--- a/third_party/blink/renderer/core/editing/markers/suggestion_marker_properties.cc
+++ b/third_party/blink/renderer/core/editing/markers/suggestion_marker_properties.cc
@@ -65,7 +65,7 @@
 
 SuggestionMarkerProperties::Builder&
 SuggestionMarkerProperties::Builder::SetThickness(
-    ws::mojom::ImeTextSpanThickness thickness) {
+    ui::mojom::ImeTextSpanThickness thickness) {
   data_.thickness_ = thickness;
   return *this;
 }
diff --git a/third_party/blink/renderer/core/editing/markers/suggestion_marker_properties.h b/third_party/blink/renderer/core/editing/markers/suggestion_marker_properties.h
index 3fe4bc29..a69b47a 100644
--- a/third_party/blink/renderer/core/editing/markers/suggestion_marker_properties.h
+++ b/third_party/blink/renderer/core/editing/markers/suggestion_marker_properties.h
@@ -9,7 +9,7 @@
 #include "third_party/blink/renderer/core/editing/markers/styleable_marker.h"
 #include "third_party/blink/renderer/core/editing/markers/suggestion_marker.h"
 
-using ws::mojom::ImeTextSpanThickness;
+using ui::mojom::ImeTextSpanThickness;
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/editing/markers/suggestion_marker_test.cc b/third_party/blink/renderer/core/editing/markers/suggestion_marker_test.cc
index f5e81d7a..6aad718 100644
--- a/third_party/blink/renderer/core/editing/markers/suggestion_marker_test.cc
+++ b/third_party/blink/renderer/core/editing/markers/suggestion_marker_test.cc
@@ -32,7 +32,7 @@
           .SetSuggestions(suggestions)
           .SetHighlightColor(Color::kTransparent)
           .SetUnderlineColor(Color::kDarkGray)
-          .SetThickness(ws::mojom::ImeTextSpanThickness::kThin)
+          .SetThickness(ui::mojom::ImeTextSpanThickness::kThin)
           .SetBackgroundColor(Color::kGray)
           .Build());
   EXPECT_EQ(suggestions, marker->Suggestions());
@@ -47,7 +47,7 @@
       SuggestionMarkerProperties::Builder()
           .SetType(SuggestionMarker::SuggestionType::kMisspelling)
           .SetHighlightColor(Color::kBlack)
-          .SetThickness(ws::mojom::ImeTextSpanThickness::kThick)
+          .SetThickness(ui::mojom::ImeTextSpanThickness::kThick)
           .Build());
   EXPECT_TRUE(marker2->HasThicknessThick());
   EXPECT_TRUE(marker2->IsMisspelling());
diff --git a/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc b/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc
index be988931..38f71c8 100644
--- a/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc
+++ b/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc
@@ -424,7 +424,7 @@
   GetFrame().Selection().SetCaretVisible(false);
   GetDocument().Markers().AddActiveSuggestionMarker(
       active_suggestion_range, SK_ColorTRANSPARENT,
-      ws::mojom::ImeTextSpanThickness::kNone,
+      ui::mojom::ImeTextSpanThickness::kNone,
       LayoutTheme::GetTheme().PlatformActiveSpellingMarkerHighlightColor());
 
   Vector<String> suggestions;
@@ -489,7 +489,7 @@
                                     Position(text_node, span_union_end));
 
   GetDocument().Markers().AddActiveSuggestionMarker(
-      marker_range, SK_ColorTRANSPARENT, ws::mojom::ImeTextSpanThickness::kThin,
+      marker_range, SK_ColorTRANSPARENT, ui::mojom::ImeTextSpanThickness::kThin,
       suggestion_infos_with_node_and_highlight_color.highlight_color);
 
   is_suggestion_menu_open_ = true;
diff --git a/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller_test.cc b/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller_test.cc
index a86bfbe..aaa175fa 100644
--- a/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller_test.cc
+++ b/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller_test.cc
@@ -13,7 +13,7 @@
 #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
 #include "third_party/blink/renderer/core/editing/visible_selection.h"
 
-using ws::mojom::ImeTextSpanThickness;
+using ui::mojom::ImeTextSpanThickness;
 
 namespace blink {
 
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 90b689d6..e22f352 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -1587,7 +1587,7 @@
   web_view->SetInitialFocus(false);
   WebVector<WebImeTextSpan> ime_text_spans(static_cast<size_t>(1));
   ime_text_spans[0] = WebImeTextSpan(WebImeTextSpan::Type::kComposition, 0, 4,
-                                     ws::mojom::ImeTextSpanThickness::kThin, 0);
+                                     ui::mojom::ImeTextSpanThickness::kThin, 0);
   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
   WebInputMethodController* active_input_method_controller =
       frame->GetInputMethodController();
@@ -1614,7 +1614,7 @@
   web_view->SetInitialFocus(false);
   WebVector<WebImeTextSpan> ime_text_spans(static_cast<size_t>(1));
   ime_text_spans[0] = WebImeTextSpan(WebImeTextSpan::Type::kComposition, 0, 4,
-                                     ws::mojom::ImeTextSpanThickness::kThin, 0);
+                                     ui::mojom::ImeTextSpanThickness::kThin, 0);
   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
   WebInputMethodController* active_input_method_controller =
       frame->FrameWidget()->GetActiveWebInputMethodController();
@@ -1658,7 +1658,7 @@
   web_view->SetInitialFocus(false);
   WebVector<WebImeTextSpan> ime_text_spans(static_cast<size_t>(1));
   ime_text_spans[0] = WebImeTextSpan(WebImeTextSpan::Type::kComposition, 0, 4,
-                                     ws::mojom::ImeTextSpanThickness::kThin, 0);
+                                     ui::mojom::ImeTextSpanThickness::kThin, 0);
   WebLocalFrameImpl* frame = web_view->MainFrameImpl();
   frame->SetEditableSelectionOffsets(1, 1);
   WebDocument document = web_view->MainFrameImpl()->GetDocument();
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 7bb3906..136a804a 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -386,11 +386,10 @@
   if (!Client())
     return;
 
-  // stopAllLoaders() needs to be called after detachChildren(), because
+  // Detach() needs to be called after detachChildren(), because
   // detachChildren() will trigger the unload event handlers of any child
   // frames, and those event handlers might start a new subresource load in this
-  // frame.
-  loader_.StopAllLoaders();
+  // frame which should be stopped by Detach.
   loader_.Detach();
   GetDocument()->Shutdown();
 
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index 44e5bda..11827668 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -94,31 +94,6 @@
     max_preferred_logical_width += margin;
     if (!IsColumnFlow()) {
       max_logical_width += max_preferred_logical_width;
-
-      EOverflow overflow = StyleRef().IsHorizontalWritingMode()
-                               ? child->StyleRef().OverflowX()
-                               : child->StyleRef().OverflowY();
-      const Length& main_axis_length = IsHorizontalFlow()
-                                           ? child->StyleRef().Width()
-                                           : child->StyleRef().Height();
-      // This code experimentally implements the proposal in
-      // https://github.com/w3c/csswg-drafts/issues/1865
-      // to see if it is web-compatible.
-      if (overflow != EOverflow::kVisible && !main_axis_length.IsFixed()) {
-        LayoutUnit border_and_padding =
-            StyleRef().IsHorizontalWritingMode()
-                ? child->BorderAndPaddingWidth() +
-                      child->VerticalScrollbarWidth()
-                : child->BorderAndPaddingHeight() +
-                      child->HorizontalScrollbarHeight();
-        if (min_preferred_logical_width != margin + border_and_padding) {
-          min_preferred_logical_width = margin + border_and_padding;
-          UseCounter::Count(
-              GetDocument(),
-              WebFeature::kFlexboxWithOverflowFlexItemIntrinsicSize);
-        }
-      }
-
       if (IsMultiline()) {
         // For multiline, the min preferred width is if you put a break between
         // each item.
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.h b/third_party/blink/renderer/core/layout/layout_flexible_box.h
index e8565c9..3df70c5 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.h
@@ -162,6 +162,7 @@
                                  const Length& flex_basis) const;
   bool NeedToStretchChildLogicalHeight(const LayoutBox& child) const;
   bool ChildHasIntrinsicMainAxisSize(const LayoutBox& child) const;
+  EOverflow MainAxisOverflowForChild(const LayoutBox& child) const;
   EOverflow CrossAxisOverflowForChild(const LayoutBox& child) const;
   void CacheChildMainSize(const LayoutBox& child);
   bool CanAvoidLayoutForNGChild(const LayoutBox& child) const;
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 7e97ab7..34ba3ab 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -191,11 +191,9 @@
 FrameLoader::FrameLoader(LocalFrame* frame)
     : frame_(frame),
       progress_tracker_(ProgressTracker::Create(frame)),
-      in_stop_all_loaders_(false),
       in_restore_scroll_(false),
       forced_sandbox_flags_(kSandboxNone),
       dispatching_did_clear_window_object_in_main_world_(false),
-      protect_provisional_loader_(false),
       detached_(false),
       virtual_time_pauser_(
           frame_->GetFrameScheduler()->CreateWebScopedVirtualTimePauser(
@@ -317,10 +315,6 @@
 
 void FrameLoader::DispatchUnloadEvent() {
   FrameNavigationDisabler navigation_disabler(*frame_);
-
-  // If the frame is unloading, the provisional loader should no longer be
-  // protected. It will be detached soon.
-  protect_provisional_loader_ = false;
   SaveScrollState();
 
   Document* document = frame_->GetDocument();
@@ -811,9 +805,6 @@
   if (HTMLFrameOwnerElement* element = frame_->DeprecatedLocalOwner())
     element->CancelPendingLazyLoad();
 
-  if (in_stop_all_loaders_)
-    return;
-
   FrameLoadRequest request(passed_request);
   ResourceRequest& resource_request = request.GetResourceRequest();
   const KURL& url = resource_request.Url();
@@ -977,7 +968,7 @@
   DCHECK(frame_->GetDocument());
   DCHECK(Client()->HasWebView());
 
-  if (in_stop_all_loaders_ || !frame_->IsNavigationAllowed() ||
+  if (!frame_->IsNavigationAllowed() ||
       frame_->GetDocument()->PageDismissalEventBeingDispatched() !=
           Document::kNoDismissal) {
     // Any of the checks above should not be necessary.
@@ -1058,12 +1049,9 @@
   DCHECK(!IsReloadLoadType(frame_load_type));
   DCHECK(frame_->GetDocument());
 
-  if (in_stop_all_loaders_)
-    return mojom::CommitResult::Aborted;
-
   bool history_navigation = IsBackForwardLoadType(frame_load_type);
 
-  if (!frame_->IsNavigationAllowed() && history_navigation)
+  if (!frame_->IsNavigationAllowed())
     return mojom::CommitResult::Aborted;
 
   if (!history_navigation) {
@@ -1123,16 +1111,15 @@
 }
 
 void FrameLoader::StopAllLoaders() {
-  if (frame_->GetDocument()->PageDismissalEventBeingDispatched() !=
-      Document::kNoDismissal)
+  if (!frame_->IsNavigationAllowed() ||
+      frame_->GetDocument()->PageDismissalEventBeingDispatched() !=
+          Document::kNoDismissal) {
     return;
+  }
 
-  // If this method is called from within this method, infinite recursion can
-  // occur (3442218). Avoid this.
-  if (in_stop_all_loaders_)
-    return;
-
-  base::AutoReset<bool> in_stop_all_loaders(&in_stop_all_loaders_, true);
+  // This method could be called from within this method, e.g. through plugin
+  // detach. Avoid infinite recursion by disabling navigations.
+  FrameNavigationDisabler navigation_disabler(*frame_);
 
   for (Frame* child = frame_->Tree().FirstChild(); child;
        child = child->Tree().NextSibling()) {
@@ -1143,8 +1130,7 @@
   frame_->GetDocument()->CancelParsing();
   if (document_loader_)
     document_loader_->StopLoading();
-  if (!protect_provisional_loader_)
-    DetachDocumentLoader(provisional_document_loader_);
+  DetachDocumentLoader(provisional_document_loader_);
   frame_->GetNavigationScheduler().Cancel();
   DidFinishNavigation();
 
@@ -1198,23 +1184,24 @@
   frame_->DetachChildren();
   // The previous calls to dispatchUnloadEvent() and detachChildren() can
   // execute arbitrary script via things like unload events. If the executed
-  // script intiates a new load or causes the current frame to be detached, we
-  // need to abandon the current load.
-  if (pdl != provisional_document_loader_)
+  // script causes the current frame to be detached, we need to abandon the
+  // current load.
+  if (!frame_->Client())
     return false;
+  // FrameNavigationDisabler should prevent another load from starting.
+  DCHECK_EQ(provisional_document_loader_, pdl);
   // detachFromFrame() will abort XHRs that haven't completed, which can trigger
   // event listeners for 'abort'. These event listeners might call
   // window.stop(), which will in turn detach the provisional document loader.
   // At this point, the provisional document loader should not detach, because
-  // then the FrameLoader would not have any attached DocumentLoaders.
-  if (document_loader_) {
-    base::AutoReset<bool> in_detach_document_loader(
-        &protect_provisional_loader_, true);
+  // then the FrameLoader would not have any attached DocumentLoaders. This is
+  // guaranteed by FrameNavigationDisabler above.
+  if (document_loader_)
     DetachDocumentLoader(document_loader_, true);
-  }
   // 'abort' listeners can also detach the frame.
   if (!frame_->Client())
     return false;
+  // FrameNavigationDisabler should prevent another load from starting.
   DCHECK_EQ(provisional_document_loader_, pdl);
 
   // No more events will be dispatched so detach the Document.
@@ -1382,8 +1369,11 @@
 }
 
 void FrameLoader::Detach() {
+  frame_->GetDocument()->CancelParsing();
   DetachDocumentLoader(document_loader_);
   DetachDocumentLoader(provisional_document_loader_);
+  frame_->GetNavigationScheduler().Cancel();
+  DidFinishNavigation();
 
   if (progress_tracker_) {
     progress_tracker_->Dispose();
diff --git a/third_party/blink/renderer/core/loader/frame_loader.h b/third_party/blink/renderer/core/loader/frame_loader.h
index fbcc2aa..352af2a 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.h
+++ b/third_party/blink/renderer/core/loader/frame_loader.h
@@ -294,13 +294,11 @@
   Member<DocumentLoader> document_loader_;
   Member<DocumentLoader> provisional_document_loader_;
 
-  bool in_stop_all_loaders_;
   bool in_restore_scroll_;
 
   SandboxFlags forced_sandbox_flags_;
 
   bool dispatching_did_clear_window_object_in_main_world_;
-  bool protect_provisional_loader_;
   bool detached_;
 
   WebScopedVirtualTimePauser virtual_time_pauser_;
diff --git a/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc b/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc
index f6a0af64..6773e44 100644
--- a/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc
@@ -75,9 +75,12 @@
   if (RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled()) {
     // We should consider using the text node as the tracking node, instead of
     // the line layout item.
-    PaintTimingDetector::NotifyTextPaint(
-        ellipsis_box_.GetLineLayoutItem().GetNode(),
-        paint_info.context.GetPaintController().CurrentPaintChunkProperties());
+    Node* node = ellipsis_box_.GetLineLayoutItem().GetNode();
+    if (node) {
+      PaintTimingDetector::NotifyTextPaint(
+          *node->GetLayoutObject(), paint_info.context.GetPaintController()
+                                        .CurrentPaintChunkProperties());
+    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.cc b/third_party/blink/renderer/core/paint/paint_timing_detector.cc
index dd34552f..874c6215 100644
--- a/third_party/blink/renderer/core/paint/paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/paint_timing_detector.cc
@@ -62,18 +62,6 @@
 
 // static
 void PaintTimingDetector::NotifyImagePaint(
-    const Node* node,
-    const PropertyTreeState& current_paint_chunk_properties) {
-  if (!node)
-    return;
-  LayoutObject* object = node->GetLayoutObject();
-  if (!object)
-    return;
-  NotifyImagePaint(*object, current_paint_chunk_properties);
-}
-
-// static
-void PaintTimingDetector::NotifyImagePaint(
     const LayoutObject& object,
     const PropertyTreeState& current_paint_chunk_properties) {
   LocalFrameView* frame_view = object.GetFrameView();
@@ -86,18 +74,6 @@
 
 // static
 void PaintTimingDetector::NotifyTextPaint(
-    const Node* node,
-    const PropertyTreeState& current_paint_chunk_properties) {
-  if (!node)
-    return;
-  LayoutObject* object = node->GetLayoutObject();
-  if (!object)
-    return;
-  NotifyTextPaint(*object, current_paint_chunk_properties);
-}
-
-// static
-void PaintTimingDetector::NotifyTextPaint(
     const LayoutObject& object,
     const PropertyTreeState& current_paint_chunk_properties) {
   LocalFrameView* frame_view = object.GetFrameView();
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.h b/third_party/blink/renderer/core/paint/paint_timing_detector.h
index f312b4ee..035707c 100644
--- a/third_party/blink/renderer/core/paint/paint_timing_detector.h
+++ b/third_party/blink/renderer/core/paint/paint_timing_detector.h
@@ -40,13 +40,9 @@
       Image* image,
       const PropertyTreeState& current_paint_chunk_properties);
   static void NotifyImagePaint(
-      const Node* node,
-      const PropertyTreeState& current_paint_chunk_properties);
-  static void NotifyImagePaint(
       const LayoutObject& object,
       const PropertyTreeState& current_paint_chunk_properties);
 
-  static void NotifyTextPaint(const Node* node, const PropertyTreeState&);
   static void NotifyTextPaint(const LayoutObject& object,
                               const PropertyTreeState&);
   void NotifyNodeRemoved(const LayoutObject& object);
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 91eb76d..8304844 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -180,7 +180,7 @@
 
 namespace blink {
 
-using ws::mojom::ImeTextSpanThickness;
+using ui::mojom::ImeTextSpanThickness;
 
 namespace {
 
diff --git a/third_party/blink/renderer/devtools/PRESUBMIT.py b/third_party/blink/renderer/devtools/PRESUBMIT.py
index 5ecc368..5fadb7a 100644
--- a/third_party/blink/renderer/devtools/PRESUBMIT.py
+++ b/third_party/blink/renderer/devtools/PRESUBMIT.py
@@ -94,6 +94,18 @@
     ]
 
 
+def _CheckDevtoolsLocalization(input_api, output_api):  # pylint: disable=invalid-name
+    affected_front_end_files = _getAffectedFrontEndFiles(input_api)
+    if len(affected_front_end_files) == 0:
+        return []
+    else:
+        affected_front_end_files = [
+            input_api.os_path.join(input_api.PresubmitLocalPath(), file_path) for file_path in affected_front_end_files
+        ]
+        script_path = input_api.os_path.join(input_api.PresubmitLocalPath(), "scripts", "check_localizability.js")
+        return _checkWithNodeScript(input_api, output_api, script_path, affected_front_end_files)
+
+
 def _CheckDevtoolsStyle(input_api, output_api):
     affected_front_end_files = _getAffectedFrontEndFiles(input_api)
     if len(affected_front_end_files) > 0:
@@ -190,6 +202,7 @@
     results = []
     results.extend(_CheckBuildGN(input_api, output_api))
     results.extend(_CheckFormat(input_api, output_api))
+    # results.extend(_CheckDevtoolsLocalization(input_api, output_api))
     results.extend(_CheckDevtoolsStyle(input_api, output_api))
     results.extend(_CompileDevtoolsFrontend(input_api, output_api))
     results.extend(_CheckConvertSVGToPNGHashes(input_api, output_api))
@@ -224,7 +237,7 @@
     return [input_api.os_path.relpath(file_name, devtools_root) for file_name in affected_js_files]
 
 
-def _checkWithNodeScript(input_api, output_api, script_path):
+def _checkWithNodeScript(input_api, output_api, script_path, files=None):  # pylint: disable=invalid-name
     original_sys_path = sys.path
     try:
         sys.path = sys.path + [input_api.os_path.join(input_api.PresubmitLocalPath(), "scripts")]
@@ -234,8 +247,11 @@
 
     node_path = local_node.node_path()
 
+    if files is None:
+        files = []
+
     process = input_api.subprocess.Popen(
-        [node_path, script_path], stdout=input_api.subprocess.PIPE, stderr=input_api.subprocess.STDOUT)
+        [node_path, script_path] + files, stdout=input_api.subprocess.PIPE, stderr=input_api.subprocess.STDOUT)
     out, _ = process.communicate()
 
     if process.returncode != 0:
diff --git a/third_party/blink/renderer/devtools/package.json b/third_party/blink/renderer/devtools/package.json
index 5fe0fdb..4a01845 100644
--- a/third_party/blink/renderer/devtools/package.json
+++ b/third_party/blink/renderer/devtools/package.json
@@ -14,6 +14,7 @@
     "extract": "node scripts/extract_module/extract_module.js",
     "check-gn": "node scripts/check_gn.js",
     "check-json": "node scripts/json_validator/validate_module_json.js",
+    "check-loc": "node scripts/check_localizability.js -a",
     "generate-jsconfig": "node scripts/generate_jsconfig.js"
   },
   "repository": {
diff --git a/third_party/blink/renderer/devtools/scripts/check_localizability.js b/third_party/blink/renderer/devtools/scripts/check_localizability.js
new file mode 100644
index 0000000..3cbe973b
--- /dev/null
+++ b/third_party/blink/renderer/devtools/scripts/check_localizability.js
@@ -0,0 +1,313 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+'use strict';
+
+// Description: Scans for localizability violations in the DevTools front-end.
+// Audits all Common.UIString(), UI.formatLocalized(), and ls`` calls and
+// checks for misuses of concatenation and conditionals. It also looks for
+// specific arguments to functions that are expected to be a localized string.
+// Since the check scans for common error patterns, it might misidentify something.
+// In this case, add it to the excluded errors at the top of the script.
+
+const path = require('path');
+
+// Use modules in third_party/node/node_modules
+const THIRD_PARTY_PATH = path.resolve(__dirname, '..', '..', '..', '..');
+const REPO_NODE_MODULES_PATH = path.resolve(THIRD_PARTY_PATH, 'node', 'node_modules');
+const escodegen = require(path.resolve(REPO_NODE_MODULES_PATH, 'escodegen'));
+const esprima = require(path.resolve(REPO_NODE_MODULES_PATH, 'esprima'));
+
+const fs = require('fs');
+const {promisify} = require('util');
+const readDirAsync = promisify(fs.readdir);
+const readFileAsync = promisify(fs.readFile);
+const statAsync = promisify(fs.stat);
+
+const excludeFiles = ['lighthouse-dt-bundle.js', 'Tests.js'];
+const excludeDirs = ['_test_runner', 'Images', 'node_modules'];
+// Exclude known errors
+const excludeErrors = [
+  'Common.UIString(view.title())', 'Common.UIString(setting.title() || \'\')', 'Common.UIString(option.text)',
+  'Common.UIString(experiment.title)', 'Common.UIString(phase.message)',
+  'Common.UIString(Help.latestReleaseNote().header)', 'Common.UIString(conditions.title)',
+  'Common.UIString(extension.title())', 'Common.UIString(this._currentValueLabel, value)'
+];
+
+const esprimaTypes = {
+  BI_EXPR: 'BinaryExpression',
+  CALL_EXPR: 'CallExpression',
+  COND_EXPR: 'ConditionalExpression',
+  IDENTIFIER: 'Identifier',
+  MEMBER_EXPR: 'MemberExpression',
+  TAGGED_TEMP_EXPR: 'TaggedTemplateExpression',
+  TEMP_LITERAL: 'TemplateLiteral'
+};
+
+const usage = `Usage: node ${path.basename(process.argv[0])} [-a | <.js file path>*]
+
+-a: If present, check all devtools frontend .js files
+<.js file path>*: List of .js files with absolute paths separated by a space
+`;
+
+async function main() {
+  if (process.argv.length < 3 || process.argv[2] === '--help') {
+    console.log(usage);
+    process.exit(0);
+  }
+
+  const errors = [];
+
+  try {
+    let filePaths = [];
+    if (process.argv[2] === '-a') {
+      const frontendPath = path.resolve(__dirname, '..', 'front_end');
+      await getFilesFromDirectory(frontendPath, filePaths);
+    } else {
+      filePaths = process.argv.slice(2);
+    }
+
+    const promises = [];
+    for (const filePath of filePaths)
+      promises.push(auditFileForLocalizability(filePath, errors));
+
+    await Promise.all(promises);
+  } catch (err) {
+    console.log(err);
+    process.exit(1);
+  }
+
+  if (errors.length > 0) {
+    console.log(`DevTools localization checker detected errors!\n${errors.join('\n')}`);
+    process.exit(1);
+  }
+  console.log('DevTools localization checker passed');
+}
+
+main();
+
+function verifyIdentifier(node, name) {
+  return node !== undefined && node.type === esprimaTypes.IDENTIFIER && node.name === name;
+}
+
+/**
+ * Verify callee of objectName.propertyName(), e.g. Common.UIString().
+ */
+function verifyCallExpressionCallee(callee, objectName, propertyName) {
+  return callee !== undefined && callee.type === esprimaTypes.MEMBER_EXPR && callee.computed === false &&
+      verifyIdentifier(callee.object, objectName) && verifyIdentifier(callee.property, propertyName);
+}
+
+function isNodeCallOnObject(node, objectName, propertyName) {
+  return node !== undefined && node.type === esprimaTypes.CALL_EXPR &&
+      verifyCallExpressionCallee(node.callee, objectName, propertyName);
+}
+
+function isNodeCommonUIStringCall(node) {
+  return isNodeCallOnObject(node, 'Common', 'UIString');
+}
+
+function isNodeUIformatLocalized(node) {
+  return isNodeCallOnObject(node, 'UI', 'formatLocalized');
+}
+
+function isNodelsTaggedTemplateExpression(node) {
+  return node !== undefined && node.type === esprimaTypes.TAGGED_TEMP_EXPR && verifyIdentifier(node.tag, 'ls') &&
+      node.quasi !== undefined && node.quasi.type !== undefined && node.quasi.type === esprimaTypes.TEMP_LITERAL;
+}
+
+function includesConditionalExpression(listOfElements) {
+  return listOfElements.filter(ele => ele !== undefined && ele.type === esprimaTypes.COND_EXPR).length > 0;
+}
+
+function getLocalizationCase(node) {
+  if (isNodeCommonUIStringCall(node))
+    return 'Common.UIString';
+  else if (isNodelsTaggedTemplateExpression(node))
+    return 'Tagged Template';
+  else if (isNodeUIformatLocalized(node))
+    return 'UI.formatLocalized';
+  else
+    return null;
+}
+
+function isLocalizationCall(node) {
+  return isNodeCommonUIStringCall(node) || isNodelsTaggedTemplateExpression(node) || isNodeUIformatLocalized(node);
+}
+
+function addError(error, errors) {
+  if (!errors.includes(error))
+    errors.push(error);
+}
+
+function getLocation(node) {
+  if (node !== undefined && node.loc !== undefined && node.loc.start !== undefined && node.loc.end !== undefined &&
+      node.loc.start.line !== undefined && node.loc.end.line !== undefined) {
+    const startLine = node.loc.start.line;
+    const endLine = node.loc.end.line;
+    if (startLine === endLine)
+      return ` Line ${startLine}`;
+    else
+      return ` Line ${node.loc.start.line}-${node.loc.end.line}`;
+  }
+  return '';
+}
+
+/**
+ * Recursively check if there is concatenation to localization call.
+ */
+function checkConcatenation(node, filePath, errors) {
+  if (node !== undefined && node.type === esprimaTypes.BI_EXPR && node.operator === '+') {
+    const code = escodegen.generate(node);
+    if (isLocalizationCall(node.left) || isLocalizationCall(node.right)) {
+      addError(
+          `${filePath}${getLocation(node)}: string concatenation should be changed to variable substitution with ls: ${
+              code}`,
+          errors);
+    } else {
+      [node.left, node.right].forEach(node => checkConcatenation(node, filePath, errors));
+    }
+  }
+}
+
+/**
+ * Verify if callee is functionName() or object.functionName().
+ */
+function verifyFunctionCallee(callee, functionName) {
+  return callee !== undefined &&
+      ((callee.type === esprimaTypes.IDENTIFIER && callee.name === functionName) ||
+       (callee.type === esprimaTypes.MEMBER_EXPR && verifyIdentifier(callee.property, functionName)));
+}
+
+/**
+ * Check if an argument of a function is localized.
+ */
+function checkFunctionArgument(functionName, argumentIndex, node, filePath, errors) {
+  if (node !== undefined && node.type === esprimaTypes.CALL_EXPR && verifyFunctionCallee(node.callee, functionName) &&
+      node.arguments !== undefined && node.arguments.length > argumentIndex) {
+    const arg = node.arguments[argumentIndex];
+    if (!isLocalizationCall(arg)) {
+      let order = '';
+      switch (argumentIndex) {
+        case 0:
+          order = 'first';
+          break;
+        case 1:
+          order = 'second';
+          break;
+        case 2:
+          order = 'third';
+          break;
+        default:
+          order = `${argumentIndex + 1}th`;
+      }
+      addError(
+          `${filePath}${getLocation(node)}: ${order} argument to ${functionName}() should be localized: ${
+              escodegen.generate(node)}`,
+          errors);
+    }
+  }
+}
+
+/**
+ * Check esprima node object that represents the AST of code
+ * to see if there is any localization error.
+ */
+function analyzeNode(node, filePath, errors) {
+  if (node === undefined || node === null)
+    return;
+
+  if (node instanceof Array) {
+    for (const child of node)
+      analyzeNode(child, filePath, errors);
+
+    return;
+  }
+
+  const keys = Object.keys(node);
+  const objKeys = keys.filter(key => {
+    return typeof node[key] === 'object' && key !== 'loc';
+  });
+  if (objKeys.length === 0) {
+    // base case: all values are non-objects -> node is a leaf
+    return;
+  }
+
+  const locCase = getLocalizationCase(node);
+  const code = escodegen.generate(node);
+  switch (locCase) {
+    case 'Common.UIString':
+    case 'UI.formatLocalized':
+      const firstArgType = node.arguments[0].type;
+      if (firstArgType !== 'Literal' && firstArgType !== 'TemplateLiteral' && firstArgType !== 'Identifier' &&
+          !excludeErrors.includes(code)) {
+        addError(`${filePath}${getLocation(node)}: first argument to call should be a string: ${code}`, errors);
+      }
+      if (includesConditionalExpression(node.arguments.slice(1))) {
+        addError(
+            `${filePath}${getLocation(node)}: conditional(s) found in ${
+                code}. Please extract conditional(s) out of the localization call.`,
+            errors);
+      }
+      break;
+    case 'Tagged Template':
+      if (includesConditionalExpression(node.quasi.expressions)) {
+        addError(
+            `${filePath}${getLocation(node)}: conditional(s) found in ${
+                code}. Please extract conditional(s) out of the localization call.`,
+            errors);
+      }
+      break;
+    default:
+      // String concatenation to localization call(s) should be changed
+      checkConcatenation(node, filePath, errors);
+      // 3rd argument to createInput() should be localized
+      checkFunctionArgument('createInput', 2, node, filePath, errors);
+      break;
+  }
+
+  for (const key of objKeys) {
+    // recursively parse all the child nodes
+    analyzeNode(node[key], filePath, errors);
+  }
+}
+
+function getRelativeFilePathFromSrc(fullFilePath) {
+  return path.relative(path.resolve(THIRD_PARTY_PATH, '..'), fullFilePath);
+}
+
+async function auditFileForLocalizability(filePath, errors) {
+  const fileContent = await readFileAsync(filePath);
+  const ast = esprima.parse(fileContent.toString(), {loc: true});
+
+  const relativeFilePath = getRelativeFilePathFromSrc(filePath);
+  for (const node of ast.body)
+    analyzeNode(node, relativeFilePath, errors);
+}
+
+function shouldParseDirectory(directoryName) {
+  return !excludeDirs.reduce((result, dir) => result || directoryName.indexOf(dir) !== -1, false);
+}
+
+function shouldParseFile(filePath) {
+  return (path.extname(filePath) === '.js' && !excludeFiles.includes(path.basename(filePath)));
+}
+
+async function getFilesFromItem(itemPath, filePaths) {
+  const stat = await statAsync(itemPath);
+  if (stat.isDirectory() && shouldParseDirectory(itemPath))
+    return await getFilesFromDirectory(itemPath, filePaths);
+
+  if (shouldParseFile(itemPath))
+    filePaths.push(itemPath);
+}
+
+async function getFilesFromDirectory(directoryPath, filePaths) {
+  const itemNames = await readDirAsync(directoryPath);
+  const promises = [];
+  for (const itemName of itemNames) {
+    const itemPath = path.resolve(directoryPath, itemName);
+    promises.push(getFilesFromItem(itemPath, filePaths));
+  }
+  await Promise.all(promises);
+}
diff --git a/third_party/blink/renderer/modules/xr/xr_grip_space.cc b/third_party/blink/renderer/modules/xr/xr_grip_space.cc
index 32e47c78..146a388 100644
--- a/third_party/blink/renderer/modules/xr/xr_grip_space.cc
+++ b/third_party/blink/renderer/modules/xr/xr_grip_space.cc
@@ -38,7 +38,7 @@
   // Account for any changes made to the reference space's origin offset so
   // that things like teleportation works.
   grip_pose = std::make_unique<TransformationMatrix>(
-      other_space->OriginOffsetMatrix().Inverse().Multiply(*grip_pose));
+      other_space->InverseOriginOffsetMatrix().Multiply(*grip_pose));
 
   return MakeGarbageCollected<XRPose>(std::move(grip_pose),
                                       input_source_->emulatedPosition());
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space.cc b/third_party/blink/renderer/modules/xr/xr_reference_space.cc
index 220f349..c5398bcb 100644
--- a/third_party/blink/renderer/modules/xr/xr_reference_space.cc
+++ b/third_party/blink/renderer/modules/xr/xr_reference_space.cc
@@ -67,8 +67,8 @@
   origin_offset_ = transform;
 }
 
-TransformationMatrix XRReferenceSpace::OriginOffsetMatrix() {
-  return origin_offset_->TransformMatrix();
+TransformationMatrix XRReferenceSpace::InverseOriginOffsetMatrix() {
+  return origin_offset_->InverseTransformMatrix();
 }
 
 void XRReferenceSpace::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space.h b/third_party/blink/renderer/modules/xr/xr_reference_space.h
index 53b73c0..3d1c507f 100644
--- a/third_party/blink/renderer/modules/xr/xr_reference_space.h
+++ b/third_party/blink/renderer/modules/xr/xr_reference_space.h
@@ -32,7 +32,7 @@
 
   XRRigidTransform* originOffset() const { return origin_offset_; }
   void setOriginOffset(XRRigidTransform*);
-  TransformationMatrix OriginOffsetMatrix() override;
+  TransformationMatrix InverseOriginOffsetMatrix() override;
 
   void Trace(blink::Visitor*) override;
 
diff --git a/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc b/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc
index adfb30fa..ee34bad 100644
--- a/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc
+++ b/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc
@@ -66,6 +66,10 @@
   if (other.matrix_) {
     matrix_ = std::make_unique<TransformationMatrix>(*(other.matrix_.get()));
   }
+  if (other.inv_matrix_) {
+    inv_matrix_ =
+        std::make_unique<TransformationMatrix>(*(other.inv_matrix_.get()));
+  }
 
   return *this;
 }
@@ -105,9 +109,16 @@
 }
 
 TransformationMatrix XRRigidTransform::InverseTransformMatrix() {
-  EnsureMatrix();
-  DCHECK(matrix_->IsInvertible());
-  return matrix_->Inverse();
+  // Only compute inverse matrix when it's requested, but cache it once we do.
+  // matrix_ does not change once the XRRigidTransfrorm has been constructed, so
+  // the caching is safe.
+  if (!inv_matrix_) {
+    EnsureMatrix();
+    DCHECK(matrix_->IsInvertible());
+    inv_matrix_ = std::make_unique<TransformationMatrix>(matrix_->Inverse());
+  }
+
+  return *inv_matrix_;
 }
 
 TransformationMatrix XRRigidTransform::TransformMatrix() {
diff --git a/third_party/blink/renderer/modules/xr/xr_rigid_transform.h b/third_party/blink/renderer/modules/xr/xr_rigid_transform.h
index 0697decc..732e006ea 100644
--- a/third_party/blink/renderer/modules/xr/xr_rigid_transform.h
+++ b/third_party/blink/renderer/modules/xr/xr_rigid_transform.h
@@ -51,6 +51,7 @@
   Member<DOMPointReadOnly> position_;
   Member<DOMPointReadOnly> orientation_;
   std::unique_ptr<TransformationMatrix> matrix_;
+  std::unique_ptr<TransformationMatrix> inv_matrix_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_space.cc b/third_party/blink/renderer/modules/xr/xr_space.cc
index 5b15d8c9..33de78b 100644
--- a/third_party/blink/renderer/modules/xr/xr_space.cc
+++ b/third_party/blink/renderer/modules/xr/xr_space.cc
@@ -37,7 +37,7 @@
   return nullptr;
 }
 
-TransformationMatrix XRSpace::OriginOffsetMatrix() {
+TransformationMatrix XRSpace::InverseOriginOffsetMatrix() {
   TransformationMatrix identity;
   return identity;
 }
@@ -90,7 +90,7 @@
   // Account for any changes made to the reference space's origin offset so that
   // things like teleportation works.
   return std::make_unique<TransformationMatrix>(
-      OriginOffsetMatrix().Inverse().Multiply(*pose));
+      InverseOriginOffsetMatrix().Multiply(*pose));
 }
 
 ExecutionContext* XRSpace::GetExecutionContext() const {
diff --git a/third_party/blink/renderer/modules/xr/xr_space.h b/third_party/blink/renderer/modules/xr/xr_space.h
index 0cc22a0..da2ce0b 100644
--- a/third_party/blink/renderer/modules/xr/xr_space.h
+++ b/third_party/blink/renderer/modules/xr/xr_space.h
@@ -53,7 +53,7 @@
   ExecutionContext* GetExecutionContext() const override;
   const AtomicString& InterfaceName() const override;
 
-  virtual TransformationMatrix OriginOffsetMatrix();
+  virtual TransformationMatrix InverseOriginOffsetMatrix();
 
   void Trace(blink::Visitor*) override;
 
diff --git a/third_party/blink/renderer/modules/xr/xr_target_ray_space.cc b/third_party/blink/renderer/modules/xr/xr_target_ray_space.cc
index 8f04c2166..e6ba36a 100644
--- a/third_party/blink/renderer/modules/xr/xr_target_ray_space.cc
+++ b/third_party/blink/renderer/modules/xr/xr_target_ray_space.cc
@@ -95,7 +95,7 @@
   // Account for any changes made to the reference space's origin offset so that
   // things like teleportation works.
   pointer_pose = std::make_unique<TransformationMatrix>(
-      other_space->OriginOffsetMatrix().Inverse().Multiply(*pointer_pose));
+      other_space->InverseOriginOffsetMatrix().Multiply(*pointer_pose));
 
   return MakeGarbageCollected<XRPose>(std::move(pointer_pose),
                                       input_source_->emulatedPosition());
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 1ffedcd..56b80cad 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -2013,7 +2013,7 @@
 external/wpt/payment-request/algorithms-manual.https.html [ WontFix ]
 external/wpt/payment-request/change-shipping-option-manual.https.html [ WontFix ]
 external/wpt/payment-request/change-shipping-option-select-last-manual.https.html [ WontFix ]
-external/wpt/payment-request/payment-request-hasenrolledinstrument-method-manual.https.html [ WontFix ]
+external/wpt/payment-request/payment-request-hasenrolledinstrument-method-manual.tentative.https.html [ WontFix ]
 external/wpt/payment-request/payment-response/complete-method-manual.https.html [ WontFix ]
 external/wpt/payment-request/payment-response/methodName-attribute-manual.https.html [ WontFix ]
 external/wpt/payment-request/payment-response/onpayerdetailchange-attribute-manual.https.html [ WontFix ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 02930e41..86349de 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1716,7 +1716,6 @@
 crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/hittest-overlapping-margin.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/hittest-overlapping-order.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/intrinsic-width-overflow-auto.tentative.html [ Failure ]
 
 ### virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-lines/
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-lines/multi-line-wrap-reverse-column-reverse.html [ Failure ]
@@ -3026,6 +3025,8 @@
 crbug.com/939181 virtual/not-site-per-process/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Failure Timeout ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/media-source/mediasource-correct-frames-after-reappend.html [ Timeout ]
+crbug.com/626703 external/wpt/media-source/mediasource-correct-frames.html [ Timeout ]
 crbug.com/626703 external/wpt/payment-method-basic-card/steps_for_selecting_the_payment_handler.html [ Timeout ]
 crbug.com/626703 external/wpt/payment-method-basic-card/apply_the_modifiers.html [ Timeout ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/tables/table-border-3s.html [ Failure ]
diff --git a/third_party/blink/web_tests/clipboard/copy-image-at-with-pinch-zoom.html b/third_party/blink/web_tests/clipboard/copy-image-at-with-pinch-zoom.html
index c3356099..2e4474c3 100644
--- a/third_party/blink/web_tests/clipboard/copy-image-at-with-pinch-zoom.html
+++ b/third_party/blink/web_tests/clipboard/copy-image-at-with-pinch-zoom.html
@@ -7,8 +7,8 @@
 testRunner.waitUntilDone();
 testRunner.dumpAsText();
 requestAnimationFrame(() => {
-  var canvas = document.querySelector('canvas');
-  var context = canvas.getContext('2d');
+  const canvas = document.querySelector('canvas');
+  const context = canvas.getContext('2d');
   context.fillStyle = 'red';
   context.fillRect(0, 0, 200, 200);
   internals.setPageScaleFactor(2);
@@ -18,7 +18,7 @@
       try {
         if (width !== 200 || height !== 200)
           testFailed('The copied image must be 200x200.');
-        var topleft = new Uint8Array(snapshot).subarray(0, 4);
+          const topleft = new Uint8Array(snapshot).subarray(0, 4);
         if (topleft[0] !== 255 || topleft[1] !== 0 || topleft[2] !== 0 || topleft[3] !== 255)
           testFailed("The copied image's top left must be red. " + JSON.stringify(topleft));
       } catch (e) {
diff --git a/third_party/blink/web_tests/clipboard/copy-image-at.html b/third_party/blink/web_tests/clipboard/copy-image-at.html
index 5abc4ce2..5146035 100644
--- a/third_party/blink/web_tests/clipboard/copy-image-at.html
+++ b/third_party/blink/web_tests/clipboard/copy-image-at.html
@@ -7,8 +7,8 @@
 testRunner.waitUntilDone();
 testRunner.dumpAsText();
 requestAnimationFrame(() => {
-  var canvas = document.querySelector('canvas');
-  var context = canvas.getContext('2d');
+  const canvas = document.querySelector('canvas');
+  const context = canvas.getContext('2d');
   context.fillStyle = 'red';
   context.fillRect(0, 0, 200, 200);
   requestAnimationFrame(() => {
@@ -16,7 +16,7 @@
       try {
         if (width !== 200 || height !== 200)
           testFailed('The copied image must be 200x200.');
-        var topleft = new Uint8Array(snapshot).subarray(0, 4);
+          const topleft = new Uint8Array(snapshot).subarray(0, 4);
         if (topleft[0] !== 255 || topleft[1] !== 0 || topleft[2] !== 0 || topleft[3] !== 255)
           testFailed("The copied image's top left must be red. " + JSON.stringify(topleft));
       } catch (e) {
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
index 3d18ee7..0ff024c 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -5641,9 +5641,9 @@
      {}
     ]
    ],
-   "payment-request/payment-request-hasenrolledinstrument-method-manual.https.html": [
+   "payment-request/payment-request-hasenrolledinstrument-method-manual.tentative.https.html": [
     [
-     "/payment-request/payment-request-hasenrolledinstrument-method-manual.https.html",
+     "/payment-request/payment-request-hasenrolledinstrument-method-manual.tentative.https.html",
      {}
     ]
    ],
@@ -74087,6 +74087,30 @@
      {}
     ]
    ],
+   "css/css-transforms/subpixel-perspective-backface-hidden.html": [
+    [
+     "/css/css-transforms/subpixel-perspective-backface-hidden.html",
+     [
+      [
+       "/css/css-transforms/subpixel-perspective-backface-hidden-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-transforms/subpixel-perspective-translate-z-0.html": [
+    [
+     "/css/css-transforms/subpixel-perspective-translate-z-0.html",
+     [
+      [
+       "/css/css-transforms/subpixel-perspective-translate-z-0-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-transforms/text-perspective-001.html": [
     [
      "/css/css-transforms/text-perspective-001.html",
@@ -148011,6 +148035,16 @@
      {}
     ]
    ],
+   "css/css-transforms/subpixel-perspective-backface-hidden-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-transforms/subpixel-perspective-translate-z-0-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-transforms/support/1x1-green.png": [
     [
      {}
@@ -178336,6 +178370,16 @@
      {}
     ]
    ],
+   "media-source/mp4/test-boxes-audio.mp4": [
+    [
+     {}
+    ]
+   ],
+   "media-source/mp4/test-boxes-video.mp4": [
+    [
+     {}
+    ]
+   ],
    "media-source/mp4/test-v-128k-320x240-24fps-8kfr-manifest.json": [
     [
      {}
@@ -180746,11 +180790,21 @@
      {}
     ]
    ],
+   "payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "payment-request/payment-request-hasenrolledinstrument-method.https-expected.txt": [
     [
      {}
     ]
    ],
+   "payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "payment-request/payment-request-show-method.https-expected.txt": [
     [
      {}
@@ -262029,6 +262083,22 @@
      {}
     ]
    ],
+   "media-source/mediasource-correct-frames-after-reappend.html": [
+    [
+     "/media-source/mediasource-correct-frames-after-reappend.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
+   "media-source/mediasource-correct-frames.html": [
+    [
+     "/media-source/mediasource-correct-frames.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
    "media-source/mediasource-detach.html": [
     [
      "/media-source/mediasource-detach.html",
@@ -275777,17 +275847,17 @@
      {}
     ]
    ],
-   "payment-request/payment-request-hasenrolledinstrument-method-protection.https.html": [
+   "payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https.html": [
     [
-     "/payment-request/payment-request-hasenrolledinstrument-method-protection.https.html",
+     "/payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https.html",
      {
       "testdriver": true
      }
     ]
    ],
-   "payment-request/payment-request-hasenrolledinstrument-method.https.html": [
+   "payment-request/payment-request-hasenrolledinstrument-method.tentative.https.html": [
     [
-     "/payment-request/payment-request-hasenrolledinstrument-method.https.html",
+     "/payment-request/payment-request-hasenrolledinstrument-method.tentative.https.html",
      {
       "testdriver": true
      }
@@ -321700,35 +321770,35 @@
    "support"
   ],
   "clipboard-apis/async-interfaces.https.html": [
-   "0617ac11ac2e7dbc2cac3f0665e2df121d1ae477",
+   "e0d0977959b5dbe943005587c1442de451d9a18d",
    "testharness"
   ],
   "clipboard-apis/async-navigator-clipboard-basics.https.html": [
-   "7d2cba8b5090d1ef268ddc6d159d1e06a49a3158",
+   "b71b43efe064c3fba60c6922c09da7e835398903",
    "testharness"
   ],
   "clipboard-apis/async-write-blobs-read-blobs-manual.https.html": [
-   "3666c93df027fd3962d0b31a6735dc56651ecd58",
+   "57cf542ca77bc648d4a839e21775957f287ec60f",
    "manual"
   ],
   "clipboard-apis/async-write-blobtext-read-blobtext-manual.https.html": [
-   "44c574247825612ec906ba42d3f0171a97a17668",
+   "fded721f9bfa1a9efd9e42b05b4ddcc40a3b8e48",
    "manual"
   ],
   "clipboard-apis/async-write-blobtext-read-text-manual.https.html": [
-   "c991f1fd324a330d4b322a1f33bb07a0f6ad6199",
+   "98ff7c27b667182432d744edcdbdfc5ca36dabb0",
    "manual"
   ],
   "clipboard-apis/async-write-image-read-image-manual.https.html": [
-   "2a32348507f7206316f5851e2ff1f6dc6829fbdb",
+   "6c326cf8ddeaa8777ef6b41d6bc9e4c32282a5c3",
    "manual"
   ],
   "clipboard-apis/async-write-text-read-blobtext-manual.https.html": [
-   "24e6b6ed3cc3510f21620d86769e0fdfa3e0a9cb",
+   "ab85a6fc649e6a6c7a86127adb1a41845324f3ff",
    "manual"
   ],
   "clipboard-apis/async-write-text-read-text-manual.https.html": [
-   "496bdd78c7ab2ec0d26adafea6449ec18cc03340",
+   "25c7edb43f061552717459caf6d4df969383e84c",
    "manual"
   ],
   "clipboard-apis/clipboard-events-synthetic.html": [
@@ -321736,15 +321806,15 @@
    "testharness"
   ],
   "clipboard-apis/copy-event-manual.html": [
-   "e4cf3379ace559671d4ca03c1ed7dcd32f565ed8",
+   "6f687af196fa198cda7d83f468945f9f69330568",
    "manual"
   ],
   "clipboard-apis/cut-event-manual.html": [
-   "abef6f94bf640c210e56121e5407a1d00e558d71",
+   "c5593171754cfa2bd684e1ff3a8a724283456cbd",
    "manual"
   ],
   "clipboard-apis/paste-event-manual.html": [
-   "4131a41bff6fd6bf5fb22fa805aea219ec7f72aa",
+   "19e6b95c5f32a0eb7dbccb0f5bd538e9dbb1360e",
    "manual"
   ],
   "clipboard-apis/resources/greenbox.png": [
@@ -380099,6 +380169,22 @@
    "a83705e3985de757804bcc7134d17129b0f26516",
    "reftest"
   ],
+  "css/css-transforms/subpixel-perspective-backface-hidden-ref.html": [
+   "8413e3e2d2cf5f0e18b5cb1a15095d2696e2c280",
+   "support"
+  ],
+  "css/css-transforms/subpixel-perspective-backface-hidden.html": [
+   "e24539bfa2f50e9db422237d089acdaa2d3c178e",
+   "reftest"
+  ],
+  "css/css-transforms/subpixel-perspective-translate-z-0-ref.html": [
+   "5f3a8e279b48f314ad8d7a46091cc6ff0a49a814",
+   "support"
+  ],
+  "css/css-transforms/subpixel-perspective-translate-z-0.html": [
+   "4033e46f8ac2cee4e54fe672560323795fb89f0d",
+   "reftest"
+  ],
   "css/css-transforms/support/1x1-green.png": [
    "b98ca0ba0a03c580ac339e4a3653539cfa8edc71",
    "support"
@@ -434504,7 +434590,7 @@
    "support"
   ],
   "infrastructure/metadata/infrastructure/testdriver/actions/actionsWithKeyPressed.html.ini": [
-   "5df5c1f4561dcebdf92ff13c64a1e2fa28092f4e",
+   "f62bf62a9713c2c12e4d572e0701efde494224c0",
    "support"
   ],
   "infrastructure/metadata/infrastructure/testdriver/actions/elementPosition.html.ini": [
@@ -436795,6 +436881,14 @@
    "b28aa90f1f3d8135a7ea86b82820ffd414451920",
    "support"
   ],
+  "media-source/mediasource-correct-frames-after-reappend.html": [
+   "5c0f2e11195c3b8fe6292f726f12bf6190df32de",
+   "testharness"
+  ],
+  "media-source/mediasource-correct-frames.html": [
+   "4ef3f4605e6580f949e4e53e6192f0eec1206e78",
+   "testharness"
+  ],
   "media-source/mediasource-detach.html": [
    "b25b5c6f02f6e6abdb32de0902438c0b24d1f1c4",
    "testharness"
@@ -436983,6 +437077,14 @@
    "f224a5426a16e0a44df788f704ce6e602663b61a",
    "support"
   ],
+  "media-source/mp4/test-boxes-audio.mp4": [
+   "b1cabbfd21efdc08bff28a6b043f8eb856b7e322",
+   "support"
+  ],
+  "media-source/mp4/test-boxes-video.mp4": [
+   "714c17ca126c110d64e9fe58a50798e2a0ebc414",
+   "support"
+  ],
   "media-source/mp4/test-v-128k-320x240-24fps-8kfr-manifest.json": [
    "a31b6d0245ba5de8a59dcdf795ba2ab008647ef4",
    "support"
@@ -448163,7 +448265,7 @@
    "5f888f0389f6c756ede8c3e481ece7bcf8b71ccf",
    "testharness"
   ],
-  "payment-request/payment-request-hasenrolledinstrument-method-manual.https.html": [
+  "payment-request/payment-request-hasenrolledinstrument-method-manual.tentative.https.html": [
    "e6b164f7cc7b8f1c57b8fa9fd14cbc7f5ef81eea",
    "manual"
   ],
@@ -448171,7 +448273,11 @@
    "20a6f53208ac5e4c29a504f3e444066cce5bba89",
    "support"
   ],
-  "payment-request/payment-request-hasenrolledinstrument-method-protection.https.html": [
+  "payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https-expected.txt": [
+   "20a6f53208ac5e4c29a504f3e444066cce5bba89",
+   "support"
+  ],
+  "payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https.html": [
    "4da11304a21427040f72317e3746feebb251d12e",
    "testharness"
   ],
@@ -448179,7 +448285,11 @@
    "fe7f16769673e2d5b809417456fd1b0c1546d9cc",
    "support"
   ],
-  "payment-request/payment-request-hasenrolledinstrument-method.https.html": [
+  "payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt": [
+   "fe7f16769673e2d5b809417456fd1b0c1546d9cc",
+   "support"
+  ],
+  "payment-request/payment-request-hasenrolledinstrument-method.tentative.https.html": [
    "c1f7b27a22b41fe64a7fb77e73336d3d0daec159",
    "testharness"
   ],
@@ -471836,7 +471946,7 @@
    "support"
   ],
   "tools/wpt/browser.py": [
-   "c4469800608ad73b4a00c3bbef558cf9d0f7e596",
+   "f5bc7c0af02697c29818a8800c1d11a379023790",
    "support"
   ],
   "tools/wpt/commands.json": [
@@ -471864,7 +471974,7 @@
    "support"
   ],
   "tools/wpt/run.py": [
-   "ea4bd1c8054ae874a098cf762627613e2511bd67",
+   "1178c5a3f6d3f041ed5e4fe8597139d21d64de00",
    "support"
   ],
   "tools/wpt/testfiles.py": [
@@ -472144,11 +472254,11 @@
    "support"
   ],
   "tools/wptrunner/wptrunner/formatters/chromium.py": [
-   "f54f23e5a9d5f6e8bf1698a50c597155c5a1d727",
+   "071c2f378902965971a77d46911fd89a85a18bdc",
    "support"
   ],
   "tools/wptrunner/wptrunner/formatters/tests/test_chromium.py": [
-   "a6e6c2e1ed08d4c0d4209230082212c7988f8f11",
+   "22d9fb4e7ea022ed109047c0887a3443d19bc28c",
    "support"
   ],
   "tools/wptrunner/wptrunner/formatters/wptreport.py": [
@@ -482968,7 +483078,7 @@
    "support"
   ],
   "webxr/idlharness.https.window-expected.txt": [
-   "e15f9c4f30f66871b2f5d1411f991ba582bdad4c",
+   "b9df588c70e3c521a84d5335f0e3e32f9cd12cbf",
    "support"
   ],
   "webxr/idlharness.https.window.js": [
@@ -483100,7 +483210,7 @@
    "testharness"
   ],
   "webxr/xrSession_requestAnimationFrame_data_valid.https.html": [
-   "41801bcd3643b9173e0b447545967beb60cee330",
+   "6c567d2fda6888ee0b30e4f4716e75ee4763516d",
    "testharness"
   ],
   "webxr/xrSession_requestAnimationFrame_getViewerPose.https.html": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/intrinsic-width-overflow-auto.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/intrinsic-width-overflow-auto.tentative.html
deleted file mode 100644
index 8310e66..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/intrinsic-width-overflow-auto.tentative.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<link rel="author" title="Google" href="https://www.google.com/" />
-<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#intrinsic-sizes" />
-<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/1865" />
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/check-layout-th.js"></script>
-
-<body onload="checkLayout('.flexbox')">
-<div class="flexbox" style="display: flex; width: min-content;" data-expected-width="0">
-  <div style="overflow: auto;">
-    <div style="width: 100px; height: 100px;"></div>
-  </div>
-</div>
-
-<div class="flexbox" style="display: flex; width: min-content;" data-expected-width="10">
-  <div style="overflow: auto; border: 5px solid;">
-    <div style="width: 100px; height: 100px;"></div>
-  </div>
-</div>
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/actions/actionsWithKeyPressed.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/actions/actionsWithKeyPressed.html.ini
index 5df5c1f4..f62bf62a 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/actions/actionsWithKeyPressed.html.ini
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/actions/actionsWithKeyPressed.html.ini
@@ -1,3 +1,9 @@
 [actionsWithKeyPressed.html]
   expected:
     if product == "safari" or product == "firefox": ERROR
+
+
+  [TestDriver actions: actions with key pressed]
+    expected:
+      if product == "chrome": FAIL
+
diff --git a/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames-after-reappend.html b/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames-after-reappend.html
new file mode 100644
index 0000000..5c0f2e1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames-after-reappend.html
@@ -0,0 +1,162 @@
+<!DOCTYPE html>
+<!-- Copyright © 2019 Igalia. -->
+<html>
+<head>
+    <title>Frame checking test for MSE playback in presence of a reappend.</title>
+    <meta name="timeout" content="long">
+    <meta name="charset" content="UTF-8">
+    <link rel="author" title="Alicia Boya García" href="mailto:aboya@igalia.com">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="mediasource-util.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<canvas id="test-canvas"></canvas>
+<script>
+    function waitForEventPromise(element, event) {
+        return new Promise(resolve => {
+            function handler(ev) {
+                element.removeEventListener(event, handler);
+                resolve(ev);
+            }
+            element.addEventListener(event, handler);
+        });
+    }
+
+    function appendBufferPromise(sourceBuffer, data) {
+        sourceBuffer.appendBuffer(data);
+        return waitForEventPromise(sourceBuffer, "update");
+    }
+
+    function waitForPlayerToReachTimePromise(mediaElement, time) {
+        return new Promise(resolve => {
+            function timeupdate() {
+                if (mediaElement.currentTime < time)
+                    return;
+
+                mediaElement.removeEventListener("timeupdate", timeupdate);
+                resolve();
+            }
+            mediaElement.addEventListener("timeupdate", timeupdate);
+        });
+    }
+
+    function readPixel(imageData, x, y) {
+        return {
+            r: imageData.data[4 * (y * imageData.width + x)],
+            g: imageData.data[1 + 4 * (y * imageData.width + x)],
+            b: imageData.data[2 + 4 * (y * imageData.width + x)],
+            a: imageData.data[3 + 4 * (y * imageData.width + x)],
+        };
+    }
+
+    function isPixelLit(pixel) {
+        const threshold = 200; // out of 255
+        return pixel.r >= threshold && pixel.g >= threshold && pixel.b >= threshold;
+    }
+
+    // The test video has a few gray boxes. Each box interval (1 second) a new box is lit white and a different note
+    // is played. This test makes sure the right number of lit boxes and the right note are played at the right time.
+    const totalBoxes = 7;
+    const boxInterval = 1; // seconds
+
+    const videoWidth = 320;
+    const videoHeight = 240;
+    const boxesY = 210;
+    const boxSide = 20;
+    const boxMargin = 20;
+    const allBoxesWidth = totalBoxes * boxSide + (totalBoxes - 1) * boxMargin;
+    const boxesX = new Array(totalBoxes).fill(undefined)
+        .map((_, i) => (videoWidth - allBoxesWidth) / 2 + boxSide / 2 + i * (boxSide + boxMargin));
+
+    // Sound starts playing A4 (440 Hz) and goes one chromatic note up with every box lit.
+    // By comparing the player position to both the amount of boxes lit and the note played we can detect A/V
+    // synchronization issues automatically.
+    const noteFrequencies = new Array(1 + totalBoxes).fill(undefined)
+        .map((_, i) => 440 * Math.pow(Math.pow(2, 1 / 12), i));
+
+    // We also check the first second [0, 1) where no boxes are lit, therefore we start counting at -1 to do the check
+    // for zero lit boxes.
+    let boxesLitSoFar = -1;
+
+    mediasource_test(async function (test, mediaElement, mediaSource) {
+        const canvas = document.getElementById("test-canvas");
+        const canvasCtx = canvas.getContext("2d");
+        canvas.width = videoWidth;
+        canvas.height = videoHeight;
+
+        const videoData = await (await fetch("mp4/test-boxes-video.mp4")).arrayBuffer();
+        const audioData = (await (await fetch("mp4/test-boxes-audio.mp4")).arrayBuffer());
+
+        const videoSb = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.4d401f"');
+        const audioSb = mediaSource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"');
+
+        mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+        mediaElement.addEventListener('ended', onEnded);
+        mediaElement.addEventListener('timeupdate', onTimeUpdate);
+
+        await appendBufferPromise(videoSb, videoData);
+        await appendBufferPromise(audioSb, audioData);
+        mediaElement.play();
+
+        audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+        source = audioCtx.createMediaElementSource(mediaElement);
+        analyser = audioCtx.createAnalyser();
+        analyser.fftSize = 8192;
+        source.connect(analyser);
+        analyser.connect(audioCtx.destination);
+
+        const freqDomainArray = new Float32Array(analyser.frequencyBinCount);
+
+        function checkNoteBeingPlayed() {
+            const expectedNoteFrequency = noteFrequencies[boxesLitSoFar];
+
+            analyser.getFloatFrequencyData(freqDomainArray);
+            const maxBin = freqDomainArray.reduce((prev, curValue, i) =>
+                curValue > prev.value ? {index: i, value: curValue} : prev,
+                {index: -1, value: -Infinity});
+            const binFrequencyWidth = audioCtx.sampleRate / analyser.fftSize;
+            const binFreq = maxBin.index * binFrequencyWidth;
+
+            assert_true(Math.abs(expectedNoteFrequency - binFreq) <= binFrequencyWidth,
+                `The note being played matches the expected one (boxes lit: ${boxesLitSoFar}, ${expectedNoteFrequency.toFixed(1)} Hz)` +
+                `, found ~${binFreq.toFixed(1)} Hz`);
+        }
+
+        function countLitBoxesInCurrentVideoFrame() {
+            canvasCtx.drawImage(mediaElement, 0, 0);
+            const imageData = canvasCtx.getImageData(0, 0, videoWidth, videoHeight);
+            const lights = boxesX.map(boxX => isPixelLit(readPixel(imageData, boxX, boxesY)));
+            let litBoxes = 0;
+            for (let i = 0; i < lights.length; i++) {
+                if (lights[i])
+                    litBoxes++;
+            }
+            for (let i = litBoxes; i < lights.length; i++) {
+                assert_false(lights[i], 'After the first non-lit box, all boxes must non-lit');
+            }
+            return litBoxes;
+        }
+
+        await waitForPlayerToReachTimePromise(mediaElement, 2.5);
+        await appendBufferPromise(audioSb, audioData);
+        mediaSource.endOfStream();
+
+        function onTimeUpdate() {
+            const graceTime = 0.5;
+            if (mediaElement.currentTime >= (1 + boxesLitSoFar) * boxInterval + graceTime && boxesLitSoFar < totalBoxes) {
+                assert_equals(countLitBoxesInCurrentVideoFrame(), boxesLitSoFar + 1, "Num of lit boxes:");
+                boxesLitSoFar++;
+                checkNoteBeingPlayed();
+            }
+        }
+
+        function onEnded() {
+            assert_equals(boxesLitSoFar, totalBoxes, "Boxes lit at video ended event");
+            test.done();
+        }
+    }, "Test the expected frames are played at the expected times, even in presence of reappends");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames.html b/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames.html
new file mode 100644
index 0000000..4ef3f46
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<!-- Copyright © 2019 Igalia. -->
+<html>
+<head>
+    <title>Frame checking test for simple MSE playback.</title>
+    <meta name="timeout" content="long">
+    <meta name="charset" content="UTF-8">
+    <link rel="author" title="Alicia Boya García" href="mailto:aboya@igalia.com">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="mediasource-util.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<canvas id="test-canvas"></canvas>
+<script>
+    function waitForEventPromise(element, event) {
+        return new Promise(resolve => {
+            function handler(ev) {
+                element.removeEventListener(event, handler);
+                resolve(ev);
+            }
+            element.addEventListener(event, handler);
+        });
+    }
+
+    function appendBufferPromise(sourceBuffer, data) {
+        sourceBuffer.appendBuffer(data);
+        return waitForEventPromise(sourceBuffer, "update");
+    }
+
+    function readPixel(imageData, x, y) {
+        return {
+            r: imageData.data[4 * (y * imageData.width + x)],
+            g: imageData.data[1 + 4 * (y * imageData.width + x)],
+            b: imageData.data[2 + 4 * (y * imageData.width + x)],
+            a: imageData.data[3 + 4 * (y * imageData.width + x)],
+        };
+    }
+
+    function isPixelLit(pixel) {
+        const threshold = 200; // out of 255
+        return pixel.r >= threshold && pixel.g >= threshold && pixel.b >= threshold;
+    }
+
+    // The test video has a few gray boxes. Each box interval (1 second) a new box is lit white and a different note
+    // is played. This test makes sure the right number of lit boxes and the right note are played at the right time.
+    const totalBoxes = 7;
+    const boxInterval = 1; // seconds
+
+    const videoWidth = 320;
+    const videoHeight = 240;
+    const boxesY = 210;
+    const boxSide = 20;
+    const boxMargin = 20;
+    const allBoxesWidth = totalBoxes * boxSide + (totalBoxes - 1) * boxMargin;
+    const boxesX = new Array(totalBoxes).fill(undefined)
+        .map((_, i) => (videoWidth - allBoxesWidth) / 2 + boxSide / 2 + i * (boxSide + boxMargin));
+
+    // Sound starts playing A4 (440 Hz) and goes one chromatic note up with every box lit.
+    // By comparing the player position to both the amount of boxes lit and the note played we can detect A/V
+    // synchronization issues automatically.
+    const noteFrequencies = new Array(1 + totalBoxes).fill(undefined)
+        .map((_, i) => 440 * Math.pow(Math.pow(2, 1 / 12), i));
+
+    // We also check the first second [0, 1) where no boxes are lit, therefore we start counting at -1 to do the check
+    // for zero lit boxes.
+    let boxesLitSoFar = -1;
+
+    mediasource_test(async function (test, mediaElement, mediaSource) {
+        const canvas = document.getElementById("test-canvas");
+        const canvasCtx = canvas.getContext("2d");
+        canvas.width = videoWidth;
+        canvas.height = videoHeight;
+
+        const videoData = await (await fetch("mp4/test-boxes-video.mp4")).arrayBuffer();
+        const audioData = (await (await fetch("mp4/test-boxes-audio.mp4")).arrayBuffer());
+
+        const videoSb = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.4d401f"');
+        const audioSb = mediaSource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"');
+
+        mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
+        mediaElement.addEventListener('ended', onEnded);
+        mediaElement.addEventListener('timeupdate', onTimeUpdate);
+
+        await appendBufferPromise(videoSb, videoData);
+        await appendBufferPromise(audioSb, audioData);
+        mediaSource.endOfStream();
+        mediaElement.play();
+
+        const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+        const source = audioCtx.createMediaElementSource(mediaElement);
+        const analyser = audioCtx.createAnalyser();
+        analyser.fftSize = 8192;
+        source.connect(analyser);
+        analyser.connect(audioCtx.destination);
+
+        const freqDomainArray = new Float32Array(analyser.frequencyBinCount);
+
+        function checkNoteBeingPlayed() {
+            const expectedNoteFrequency = noteFrequencies[boxesLitSoFar];
+
+            analyser.getFloatFrequencyData(freqDomainArray);
+            const maxBin = freqDomainArray.reduce((prev, curValue, i) =>
+                curValue > prev.value ? {index: i, value: curValue} : prev,
+                {index: -1, value: -Infinity});
+            const binFrequencyWidth = audioCtx.sampleRate / analyser.fftSize;
+            const binFreq = maxBin.index * binFrequencyWidth;
+
+            assert_true(Math.abs(expectedNoteFrequency - binFreq) <= binFrequencyWidth,
+                `The note being played matches the expected one (boxes lit: ${boxesLitSoFar}, ${expectedNoteFrequency.toFixed(1)} Hz)` +
+                `, found ~${binFreq.toFixed(1)} Hz`);
+        }
+
+        function countLitBoxesInCurrentVideoFrame() {
+            canvasCtx.drawImage(mediaElement, 0, 0);
+            const imageData = canvasCtx.getImageData(0, 0, videoWidth, videoHeight);
+            const lights = boxesX.map(boxX => isPixelLit(readPixel(imageData, boxX, boxesY)));
+            let litBoxes = 0;
+            for (let i = 0; i < lights.length; i++) {
+                if (lights[i])
+                    litBoxes++;
+            }
+            for (let i = litBoxes; i < lights.length; i++) {
+                assert_false(lights[i], 'After the first non-lit box, all boxes must non-lit');
+            }
+            return litBoxes;
+        }
+
+        function onTimeUpdate() {
+            const graceTime = 0.5;
+            if (mediaElement.currentTime >= (1 + boxesLitSoFar) * boxInterval + graceTime && boxesLitSoFar < totalBoxes) {
+                assert_equals(countLitBoxesInCurrentVideoFrame(), boxesLitSoFar + 1, "Num of lit boxes:");
+                boxesLitSoFar++;
+                checkNoteBeingPlayed();
+            }
+        }
+
+        function onEnded() {
+            assert_equals(boxesLitSoFar, totalBoxes, "Boxes lit at video ended event");
+            test.done();
+        }
+    }, "Test the expected frames are played at the expected times");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/media-source/mp4/test-boxes-audio.mp4 b/third_party/blink/web_tests/external/wpt/media-source/mp4/test-boxes-audio.mp4
new file mode 100644
index 0000000..b1cabbf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/media-source/mp4/test-boxes-audio.mp4
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/media-source/mp4/test-boxes-video.mp4 b/third_party/blink/web_tests/external/wpt/media-source/mp4/test-boxes-video.mp4
new file mode 100644
index 0000000..714c17c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/media-source/mp4/test-boxes-video.mp4
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-manual.tentative.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-manual.https.html
rename to third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-manual.tentative.https.html
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https-expected.txt b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https-expected.txt
new file mode 100644
index 0000000..20a6f53
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Optionally, at the user agent's discretion, return a promise rejected with a "NotAllowedError" DOMException. assert_equals: If it throws, then it must be a NotAllowedError. expected "NotAllowedError" but got "UnknownError"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-protection.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-protection.https.html
rename to third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method-protection.tentative.https.html
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
new file mode 100644
index 0000000..fe7f1676
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Already called show() once
+FAIL hasEnrolledInstrument() resolves to false for unsupported payment methods. promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
+FAIL If request.[[state]] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "InvalidStateError: No show() or retry() in progress, so nothing to abort"
+FAIL If request.[[state]] is "closed", then return a promise rejected with an "InvalidStateError" DOMException. promise_test: Unhandled rejection with value: object "InvalidStateError: No show() or retry() in progress, so nothing to abort"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.https.html
rename to third_party/blink/web_tests/external/wpt/payment-request/payment-request-hasenrolledinstrument-method.tentative.https.html
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py b/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py
index c446980..f5bc7c0 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py
@@ -29,7 +29,7 @@
         return NotImplemented
 
     @abstractmethod
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         """Install the WebDriver implementation for this browser."""
         return NotImplemented
 
@@ -166,11 +166,11 @@
         os.remove(installer_path)
         return self.find_binary_path(dest)
 
-    def find_binary_path(self,path=None, channel="nightly"):
+    def find_binary_path(self, path=None, channel="nightly"):
         """Looks for the firefox binary in the virtual environment"""
 
         if path is None:
-            #os.getcwd() doesn't include the venv path
+            # os.getcwd() doesn't include the venv path
             path = os.path.join(os.getcwd(), "_venv", "browsers", channel)
 
         binary = None
@@ -315,7 +315,7 @@
         assert latest_release != 0
         return "v%s.%s.%s" % tuple(str(item) for item in latest_release)
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         """Install latest Geckodriver."""
         if dest is None:
             dest = os.getcwd()
@@ -392,7 +392,7 @@
     def find_webdriver(self, channel=None):
         raise NotImplementedError
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         raise NotImplementedError
 
     def version(self, binary=None, webdriver_binary=None):
@@ -440,24 +440,66 @@
 
         return "%s%s" % (platform, bits)
 
+    def chromium_platform_string(self):
+        platform = {
+            "Linux": "Linux",
+            "Windows": "Win",
+            "Darwin": "Mac"
+        }.get(uname[0])
+
+        if platform is None:
+            raise ValueError("Unable to construct a valid Chromium package name for current platform")
+
+        if (platform == "Linux" or platform == "Win") and uname[4] == "x86_64":
+            platform += "_x64"
+
+        return platform
+
     def find_binary(self, venv_path=None, channel=None):
         raise NotImplementedError
 
     def find_webdriver(self, channel=None):
         return find_executable("chromedriver")
 
-    def install_webdriver(self, dest=None, channel=None):
+    def _latest_chromedriver_url(self, browser_binary=None):
+        latest = None
+        chrome_version = self.version(browser_binary)
+        if chrome_version is not None:
+            parts = chrome_version.split(".")
+            if len(parts) == 4:
+                latest_url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_%s.%s.%s" % (
+                    parts[0], parts[1], parts[2])
+                try:
+                    latest = get(latest_url).text.strip()
+                except requests.RequestException:
+                    latest_url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_%s" % parts[0]
+                    try:
+                        latest = get(latest_url).text.strip()
+                    except requests.RequestException:
+                        pass
+        if latest is None:
+            # Fall back to the tip-of-tree *Chromium* build.
+            latest_url = "https://storage.googleapis.com/chromium-browser-snapshots/%s/LAST_CHANGE" % (
+                self.chromium_platform_string())
+            latest = get(latest_url).text.strip()
+            url = "https://storage.googleapis.com/chromium-browser-snapshots/%s/%s/chromedriver_%s.zip" % (
+                self.chromium_platform_string(), latest, self.platform_string())
+        else:
+            url = "https://chromedriver.storage.googleapis.com/%s/chromedriver_%s.zip" % (
+                latest, self.platform_string())
+        return url
+
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         if dest is None:
             dest = os.pwd
-        latest = get("http://chromedriver.storage.googleapis.com/LATEST_RELEASE").text.strip()
-        url = "http://chromedriver.storage.googleapis.com/%s/chromedriver_%s.zip" % (latest,
-                                                                                     self.platform_string())
+        url = self._latest_chromedriver_url(browser_binary)
+        self.logger.info("Downloading ChromeDriver from %s" % url)
         unzip(get(url).raw, dest)
-
-        path = find_executable("chromedriver", dest)
-        st = os.stat(path)
-        os.chmod(path, st.st_mode | stat.S_IEXEC)
-        return path
+        chromedriver_dir = os.path.join(dest, 'chromedriver_%s' % self.platform_string())
+        if os.path.isfile(os.path.join(chromedriver_dir, "chromedriver")):
+            shutil.move(os.path.join(chromedriver_dir, "chromedriver"), dest)
+            shutil.rmtree(chromedriver_dir)
+        return find_executable("chromedriver", dest)
 
     def version(self, binary=None, webdriver_binary=None):
         binary = binary or self.binary
@@ -465,11 +507,11 @@
             try:
                 version_string = call(binary, "--version").strip()
             except subprocess.CalledProcessError:
-                self.logger.warning("Failed to call %s", binary)
+                self.logger.warning("Failed to call %s" % binary)
                 return None
-            m = re.match(r"Google Chrome (.*)", version_string)
+            m = re.match(r"(?:Google Chrome|Chromium) (.*)", version_string)
             if not m:
-                self.logger.warning("Failed to extract version from: %s", version_string)
+                self.logger.warning("Failed to extract version from: %s" % version_string)
                 return None
             return m.group(1)
         self.logger.warning("Unable to extract version from binary on Windows.")
@@ -494,13 +536,14 @@
     def find_webdriver(self, channel=None):
         return find_executable("chromedriver")
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         chrome = Chrome()
         return chrome.install_webdriver(dest, channel)
 
     def version(self, binary=None, webdriver_binary=None):
         return None
 
+
 class Opera(Browser):
     """Opera-specific interface.
 
@@ -546,7 +589,7 @@
     def find_webdriver(self, channel=None):
         return find_executable("operadriver")
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         if dest is None:
             dest = os.pwd
         latest = get("https://api.github.com/repos/operasoftware/operachromiumdriver/releases/latest").json()["tag_name"]
@@ -569,7 +612,7 @@
         try:
             output = call(binary, "--version")
         except subprocess.CalledProcessError:
-            self.logger.warning("Failed to call %s", binary)
+            self.logger.warning("Failed to call %s" % binary)
             return None
         m = re.search(r"[0-9\.]+( [a-z]+)?$", output.strip())
         if m:
@@ -591,7 +634,7 @@
     def find_webdriver(self, channel=None):
         return find_executable("MicrosoftWebDriver")
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         raise NotImplementedError
 
     def version(self, binary=None, webdriver_binary=None):
@@ -599,9 +642,10 @@
         try:
             return call("powershell.exe", command).strip()
         except (subprocess.CalledProcessError, OSError):
-            self.logger.warning("Failed to call %s in PowerShell", command)
+            self.logger.warning("Failed to call %s in PowerShell" % command)
             return None
 
+
 class EdgeWebDriver(Edge):
     product = "edge_webdriver"
 
@@ -621,7 +665,7 @@
     def find_webdriver(self, channel=None):
         return find_executable("IEDriverServer.exe")
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         raise NotImplementedError
 
     def version(self, binary=None, webdriver_binary=None):
@@ -649,7 +693,7 @@
             path = "/Applications/Safari Technology Preview.app/Contents/MacOS"
         return find_executable("safaridriver", path)
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         raise NotImplementedError
 
     def version(self, binary=None, webdriver_binary=None):
@@ -663,11 +707,11 @@
         try:
             version_string = call(webdriver_binary, "--version").strip()
         except subprocess.CalledProcessError:
-            self.logger.warning("Failed to call %s --version", webdriver_binary)
+            self.logger.warning("Failed to call %s --version" % webdriver_binary)
             return None
         m = re.match(r"Included with Safari (.*)", version_string)
         if not m:
-            self.logger.warning("Failed to extract version from: %s", version_string)
+            self.logger.warning("Failed to extract version from: %s" % version_string)
             return None
         return m.group(1)
 
@@ -721,7 +765,7 @@
     def find_webdriver(self, channel=None):
         return None
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         raise NotImplementedError
 
     def version(self, binary=None, webdriver_binary=None):
@@ -751,7 +795,7 @@
     def find_webdriver(self, channel=None):
         raise NotImplementedError
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         raise NotImplementedError
 
     def version(self, binary=None, webdriver_binary=None):
@@ -773,7 +817,7 @@
     def find_webdriver(self, channel=None):
         return None
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         raise NotImplementedError
 
     def version(self, binary=None, webdriver_binary=None):
@@ -795,7 +839,7 @@
     def find_webdriver(self, channel=None):
         return find_executable("WebKitWebDriver")
 
-    def install_webdriver(self, dest=None, channel=None):
+    def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         raise NotImplementedError
 
     def version(self, binary=None, webdriver_binary=None):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/run.py b/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
index ea4bd1c..1178c5a3 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
@@ -266,7 +266,7 @@
 
                 if install:
                     logger.info("Downloading chromedriver")
-                    webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path)
+                    webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path, browser_binary=kwargs["binary"])
             else:
                 logger.info("Using webdriver binary %s" % webdriver_binary)
 
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/formatters/chromium.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/formatters/chromium.py
index f54f23e5..071c2f3 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/formatters/chromium.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/formatters/chromium.py
@@ -88,7 +88,7 @@
         final_result = {
             # There are some required fields that we just hard-code.
             "interrupted": False,
-            "path_delimeter": "/",
+            "path_delimiter": "/",
             "version": 3,
             "seconds_since_epoch": self.start_timestamp_seconds,
             "num_failures_by_type": self.num_failures_by_status,
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/formatters/tests/test_chromium.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/formatters/tests/test_chromium.py
index a6e6c2e..22d9fb4 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/formatters/tests/test_chromium.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/formatters/tests/test_chromium.py
@@ -35,7 +35,7 @@
 
     # Check for existence of required fields
     assert "interrupted" in output_obj
-    assert "path_delimeter" in output_obj
+    assert "path_delimiter" in output_obj
     assert "version" in output_obj
     assert "num_failures_by_type" in output_obj
     assert "tests" in output_obj
diff --git a/third_party/blink/web_tests/resources/idlharness.js b/third_party/blink/web_tests/resources/idlharness.js
index 950df6fa..c7a0409 100644
--- a/third_party/blink/web_tests/resources/idlharness.js
+++ b/third_party/blink/web_tests/resources/idlharness.js
@@ -298,15 +298,29 @@
         }.bind(this));
 
         deps.forEach(function(name) {
-            new_options.only.push(name);
+            if (!new_options.only.includes(name)) {
+                new_options.only.push(name);
+            }
 
             const follow_up = new Set();
             for (const dep_type of ["inheritance", "implements", "includes"]) {
                 if (parsed[dep_type]) {
                     const inheriting = parsed[dep_type];
                     const inheritor = parsed.name || parsed.target;
-                    for (const dep of [inheriting, inheritor]) {
-                        new_options.only.push(dep);
+                    const deps = [inheriting];
+                    // For A includes B, we can ignore A, unless B (or some of its
+                    // members) is being tested.
+                    if (dep_type !== "includes"
+                        || inheriting in this.members && !this.members[inheriting].untested
+                        || this.partials.some(function(p) {
+                                return p.name === inheriting;
+                            })) {
+                        deps.push(inheritor);
+                    }
+                    for (const dep of deps) {
+                        if (!new_options.only.includes(dep)) {
+                            new_options.only.push(dep);
+                        }
                         all_deps.add(dep);
                         follow_up.add(dep);
                     }
@@ -320,7 +334,7 @@
                     next.forEach(process);
                 }
             }
-        });
+        }.bind(this));
     }.bind(this);
 
     for (let parsed of parsed_idls) {
@@ -1256,6 +1270,48 @@
     });
 };
 
+/**
+ * Value of the LegacyNamespace extended attribute, if any.
+ *
+ * https://heycam.github.io/webidl/#LegacyNamespace
+ */
+IdlInterface.prototype.get_legacy_namespace = function()
+{
+    var legacyNamespace = this.extAttrs.find(function(attribute) {
+        return attribute.name === "LegacyNamespace";
+    });
+    return legacyNamespace ? legacyNamespace.rhs.value : undefined;
+};
+
+IdlInterface.prototype.get_interface_object_owner = function()
+{
+    var legacyNamespace = this.get_legacy_namespace();
+    return legacyNamespace ? self[legacyNamespace] : self;
+};
+
+IdlInterface.prototype.assert_interface_object_exists = function()
+{
+    var owner = this.get_legacy_namespace() || "self";
+    assert_own_property(self[owner], this.name, owner + " does not have own property " + format_value(this.name));
+};
+
+IdlInterface.prototype.get_interface_object = function() {
+    if (this.has_extended_attribute("NoInterfaceObject")) {
+        throw new IdlHarnessError(this.name + " has no interface object due to NoInterfaceObject");
+    }
+
+    return this.get_interface_object_owner()[this.name];
+};
+
+IdlInterface.prototype.get_qualified_name = function() {
+    // https://heycam.github.io/webidl/#qualified-name
+    var legacyNamespace = this.get_legacy_namespace();
+    if (legacyNamespace) {
+        return legacyNamespace + "." + this.name;
+    }
+    return this.name;
+};
+
 IdlInterface.prototype.has_to_json_regular_operation = function() {
     return this.members.some(function(m) {
         return m.is_to_json_regular_operation();
@@ -1436,9 +1492,8 @@
 
         // TODO: Should we test here that the property is actually writable
         // etc., or trust getOwnPropertyDescriptor?
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
-        var desc = Object.getOwnPropertyDescriptor(self, this.name);
+        this.assert_interface_object_exists();
+        var desc = Object.getOwnPropertyDescriptor(this.get_interface_object_owner(), this.name);
         assert_false("get" in desc, "self's property " + format_value(this.name) + " should not have a getter");
         assert_false("set" in desc, "self's property " + format_value(this.name) + " should not have a setter");
         assert_true(desc.writable, "self's property " + format_value(this.name) + " should be writable");
@@ -1448,7 +1503,7 @@
         if (this.is_callback()) {
             // "The internal [[Prototype]] property of an interface object for
             // a callback interface must be the Function.prototype object."
-            assert_equals(Object.getPrototypeOf(self[this.name]), Function.prototype,
+            assert_equals(Object.getPrototypeOf(this.get_interface_object()), Function.prototype,
                           "prototype of self's property " + format_value(this.name) + " is not Object.prototype");
 
             return;
@@ -1478,24 +1533,19 @@
         // ES6 (rev 30) 19.1.3.6:
         // "Else, if O has a [[Call]] internal method, then let builtinTag be
         // "Function"."
-        assert_class_string(self[this.name], "Function", "class string of " + this.name);
+        assert_class_string(this.get_interface_object(), "Function", "class string of " + this.name);
 
         // "The [[Prototype]] internal property of an interface object for a
         // non-callback interface is determined as follows:"
-        var prototype = Object.getPrototypeOf(self[this.name]);
+        var prototype = Object.getPrototypeOf(this.get_interface_object());
         if (this.base) {
             // "* If the interface inherits from some other interface, the
             //    value of [[Prototype]] is the interface object for that other
             //    interface."
-            var has_interface_object =
-                !this.array
-                     .members[this.base]
-                     .has_extended_attribute("NoInterfaceObject");
-            if (has_interface_object) {
-                assert_own_property(self, this.base,
-                                    'should inherit from ' + this.base +
-                                    ', but self has no such property');
-                assert_equals(prototype, self[this.base],
+            var inherited_interface = this.array.members[this.base];
+            if (!inherited_interface.has_extended_attribute("NoInterfaceObject")) {
+                inherited_interface.assert_interface_object_exists();
+                assert_equals(prototype, inherited_interface.get_interface_object(),
                               'prototype of ' + this.name + ' is not ' +
                               this.base);
             }
@@ -1513,12 +1563,13 @@
             //
             // "If I was not declared with a [Constructor] extended attribute,
             // then throw a TypeError."
+            var interface_object = this.get_interface_object();
             assert_throws(new TypeError(), function() {
-                self[this.name]();
-            }.bind(this), "interface object didn't throw TypeError when called as a function");
+                interface_object();
+            }, "interface object didn't throw TypeError when called as a function");
             assert_throws(new TypeError(), function() {
-                new self[this.name]();
-            }.bind(this), "interface object didn't throw TypeError when called as a constructor");
+                new interface_object();
+            }, "interface object didn't throw TypeError when called as a constructor");
         }
     }.bind(this), this.name + " interface: existence and properties of interface object");
 
@@ -1527,15 +1578,14 @@
             // This function tests WebIDL as of 2014-10-25.
             // https://heycam.github.io/webidl/#es-interface-call
 
-            assert_own_property(self, this.name,
-                                "self does not have own property " + format_value(this.name));
+            this.assert_interface_object_exists();
 
             // "Interface objects for non-callback interfaces MUST have a
             // property named “length” with attributes { [[Writable]]: false,
             // [[Enumerable]]: false, [[Configurable]]: true } whose value is
             // a Number."
-            assert_own_property(self[this.name], "length");
-            var desc = Object.getOwnPropertyDescriptor(self[this.name], "length");
+            assert_own_property(this.get_interface_object(), "length");
+            var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "length");
             assert_false("get" in desc, this.name + ".length should not have a getter");
             assert_false("set" in desc, this.name + ".length should not have a setter");
             assert_false(desc.writable, this.name + ".length should not be writable");
@@ -1545,7 +1595,7 @@
             var constructors = this.extAttrs
                 .filter(function(attr) { return attr.name == "Constructor"; });
             var expected_length = minOverloadLength(constructors);
-            assert_equals(self[this.name].length, expected_length, "wrong value for " + this.name + ".length");
+            assert_equals(this.get_interface_object().length, expected_length, "wrong value for " + this.name + ".length");
         }.bind(this), this.name + " interface object length");
     }
 
@@ -1554,22 +1604,21 @@
             // This function tests WebIDL as of 2015-11-17.
             // https://heycam.github.io/webidl/#interface-object
 
-            assert_own_property(self, this.name,
-                                "self does not have own property " + format_value(this.name));
+            this.assert_interface_object_exists();
 
             // "All interface objects must have a property named “name” with
             // attributes { [[Writable]]: false, [[Enumerable]]: false,
             // [[Configurable]]: true } whose value is the identifier of the
             // corresponding interface."
 
-            assert_own_property(self[this.name], "name");
-            var desc = Object.getOwnPropertyDescriptor(self[this.name], "name");
+            assert_own_property(this.get_interface_object(), "name");
+            var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "name");
             assert_false("get" in desc, this.name + ".name should not have a getter");
             assert_false("set" in desc, this.name + ".name should not have a setter");
             assert_false(desc.writable, this.name + ".name should not be writable");
             assert_false(desc.enumerable, this.name + ".name should not be enumerable");
             assert_true(desc.configurable, this.name + ".name should be configurable");
-            assert_equals(self[this.name].name, this.name, "wrong value for " + this.name + ".name");
+            assert_equals(this.get_interface_object().name, this.name, "wrong value for " + this.name + ".name");
         }.bind(this), this.name + " interface object name");
     }
 
@@ -1608,9 +1657,9 @@
             if (exposed_in(exposure_set(this, this.exposureSet)) && 'document' in self) {
                 for (alias of aliases) {
                     assert_true(alias in self, alias + " should exist");
-                    assert_equals(self[alias], self[this.name], "self." + alias + " should be the same value as self." + this.name);
+                    assert_equals(self[alias], this.get_interface_object(), "self." + alias + " should be the same value as self." + this.get_qualified_name());
                     var desc = Object.getOwnPropertyDescriptor(self, alias);
-                    assert_equals(desc.value, self[this.name], "wrong value in " + alias + " property descriptor");
+                    assert_equals(desc.value, this.get_interface_object(), "wrong value in " + alias + " property descriptor");
                     assert_true(desc.writable, alias + " should be writable");
                     assert_false(desc.enumerable, alias + " should not be enumerable");
                     assert_true(desc.configurable, alias + " should be configurable");
@@ -1625,7 +1674,122 @@
 
         }.bind(this), this.name + " interface: legacy window alias");
     }
-    // TODO: Test named constructors if I find any interfaces that have them.
+
+    if (this.has_extended_attribute("NamedConstructor")) {
+        var constructors = this.extAttrs
+            .filter(function(attr) { return attr.name == "NamedConstructor"; });
+        if (constructors.length !== 1) {
+            throw new IdlHarnessError("Internal error: missing support for multiple NamedConstructor extended attributes");
+        }
+        var constructor = constructors[0];
+        var min_length = minOverloadLength([constructor]);
+
+        subsetTestByKey(this.name, test, function()
+        {
+            // This function tests WebIDL as of 2019-01-14.
+
+            // "for every [NamedConstructor] extended attribute on an exposed
+            // interface, a corresponding property must exist on the ECMAScript
+            // global object. The name of the property is the
+            // [NamedConstructor]'s identifier, and its value is an object
+            // called a named constructor, ... . The property has the attributes
+            // { [[Writable]]: true, [[Enumerable]]: false,
+            // [[Configurable]]: true }."
+            var name = constructor.rhs.value;
+            assert_own_property(self, name);
+            var desc = Object.getOwnPropertyDescriptor(self, name);
+            assert_equals(desc.value, self[name], "wrong value in " + name + " property descriptor");
+            assert_true(desc.writable, name + " should be writable");
+            assert_false(desc.enumerable, name + " should not be enumerable");
+            assert_true(desc.configurable, name + " should be configurable");
+            assert_false("get" in desc, name + " should not have a getter");
+            assert_false("set" in desc, name + " should not have a setter");
+        }.bind(this), this.name + " interface: named constructor");
+
+        subsetTestByKey(this.name, test, function()
+        {
+            // This function tests WebIDL as of 2019-01-14.
+
+            // "2. Let F be ! CreateBuiltinFunction(realm, steps,
+            //     realm.[[Intrinsics]].[[%FunctionPrototype%]])."
+            var name = constructor.rhs.value;
+            var value = self[name];
+            assert_equals(typeof value, "function", "type of value in " + name + " property descriptor");
+            assert_not_equals(value, this.get_interface_object(), "wrong value in " + name + " property descriptor");
+            assert_equals(Object.getPrototypeOf(value), Function.prototype, "wrong value for " + name + "'s prototype");
+        }.bind(this), this.name + " interface: named constructor object");
+
+        subsetTestByKey(this.name, test, function()
+        {
+            // This function tests WebIDL as of 2019-01-14.
+
+            // "7. Let proto be the interface prototype object of interface I
+            //     in realm.
+            // "8. Perform ! DefinePropertyOrThrow(F, "prototype",
+            //     PropertyDescriptor{
+            //         [[Value]]: proto, [[Writable]]: false,
+            //         [[Enumerable]]: false, [[Configurable]]: false
+            //     })."
+            var name = constructor.rhs.value;
+            var expected = this.get_interface_object().prototype;
+            var desc = Object.getOwnPropertyDescriptor(self[name], "prototype");
+            assert_equals(desc.value, expected, "wrong value for " + name + ".prototype");
+            assert_false(desc.writable, "prototype should not be writable");
+            assert_false(desc.enumerable, "prototype should not be enumerable");
+            assert_false(desc.configurable, "prototype should not be configurable");
+            assert_false("get" in desc, "prototype should not have a getter");
+            assert_false("set" in desc, "prototype should not have a setter");
+        }.bind(this), this.name + " interface: named constructor prototype property");
+
+        subsetTestByKey(this.name, test, function()
+        {
+            // This function tests WebIDL as of 2019-01-14.
+
+            // "3. Perform ! SetFunctionName(F, id)."
+            var name = constructor.rhs.value;
+            var desc = Object.getOwnPropertyDescriptor(self[name], "name");
+            assert_equals(desc.value, name, "wrong value for " + name + ".name");
+            assert_false(desc.writable, "name should not be writable");
+            assert_false(desc.enumerable, "name should not be enumerable");
+            assert_true(desc.configurable, "name should be configurable");
+            assert_false("get" in desc, "name should not have a getter");
+            assert_false("set" in desc, "name should not have a setter");
+        }.bind(this), this.name + " interface: named constructor name");
+
+        subsetTestByKey(this.name, test, function()
+        {
+            // This function tests WebIDL as of 2019-01-14.
+
+            // "4. Initialize S to the effective overload set for constructors
+            //     with identifier id on interface I and with argument count 0.
+            // "5. Let length be the length of the shortest argument list of
+            //     the entries in S.
+            // "6. Perform ! SetFunctionLength(F, length)."
+            var name = constructor.rhs.value;
+            var desc = Object.getOwnPropertyDescriptor(self[name], "length");
+            assert_equals(desc.value, min_length, "wrong value for " + name + ".length");
+            assert_false(desc.writable, "length should not be writable");
+            assert_false(desc.enumerable, "length should not be enumerable");
+            assert_true(desc.configurable, "length should be configurable");
+            assert_false("get" in desc, "length should not have a getter");
+            assert_false("set" in desc, "length should not have a setter");
+        }.bind(this), this.name + " interface: named constructor length");
+
+        subsetTestByKey(this.name, test, function()
+        {
+            // This function tests WebIDL as of 2019-01-14.
+
+            // "1. Let steps be the following steps:
+            // "    1. If NewTarget is undefined, then throw a TypeError."
+            var name = constructor.rhs.value;
+            var args = constructor.arguments.map(function(arg) {
+                return create_suitable_object(arg.idlType);
+            });
+            assert_throws(new TypeError(), function() {
+                self[name](...args);
+            }.bind(this));
+        }.bind(this), this.name + " interface: named constructor without 'new'");
+    }
 
     subsetTestByKey(this.name, test, function()
     {
@@ -1636,11 +1800,10 @@
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             return;
         }
@@ -1652,9 +1815,9 @@
         // properties that correspond to the regular attributes and regular
         // operations defined on the interface, and is described in more detail
         // in section 4.5.4 below."
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
-        var desc = Object.getOwnPropertyDescriptor(self[this.name], "prototype");
+        var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "prototype");
         assert_false("get" in desc, this.name + ".prototype should not have a getter");
         assert_false("set" in desc, this.name + ".prototype should not have a setter");
         assert_false(desc.writable, this.name + ".prototype should not be writable");
@@ -1687,38 +1850,39 @@
         //     object %ErrorPrototype%."
         //
         if (this.name === "Window") {
-            assert_class_string(Object.getPrototypeOf(self[this.name].prototype),
+            assert_class_string(Object.getPrototypeOf(this.get_interface_object().prototype),
                                 'WindowProperties',
                                 'Class name for prototype of Window' +
                                 '.prototype is not "WindowProperties"');
         } else {
-            var inherit_interface, inherit_interface_has_interface_object;
+            var inherit_interface, inherit_interface_interface_object;
             if (this.base) {
                 inherit_interface = this.base;
-                inherit_interface_has_interface_object =
-                    !this.array
-                         .members[inherit_interface]
-                         .has_extended_attribute("NoInterfaceObject");
+                var parent = this.array.members[inherit_interface];
+                if (!parent.has_extended_attribute("NoInterfaceObject")) {
+                    parent.assert_interface_object_exists();
+                    inherit_interface_interface_object = parent.get_interface_object();
+                }
             } else if (this.name === "DOMException") {
                 inherit_interface = 'Error';
-                inherit_interface_has_interface_object = true;
+                inherit_interface_interface_object = self.Error;
             } else {
                 inherit_interface = 'Object';
-                inherit_interface_has_interface_object = true;
+                inherit_interface_interface_object = self.Object;
             }
-            if (inherit_interface_has_interface_object) {
-                assert_own_property(self, inherit_interface,
-                                    'should inherit from ' + inherit_interface + ', but self has no such property');
-                assert_own_property(self[inherit_interface], 'prototype',
+            if (inherit_interface_interface_object) {
+                assert_not_equals(inherit_interface_interface_object, undefined,
+                                  'should inherit from ' + inherit_interface + ', but there is no such property');
+                assert_own_property(inherit_interface_interface_object, 'prototype',
                                     'should inherit from ' + inherit_interface + ', but that object has no "prototype" property');
-                assert_equals(Object.getPrototypeOf(self[this.name].prototype),
-                              self[inherit_interface].prototype,
+                assert_equals(Object.getPrototypeOf(this.get_interface_object().prototype),
+                              inherit_interface_interface_object.prototype,
                               'prototype of ' + this.name + '.prototype is not ' + inherit_interface + '.prototype');
             } else {
                 // We can't test that we get the correct object, because this is the
                 // only way to get our hands on it. We only test that its class
                 // string, at least, is correct.
-                assert_class_string(Object.getPrototypeOf(self[this.name].prototype),
+                assert_class_string(Object.getPrototypeOf(this.get_interface_object().prototype),
                                     inherit_interface + 'Prototype',
                                     'Class name for prototype of ' + this.name +
                                     '.prototype is not "' + inherit_interface + 'Prototype"');
@@ -1726,20 +1890,20 @@
         }
 
         // "The class string of an interface prototype object is the
-        // concatenation of the interface’s identifier and the string
+        // concatenation of the interface’s qualified identifier and the string
         // “Prototype”."
 
         // Skip these tests for now due to a specification issue about
         // prototype name.
         // https://www.w3.org/Bugs/Public/show_bug.cgi?id=28244
 
-        // assert_class_string(self[this.name].prototype, this.name + "Prototype",
+        // assert_class_string(this.get_interface_object().prototype, this.get_qualified_name() + "Prototype",
         //                     "class string of " + this.name + ".prototype");
 
         // String() should end up calling {}.toString if nothing defines a
         // stringifier.
         if (!this.has_stringifier()) {
-            // assert_equals(String(self[this.name].prototype), "[object " + this.name + "Prototype]",
+            // assert_equals(String(this.get_interface_object().prototype), "[object " + this.get_qualified_name() + "Prototype]",
             //         "String(" + this.name + ".prototype)");
         }
     }.bind(this), this.name + " interface: existence and properties of interface prototype object");
@@ -1751,7 +1915,7 @@
     // prototype exotic object."
     // https://heycam.github.io/webidl/#interface-prototype-object
     if (this.is_global()) {
-        this.test_immutable_prototype("interface prototype object", self[this.name].prototype);
+        this.test_immutable_prototype("interface prototype object", this.get_interface_object().prototype);
     }
 
     subsetTestByKey(this.name, test, function()
@@ -1760,16 +1924,15 @@
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             return;
         }
 
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
         // "If the [NoInterfaceObject] extended attribute was not specified on
@@ -1777,15 +1940,15 @@
         // property named “constructor” with attributes { [[Writable]]: true,
         // [[Enumerable]]: false, [[Configurable]]: true } whose value is a
         // reference to the interface object for the interface."
-        assert_own_property(self[this.name].prototype, "constructor",
+        assert_own_property(this.get_interface_object().prototype, "constructor",
                             this.name + '.prototype does not have own property "constructor"');
-        var desc = Object.getOwnPropertyDescriptor(self[this.name].prototype, "constructor");
+        var desc = Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, "constructor");
         assert_false("get" in desc, this.name + ".prototype.constructor should not have a getter");
         assert_false("set" in desc, this.name + ".prototype.constructor should not have a setter");
         assert_true(desc.writable, this.name + ".prototype.constructor should be writable");
         assert_false(desc.enumerable, this.name + ".prototype.constructor should not be enumerable");
         assert_true(desc.configurable, this.name + ".prototype.constructor should be configurable");
-        assert_equals(self[this.name].prototype.constructor, self[this.name],
+        assert_equals(this.get_interface_object().prototype.constructor, this.get_interface_object(),
                       this.name + '.prototype.constructor is not the same object as ' + this.name);
     }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property');
 
@@ -1796,16 +1959,15 @@
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             return;
         }
 
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
         // If the interface has any member declared with the [Unscopable] extended
@@ -1814,7 +1976,7 @@
         // { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true },
         // and whose value is an object created as follows...
         var unscopables = this.get_unscopables().map(m => m.name);
-        var proto = self[this.name].prototype;
+        var proto = this.get_interface_object().prototype;
         if (unscopables.length != 0) {
             assert_own_property(
                 proto, Symbol.unscopables,
@@ -1845,7 +2007,7 @@
                                   this.name + '.prototype[Symbol.unscopables] has unexpected property "' + prop + '"');
             }
         } else {
-            assert_equals(Object.getOwnPropertyDescriptor(self[this.name].prototype, Symbol.unscopables),
+            assert_equals(Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, Symbol.unscopables),
                           undefined,
                           this.name + '.prototype should not have @@unscopables');
         }
@@ -1962,21 +2124,20 @@
 
     subsetTestByKey(this.name, test, function()
     {
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         // "For each constant defined on an interface A, there must be
         // a corresponding property on the interface object, if it
         // exists."
-        assert_own_property(self[this.name], member.name);
+        assert_own_property(this.get_interface_object(), member.name);
         // "The value of the property is that which is obtained by
         // converting the constant’s IDL value to an ECMAScript
         // value."
-        assert_equals(self[this.name][member.name], constValue(member.value),
+        assert_equals(this.get_interface_object()[member.name], constValue(member.value),
                       "property has wrong value");
         // "The property has attributes { [[Writable]]: false,
         // [[Enumerable]]: true, [[Configurable]]: false }."
-        var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name);
+        var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), member.name);
         assert_false("get" in desc, "property should not have a getter");
         assert_false("set" in desc, "property should not have a setter");
         assert_false(desc.writable, "property should not be writable");
@@ -1988,22 +2149,21 @@
     // exist on the interface prototype object."
     subsetTestByKey(this.name, test, function()
     {
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             return;
         }
 
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
-        assert_own_property(self[this.name].prototype, member.name);
-        assert_equals(self[this.name].prototype[member.name], constValue(member.value),
+        assert_own_property(this.get_interface_object().prototype, member.name);
+        assert_equals(this.get_interface_object().prototype[member.name], constValue(member.value),
                       "property has wrong value");
-        var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name);
+        var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), member.name);
         assert_false("get" in desc, "property should not have a getter");
         assert_false("set" in desc, "property should not have a setter");
         assert_false(desc.writable, "property should not be writable");
@@ -2026,13 +2186,12 @@
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
-        assert_own_property(self[this.name], "prototype",
+        this.assert_interface_object_exists();
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
         if (member["static"]) {
-            assert_own_property(self[this.name], member.name,
+            assert_own_property(this.get_interface_object(), member.name,
                 "The interface object must have a property " +
                 format_value(member.name));
             a_test.done();
@@ -2045,7 +2204,7 @@
             assert_own_property(self, member.name,
                 "The global object must have a property " +
                 format_value(member.name));
-            assert_false(member.name in self[this.name].prototype,
+            assert_false(member.name in this.get_interface_object().prototype,
                 "The prototype object should not have a property " +
                 format_value(member.name));
 
@@ -2073,34 +2232,34 @@
             // since it will call done() on a_test.
             this.do_interface_attribute_asserts(self, member, a_test);
         } else {
-            assert_true(member.name in self[this.name].prototype,
+            assert_true(member.name in this.get_interface_object().prototype,
                 "The prototype object must have a property " +
                 format_value(member.name));
 
             if (!member.has_extended_attribute("LenientThis")) {
                 if (member.idlType.generic !== "Promise") {
                     assert_throws(new TypeError(), function() {
-                        self[this.name].prototype[member.name];
+                        this.get_interface_object().prototype[member.name];
                     }.bind(this), "getting property on prototype object must throw TypeError");
                     // do_interface_attribute_asserts must be the last thing we
                     // do, since it will call done() on a_test.
-                    this.do_interface_attribute_asserts(self[this.name].prototype, member, a_test);
+                    this.do_interface_attribute_asserts(this.get_interface_object().prototype, member, a_test);
                 } else {
                     promise_rejects(a_test, new TypeError(),
-                                    self[this.name].prototype[member.name])
+                                    this.get_interface_object().prototype[member.name])
                         .then(function() {
                             // do_interface_attribute_asserts must be the last
                             // thing we do, since it will call done() on a_test.
-                            this.do_interface_attribute_asserts(self[this.name].prototype,
+                            this.do_interface_attribute_asserts(this.get_interface_object().prototype,
                                                                 member, a_test);
                         }.bind(this));
                 }
             } else {
-                assert_equals(self[this.name].prototype[member.name], undefined,
+                assert_equals(this.get_interface_object().prototype[member.name], undefined,
                               "getting property on prototype object must return undefined");
               // do_interface_attribute_asserts must be the last thing we do,
               // since it will call done() on a_test.
-              this.do_interface_attribute_asserts(self[this.name].prototype, member, a_test);
+              this.do_interface_attribute_asserts(this.get_interface_object().prototype, member, a_test);
             }
         }
     }.bind(this));
@@ -2125,17 +2284,16 @@
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             a_test.done();
             return;
         }
 
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
         // "For each unique identifier of an exposed operation defined on the
@@ -2150,9 +2308,9 @@
         // "* If the operation is static, then the property exists on the
         //    interface object."
         if (member["static"]) {
-            assert_own_property(self[this.name], member.name,
+            assert_own_property(this.get_interface_object(), member.name,
                     "interface object missing static operation");
-            memberHolderObject = self[this.name];
+            memberHolderObject = this.get_interface_object();
         // "* Otherwise, [...] if the interface was declared with the [Global]
         //    extended attribute, then the property exists
         //    on every object that implements the interface."
@@ -2163,9 +2321,9 @@
         // "* Otherwise, the property exists solely on the interface’s
         //    interface prototype object."
         } else {
-            assert_own_property(self[this.name].prototype, member.name,
+            assert_own_property(this.get_interface_object().prototype, member.name,
                     "interface prototype object missing non-static operation");
-            memberHolderObject = self[this.name].prototype;
+            memberHolderObject = this.get_interface_object().prototype;
         }
         this.do_member_unscopable_asserts(member);
         this.do_member_operation_asserts(memberHolderObject, member, a_test);
@@ -2180,7 +2338,7 @@
         return;
     }
 
-    var unscopables = self[this.name].prototype[Symbol.unscopables];
+    var unscopables = this.get_interface_object().prototype[Symbol.unscopables];
     var prop = member.name;
     var propDesc = Object.getOwnPropertyDescriptor(unscopables, prop);
     assert_equals(typeof propDesc, "object",
@@ -2266,22 +2424,7 @@
     }
 }
 
-IdlInterface.prototype.add_iterable_members = function(member)
-{
-    this.members.push(new IdlInterfaceMember(
-        { type: "operation", name: "entries", idlType: "iterator", arguments: []}));
-    this.members.push(new IdlInterfaceMember(
-        { type: "operation", name: "keys", idlType: "iterator", arguments: []}));
-    this.members.push(new IdlInterfaceMember(
-        { type: "operation", name: "values", idlType: "iterator", arguments: []}));
-    this.members.push(new IdlInterfaceMember(
-        { type: "operation", name: "forEach", idlType: "void",
-          arguments:
-          [{ name: "callback", idlType: {idlType: "function"}},
-           { name: "thisValue", idlType: {idlType: "any"}, optional: true}]}));
-};
-
-IdlInterface.prototype.test_to_json_operation = function(memberHolderObject, member) {
+IdlInterface.prototype.test_to_json_operation = function(desc, memberHolderObject, member) {
     var instanceName = memberHolderObject && memberHolderObject.constructor.name
         || member.name + " object";
     if (member.has_extended_attribute("Default")) {
@@ -2297,39 +2440,40 @@
                 this.array.assert_type_is(json[k], type);
                 delete json[k];
             }, this);
-        }.bind(this), "Test default toJSON operation of " + instanceName);
+        }.bind(this), this.name + " interface: default toJSON operation on " + desc);
     } else {
         subsetTestByKey(this.name, test, function() {
             assert_true(this.array.is_json_type(member.idlType), JSON.stringify(member.idlType) + " is not an appropriate return value for the toJSON operation of " + instanceName);
             this.array.assert_type_is(memberHolderObject.toJSON(), member.idlType);
-        }.bind(this), "Test toJSON operation of " + instanceName);
+        }.bind(this), this.name + " interface: toJSON operation on " + desc);
     }
 };
 
 IdlInterface.prototype.test_member_iterable = function(member)
 {
-    var interfaceName = this.name;
-    var isPairIterator = member.idlType.length === 2;
     subsetTestByKey(this.name, test, function()
     {
-        var descriptor = Object.getOwnPropertyDescriptor(self[interfaceName].prototype, Symbol.iterator);
-        assert_true(descriptor.writable, "property should be writable");
-        assert_true(descriptor.configurable, "property should be configurable");
-        assert_false(descriptor.enumerable, "property should not be enumerable");
-        assert_equals(self[interfaceName].prototype[Symbol.iterator].name, isPairIterator ? "entries" : "values", "@@iterator function does not have the right name");
-    }, "Testing Symbol.iterator property of iterable interface " + interfaceName);
+        var isPairIterator = member.idlType.length === 2;
+        var proto = this.get_interface_object().prototype;
+        var descriptor = Object.getOwnPropertyDescriptor(proto, Symbol.iterator);
 
-    if (isPairIterator) {
-        subsetTestByKey(this.name, test, function() {
-            assert_equals(self[interfaceName].prototype[Symbol.iterator], self[interfaceName].prototype["entries"], "entries method is not the same as @@iterator");
-        }, "Testing pair iterable interface " + interfaceName);
-    } else {
-        subsetTestByKey(this.name, test, function() {
-            ["entries", "keys", "values", "forEach", Symbol.Iterator].forEach(function(property) {
-                assert_equals(self[interfaceName].prototype[property], Array.prototype[property], property + " function is not the same as Array one");
-            });
-        }, "Testing value iterable interface " + interfaceName);
-    }
+        assert_true(descriptor.writable, "@@iterator property should be writable");
+        assert_true(descriptor.configurable, "@@iterator property should be configurable");
+        assert_false(descriptor.enumerable, "@@iterator property should not be enumerable");
+        assert_equals(typeof descriptor.value, "function", "@@iterator property should be a function");
+        assert_equals(descriptor.value.length, 0, "@@iterator function object length should be 0");
+        assert_equals(descriptor.value.name, isPairIterator ? "entries" : "values", "@@iterator function object should have the right name");
+
+        if (isPairIterator) {
+            assert_equals(proto["entries"], proto[Symbol.iterator], "entries method should be the same as @@iterator method");
+        } else {
+            assert_equals(proto[Symbol.iterator], Array.prototype[Symbol.iterator], "@@iterator method should be the same as Array prototype's");
+            ["entries", "keys", "values", "forEach", Symbol.iterator].forEach(function(property) {
+                var propertyName = property === Symbol.iterator ? "@@iterator" : property;
+                assert_equals(proto[property], Array.prototype[property], propertyName + " method should be the same as Array prototype's");
+            }.bind(this));
+        }
+    }.bind(this), this.name + " interface: iterable<" + member.idlType.map(function(t) { return t.idlType; }).join(", ") + ">");
 };
 
 IdlInterface.prototype.test_member_stringifier = function(member)
@@ -2340,21 +2484,20 @@
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             return;
         }
 
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
         // ". . . the property exists on the interface prototype object."
-        var interfacePrototypeObject = self[this.name].prototype;
-        assert_own_property(self[this.name].prototype, "toString",
+        var interfacePrototypeObject = this.get_interface_object().prototype;
+        assert_own_property(interfacePrototypeObject, "toString",
                 "interface prototype object missing non-static operation");
 
         var stringifierUnforgeable = member.isUnforgeable;
@@ -2380,7 +2523,7 @@
 
         // "Let O be the result of calling ToObject on the this value."
         assert_throws(new TypeError(), function() {
-            self[this.name].prototype.toString.apply(null, []);
+            interfacePrototypeObject.toString.apply(null, []);
         }, "calling stringifier with this = null didn't throw TypeError");
 
         // "If O is not an object that implements the interface on which the
@@ -2389,7 +2532,7 @@
         // TODO: Test a platform object that implements some other
         // interface.  (Have to be sure to get inheritance right.)
         assert_throws(new TypeError(), function() {
-            self[this.name].prototype.toString.apply({}, []);
+            interfacePrototypeObject.toString.apply({}, []);
         }, "calling stringifier with this = {} didn't throw TypeError");
     }.bind(this), this.name + " interface: stringifier");
 };
@@ -2399,19 +2542,6 @@
     for (var i = 0; i < this.members.length; i++)
     {
         var member = this.members[i];
-        switch (member.type) {
-        case "iterable":
-            this.add_iterable_members(member);
-            break;
-        // TODO: add setlike and maplike handling.
-        default:
-            break;
-        }
-    }
-
-    for (var i = 0; i < this.members.length; i++)
-    {
-        var member = this.members[i];
         if (member.untested) {
             continue;
         }
@@ -2419,10 +2549,10 @@
         if (!exposed_in(exposure_set(member, this.exposureSet))) {
             subsetTestByKey(this.name, test, function() {
                 // It's not exposed, so we shouldn't find it anywhere.
-                assert_false(member.name in self[this.name],
+                assert_false(member.name in this.get_interface_object(),
                              "The interface object must not have a property " +
                              format_value(member.name));
-                assert_false(member.name in self[this.name].prototype,
+                assert_false(member.name in this.get_interface_object().prototype,
                              "The prototype object must not have a property " +
                              format_value(member.name));
             }.bind(this), this.name + " interface: member " + member.name);
@@ -2538,9 +2668,8 @@
         {
             assert_equals(exception, null, "Unexpected exception when evaluating object");
             assert_equals(typeof obj, expected_typeof, "wrong typeof object");
-            assert_own_property(self, this.name,
-                                "self does not have own property " + format_value(this.name));
-            assert_own_property(self[this.name], "prototype",
+            this.assert_interface_object_exists();
+            assert_own_property(this.get_interface_object(), "prototype",
                                 'interface "' + this.name + '" does not have own property "prototype"');
 
             // "The value of the internal [[Prototype]] property of the
@@ -2548,22 +2677,22 @@
             // interface from the platform object’s associated global
             // environment."
             assert_equals(Object.getPrototypeOf(obj),
-                          self[this.name].prototype,
+                          this.get_interface_object().prototype,
                           desc + "'s prototype is not " + this.name + ".prototype");
         }.bind(this), this.name + " must be primary interface of " + desc);
     }
 
     // "The class string of a platform object that implements one or more
-    // interfaces must be the identifier of the primary interface of the
+    // interfaces must be the qualified name of the primary interface of the
     // platform object."
     subsetTestByKey(this.name, test, function()
     {
         assert_equals(exception, null, "Unexpected exception when evaluating object");
         assert_equals(typeof obj, expected_typeof, "wrong typeof object");
-        assert_class_string(obj, this.name, "class string of " + desc);
+        assert_class_string(obj, this.get_qualified_name(), "class string of " + desc);
         if (!this.has_stringifier())
         {
-            assert_equals(String(obj), "[object " + this.name + "]", "String(" + desc + ")");
+            assert_equals(String(obj), "[object " + this.get_qualified_name() + "]", "String(" + desc + ")");
         }
     }.bind(this), "Stringification of " + desc);
 };
@@ -2708,7 +2837,7 @@
         }
 
         if (member.is_to_json_regular_operation()) {
-            this.test_to_json_operation(obj, member);
+            this.test_to_json_operation(desc, obj, member);
         }
     }
 };
diff --git a/third_party/blink/web_tests/resources/testdriver.js b/third_party/blink/web_tests/resources/testdriver.js
index 8ffd7650..031be1b 100644
--- a/third_party/blink/web_tests/resources/testdriver.js
+++ b/third_party/blink/web_tests/resources/testdriver.js
@@ -194,30 +194,87 @@
          */
         action_sequence: function(actions) {
             return window.test_driver_internal.action_sequence(actions);
+        },
+
+        /**
+         * Generates a test report on the current page
+         *
+         * The generate_test_report function generates a report (to be observed
+         * by ReportingObserver) for testing purposes, as described in
+         * {@link https://w3c.github.io/reporting/#generate-test-report-command}
+         *
+         * @returns {Promise} fulfilled after the report is generated, or
+         *                    rejected if the report generation fails
+         */
+        generate_test_report: function(message) {
+            return window.test_driver_internal.generate_test_report(message);
         }
     };
 
     window.test_driver_internal = {
         /**
-         * Triggers a user-initiated click
+         * This flag should be set to `true` by any code which implements the
+         * internal methods defined below for automation purposes. Doing so
+         * allows the library to signal failure immediately when an automated
+         * implementation of one of the methods is not available.
+         */
+        in_automation: false,
+
+        /**
+         * Waits for a user-initiated click
          *
          * @param {Element} element - element to be clicked
          * @param {{x: number, y: number} coords - viewport coordinates to click at
-         * @returns {Promise} fulfilled after click occurs or rejected if click fails
+         * @returns {Promise} fulfilled after click occurs
          */
         click: function(element, coords) {
-            return Promise.reject(new Error("unimplemented"));
+            if (this.in_automation) {
+                return Promise.reject(new Error('Not implemented'));
+            }
+
+            return new Promise(function(resolve, reject) {
+                element.addEventListener("click", resolve);
+            });
         },
 
         /**
-         * Triggers a user-initiated click
+         * Waits for an element to receive a series of key presses
          *
-         * @param {Element} element - element to be clicked
-         * @param {String} keys - keys to send to the element
-         * @returns {Promise} fulfilled after keys are sent or rejected if click fails
+         * @param {Element} element - element which should receve key presses
+         * @param {String} keys - keys to expect
+         * @returns {Promise} fulfilled after keys are received or rejected if
+         *                    an incorrect key sequence is received
          */
         send_keys: function(element, keys) {
-            return Promise.reject(new Error("unimplemented"));
+            if (this.in_automation) {
+                return Promise.reject(new Error('Not implemented'));
+            }
+
+            return new Promise(function(resolve, reject) {
+                var seen = "";
+
+                function remove() {
+                    element.removeEventListener("keydown", onKeyDown);
+                }
+
+                function onKeyDown(event) {
+                    if (event.key.length > 1) {
+                        return;
+                    }
+
+                    seen += event.key;
+
+                    if (keys.indexOf(seen) !== 0) {
+                        reject(new Error("Unexpected key sequence: " + seen));
+                        remove();
+                    } else if (seen === keys) {
+                        resolve();
+                        remove();
+                    }
+                }
+
+                element.addEventListener("keydown", onKeyDown);
+            });
         },
 
         /**
@@ -233,11 +290,22 @@
         /**
          * Send a sequence of pointer actions
          *
-         * @returns {Promise} fulfilled after actions are sent, rejected if any actions
+         * @returns {Promise} fufilled after actions are sent, rejected if any actions
          *                    fail
          */
         action_sequence: function(actions) {
             return Promise.reject(new Error("unimplemented"));
+        },
+
+        /**
+         * Generates a test report on the current page
+         *
+         * @param {String} message - the message to be contained in the report
+         * @returns {Promise} fulfilled after the report is generated, or
+         *                    rejected if the report generation fails
+         */
+        generate_test_report: function(message) {
+            return Promise.reject(new Error("unimplemented"));
         }
     };
 })();
diff --git a/third_party/blink/web_tests/resources/testharness.js b/third_party/blink/web_tests/resources/testharness.js
index 867f88b3..d40817c 100644
--- a/third_party/blink/web_tests/resources/testharness.js
+++ b/third_party/blink/web_tests/resources/testharness.js
@@ -145,9 +145,9 @@
     };
 
     WindowTestEnvironment.prototype._forEach_windows = function(callback) {
-        // Iterate of the the windows [self ... top, opener]. The callback is passed
-        // two objects, the first one is the windows object itself, the second one
-        // is a boolean indicating whether or not its on the same origin as the
+        // Iterate over the windows [self ... top, opener]. The callback is passed
+        // two objects, the first one is the window object itself, the second one
+        // is a boolean indicating whether or not it's on the same origin as the
         // current window.
         var cache = this.window_cache;
         if (!cache) {
@@ -513,7 +513,7 @@
             return new DedicatedWorkerTestEnvironment();
         }
 
-        if (!('self' in global_scope)) {
+        if (!('location' in global_scope)) {
             return new ShellTestEnvironment();
         }
 
@@ -635,7 +635,7 @@
      * which can make it a lot easier to test a very specific series of events,
      * including ensuring that unexpected events are not fired at any point.
      */
-    function EventWatcher(test, watchedNode, eventTypes)
+    function EventWatcher(test, watchedNode, eventTypes, timeoutPromise)
     {
         if (typeof eventTypes == 'string') {
             eventTypes = [eventTypes];
@@ -712,6 +712,27 @@
                 recordedEvents = [];
             }
             return new Promise(function(resolve, reject) {
+                var timeout = test.step_func(function() {
+                    // If the timeout fires after the events have been received
+                    // or during a subsequent call to wait_for, ignore it.
+                    if (!waitingFor || waitingFor.resolve !== resolve)
+                        return;
+
+                    // This should always fail, otherwise we should have
+                    // resolved the promise.
+                    assert_true(waitingFor.types.length == 0,
+                                'Timed out waiting for ' + waitingFor.types.join(', '));
+                    var result = recordedEvents;
+                    recordedEvents = null;
+                    var resolveFunc = waitingFor.resolve;
+                    waitingFor = null;
+                    resolveFunc(result);
+                });
+
+                if (timeoutPromise) {
+                    timeoutPromise().then(timeout);
+                }
+
                 waitingFor = {
                     types: types,
                     resolve: resolve,
@@ -754,7 +775,7 @@
         }
         if (tests.file_is_test) {
             // file is test files never have asynchronous cleanup logic,
-            // meaning the fully-sycnronous `done` function can be used here.
+            // meaning the fully-synchronous `done` function can be used here.
             tests.tests[0].done();
         }
         tests.end_wait();
@@ -1262,6 +1283,13 @@
     }
     expose(assert_own_property, "assert_own_property");
 
+    function assert_not_own_property(object, property_name, description) {
+        assert(!object.hasOwnProperty(property_name),
+               "assert_not_own_property", description,
+               "unexpected property ${p} is found on object", {p:property_name});
+    }
+    expose(assert_not_own_property, "assert_not_own_property");
+
     function _assert_inherits(name) {
         return function (object, property_name, description)
         {
@@ -1479,11 +1507,9 @@
         this.index = null;
 
         this.properties = properties;
-        var timeout = properties.timeout ? properties.timeout : settings.test_timeout;
-        if (timeout !== null) {
-            this.timeout_length = timeout * tests.timeout_multiplier;
-        } else {
-            this.timeout_length = null;
+        this.timeout_length = settings.test_timeout;
+        if (this.timeout_length !== null) {
+            this.timeout_length *= tests.timeout_multiplier;
         }
 
         this.message = null;
@@ -1541,7 +1567,7 @@
             return;
         }
         this.phase = this.phases.STARTED;
-        //If we don't get a result before the harness times out that will be a test timout
+        //If we don't get a result before the harness times out that will be a test timeout
         this.set_status(this.TIMEOUT, "Test timed out");
 
         tests.started = true;
@@ -1897,7 +1923,9 @@
      */
     function RemoteContext(remote, message_target, message_filter) {
         this.running = true;
+        this.started = false;
         this.tests = new Array();
+        this.early_exception = null;
 
         var this_obj = this;
         // If remote context is cross origin assigning to onerror is not
@@ -1936,6 +1964,21 @@
     }
 
     RemoteContext.prototype.remote_error = function(error) {
+        if (error.preventDefault) {
+            error.preventDefault();
+        }
+
+        // Defer interpretation of errors until the testing protocol has
+        // started and the remote test's `allow_uncaught_exception` property
+        // is available.
+        if (!this.started) {
+            this.early_exception = error;
+        } else if (!this.allow_uncaught_exception) {
+            this.report_uncaught(error);
+        }
+    };
+
+    RemoteContext.prototype.report_uncaught = function(error) {
         var message = error.message || String(error);
         var filename = (error.filename ? " " + error.filename: "");
         // FIXME: Display remote error states separately from main document
@@ -1943,9 +1986,14 @@
         tests.set_status(tests.status.ERROR,
                          "Error in remote" + filename + ": " + message,
                          error.stack);
+    };
 
-        if (error.preventDefault) {
-            error.preventDefault();
+    RemoteContext.prototype.start = function(data) {
+        this.started = true;
+        this.allow_uncaught_exception = data.properties.allow_uncaught_exception;
+
+        if (this.early_exception && !this.allow_uncaught_exception) {
+            this.report_uncaught(this.early_exception);
         }
     };
 
@@ -1995,6 +2043,7 @@
     };
 
     RemoteContext.prototype.message_handlers = {
+        start: RemoteContext.prototype.start,
         test_state: RemoteContext.prototype.test_state,
         result: RemoteContext.prototype.test_done,
         complete: RemoteContext.prototype.remote_done
@@ -2107,6 +2156,9 @@
                     }
                 } else if (p == "timeout_multiplier") {
                     this.timeout_multiplier = value;
+                    if (this.timeout_length) {
+                         this.timeout_length *= this.timeout_multiplier;
+                    }
                 }
             }
         }
@@ -2529,6 +2581,9 @@
 
     Output.prototype.resolve_log = function() {
         var output_document;
+        if (this.output_node) {
+            return;
+        }
         if (typeof this.output_document === "function") {
             output_document = this.output_document.apply(undefined);
         } else {
@@ -2539,7 +2594,7 @@
         }
         var node = output_document.getElementById("log");
         if (!node) {
-            if (!document.readyState == "loading") {
+            if (output_document.readyState === "loading") {
                 return;
             }
             node = output_document.createElementNS("http://www.w3.org/1999/xhtml", "div");
@@ -2579,8 +2634,8 @@
         if (!this.enabled) {
             return;
         }
+        this.resolve_log();
         if (this.phase < this.HAVE_RESULTS) {
-            this.resolve_log();
             this.phase = this.HAVE_RESULTS;
         }
         var done_count = tests.tests.length - tests.num_pending;
@@ -2787,7 +2842,7 @@
     /*
      * Template code
      *
-     * A template is just a javascript structure. An element is represented as:
+     * A template is just a JavaScript structure. An element is represented as:
      *
      * [tag_name, {attr_name:attr_value}, child1, child2]
      *
@@ -2949,7 +3004,7 @@
     }
 
     /*
-     * Utility funcions
+     * Utility functions
      */
     function assert(expected_true, function_name, description, error, substitutions)
     {
@@ -3212,7 +3267,7 @@
         // Touching the postMessage prop on a window can throw if the window is
         // not from the same origin AND post message is not supported in that
         // browser. So just doing an existence test here won't do, you also need
-        // to wrap it in a try..cacth block.
+        // to wrap it in a try..catch block.
         try {
             type = typeof w.postMessage;
             if (type === "function") {
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index a9e9d86..f8d2d1a 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -696,6 +696,16 @@
       'fuchsia-fyi-x64-rel': 'release_trybot_fuchsia',
       'fuchsia_x64': 'release_trybot_fuchsia',
       'fuchsia-x64-cast': 'release_trybot_fuchsia_cast',
+      'gpu-manual-try-linux-amd-rel': 'gpu_fyi_tests_release_trybot',
+      'gpu-manual-try-linux-intel-dqp': 'deqp_release_trybot',
+      'gpu-manual-try-linux-intel-exp': 'gpu_fyi_tests_release_trybot',
+      'gpu-manual-try-linux-intel-ozn': 'gpu_fyi_tests_ozone_linux_system_gbm_libdrm_release_trybot',
+      'gpu-manual-try-linux-intel-rel': 'gpu_fyi_tests_release_trybot',
+      'gpu-manual-try-linux-nvidia-dbg': 'gpu_fyi_tests_debug_trybot',
+      'gpu-manual-try-linux-nvidia-dqp': 'deqp_release_trybot',
+      'gpu-manual-try-linux-nvidia-exp': 'gpu_fyi_tests_release_trybot',
+      'gpu-manual-try-linux-nvidia-rel': 'gpu_fyi_tests_release_trybot',
+      'gpu-manual-try-linux-nvidia-tsn': 'gpu_fyi_tests_release_trybot_tsan',
       'layout_test_leak_detection': 'release_trybot',
       'leak_detection_linux': 'release_trybot',
       'linux-blink-heap-incremental-marking': 'debug_trybot_enable_blink_heap_incremental_marking',
@@ -771,7 +781,19 @@
     },
 
     'tryserver.chromium.win': {
-      'gpu_manual_try_win7_nvidia_rel': 'gpu_fyi_tests_release_trybot_x86',
+      'gpu-manual-try-win7-amd-dbg': 'gpu_fyi_tests_debug_trybot_x86',
+      'gpu-manual-try-win7-amd-dqp': 'deqp_release_trybot_x86',
+      'gpu-manual-try-win7-amd-rel': 'gpu_fyi_tests_release_trybot_x86',
+      'gpu-manual-try-win7-nvidia-dqp-64': 'deqp_release_trybot',
+      'gpu-manual-try-win7-nvidia-rel': 'gpu_fyi_tests_release_trybot_x86',
+      'gpu-manual-try-win7-nvidia-rel-64': 'gpu_fyi_tests_release_trybot',
+      'gpu-manual-try-win10-intel-dqp': 'deqp_release_trybot_x86',
+      'gpu-manual-try-win10-intel-exp': 'gpu_fyi_tests_release_trybot_x86',
+      'gpu-manual-try-win10-intel-rel': 'gpu_fyi_tests_release_trybot_x86',
+      'gpu-manual-try-win10-nvidia-dbg': 'gpu_fyi_tests_debug_trybot_x86',
+      'gpu-manual-try-win10-nvidia-dqp': 'deqp_release_trybot_x86',
+      'gpu-manual-try-win10-nvidia-exp': 'gpu_fyi_tests_release_trybot_x86',
+      'gpu-manual-try-win10-nvidia-rel': 'gpu_fyi_tests_release_trybot_x86',
       'win7_chromium_rel_loc_exp': 'gpu_tests_release_trybot_x86_minimal_symbols_resource_whitelisting',
       'win10_chromium_x64_dbg_ng': 'gpu_tests_debug_trybot',
       'win10_chromium_x64_rel_ng': 'gpu_tests_release_trybot_resource_whitelisting',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 2a9fdb4..2985d30 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -22534,7 +22534,6 @@
   <int value="2825" label="BuiltInModuleVirtualScroller"/>
   <int value="2826" label="AdClickNavigation"/>
   <int value="2827" label="RTCStatsRelativePacketArrivalDelay"/>
-  <int value="2828" label="FlexboxWithOverflowFlexItemIntrinsicSize"/>
   <int value="2829" label="CSSSelectorHostContextInSnapshotProfile"/>
   <int value="2830" label="CSSSelectorHostContextInLiveProfile"/>
   <int value="2831" label="ImportMap"/>
@@ -31765,6 +31764,8 @@
   <int value="-2133892372" label="ResamplingInputEvents:disabled"/>
   <int value="-2133277113" label="CCTModuleCustomHeader:disabled"/>
   <int value="-2132591642" label="enable-input-view"/>
+  <int value="-2131746498"
+      label="AutofillUseImprovedLabelDisambiguation:enabled"/>
   <int value="-2128705444" label="AssistantAppSupport:enabled"/>
   <int value="-2124839789"
       label="OmniboxUIExperimentHideSteadyStateUrlSchemeAndSubdomains:enabled"/>
@@ -32298,7 +32299,6 @@
   <int value="-1349826793" label="ArcInputMethod:disabled"/>
   <int value="-1349532167" label="enable-wifi-credential-sync"/>
   <int value="-1346722635" label="gesture-selection"/>
-  <int value="-1346288427" label="AutofillShowFullDisclosureLabel:disabled"/>
   <int value="-1344375439" label="ServiceWorkerPaymentApps:disabled"/>
   <int value="-1343259222" label="RegionalLocalesAsDisplayUI:disabled"/>
   <int value="-1342961844" label="InlineUpdateFlow:disabled"/>
@@ -32496,6 +32496,7 @@
   <int value="-1039555838" label="GamepadExtensions:enabled"/>
   <int value="-1037128156" label="HomeLauncherGestures:disabled"/>
   <int value="-1034344165" label="V8NoTurbo:disabled"/>
+  <int value="-1034152207" label="SendTabToSelfReceive:enabled"/>
   <int value="-1033738911" label="enable-mac-views-dialogs"/>
   <int value="-1031350684" label="PdfIsolation:disabled"/>
   <int value="-1029920490" label="IdleTimeSpellChecking:enabled"/>
@@ -33369,7 +33370,6 @@
   <int value="417709910"
       label="AutofillSendExperimentIdsInPaymentsRPCs:disabled"/>
   <int value="422307097" label="PhysicalWeb:disabled"/>
-  <int value="422426657" label="AutofillShowFullDisclosureLabel:enabled"/>
   <int value="423615350" label="enable-tab-audio-muting"/>
   <int value="423855924" label="enable-tab-switcher-theme-colors"/>
   <int value="430959979" label="SyncStandaloneTransport:disabled"/>
@@ -33717,6 +33717,8 @@
   <int value="1005684777" label="PictureInPicture:disabled"/>
   <int value="1006608931" label="ArcEnableUnifiedAudioFocus:disabled"/>
   <int value="1007444341" label="enable-prefixed-encrypted-media"/>
+  <int value="1008677979"
+      label="AutofillUseImprovedLabelDisambiguation:disabled"/>
   <int value="1012942422" label="HorizontalTabSwitcherAndroid:disabled"/>
   <int value="1015895665" label="drop-sync-credential:enabled"/>
   <int value="1017364362" label="VrIconInDaydreamHome:enabled"/>
@@ -33893,6 +33895,7 @@
   <int value="1277386636" label="QueryInOmnibox:disabled"/>
   <int value="1279584261" label="enable-carrier-switching"/>
   <int value="1280614081" label="show-overdraw-feedback"/>
+  <int value="1281553299" label="SendTabToSelfReceive:disabled"/>
   <int value="1283908088" label="ImprovedLanguageSettings:disabled"/>
   <int value="1283956865" label="force-tablet-mode"/>
   <int value="1283960113" label="disable-fixed-position-compositing"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 2c1a07cf..5f641b7 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -39744,6 +39744,16 @@
   </summary>
 </histogram>
 
+<histogram name="GoogleUpdate.InstallDetails.UpdateCohort"
+    expires_after="2019-06-01">
+  <owner>nikunjb@chromium.org</owner>
+  <owner>chrome-metrics-team@google.com</owner>
+  <summary>
+    Store the hash of update cohort name as reported by Chrome Updater on
+    Windows. Recorded at the start of metrics service.
+  </summary>
+</histogram>
+
 <histogram name="GoogleUpdate.InstallerExitCode" enum="InstallStatus">
   <owner>grt@chromium.org</owner>
   <summary>
@@ -86491,6 +86501,15 @@
   </summary>
 </histogram>
 
+<histogram name="Platform.StatefulLifetimeWrites" units="GB"
+    expires_after="2020-03-07">
+  <owner>asavery@chromium.org</owner>
+  <owner>gwendal@chromium.org</owner>
+  <summary>
+    Chrome OS stateful partition lifetime writes. Sampled once daily.
+  </summary>
+</histogram>
+
 <histogram name="Platform.StatefulUsage" units="%">
   <owner>achuith@chromium.org</owner>
   <owner>omrilio@chromium.org</owner>
@@ -110487,7 +110506,7 @@
 </histogram>
 
 <histogram name="Signin.RefreshTokenRevocationCompleted"
-    enum="GaiaTokenRevocationStatus" expires_after="2019-03-31">
+    enum="GaiaTokenRevocationStatus" expires_after="2021-03-31">
   <owner>droger@chromium.org</owner>
   <owner>msarda@chromium.org</owner>
   <summary>
diff --git a/ui/accessibility/ax_event_generator.cc b/ui/accessibility/ax_event_generator.cc
index 0fac38e..36844d9 100644
--- a/ui/accessibility/ax_event_generator.cc
+++ b/ui/accessibility/ax_event_generator.cc
@@ -178,6 +178,35 @@
   DCHECK_EQ(tree_, tree);
 
   switch (attr) {
+    case ax::mojom::StringAttribute::kAccessKey:
+      AddEvent(node, Event::ACCESS_KEY_CHANGED);
+      break;
+    case ax::mojom::StringAttribute::kAriaInvalidValue:
+      AddEvent(node, Event::INVALID_STATUS_CHANGED);
+      break;
+    case ax::mojom::StringAttribute::kAutoComplete:
+      AddEvent(node, Event::AUTO_COMPLETE_CHANGED);
+      break;
+    case ax::mojom::StringAttribute::kClassName:
+      AddEvent(node, Event::CLASS_NAME_CHANGED);
+      break;
+    case ax::mojom::StringAttribute::kDescription:
+      AddEvent(node, Event::DESCRIPTION_CHANGED);
+      break;
+    case ax::mojom::StringAttribute::kKeyShortcuts:
+      AddEvent(node, Event::KEY_SHORTCUTS_CHANGED);
+      break;
+    case ax::mojom::StringAttribute::kLanguage:
+      AddEvent(node, Event::LANGUAGE_CHANGED);
+      break;
+    case ax::mojom::StringAttribute::kLiveStatus:
+      // TODO(accessibility): tree in the midst of updates. Disallow access to
+      // |node|.
+      if (node->data().GetStringAttribute(
+              ax::mojom::StringAttribute::kLiveStatus) != "off" &&
+          node->data().role != ax::mojom::Role::kAlert)
+        AddEvent(node, Event::LIVE_REGION_CREATED);
+      break;
     case ax::mojom::StringAttribute::kName:
       // If the name of the root node changes, we expect OnTreeDataChanged to
       // add a DOCUMENT_TITLE_CHANGED event instead.
@@ -191,26 +220,12 @@
         FireLiveRegionEvents(node);
       }
       break;
-    case ax::mojom::StringAttribute::kDescription:
-      AddEvent(node, Event::DESCRIPTION_CHANGED);
+    case ax::mojom::StringAttribute::kPlaceholder:
+      AddEvent(node, Event::PLACEHOLDER_CHANGED);
       break;
     case ax::mojom::StringAttribute::kValue:
       AddEvent(node, Event::VALUE_CHANGED);
       break;
-    case ax::mojom::StringAttribute::kAriaInvalidValue:
-      AddEvent(node, Event::INVALID_STATUS_CHANGED);
-      break;
-    case ax::mojom::StringAttribute::kLiveStatus:
-      // TODO(accessibility): tree in the midst of updates. Disallow access to
-      // |node|.
-      if (node->data().GetStringAttribute(
-              ax::mojom::StringAttribute::kLiveStatus) != "off" &&
-          node->data().role != ax::mojom::Role::kAlert)
-        AddEvent(node, Event::LIVE_REGION_CREATED);
-      break;
-    case ax::mojom::StringAttribute::kAutoComplete:
-      AddEvent(node, Event::AUTO_COMPLETE_CHANGED);
-      break;
     case ax::mojom::StringAttribute::kImageAnnotation:
       // The image annotation is reported as part of the accessible name.
       AddEvent(node, Event::IMAGE_ANNOTATION_CHANGED);
@@ -240,9 +255,15 @@
     case ax::mojom::IntAttribute::kCheckedState:
       AddEvent(node, Event::CHECKED_STATE_CHANGED);
       break;
+    case ax::mojom::IntAttribute::kHierarchicalLevel:
+      AddEvent(node, Event::HIERARCHICAL_LEVEL_CHANGED);
+      break;
     case ax::mojom::IntAttribute::kInvalidState:
       AddEvent(node, Event::INVALID_STATUS_CHANGED);
       break;
+    case ax::mojom::IntAttribute::kPosInSet:
+      AddEvent(node, Event::POSITION_IN_SET_CHANGED);
+      break;
     case ax::mojom::IntAttribute::kRestriction:
       AddEvent(node, Event::STATE_CHANGED);
       break;
@@ -254,6 +275,9 @@
       // The image annotation is reported as part of the accessible name.
       AddEvent(node, Event::IMAGE_ANNOTATION_CHANGED);
       break;
+    case ax::mojom::IntAttribute::kSetSize:
+      AddEvent(node, Event::SET_SIZE_CHANGED);
+      break;
     default:
       AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED);
       break;
@@ -300,7 +324,21 @@
     const std::vector<int32_t>& old_value,
     const std::vector<int32_t>& new_value) {
   DCHECK_EQ(tree_, tree);
-  AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED);
+
+  switch (attr) {
+    case ax::mojom::IntListAttribute::kDescribedbyIds:
+      AddEvent(node, Event::DESCRIBED_BY_CHANGED);
+      break;
+    case ax::mojom::IntListAttribute::kFlowtoIds:
+      AddEvent(node, Event::FLOW_TO_CHANGED);
+      break;
+    case ax::mojom::IntListAttribute::kLabelledbyIds:
+      AddEvent(node, Event::LABELED_BY_CHANGED);
+      break;
+    default:
+      AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED);
+      break;
+  }
 }
 
 void AXEventGenerator::OnTreeDataChanged(AXTree* tree,
diff --git a/ui/accessibility/ax_event_generator.h b/ui/accessibility/ax_event_generator.h
index f68a285..72cc658 100644
--- a/ui/accessibility/ax_event_generator.h
+++ b/ui/accessibility/ax_event_generator.h
@@ -22,18 +22,26 @@
 class AX_EXPORT AXEventGenerator : public AXTreeObserver {
  public:
   enum class Event : int32_t {
+    ACCESS_KEY_CHANGED,
     ACTIVE_DESCENDANT_CHANGED,
     ALERT,
     AUTO_COMPLETE_CHANGED,
     CHECKED_STATE_CHANGED,
     CHILDREN_CHANGED,
+    CLASS_NAME_CHANGED,
     COLLAPSED,
+    DESCRIBED_BY_CHANGED,
     DESCRIPTION_CHANGED,
     DOCUMENT_SELECTION_CHANGED,
     DOCUMENT_TITLE_CHANGED,
     EXPANDED,
+    FLOW_TO_CHANGED,
+    HIERARCHICAL_LEVEL_CHANGED,
     IMAGE_ANNOTATION_CHANGED,
     INVALID_STATUS_CHANGED,
+    KEY_SHORTCUTS_CHANGED,
+    LABELED_BY_CHANGED,
+    LANGUAGE_CHANGED,
     LIVE_REGION_CHANGED,  // Fired on the root of a live region.
     LIVE_REGION_CREATED,
     LIVE_REGION_NODE_CHANGED,  // Fired on a node within a live region.
@@ -42,12 +50,15 @@
     MENU_ITEM_SELECTED,
     NAME_CHANGED,
     OTHER_ATTRIBUTE_CHANGED,
+    PLACEHOLDER_CHANGED,
+    POSITION_IN_SET_CHANGED,
     RELATED_NODE_CHANGED,
     ROLE_CHANGED,
     ROW_COUNT_CHANGED,
     SCROLL_POSITION_CHANGED,
     SELECTED_CHANGED,
     SELECTED_CHILDREN_CHANGED,
+    SET_SIZE_CHANGED,
     STATE_CHANGED,
     VALUE_CHANGED,
   };
diff --git a/ui/accessibility/ax_event_generator_unittest.cc b/ui/accessibility/ax_event_generator_unittest.cc
index 850922e..92bc42e1 100644
--- a/ui/accessibility/ax_event_generator_unittest.cc
+++ b/ui/accessibility/ax_event_generator_unittest.cc
@@ -20,6 +20,9 @@
   for (auto targeted_event : *generator) {
     const char* event_name;
     switch (targeted_event.event_params.event) {
+      case AXEventGenerator::Event::ACCESS_KEY_CHANGED:
+        event_name = "ACCESS_KEY_CHANGED";
+        break;
       case AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED:
         event_name = "ACTIVE_DESCENDANT_CHANGED";
         break;
@@ -32,9 +35,15 @@
       case AXEventGenerator::Event::CHILDREN_CHANGED:
         event_name = "CHILDREN_CHANGED";
         break;
+      case AXEventGenerator::Event::CLASS_NAME_CHANGED:
+        event_name = "CLASS_NAME_CHANGED";
+        break;
       case AXEventGenerator::Event::COLLAPSED:
         event_name = "COLLAPSED";
         break;
+      case AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
+        event_name = "DESCRIBED_BY_CHANGED";
+        break;
       case AXEventGenerator::Event::DESCRIPTION_CHANGED:
         event_name = "DESCRIPTION_CHANGED";
         break;
@@ -47,12 +56,27 @@
       case AXEventGenerator::Event::EXPANDED:
         event_name = "EXPANDED";
         break;
+      case AXEventGenerator::Event::FLOW_TO_CHANGED:
+        event_name = "FLOW_TO_CHANGED";
+        break;
+      case AXEventGenerator::Event::HIERARCHICAL_LEVEL_CHANGED:
+        event_name = "HIERARCHICAL_LEVEL_CHANGED";
+        break;
       case AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED:
         event_name = "IMAGE_ANNOTATION_CHANGED";
         break;
       case AXEventGenerator::Event::INVALID_STATUS_CHANGED:
         event_name = "INVALID_STATUS_CHANGED";
         break;
+      case AXEventGenerator::Event::KEY_SHORTCUTS_CHANGED:
+        event_name = "KEY_SHORTCUTS_CHANGED";
+        break;
+      case AXEventGenerator::Event::LABELED_BY_CHANGED:
+        event_name = "LABELED_BY_CHANGED";
+        break;
+      case AXEventGenerator::Event::LANGUAGE_CHANGED:
+        event_name = "LANGUAGE_CHANGED";
+        break;
       case AXEventGenerator::Event::LIVE_REGION_CHANGED:
         event_name = "LIVE_REGION_CHANGED";
         break;
@@ -77,6 +101,12 @@
       case AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED:
         event_name = "OTHER_ATTRIBUTE_CHANGED";
         break;
+      case AXEventGenerator::Event::PLACEHOLDER_CHANGED:
+        event_name = "PLACEHOLDER_CHANGED";
+        break;
+      case AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
+        event_name = "POSITION_IN_SET_CHANGED";
+        break;
       case AXEventGenerator::Event::RELATED_NODE_CHANGED:
         event_name = "RELATED_NODE_CHANGED";
         break;
@@ -95,6 +125,9 @@
       case AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED:
         event_name = "SELECTED_CHILDREN_CHANGED";
         break;
+      case AXEventGenerator::Event::SET_SIZE_CHANGED:
+        event_name = "SET_SIZE_CHANGED";
+        break;
       case AXEventGenerator::Event::STATE_CHANGED:
         event_name = "STATE_CHANGED";
         break;
@@ -685,7 +718,7 @@
                                       ids);
   ASSERT_TRUE(tree.Unserialize(update));
   EXPECT_EQ(
-      "OTHER_ATTRIBUTE_CHANGED on 2, "
+      "LANGUAGE_CHANGED on 2, "
       "OTHER_ATTRIBUTE_CHANGED on 3, "
       "OTHER_ATTRIBUTE_CHANGED on 4, "
       "OTHER_ATTRIBUTE_CHANGED on 5, "
@@ -865,8 +898,10 @@
   AXTreeUpdate update = initial_state;
   update.node_id_to_clear = 2;
   ASSERT_TRUE(tree.Unserialize(update));
-  EXPECT_EQ("ACTIVE_DESCENDANT_CHANGED on 3, RELATED_NODE_CHANGED on 3",
-            DumpEvents(&event_generator));
+  EXPECT_EQ(
+      "ACTIVE_DESCENDANT_CHANGED on 3, "
+      "RELATED_NODE_CHANGED on 3",
+      DumpEvents(&event_generator));
 }
 
 TEST(AXEventGeneratorTest, ImageAnnotationChanged) {
@@ -900,4 +935,129 @@
   EXPECT_EQ("IMAGE_ANNOTATION_CHANGED on 1", DumpEvents(&event_generator));
 }
 
+TEST(AXEventGeneratorTest, StringPropertyChanges) {
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(1);
+  initial_state.nodes[0].id = 1;
+
+  struct {
+    ax::mojom::StringAttribute id;
+    std::string old_value;
+    std::string new_value;
+  } attributes[] = {
+      {ax::mojom::StringAttribute::kAccessKey, "a", "b"},
+      {ax::mojom::StringAttribute::kClassName, "a", "b"},
+      {ax::mojom::StringAttribute::kKeyShortcuts, "a", "b"},
+      {ax::mojom::StringAttribute::kLanguage, "a", "b"},
+      {ax::mojom::StringAttribute::kPlaceholder, "a", "b"},
+  };
+  for (auto&& attrib : attributes) {
+    initial_state.nodes.push_back({});
+    initial_state.nodes.back().id = initial_state.nodes.size();
+    initial_state.nodes.back().AddStringAttribute(attrib.id, attrib.old_value);
+    initial_state.nodes[0].child_ids.push_back(initial_state.nodes.size());
+  }
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  int index = 1;
+  for (auto&& attrib : attributes) {
+    initial_state.nodes[index++].AddStringAttribute(attrib.id,
+                                                    attrib.new_value);
+  }
+
+  AXTreeUpdate update = initial_state;
+  EXPECT_TRUE(tree.Unserialize(update));
+  EXPECT_EQ(
+      "ACCESS_KEY_CHANGED on 2, "
+      "CLASS_NAME_CHANGED on 3, "
+      "KEY_SHORTCUTS_CHANGED on 4, "
+      "LANGUAGE_CHANGED on 5, "
+      "PLACEHOLDER_CHANGED on 6",
+      DumpEvents(&event_generator));
+}
+
+TEST(AXEventGeneratorTest, IntPropertyChanges) {
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(1);
+  initial_state.nodes[0].id = 1;
+
+  struct {
+    ax::mojom::IntAttribute id;
+    int old_value;
+    int new_value;
+  } attributes[] = {
+      {ax::mojom::IntAttribute::kHierarchicalLevel, 1, 2},
+      {ax::mojom::IntAttribute::kPosInSet, 1, 2},
+      {ax::mojom::IntAttribute::kSetSize, 1, 2},
+  };
+  for (auto&& attrib : attributes) {
+    initial_state.nodes.push_back({});
+    initial_state.nodes.back().id = initial_state.nodes.size();
+    initial_state.nodes.back().AddIntAttribute(attrib.id, attrib.old_value);
+    initial_state.nodes[0].child_ids.push_back(initial_state.nodes.size());
+  }
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  int index = 1;
+  for (auto&& attrib : attributes)
+    initial_state.nodes[index++].AddIntAttribute(attrib.id, attrib.new_value);
+
+  AXTreeUpdate update = initial_state;
+  EXPECT_TRUE(tree.Unserialize(update));
+  EXPECT_EQ(
+      "HIERARCHICAL_LEVEL_CHANGED on 2, "
+      "POSITION_IN_SET_CHANGED on 3, "
+      "SET_SIZE_CHANGED on 4",
+      DumpEvents(&event_generator));
+}
+
+TEST(AXEventGeneratorTest, IntListPropertyChanges) {
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(1);
+  initial_state.nodes[0].id = 1;
+
+  struct {
+    ax::mojom::IntListAttribute id;
+    std::vector<int> old_value;
+    std::vector<int> new_value;
+  } attributes[] = {
+      {ax::mojom::IntListAttribute::kDescribedbyIds, {1}, {2}},
+      {ax::mojom::IntListAttribute::kFlowtoIds, {1}, {2}},
+      {ax::mojom::IntListAttribute::kLabelledbyIds, {1}, {2}},
+  };
+  for (auto&& attrib : attributes) {
+    initial_state.nodes.push_back({});
+    initial_state.nodes.back().id = initial_state.nodes.size();
+    initial_state.nodes.back().AddIntListAttribute(attrib.id, attrib.old_value);
+    initial_state.nodes[0].child_ids.push_back(initial_state.nodes.size());
+  }
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  int index = 1;
+  for (auto&& attrib : attributes) {
+    initial_state.nodes[index++].AddIntListAttribute(attrib.id,
+                                                     attrib.new_value);
+  }
+
+  AXTreeUpdate update = initial_state;
+  EXPECT_TRUE(tree.Unserialize(update));
+  EXPECT_EQ(
+      "DESCRIBED_BY_CHANGED on 2, "
+      "FLOW_TO_CHANGED on 3, "
+      "LABELED_BY_CHANGED on 4, "
+      "RELATED_NODE_CHANGED on 2, "
+      "RELATED_NODE_CHANGED on 3, "
+      "RELATED_NODE_CHANGED on 4",
+      DumpEvents(&event_generator));
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index aacf91a4..635b1a1 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -3757,7 +3757,7 @@
 
     case UIA_ClassNamePropertyId:
       result->vt = VT_BSTR;
-      GetStringAttributeAsBstr(ax::mojom::StringAttribute::kName,
+      GetStringAttributeAsBstr(ax::mojom::StringAttribute::kClassName,
                                &result->bstrVal);
       break;
 
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index c1319fc6..004df13 100644
--- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -3265,7 +3265,6 @@
   EXPECT_UIA_BSTR_EQ(root_node, UIA_AriaPropertiesPropertyId,
                      L"readonly=true;expanded=false;multiline=false;"
                      L"multiselectable=false;required=false;setsize=2");
-  EXPECT_UIA_BSTR_EQ(root_node, UIA_ClassNamePropertyId, L"fake name");
   EXPECT_UIA_BSTR_EQ(root_node, UIA_CulturePropertyId, L"en-us");
   EXPECT_UIA_BSTR_EQ(root_node, UIA_NamePropertyId, L"fake name");
   EXPECT_UIA_INT_EQ(root_node, UIA_ControlTypePropertyId,
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn
index 5a058e6..141af6a 100644
--- a/ui/aura/BUILD.gn
+++ b/ui/aura/BUILD.gn
@@ -187,7 +187,6 @@
     "//skia",
     "//ui/base",
     "//ui/base/clipboard",
-    "//ui/base/ime",
     "//ui/display",
     "//ui/events",
     "//ui/events:dom_keyboard_layout",
@@ -202,6 +201,7 @@
   ]
 
   public_deps = [
+    "//ui/base/ime",
     "//ui/compositor",
   ]
 
diff --git a/ui/aura/native_window_occlusion_tracker_win.cc b/ui/aura/native_window_occlusion_tracker_win.cc
index e2500b1f..aed87f55 100644
--- a/ui/aura/native_window_occlusion_tracker_win.cc
+++ b/ui/aura/native_window_occlusion_tracker_win.cc
@@ -535,8 +535,8 @@
 void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
     ProcessEventHookCallback(DWORD event,
                              HWND hwnd,
-                             LONG idObject,
-                             LONG idChild) {
+                             LONG id_object,
+                             LONG id_child) {
   // Can't do DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_) here. See
   // comment before call to PostTask below as to why.
 
@@ -545,6 +545,12 @@
   // events.
   if (!hwnd)
     return;
+
+  // We only care about events for window objects. In particular, we don't care
+  // about OBJID_CARET, which is spammy.
+  if (id_object != OBJID_WINDOW)
+    return;
+
   // Don't continually calculate occlusion while a window is moving, but rather
   // once at the beginning and once at the end.
   if (event == EVENT_SYSTEM_MOVESIZESTART) {
@@ -561,6 +567,7 @@
     // that case, we want to go back to calculating occlusion.
     window_is_moving_ = false;
   }
+
   // ProcessEventHookCallback is called from the task_runner's PeekMessage
   // call, on the task runner's thread, but before the task_tracker thread sets
   // up the thread sequence. In order to prevent DCHECK failures with the
diff --git a/ui/aura/native_window_occlusion_tracker_win.h b/ui/aura/native_window_occlusion_tracker_win.h
index 96c46737..8c6d85f0 100644
--- a/ui/aura/native_window_occlusion_tracker_win.h
+++ b/ui/aura/native_window_occlusion_tracker_win.h
@@ -84,8 +84,8 @@
     static void CALLBACK EventHookCallback(HWINEVENTHOOK hWinEventHook,
                                            DWORD event,
                                            HWND hwnd,
-                                           LONG idObject,
-                                           LONG idChild,
+                                           LONG id_object,
+                                           LONG id_child,
                                            DWORD dwEventThread,
                                            DWORD dwmsEventTime);
 
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 2d8e6b12..c063211 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -265,8 +265,6 @@
     "win/accessibility_misc_utils.cc",
     "win/accessibility_misc_utils.h",
     "win/atl_module.h",
-    "win/direct_manipulation.cc",
-    "win/direct_manipulation.h",
     "win/foreground_helper.cc",
     "win/foreground_helper.h",
     "win/hidden_window.cc",
@@ -969,6 +967,7 @@
     deps += [
       "//ui/base/ime",
       "//ui/base/ime/mojo:test_interfaces",
+      "//ui/gfx/range/mojo:struct_traits",
     ]
   }
 
@@ -984,7 +983,6 @@
   if (is_win) {
     sources += [
       "dragdrop/os_exchange_data_win_unittest.cc",
-      "win/direct_manipulation_unittest.cc",
       "win/hwnd_subclass_unittest.cc",
     ]
 
diff --git a/ui/base/ime/mojo/BUILD.gn b/ui/base/ime/mojo/BUILD.gn
index 7443702..29d64d0 100644
--- a/ui/base/ime/mojo/BUILD.gn
+++ b/ui/base/ime/mojo/BUILD.gn
@@ -8,6 +8,11 @@
   sources = [
     "ime_types.mojom",
   ]
+
+  public_deps = [
+    "//mojo/public/mojom/base",
+    "//ui/gfx/range/mojo",
+  ]
 }
 
 mojom("test_interfaces") {
diff --git a/ui/base/ime/mojo/ime_struct_traits_unittest.cc b/ui/base/ime/mojo/ime_struct_traits_unittest.cc
index 21ad47c5..86f6d56 100644
--- a/ui/base/ime/mojo/ime_struct_traits_unittest.cc
+++ b/ui/base/ime/mojo/ime_struct_traits_unittest.cc
@@ -8,9 +8,12 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "mojo/public/cpp/base/string16_mojom_traits.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/mojo/ime_struct_traits_test.mojom.h"
+#include "ui/gfx/range/mojo/range_struct_traits.h"
 
 namespace ui {
 
@@ -93,4 +96,24 @@
   }
 }
 
+TEST_F(IMEStructTraitsTest, CompositionText) {
+  ui::CompositionText input;
+  input.text = base::UTF8ToUTF16("abcdefghij");
+  ui::ImeTextSpan ime_text_span_1(0, 2, ui::ImeTextSpan::Thickness::kThin);
+  ime_text_span_1.underline_color = SK_ColorGRAY;
+  input.ime_text_spans.push_back(ime_text_span_1);
+  ui::ImeTextSpan ime_text_span_2(ui::ImeTextSpan::Type::kComposition, 3, 6,
+                                  ui::ImeTextSpan::Thickness::kThick,
+                                  SK_ColorGREEN);
+  ime_text_span_2.underline_color = SK_ColorRED;
+  input.ime_text_spans.push_back(ime_text_span_2);
+  input.selection = gfx::Range(1, 7);
+
+  ui::CompositionText output;
+  EXPECT_TRUE(mojom::CompositionText::Deserialize(
+      mojom::CompositionText::Serialize(&input), &output));
+
+  EXPECT_EQ(input, output);
+}
+
 }  // namespace ui
diff --git a/ui/base/ime/mojo/ime_types.mojom b/ui/base/ime/mojo/ime_types.mojom
index d1356e3..c575a30 100644
--- a/ui/base/ime/mojo/ime_types.mojom
+++ b/ui/base/ime/mojo/ime_types.mojom
@@ -4,6 +4,9 @@
 
 module ui.mojom;
 
+import "mojo/public/mojom/base/string16.mojom";
+import "ui/gfx/range/mojo/range.mojom";
+
 // Text input type which is based on blink::WebTextInputType.
 enum TextInputType {
   NONE,
@@ -54,3 +57,54 @@
   AUTOCAPITALIZE_SENTENCES = 0x200,
   ALL = 0x3FF,
 };
+
+// See comments for ui::ImeTextSpan::Type for more details.
+enum ImeTextSpanType {
+  kComposition,
+  kSuggestion,
+  kMisspellingSuggestion,
+};
+
+// This enum represents the thickness of an underline segment of text,
+// the thickness of a ui::ImeTextSpan element.
+// The possible values are:
+// * kNone: When you don't want to paint the underline.
+// * kThin: For regular size.
+// * kThick: For thick underlines.
+enum ImeTextSpanThickness {
+  kNone,
+  kThin,
+  kThick,
+};
+
+// Represents an underlined segment of text currently composed by IME.
+// Corresponds to ui::ImeTextSpan.
+struct ImeTextSpan {
+  ImeTextSpanType type;
+  uint32 start_offset;
+  uint32 end_offset;
+  uint32 underline_color;
+  ImeTextSpanThickness thickness;
+  uint32 background_color;
+  uint32 suggestion_highlight_color;
+  bool remove_on_finish_composing;
+  array<string> suggestions;
+};
+
+// Represents a text currently being composed by IME. Corresponds to
+// ui::CompositionText.
+struct CompositionText {
+  mojo_base.mojom.String16 text;
+  array<ImeTextSpan> ime_text_spans;
+  gfx.mojom.Range selection;
+};
+
+// Represents how a text client gets focused. Corresponds to
+// ui::TextInputClient::FocusReason.
+enum FocusReason {
+  kNone,   // Not focused.
+  kMouse,  // User initiated with mouse.
+  kTouch,  // User initiated with touch.
+  kPen,    // User initiated with pen.
+  kOther,  // All other reasons (e.g. system initiated, mouse)
+};
diff --git a/ui/base/ime/mojo/ime_types.typemap b/ui/base/ime/mojo/ime_types.typemap
index 57f6b1b..ee4d337 100644
--- a/ui/base/ime/mojo/ime_types.typemap
+++ b/ui/base/ime/mojo/ime_types.typemap
@@ -4,6 +4,9 @@
 
 mojom = "//ui/base/ime/mojo/ime_types.mojom"
 public_headers = [
+  "//ui/base/ime/composition_text.h",
+  "//ui/base/ime/ime_text_span.h",
+  "//ui/base/ime/text_input_client.h",
   "//ui/base/ime/text_input_mode.h",
   "//ui/base/ime/text_input_type.h",
 ]
@@ -14,8 +17,16 @@
 public_deps = [
   "//ui/base/ime:ime_types",
 ]
+deps = [
+  "//ui/gfx/range",
+  "//ui/gfx/range/mojo:struct_traits",
+]
 
 type_mappings = [
+  "ui.mojom.CompositionText=ui::CompositionText",
+  "ui.mojom.FocusReason=ui::TextInputClient::FocusReason",
+  "ui.mojom.ImeTextSpan=ui::ImeTextSpan",
+  "ui.mojom.ImeTextSpanThickness=ui::ImeTextSpan::Thickness",
   "ui.mojom.TextInputType=ui::TextInputType",
   "ui.mojom.TextInputMode=ui::TextInputMode",
 ]
diff --git a/ui/base/ime/mojo/ime_types_struct_traits.cc b/ui/base/ime/mojo/ime_types_struct_traits.cc
index eb3df29..3bdd895 100644
--- a/ui/base/ime/mojo/ime_types_struct_traits.cc
+++ b/ui/base/ime/mojo/ime_types_struct_traits.cc
@@ -4,6 +4,9 @@
 
 #include "ui/base/ime/mojo/ime_types_struct_traits.h"
 
+#include "mojo/public/cpp/base/string16_mojom_traits.h"
+#include "ui/gfx/range/mojo/range_struct_traits.h"
+
 namespace mojo {
 
 #define UI_TO_MOJO_TYPE_CASE(name) \
@@ -135,4 +138,154 @@
   return false;
 }
 
+// static
+bool StructTraits<ui::mojom::ImeTextSpanDataView, ui::ImeTextSpan>::Read(
+    ui::mojom::ImeTextSpanDataView data,
+    ui::ImeTextSpan* out) {
+  if (data.is_null())
+    return false;
+  if (!data.ReadType(&out->type))
+    return false;
+  out->start_offset = data.start_offset();
+  out->end_offset = data.end_offset();
+  out->underline_color = data.underline_color();
+  if (!data.ReadThickness(&out->thickness))
+    return false;
+  out->background_color = data.background_color();
+  out->suggestion_highlight_color = data.suggestion_highlight_color();
+  out->remove_on_finish_composing = data.remove_on_finish_composing();
+  if (!data.ReadSuggestions(&out->suggestions))
+    return false;
+  return true;
+}
+
+// static
+bool StructTraits<ui::mojom::CompositionTextDataView, ui::CompositionText>::
+    Read(ui::mojom::CompositionTextDataView data, ui::CompositionText* out) {
+  return !data.is_null() && data.ReadText(&out->text) &&
+         data.ReadImeTextSpans(&out->ime_text_spans) &&
+         data.ReadSelection(&out->selection);
+}
+
+// static
+ui::mojom::FocusReason
+EnumTraits<ui::mojom::FocusReason, ui::TextInputClient::FocusReason>::ToMojom(
+    ui::TextInputClient::FocusReason input) {
+  switch (input) {
+    case ui::TextInputClient::FOCUS_REASON_NONE:
+      return ui::mojom::FocusReason::kNone;
+    case ui::TextInputClient::FOCUS_REASON_MOUSE:
+      return ui::mojom::FocusReason::kMouse;
+    case ui::TextInputClient::FOCUS_REASON_TOUCH:
+      return ui::mojom::FocusReason::kTouch;
+    case ui::TextInputClient::FOCUS_REASON_PEN:
+      return ui::mojom::FocusReason::kPen;
+    case ui::TextInputClient::FOCUS_REASON_OTHER:
+      return ui::mojom::FocusReason::kOther;
+  }
+
+  NOTREACHED();
+  return ui::mojom::FocusReason::kNone;
+}
+
+// static
+bool EnumTraits<ui::mojom::FocusReason, ui::TextInputClient::FocusReason>::
+    FromMojom(ui::mojom::FocusReason input,
+              ui::TextInputClient::FocusReason* out) {
+  switch (input) {
+    case ui::mojom::FocusReason::kNone:
+      *out = ui::TextInputClient::FOCUS_REASON_NONE;
+      return true;
+    case ui::mojom::FocusReason::kMouse:
+      *out = ui::TextInputClient::FOCUS_REASON_MOUSE;
+      return true;
+    case ui::mojom::FocusReason::kTouch:
+      *out = ui::TextInputClient::FOCUS_REASON_TOUCH;
+      return true;
+    case ui::mojom::FocusReason::kPen:
+      *out = ui::TextInputClient::FOCUS_REASON_PEN;
+      return true;
+    case ui::mojom::FocusReason::kOther:
+      *out = ui::TextInputClient::FOCUS_REASON_OTHER;
+      return true;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
+// static
+ui::mojom::ImeTextSpanType
+EnumTraits<ui::mojom::ImeTextSpanType, ui::ImeTextSpan::Type>::ToMojom(
+    ui::ImeTextSpan::Type ime_text_span_type) {
+  switch (ime_text_span_type) {
+    case ui::ImeTextSpan::Type::kComposition:
+      return ui::mojom::ImeTextSpanType::kComposition;
+    case ui::ImeTextSpan::Type::kSuggestion:
+      return ui::mojom::ImeTextSpanType::kSuggestion;
+    case ui::ImeTextSpan::Type::kMisspellingSuggestion:
+      return ui::mojom::ImeTextSpanType::kMisspellingSuggestion;
+  }
+
+  NOTREACHED();
+  return ui::mojom::ImeTextSpanType::kComposition;
+}
+
+// static
+bool EnumTraits<ui::mojom::ImeTextSpanType, ui::ImeTextSpan::Type>::FromMojom(
+    ui::mojom::ImeTextSpanType type,
+    ui::ImeTextSpan::Type* out) {
+  switch (type) {
+    case ui::mojom::ImeTextSpanType::kComposition:
+      *out = ui::ImeTextSpan::Type::kComposition;
+      return true;
+    case ui::mojom::ImeTextSpanType::kSuggestion:
+      *out = ui::ImeTextSpan::Type::kSuggestion;
+      return true;
+    case ui::mojom::ImeTextSpanType::kMisspellingSuggestion:
+      *out = ui::ImeTextSpan::Type::kMisspellingSuggestion;
+      return true;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
+// static
+ui::mojom::ImeTextSpanThickness EnumTraits<
+    ui::mojom::ImeTextSpanThickness,
+    ui::ImeTextSpan::Thickness>::ToMojom(ui::ImeTextSpan::Thickness thickness) {
+  switch (thickness) {
+    case ui::ImeTextSpan::Thickness::kNone:
+      return ui::mojom::ImeTextSpanThickness::kNone;
+    case ui::ImeTextSpan::Thickness::kThin:
+      return ui::mojom::ImeTextSpanThickness::kThin;
+    case ui::ImeTextSpan::Thickness::kThick:
+      return ui::mojom::ImeTextSpanThickness::kThick;
+  }
+
+  NOTREACHED();
+  return ui::mojom::ImeTextSpanThickness::kThin;
+}
+
+// static
+bool EnumTraits<ui::mojom::ImeTextSpanThickness, ui::ImeTextSpan::Thickness>::
+    FromMojom(ui::mojom::ImeTextSpanThickness input,
+              ui::ImeTextSpan::Thickness* out) {
+  switch (input) {
+    case ui::mojom::ImeTextSpanThickness::kNone:
+      *out = ui::ImeTextSpan::Thickness::kNone;
+      return true;
+    case ui::mojom::ImeTextSpanThickness::kThin:
+      *out = ui::ImeTextSpan::Thickness::kThin;
+      return true;
+    case ui::mojom::ImeTextSpanThickness::kThick:
+      *out = ui::ImeTextSpan::Thickness::kThick;
+      return true;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
 }  // namespace mojo
diff --git a/ui/base/ime/mojo/ime_types_struct_traits.h b/ui/base/ime/mojo/ime_types_struct_traits.h
index 6af23bb..dd0dde67 100644
--- a/ui/base/ime/mojo/ime_types_struct_traits.h
+++ b/ui/base/ime/mojo/ime_types_struct_traits.h
@@ -7,7 +7,10 @@
 
 #include <vector>
 
+#include "ui/base/ime/composition_text.h"
+#include "ui/base/ime/ime_text_span.h"
 #include "ui/base/ime/mojo/ime_types.mojom.h"
+#include "ui/base/ime/text_input_client.h"
 #include "ui/base/ime/text_input_mode.h"
 #include "ui/base/ime/text_input_type.h"
 
@@ -25,6 +28,70 @@
   static bool FromMojom(ui::mojom::TextInputMode input, ui::TextInputMode* out);
 };
 
+template <>
+struct StructTraits<ui::mojom::CompositionTextDataView, ui::CompositionText> {
+  static base::string16 text(const ui::CompositionText& c) { return c.text; }
+  static ui::ImeTextSpans ime_text_spans(const ui::CompositionText& c) {
+    return c.ime_text_spans;
+  }
+  static gfx::Range selection(const ui::CompositionText& c) {
+    return c.selection;
+  }
+  static bool Read(ui::mojom::CompositionTextDataView data,
+                   ui::CompositionText* out);
+};
+
+template <>
+struct EnumTraits<ui::mojom::FocusReason, ui::TextInputClient::FocusReason> {
+  static ui::mojom::FocusReason ToMojom(ui::TextInputClient::FocusReason input);
+  static bool FromMojom(ui::mojom::FocusReason input,
+                        ui::TextInputClient::FocusReason* out);
+};
+
+template <>
+struct StructTraits<ui::mojom::ImeTextSpanDataView, ui::ImeTextSpan> {
+  static ui::ImeTextSpan::Type type(const ui::ImeTextSpan& c) { return c.type; }
+  static uint32_t start_offset(const ui::ImeTextSpan& c) {
+    return c.start_offset;
+  }
+  static uint32_t end_offset(const ui::ImeTextSpan& c) { return c.end_offset; }
+  static uint32_t underline_color(const ui::ImeTextSpan& c) {
+    return c.underline_color;
+  }
+  static ui::ImeTextSpan::Thickness thickness(const ui::ImeTextSpan& i) {
+    return i.thickness;
+  }
+  static uint32_t background_color(const ui::ImeTextSpan& c) {
+    return c.background_color;
+  }
+  static uint32_t suggestion_highlight_color(const ui::ImeTextSpan& c) {
+    return c.suggestion_highlight_color;
+  }
+  static bool remove_on_finish_composing(const ui::ImeTextSpan& c) {
+    return c.remove_on_finish_composing;
+  }
+  static std::vector<std::string> suggestions(const ui::ImeTextSpan& c) {
+    return c.suggestions;
+  }
+  static bool Read(ui::mojom::ImeTextSpanDataView data, ui::ImeTextSpan* out);
+};
+
+template <>
+struct EnumTraits<ui::mojom::ImeTextSpanType, ui::ImeTextSpan::Type> {
+  static ui::mojom::ImeTextSpanType ToMojom(
+      ui::ImeTextSpan::Type ime_text_span_type);
+  static bool FromMojom(ui::mojom::ImeTextSpanType input,
+                        ui::ImeTextSpan::Type* out);
+};
+
+template <>
+struct EnumTraits<ui::mojom::ImeTextSpanThickness, ui::ImeTextSpan::Thickness> {
+  static ui::mojom::ImeTextSpanThickness ToMojom(
+      ui::ImeTextSpan::Thickness thickness);
+  static bool FromMojom(ui::mojom::ImeTextSpanThickness input,
+                        ui::ImeTextSpan::Thickness* out);
+};
+
 }  // namespace mojo
 
 #endif  // UI_BASE_IME_MOJO_IME_TYPES_STRUCT_TRAITS_H_
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index 7ba4860..a57fa8c 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -571,6 +571,7 @@
       "//ui/events/devices",
       "//ui/events/devices/mojo:test_interfaces",
       "//ui/events/gestures/blink",
+      "//ui/events/mojo:interfaces",
       "//ui/events/platform",
       "//ui/gfx/geometry/mojo:struct_traits",
       "//ui/gfx/ipc/geometry",
diff --git a/ui/file_manager/file_manager/foreground/js/actions_controller.js b/ui/file_manager/file_manager/foreground/js/actions_controller.js
index c9978e52..53611a1 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_controller.js
@@ -164,8 +164,9 @@
     return;
   }
 
-  const actionsModel = new ActionsModel(this.volumeManager_, this.metadataModel_,
-        this.shortcutsModel_, this.driveSyncHandler_, this.ui_, entries);
+  const actionsModel = new ActionsModel(
+      this.volumeManager_, this.metadataModel_, this.shortcutsModel_,
+      this.driveSyncHandler_, this.ui_, entries);
 
   const initializeAndUpdateUI =
       /** @type {function(Event=)} */ (opt_event => {
@@ -205,14 +206,16 @@
   this.updateUI_();
 
   const entry = this.ui_.directoryTree.selectedItem ?
-      (this.ui_.directoryTree.selectedItem.entry || null) : null;
+      (this.ui_.directoryTree.selectedItem.entry || null) :
+      null;
   if (!entry) {
     return;
   }
 
   const sequence = ++this.navigationListSequence_;
-  const actionsModel = new ActionsModel(this.volumeManager_, this.metadataModel_,
-        this.shortcutsModel_, this.driveSyncHandler_, this.ui_, [entry]);
+  const actionsModel = new ActionsModel(
+      this.volumeManager_, this.metadataModel_, this.shortcutsModel_,
+      this.driveSyncHandler_, this.ui_, [entry]);
 
   const initializeAndUpdateUI =
       /** @type {function(Event=)} */ (opt_event => {
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model.js b/ui/file_manager/file_manager/foreground/js/actions_model.js
index c97e7037..9f676723 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model.js
@@ -6,28 +6,24 @@
  * A single action, that can be taken on a set of entries.
  * @interface
  */
-function Action() {
-}
+function Action() {}
 
 /**
  * Executes this action on the set of entries.
  */
-Action.prototype.execute = () => {
-};
+Action.prototype.execute = () => {};
 
 /**
  * Checks whether this action can execute on the set of entries.
  *
  * @return {boolean} True if the function can execute, false if not.
  */
-Action.prototype.canExecute = () => {
-};
+Action.prototype.canExecute = () => {};
 
 /**
  * @return {?string}
  */
-Action.prototype.getTitle = () => {
-};
+Action.prototype.getTitle = () => {};
 
 /**
  * @typedef {{
@@ -144,8 +140,8 @@
  * @constructor
  * @struct
  */
-function DriveToggleOfflineAction(entries, metadataModel, driveSyncHandler, ui,
-    value, onExecute) {
+function DriveToggleOfflineAction(
+    entries, metadataModel, driveSyncHandler, ui, value, onExecute) {
   /**
    * @private {!Array<!Entry>}
    * @const
@@ -192,35 +188,37 @@
  * @param {function()} onExecute
  * @return {DriveToggleOfflineAction}
  */
-DriveToggleOfflineAction.create = (entries, metadataModel, driveSyncHandler, ui, value, onExecute) => {
-  if (!loadTimeData.getBoolean('DRIVE_FS_ENABLED')) {
-    if (entries.some((entry) => entry.isDirectory)) {
-      return null;
-    }
-  }
+DriveToggleOfflineAction.create =
+    (entries, metadataModel, driveSyncHandler, ui, value, onExecute) => {
+      if (!loadTimeData.getBoolean('DRIVE_FS_ENABLED')) {
+        if (entries.some((entry) => entry.isDirectory)) {
+          return null;
+        }
+      }
 
-  const actionableEntries = entries.filter(entry => {
-    if (entry.isDirectory && !loadTimeData.getBoolean('DRIVE_FS_ENABLED')) {
-      return false;
-    }
-    const metadata = metadataModel.getCache(
-        [entry], ['hosted', 'pinned'])[0];
-    if (metadata.hosted) {
-      return false;
-    }
-    if (metadata.pinned === value) {
-      return false;
-    }
-    return true;
-  });
+      const actionableEntries = entries.filter(entry => {
+        if (entry.isDirectory && !loadTimeData.getBoolean('DRIVE_FS_ENABLED')) {
+          return false;
+        }
+        const metadata =
+            metadataModel.getCache([entry], ['hosted', 'pinned'])[0];
+        if (metadata.hosted) {
+          return false;
+        }
+        if (metadata.pinned === value) {
+          return false;
+        }
+        return true;
+      });
 
-  if (actionableEntries.length === 0) {
-    return null;
-  }
+      if (actionableEntries.length === 0) {
+        return null;
+      }
 
-  return new DriveToggleOfflineAction(actionableEntries, metadataModel,
-      driveSyncHandler, ui, value, onExecute);
-};
+      return new DriveToggleOfflineAction(
+          actionableEntries, metadataModel, driveSyncHandler, ui, value,
+          onExecute);
+    };
 
 /**
  * @override
@@ -244,19 +242,16 @@
       }
       currentEntry = entries.shift();
       chrome.fileManagerPrivate.pinDriveFile(
-          currentEntry,
-          this.value_,
-          steps.entryPinned);
+          currentEntry, this.value_, steps.entryPinned);
     },
 
     // Check the result of pinning.
     entryPinned: () => {
       error = !!chrome.runtime.lastError;
       if (error && this.value_) {
-        this.metadataModel_.get([currentEntry], ['size']).then(
-            results => {
-              steps.showError(results[0].size);
-            });
+        this.metadataModel_.get([currentEntry], ['size']).then(results => {
+          steps.showError(results[0].size);
+        });
         return;
       }
       this.metadataModel_.notifyEntriesChanged([currentEntry]);
@@ -276,9 +271,9 @@
     showError: size => {
       this.ui_.alertDialog.showHtml(
           str('DRIVE_OUT_OF_SPACE_HEADER'),
-          strf('DRIVE_OUT_OF_SPACE_MESSAGE',
-               unescape(currentEntry.name),
-               util.bytesToString(size)),
+          strf(
+              'DRIVE_OUT_OF_SPACE_MESSAGE', unescape(currentEntry.name),
+              util.bytesToString(size)),
           null, null, null);
     }
   };
@@ -338,18 +333,19 @@
  * @param {function()} onExecute
  * @return {DriveCreateFolderShortcutAction}
  */
-DriveCreateFolderShortcutAction.create = (entries, volumeManager, shortcutsModel, onExecute) => {
-  if (entries.length !== 1 || entries[0].isFile) {
-    return null;
-  }
-  const locationInfo = volumeManager.getLocationInfo(entries[0]);
-  if (!locationInfo || locationInfo.isSpecialSearchRoot ||
-      locationInfo.isRootEntry) {
-    return null;
-  }
-  return new DriveCreateFolderShortcutAction(
-      entries[0], shortcutsModel, onExecute);
-};
+DriveCreateFolderShortcutAction.create =
+    (entries, volumeManager, shortcutsModel, onExecute) => {
+      if (entries.length !== 1 || entries[0].isFile) {
+        return null;
+      }
+      const locationInfo = volumeManager.getLocationInfo(entries[0]);
+      if (!locationInfo || locationInfo.isSpecialSearchRoot ||
+          locationInfo.isRootEntry) {
+        return null;
+      }
+      return new DriveCreateFolderShortcutAction(
+          entries[0], shortcutsModel, onExecute);
+    };
 
 /**
  * @override
@@ -407,14 +403,15 @@
  * @param {function()} onExecute
  * @return {DriveRemoveFolderShortcutAction}
  */
-DriveRemoveFolderShortcutAction.create = (entries, shortcutsModel, onExecute) => {
-  if (entries.length !== 1 || entries[0].isFile ||
-      !shortcutsModel.exists(entries[0])) {
-    return null;
-  }
-  return new DriveRemoveFolderShortcutAction(
-      entries[0], shortcutsModel, onExecute);
-};
+DriveRemoveFolderShortcutAction.create =
+    (entries, shortcutsModel, onExecute) => {
+      if (entries.length !== 1 || entries[0].isFile ||
+          !shortcutsModel.exists(entries[0])) {
+        return null;
+      }
+      return new DriveRemoveFolderShortcutAction(
+          entries[0], shortcutsModel, onExecute);
+    };
 
 /**
  * @override
@@ -571,14 +568,14 @@
  * @override
  */
 CustomAction.prototype.execute = function() {
-  chrome.fileManagerPrivate.executeCustomAction(this.entries_, this.id_,
-      () => {
-        if (chrome.runtime.lastError) {
-          console.error('Failed to execute a custom action because of: ' +
-            chrome.runtime.lastError.message);
-        }
-        this.onExecute_();
-      });
+  chrome.fileManagerPrivate.executeCustomAction(this.entries_, this.id_, () => {
+    if (chrome.runtime.lastError) {
+      console.error(
+          'Failed to execute a custom action because of: ' +
+          chrome.runtime.lastError.message);
+    }
+    this.onExecute_();
+  });
 };
 
 /**
@@ -703,109 +700,113 @@
     return this.initializePromise_;
   }
 
-  this.initializePromise_ = new Promise((fulfill, reject) => {
-    if (this.destroyed_) {
-      reject();
-      return;
-    }
-    this.initializePromiseReject_ = reject;
+  this.initializePromise_ =
+      new Promise((fulfill, reject) => {
+        if (this.destroyed_) {
+          reject();
+          return;
+        }
+        this.initializePromiseReject_ = reject;
 
-    const volumeInfo = this.entries_.length >= 1 &&
-        this.volumeManager_.getVolumeInfo(this.entries_[0]);
-    if (!volumeInfo) {
-      fulfill({});
-      return;
-    }
-    // All entries need to be on the same volume to execute ActionsModel
-    // commands.
-    // TODO(sashab): Move this to util.js.
-    for (let i = 1; i < this.entries_.length; i++) {
-      const volumeInfoToCompare =
-          this.volumeManager_.getVolumeInfo(this.entries_[i]);
-      if (!volumeInfoToCompare ||
-          volumeInfoToCompare.volumeId != volumeInfo.volumeId) {
-        fulfill({});
-        return;
-      }
-    }
-
-    const actions = {};
-    switch (volumeInfo.volumeType) {
-      // For Drive, actions are constructed directly in the Files app code.
-      case VolumeManagerCommon.VolumeType.DRIVE:
-        const shareAction = DriveShareAction.create(
-            this.entries_, this.metadataModel_, this.volumeManager_, this.ui_);
-        if (shareAction) {
-          actions[ActionsModel.CommonActionId.SHARE] = shareAction;
+        const volumeInfo = this.entries_.length >= 1 &&
+            this.volumeManager_.getVolumeInfo(this.entries_[0]);
+        if (!volumeInfo) {
+          fulfill({});
+          return;
+        }
+        // All entries need to be on the same volume to execute ActionsModel
+        // commands.
+        // TODO(sashab): Move this to util.js.
+        for (let i = 1; i < this.entries_.length; i++) {
+          const volumeInfoToCompare =
+              this.volumeManager_.getVolumeInfo(this.entries_[i]);
+          if (!volumeInfoToCompare ||
+              volumeInfoToCompare.volumeId != volumeInfo.volumeId) {
+            fulfill({});
+            return;
+          }
         }
 
-        const saveForOfflineAction = DriveToggleOfflineAction.create(
-            this.entries_, this.metadataModel_, this.driveSyncHandler_,
-            this.ui_, true, this.invalidate_.bind(this));
-        if (saveForOfflineAction) {
-          actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE] =
-              saveForOfflineAction;
-        }
+        const actions = {};
+        switch (volumeInfo.volumeType) {
+          // For Drive, actions are constructed directly in the Files app code.
+          case VolumeManagerCommon.VolumeType.DRIVE:
+            const shareAction = DriveShareAction.create(
+                this.entries_, this.metadataModel_, this.volumeManager_,
+                this.ui_);
+            if (shareAction) {
+              actions[ActionsModel.CommonActionId.SHARE] = shareAction;
+            }
 
-        const offlineNotNecessaryAction = DriveToggleOfflineAction.create(
-            this.entries_, this.metadataModel_, this.driveSyncHandler_,
-            this.ui_, false, this.invalidate_.bind(this));
-        if (offlineNotNecessaryAction) {
-          actions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY] =
-              offlineNotNecessaryAction;
-        }
+            const saveForOfflineAction = DriveToggleOfflineAction.create(
+                this.entries_, this.metadataModel_, this.driveSyncHandler_,
+                this.ui_, true, this.invalidate_.bind(this));
+            if (saveForOfflineAction) {
+              actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE] =
+                  saveForOfflineAction;
+            }
 
-        const createFolderShortcutAction =
-            DriveCreateFolderShortcutAction.create(this.entries_,
-                this.volumeManager_, this.shortcutsModel_,
-                this.invalidate_.bind(this));
-        if (createFolderShortcutAction) {
-          actions[ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT] =
-              createFolderShortcutAction;
-        }
+            const offlineNotNecessaryAction = DriveToggleOfflineAction.create(
+                this.entries_, this.metadataModel_, this.driveSyncHandler_,
+                this.ui_, false, this.invalidate_.bind(this));
+            if (offlineNotNecessaryAction) {
+              actions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY] =
+                  offlineNotNecessaryAction;
+            }
 
-        const removeFolderShortcutAction =
-            DriveRemoveFolderShortcutAction.create(this.entries_,
-                this.shortcutsModel_, this.invalidate_.bind(this));
-        if (removeFolderShortcutAction) {
-          actions[ActionsModel.InternalActionId.REMOVE_FOLDER_SHORTCUT] =
-              removeFolderShortcutAction;
-        }
+            const createFolderShortcutAction =
+                DriveCreateFolderShortcutAction.create(
+                    this.entries_, this.volumeManager_, this.shortcutsModel_,
+                    this.invalidate_.bind(this));
+            if (createFolderShortcutAction) {
+              actions[ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT] =
+                  createFolderShortcutAction;
+            }
 
-        const manageInDriveAction = DriveManageAction.create(
-            this.entries_, this.volumeManager_, this.ui_);
-        if (manageInDriveAction) {
-          actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE] =
-              manageInDriveAction;
-        }
+            const removeFolderShortcutAction =
+                DriveRemoveFolderShortcutAction.create(
+                    this.entries_, this.shortcutsModel_,
+                    this.invalidate_.bind(this));
+            if (removeFolderShortcutAction) {
+              actions[ActionsModel.InternalActionId.REMOVE_FOLDER_SHORTCUT] =
+                  removeFolderShortcutAction;
+            }
 
-        fulfill(actions);
-        break;
+            const manageInDriveAction = DriveManageAction.create(
+                this.entries_, this.volumeManager_, this.ui_);
+            if (manageInDriveAction) {
+              actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE] =
+                  manageInDriveAction;
+            }
 
-      // For FSP, fetch custom actions via an API.
-      case VolumeManagerCommon.VolumeType.PROVIDED:
-        chrome.fileManagerPrivate.getCustomActions(this.entries_,
-            customActions => {
-              if (chrome.runtime.lastError) {
-                console.error('Failed to fetch custom actions because of: ' +
-                    chrome.runtime.lastError.message);
-              } else {
-                customActions.forEach(action => {
-                  actions[action.id] = new CustomAction(
-                      this.entries_, action.id, action.title || null,
-                      this.invalidate_.bind(this));
+            fulfill(actions);
+            break;
+
+          // For FSP, fetch custom actions via an API.
+          case VolumeManagerCommon.VolumeType.PROVIDED:
+            chrome.fileManagerPrivate.getCustomActions(
+                this.entries_, customActions => {
+                  if (chrome.runtime.lastError) {
+                    console.error(
+                        'Failed to fetch custom actions because of: ' +
+                        chrome.runtime.lastError.message);
+                  } else {
+                    customActions.forEach(action => {
+                      actions[action.id] = new CustomAction(
+                          this.entries_, action.id, action.title || null,
+                          this.invalidate_.bind(this));
+                    });
+                  }
+                  fulfill(actions);
                 });
-              }
-              fulfill(actions);
-            });
-        break;
+            break;
 
-      default:
-        fulfill(actions);
-    }
-  }).then(actions => {
-    this.actions_ = actions;
-  });
+          default:
+            fulfill(actions);
+        }
+      }).then(actions => {
+        this.actions_ = actions;
+      });
 
   return this.initializePromise_;
 };
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
index 83fa77c0..538b008 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
@@ -127,63 +127,72 @@
     canShare: true,
   });
 
-  let model = new ActionsModel(volumeManager, metadataModel, shortcutsModel,
-      driveSyncHandler, ui, [driveFileSystem.entries['/test']]);
+  let model = new ActionsModel(
+      volumeManager, metadataModel, shortcutsModel, driveSyncHandler, ui,
+      [driveFileSystem.entries['/test']]);
 
   let invalidated = 0;
   model.addEventListener('invalidated', () => {
     invalidated++;
   });
 
-  return reportPromise(model.initialize().then(() => {
-    const actions = model.getActions();
-    assertEquals(3, Object.keys(actions).length);
+  return reportPromise(
+      model.initialize()
+          .then(() => {
+            const actions = model.getActions();
+            assertEquals(3, Object.keys(actions).length);
 
-    // 'Share' should be disabled in offline mode.
-    const shareAction = actions[ActionsModel.CommonActionId.SHARE];
-    assertTrue(!!shareAction);
-    volumeManager.driveConnectionState = {
-      type: VolumeManagerCommon.DriveConnectionType.OFFLINE
-    };
-    assertFalse(shareAction.canExecute());
+            // 'Share' should be disabled in offline mode.
+            const shareAction = actions[ActionsModel.CommonActionId.SHARE];
+            assertTrue(!!shareAction);
+            volumeManager.driveConnectionState = {
+              type: VolumeManagerCommon.DriveConnectionType.OFFLINE
+            };
+            assertFalse(shareAction.canExecute());
 
-    // 'Manage in Drive' should be disabled in offline mode.
-    const manageInDriveAction =
-        actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
-    assertTrue(!!manageInDriveAction);
-    assertFalse(manageInDriveAction.canExecute());
+            // 'Manage in Drive' should be disabled in offline mode.
+            const manageInDriveAction =
+                actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
+            assertTrue(!!manageInDriveAction);
+            assertFalse(manageInDriveAction.canExecute());
 
-    // 'Create Shortcut' should be enabled, until it's executed, then disabled.
-    const createFolderShortcutAction =
-        actions[ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT];
-    assertTrue(!!createFolderShortcutAction);
-    assertTrue(createFolderShortcutAction.canExecute());
-    createFolderShortcutAction.execute();
-    assertFalse(createFolderShortcutAction.canExecute());
-    assertEquals(1, invalidated);
+            // 'Create Shortcut' should be enabled, until it's executed, then
+            // disabled.
+            const createFolderShortcutAction =
+                actions[ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT];
+            assertTrue(!!createFolderShortcutAction);
+            assertTrue(createFolderShortcutAction.canExecute());
+            createFolderShortcutAction.execute();
+            assertFalse(createFolderShortcutAction.canExecute());
+            assertEquals(1, invalidated);
 
-    // The model is invalidated, as list of actions have changed. Recreated
-    // the model and check that the actions are updated.
-    model = new ActionsModel(volumeManager, metadataModel, shortcutsModel,
-        driveSyncHandler, ui, [driveFileSystem.entries['/test']]);
-    model.addEventListener('invalidated', () => {
-      invalidated++;
-    });
-    return model.initialize();
-  }).then(() => {
-    const actions = model.getActions();
-    assertEquals(4, Object.keys(actions).length);
-    assertTrue(!!actions[ActionsModel.CommonActionId.SHARE]);
-    assertTrue(!!actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE]);
-    assertTrue(!!actions[ActionsModel.InternalActionId.REMOVE_FOLDER_SHORTCUT]);
+            // The model is invalidated, as list of actions have changed.
+            // Recreated the model and check that the actions are updated.
+            model = new ActionsModel(
+                volumeManager, metadataModel, shortcutsModel, driveSyncHandler,
+                ui, [driveFileSystem.entries['/test']]);
+            model.addEventListener('invalidated', () => {
+              invalidated++;
+            });
+            return model.initialize();
+          })
+          .then(() => {
+            const actions = model.getActions();
+            assertEquals(4, Object.keys(actions).length);
+            assertTrue(!!actions[ActionsModel.CommonActionId.SHARE]);
+            assertTrue(
+                !!actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE]);
+            assertTrue(!!actions[ActionsModel.InternalActionId
+                                     .REMOVE_FOLDER_SHORTCUT]);
 
-    // 'Create shortcut' should be disabled.
-    const createFolderShortcutAction =
-        actions[ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT];
-    assertTrue(!!createFolderShortcutAction);
-    assertFalse(createFolderShortcutAction.canExecute());
-    assertEquals(1, invalidated);
-  }), callback);
+            // 'Create shortcut' should be disabled.
+            const createFolderShortcutAction =
+                actions[ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT];
+            assertTrue(!!createFolderShortcutAction);
+            assertFalse(createFolderShortcutAction.canExecute());
+            assertEquals(1, invalidated);
+          }),
+      callback);
 }
 
 /**
@@ -198,87 +207,95 @@
     pinned: false,
   });
 
-  let model = new ActionsModel(volumeManager, metadataModel, shortcutsModel,
-      driveSyncHandler, ui, [driveFileSystem.entries['/test.txt']]);
+  let model = new ActionsModel(
+      volumeManager, metadataModel, shortcutsModel, driveSyncHandler, ui,
+      [driveFileSystem.entries['/test.txt']]);
   let invalidated = 0;
 
-  return reportPromise(model.initialize().then(() => {
-    const actions = model.getActions();
-    assertEquals(3, Object.keys(actions).length);
-    assertTrue(!!actions[ActionsModel.CommonActionId.SHARE]);
+  return reportPromise(
+      model.initialize()
+          .then(() => {
+            const actions = model.getActions();
+            assertEquals(3, Object.keys(actions).length);
+            assertTrue(!!actions[ActionsModel.CommonActionId.SHARE]);
 
-    // 'Save for Offline' should be enabled.
-    const saveForOfflineAction =
-        actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE];
-    assertTrue(!!saveForOfflineAction);
-    assertTrue(saveForOfflineAction.canExecute());
+            // 'Save for Offline' should be enabled.
+            const saveForOfflineAction =
+                actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE];
+            assertTrue(!!saveForOfflineAction);
+            assertTrue(saveForOfflineAction.canExecute());
 
-    // 'Manage in Drive' should be enabled.
-    const manageInDriveAction =
-        actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
-    assertTrue(!!manageInDriveAction);
-    assertTrue(manageInDriveAction.canExecute());
+            // 'Manage in Drive' should be enabled.
+            const manageInDriveAction =
+                actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
+            assertTrue(!!manageInDriveAction);
+            assertTrue(manageInDriveAction.canExecute());
 
-    chrome.fileManagerPrivate.pinDriveFile = (entry, pin, callback) => {
-      metadataModel.properties.pinned = true;
-      assertEquals(driveFileSystem.entries['/test.txt'], entry);
-      assertTrue(pin);
-      callback();
-    };
+            chrome.fileManagerPrivate.pinDriveFile = (entry, pin, callback) => {
+              metadataModel.properties.pinned = true;
+              assertEquals(driveFileSystem.entries['/test.txt'], entry);
+              assertTrue(pin);
+              callback();
+            };
 
-    // For pinning, invalidating is done asynchronously, so we need to wait
-    // for it with a promise.
-    return new Promise((fulfill, reject) => {
-      model.addEventListener('invalidated', () => {
-        invalidated++;
-        fulfill();
-      });
-      saveForOfflineAction.execute();
-    });
-  }).then(() => {
-    assertTrue(metadataModel.properties.pinned);
-    assertEquals(1, invalidated);
+            // For pinning, invalidating is done asynchronously, so we need to
+            // wait for it with a promise.
+            return new Promise((fulfill, reject) => {
+              model.addEventListener('invalidated', () => {
+                invalidated++;
+                fulfill();
+              });
+              saveForOfflineAction.execute();
+            });
+          })
+          .then(() => {
+            assertTrue(metadataModel.properties.pinned);
+            assertEquals(1, invalidated);
 
-    // The model is invalidated, as list of actions have changed. Recreated
-    // the model and check that the actions are updated.
-    model = new ActionsModel(volumeManager, metadataModel, shortcutsModel,
-        driveSyncHandler, ui, [driveFileSystem.entries['/test.txt']]);
-    return model.initialize();
-  }).then(() => {
-    const actions = model.getActions();
-    assertEquals(3, Object.keys(actions).length);
-    assertTrue(!!actions[ActionsModel.CommonActionId.SHARE]);
+            // The model is invalidated, as list of actions have changed.
+            // Recreated the model and check that the actions are updated.
+            model = new ActionsModel(
+                volumeManager, metadataModel, shortcutsModel, driveSyncHandler,
+                ui, [driveFileSystem.entries['/test.txt']]);
+            return model.initialize();
+          })
+          .then(() => {
+            const actions = model.getActions();
+            assertEquals(3, Object.keys(actions).length);
+            assertTrue(!!actions[ActionsModel.CommonActionId.SHARE]);
 
-    // 'Offline not Necessary' should be enabled.
-    const offlineNotNecessaryAction =
-        actions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY];
-    assertTrue(!!offlineNotNecessaryAction);
-    assertTrue(offlineNotNecessaryAction.canExecute());
+            // 'Offline not Necessary' should be enabled.
+            const offlineNotNecessaryAction =
+                actions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY];
+            assertTrue(!!offlineNotNecessaryAction);
+            assertTrue(offlineNotNecessaryAction.canExecute());
 
-    // 'Manage in Drive' should be enabled.
-    const manageInDriveAction =
-        actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
-    assertTrue(!!manageInDriveAction);
-    assertTrue(manageInDriveAction.canExecute());
+            // 'Manage in Drive' should be enabled.
+            const manageInDriveAction =
+                actions[ActionsModel.InternalActionId.MANAGE_IN_DRIVE];
+            assertTrue(!!manageInDriveAction);
+            assertTrue(manageInDriveAction.canExecute());
 
-    chrome.fileManagerPrivate.pinDriveFile = (entry, pin, callback) => {
-      metadataModel.properties.pinned = false;
-      assertEquals(driveFileSystem.entries['/test.txt'], entry);
-      assertFalse(pin);
-      callback();
-    };
+            chrome.fileManagerPrivate.pinDriveFile = (entry, pin, callback) => {
+              metadataModel.properties.pinned = false;
+              assertEquals(driveFileSystem.entries['/test.txt'], entry);
+              assertFalse(pin);
+              callback();
+            };
 
-    return new Promise((fulfill, reject) => {
-      model.addEventListener('invalidated', () => {
-        invalidated++;
-        fulfill();
-      });
-      offlineNotNecessaryAction.execute();
-    });
-  }).then(() => {
-    assertFalse(metadataModel.properties.pinned);
-    assertEquals(2, invalidated);
-  }), callback);
+            return new Promise((fulfill, reject) => {
+              model.addEventListener('invalidated', () => {
+                invalidated++;
+                fulfill();
+              });
+              offlineNotNecessaryAction.execute();
+            });
+          })
+          .then(() => {
+            assertFalse(metadataModel.properties.pinned);
+            assertEquals(2, invalidated);
+          }),
+      callback);
 }
 
 /**
@@ -411,63 +428,68 @@
     callback([
       {
         id: ActionsModel.CommonActionId.SHARE,
-        title: 'Share it!'
+        title: 'Share it!',
       },
       {
         id: 'some-custom-id',
-        title: 'Turn into chocolate!'
-      }
+        title: 'Turn into chocolate!',
+      },
     ]);
   };
 
   const metadataModel = new MockMetadataModel(null);
 
-  const model = new ActionsModel(volumeManager, metadataModel, shortcutsModel,
-      driveSyncHandler, ui, [providedFileSystem.entries['/test']]);
+  const model = new ActionsModel(
+      volumeManager, metadataModel, shortcutsModel, driveSyncHandler, ui,
+      [providedFileSystem.entries['/test']]);
 
   let invalidated = 0;
   model.addEventListener('invalidated', () => {
     invalidated++;
   });
 
-  return reportPromise(model.initialize().then(() => {
-    const actions = model.getActions();
-    assertEquals(2, Object.keys(actions).length);
+  return reportPromise(
+      model.initialize().then(() => {
+        const actions = model.getActions();
+        assertEquals(2, Object.keys(actions).length);
 
-    const shareAction = actions[ActionsModel.CommonActionId.SHARE];
-    assertTrue(!!shareAction);
-    // Sharing on FSP is possible even if Drive is offline. Custom actions are
-    // always executable, as we don't know the actions implementation.
-    volumeManager.driveConnectionState = {
-      type: VolumeManagerCommon.DriveConnectionType.OFFLINE
-    };
-    assertTrue(shareAction.canExecute());
-    assertEquals('Share it!', shareAction.getTitle());
+        const shareAction = actions[ActionsModel.CommonActionId.SHARE];
+        assertTrue(!!shareAction);
+        // Sharing on FSP is possible even if Drive is offline. Custom actions
+        // are always executable, as we don't know the actions implementation.
+        volumeManager.driveConnectionState = {
+          type: VolumeManagerCommon.DriveConnectionType.OFFLINE
+        };
+        assertTrue(shareAction.canExecute());
+        assertEquals('Share it!', shareAction.getTitle());
 
-    chrome.fileManagerPrivate.executeCustomAction = (entries, actionId, callback) => {
-      assertEquals(1, entries.length);
-      assertEquals(providedFileSystem.entries['/test'], entries[0]);
-      assertEquals(ActionsModel.CommonActionId.SHARE, actionId);
-      callback();
-    };
-    shareAction.execute();
-    assertEquals(1, invalidated);
+        chrome.fileManagerPrivate.executeCustomAction =
+            (entries, actionId, callback) => {
+              assertEquals(1, entries.length);
+              assertEquals(providedFileSystem.entries['/test'], entries[0]);
+              assertEquals(ActionsModel.CommonActionId.SHARE, actionId);
+              callback();
+            };
+        shareAction.execute();
+        assertEquals(1, invalidated);
 
-    assertTrue(!!actions['some-custom-id']);
-    assertTrue(actions['some-custom-id'].canExecute());
-    assertEquals('Turn into chocolate!',
-        actions['some-custom-id'].getTitle());
+        assertTrue(!!actions['some-custom-id']);
+        assertTrue(actions['some-custom-id'].canExecute());
+        assertEquals(
+            'Turn into chocolate!', actions['some-custom-id'].getTitle());
 
-    chrome.fileManagerPrivate.executeCustomAction = (entries, actionId, callback) => {
-      assertEquals(1, entries.length);
-      assertEquals(providedFileSystem.entries['/test'], entries[0]);
-      assertEquals('some-custom-id', actionId);
-      callback();
-    };
+        chrome.fileManagerPrivate.executeCustomAction =
+            (entries, actionId, callback) => {
+              assertEquals(1, entries.length);
+              assertEquals(providedFileSystem.entries['/test'], entries[0]);
+              assertEquals('some-custom-id', actionId);
+              callback();
+            };
 
-    actions['some-custom-id'].execute();
-    assertEquals(2, invalidated);
-  }), callback);
+        actions['some-custom-id'].execute();
+        assertEquals(2, invalidated);
+      }),
+      callback);
 }
 
 /**
@@ -479,18 +501,21 @@
 
   chrome.fileManagerPrivate.getCustomActions = (entries, callback) => {
     chrome.runtime.lastError = {
-      message: 'Failed to fetch custom actions.'
+      message: 'Failed to fetch custom actions.',
     };
     callback(['error']);
   };
 
   const metadataModel = new MockMetadataModel(null);
 
-  const model = new ActionsModel(volumeManager, metadataModel, shortcutsModel,
-      driveSyncHandler, ui, [providedFileSystem.entries['/test']]);
+  const model = new ActionsModel(
+      volumeManager, metadataModel, shortcutsModel, driveSyncHandler, ui,
+      [providedFileSystem.entries['/test']]);
 
-  return reportPromise(model.initialize().then(() => {
-    const actions = model.getActions();
-    assertEquals(0, Object.keys(actions).length);
-  }), callback);
+  return reportPromise(
+      model.initialize().then(() => {
+        const actions = model.getActions();
+        assertEquals(0, Object.keys(actions).length);
+      }),
+      callback);
 }
diff --git a/ui/file_manager/file_manager/foreground/js/app_state_controller.js b/ui/file_manager/file_manager/foreground/js/app_state_controller.js
index 2d31b57c..49649cb 100644
--- a/ui/file_manager/file_manager/foreground/js/app_state_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/app_state_controller.js
@@ -62,38 +62,42 @@
 AppStateController.prototype.loadInitialViewOptions = function() {
   // Load initial view option.
   return new Promise((fulfill, reject) => {
-    chrome.storage.local.get(this.viewOptionStorageKey_, values => {
-      if (chrome.runtime.lastError) {
-        reject('Failed to load view options: ' +
-            chrome.runtime.lastError.message);
-      } else {
-        fulfill(values);
-      }
-    });
-  }).then(values => {
-    this.viewOptions_ = {};
-    const value = values[this.viewOptionStorageKey_];
-    if (!value) {
-      return;
-    }
-
-    // Load the global default options.
-    try {
-      this.viewOptions_ = JSON.parse(value);
-    } catch (ignore) {}
-
-    // Override with window-specific options.
-    if (window.appState && window.appState.viewOptions) {
-      for (const key in window.appState.viewOptions) {
-        if (window.appState.viewOptions.hasOwnProperty(key)) {
-          this.viewOptions_[key] = window.appState.viewOptions[key];
+           chrome.storage.local.get(this.viewOptionStorageKey_, values => {
+             if (chrome.runtime.lastError) {
+               reject(
+                   'Failed to load view options: ' +
+                   chrome.runtime.lastError.message);
+             } else {
+               fulfill(values);
+             }
+           });
+         })
+      .then(values => {
+        this.viewOptions_ = {};
+        const value = values[this.viewOptionStorageKey_];
+        if (!value) {
+          return;
         }
-      }
-    }
-  }).catch(error => {
-    this.viewOptions_ = {};
-    console.error(error);
-  });
+
+        // Load the global default options.
+        try {
+          this.viewOptions_ = JSON.parse(value);
+        } catch (ignore) {
+        }
+
+        // Override with window-specific options.
+        if (window.appState && window.appState.viewOptions) {
+          for (const key in window.appState.viewOptions) {
+            if (window.appState.viewOptions.hasOwnProperty(key)) {
+              this.viewOptions_[key] = window.appState.viewOptions[key];
+            }
+          }
+        }
+      })
+      .catch(error => {
+        this.viewOptions_ = {};
+        console.error(error);
+      });
 };
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/column_visibility_controller.js b/ui/file_manager/file_manager/foreground/js/column_visibility_controller.js
index ce80d40f..51349c82 100644
--- a/ui/file_manager/file_manager/foreground/js/column_visibility_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/column_visibility_controller.js
@@ -16,7 +16,7 @@
   this.directoryModel_ = directoryModel;
 
   /** @private {!VolumeManager} */
-  this.volumeManager_  = volumeManager;
+  this.volumeManager_ = volumeManager;
 
   /** @private {!FileManagerUI} */
   this.ui_ = ui;
diff --git a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
index a2ce9e1..be393f1bd 100644
--- a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
@@ -20,15 +20,8 @@
  * @struct
  */
 function DialogActionController(
-    dialogType,
-    dialogFooter,
-    directoryModel,
-    metadataModel,
-    volumeManager,
-    fileFilter,
-    namingController,
-    fileSelectionHandler,
-    launchParam) {
+    dialogType, dialogFooter, directoryModel, metadataModel, volumeManager,
+    fileFilter, namingController, fileSelectionHandler, launchParam) {
   /**
    * @type {!DialogType}
    * @const
@@ -109,8 +102,7 @@
 
   dialogFooter.okButton.addEventListener(
       'click', this.processOKAction_.bind(this));
-  dialogFooter.cancelButton.addEventListener(
-      'click', this.onCancelBound_);
+  dialogFooter.cancelButton.addEventListener('click', this.onCancelBound_);
   dialogFooter.newFolderButton.addEventListener(
       'click', this.processNewFolderAction_.bind(this));
   dialogFooter.fileTypeSelector.addEventListener(
@@ -123,8 +115,7 @@
   volumeManager.addEventListener(
       'drive-connection-changed', this.updateOkButton_.bind(this));
 
-  dialogFooter.initFileTypeFilter(
-      this.fileTypes_, launchParam.includeAllFiles);
+  dialogFooter.initFileTypeFilter(this.fileTypes_, launchParam.includeAllFiles);
   this.onFileTypeFilterChanged_();
 
   this.newFolderCommand_ =
@@ -225,7 +216,7 @@
   if (this.dialogType_ === DialogType.SELECT_OPEN_MULTI_FILE) {
     const multipleSelection = {
       urls: files,
-      multiple: true
+      multiple: true,
     };
     this.selectFilesAndClose_(multipleSelection);
     return;
@@ -308,16 +299,13 @@
     }
     if (selection.multiple) {
       chrome.fileManagerPrivate.selectFiles(
-          selection.urls,
-          this.allowedPaths_ === AllowedPaths.NATIVE_PATH,
+          selection.urls, this.allowedPaths_ === AllowedPaths.NATIVE_PATH,
           onFileSelected);
     } else {
       chrome.fileManagerPrivate.selectFile(
-          selection.urls[0],
-          selection.filterIndex,
+          selection.urls[0], selection.filterIndex,
           this.dialogType_ !== DialogType.SELECT_SAVEAS_FILE /* for opening */,
-          this.allowedPaths_ === AllowedPaths.NATIVE_PATH,
-          onFileSelected);
+          this.allowedPaths_ === AllowedPaths.NATIVE_PATH, onFileSelected);
     }
   };
 
@@ -428,9 +416,10 @@
 DialogActionController.prototype.onFileTypeFilterChanged_ = function() {
   this.fileFilter_.removeFilter('fileType');
   const selectedIndex = this.dialogFooter_.selectedFilterIndex;
-  if (selectedIndex > 0) { // Specific filter selected.
-    const regexp = new RegExp('\\.(' +
-        this.fileTypes_[selectedIndex - 1].extensions.join('|') + ')$', 'i');
+  if (selectedIndex > 0) {  // Specific filter selected.
+    const regexp = new RegExp(
+        '\\.(' + this.fileTypes_[selectedIndex - 1].extensions.join('|') + ')$',
+        'i');
     const filter = entry => {
       return entry.isDirectory || regexp.test(entry.name);
     };
@@ -462,8 +451,7 @@
   // input text box.
   const selection = this.fileSelectionHandler_.selection;
   if (this.dialogType_ === DialogType.SELECT_SAVEAS_FILE &&
-      selection.totalCount === 1 &&
-      selection.entries[0].isFile &&
+      selection.totalCount === 1 && selection.entries[0].isFile &&
       this.dialogFooter_.filenameInput.value !== selection.entries[0].name) {
     this.dialogFooter_.filenameInput.value = selection.entries[0].name;
   }
@@ -510,18 +498,14 @@
   }
 
   if (this.dialogType_ === DialogType.SELECT_OPEN_FILE) {
-    this.dialogFooter_.okButton.disabled =
-        selection.directoryCount !== 0 ||
-        selection.fileCount !== 1 ||
-        !this.fileSelectionHandler_.isAvailable();
+    this.dialogFooter_.okButton.disabled = selection.directoryCount !== 0 ||
+        selection.fileCount !== 1 || !this.fileSelectionHandler_.isAvailable();
     return;
   }
 
   if (this.dialogType_ === DialogType.SELECT_OPEN_MULTI_FILE) {
-    this.dialogFooter_.okButton.disabled =
-        selection.directoryCount !== 0 ||
-        selection.fileCount === 0 ||
-        !this.fileSelectionHandler_.isAvailable();
+    this.dialogFooter_.okButton.disabled = selection.directoryCount !== 0 ||
+        selection.fileCount === 0 || !this.fileSelectionHandler_.isAvailable();
     return;
   }
 
diff --git a/ui/file_manager/file_manager/foreground/js/dialog_type.js b/ui/file_manager/file_manager/foreground/js/dialog_type.js
index b9ef0b7..b0e4721 100644
--- a/ui/file_manager/file_manager/foreground/js/dialog_type.js
+++ b/ui/file_manager/file_manager/foreground/js/dialog_type.js
@@ -38,9 +38,9 @@
  */
 DialogType.isOpenDialog = type => {
   return type == DialogType.SELECT_OPEN_FILE ||
-         type == DialogType.SELECT_OPEN_MULTI_FILE ||
-         type == DialogType.SELECT_FOLDER ||
-         type == DialogType.SELECT_UPLOAD_FOLDER;
+      type == DialogType.SELECT_OPEN_MULTI_FILE ||
+      type == DialogType.SELECT_FOLDER ||
+      type == DialogType.SELECT_UPLOAD_FOLDER;
 };
 
 /**
@@ -49,7 +49,7 @@
  */
 DialogType.isOpenFileDialog = type => {
   return type == DialogType.SELECT_OPEN_FILE ||
-         type == DialogType.SELECT_OPEN_MULTI_FILE;
+      type == DialogType.SELECT_OPEN_MULTI_FILE;
 };
 
 /**
@@ -58,5 +58,5 @@
  */
 DialogType.isFolderDialog = type => {
   return type == DialogType.SELECT_FOLDER ||
-         type == DialogType.SELECT_UPLOAD_FOLDER;
+      type == DialogType.SELECT_UPLOAD_FOLDER;
 };
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index af95c70..192d493 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -201,8 +201,7 @@
    */
   scan(entriesCallback, successCallback, errorCallback) {
     chrome.fileManagerPrivate.searchDriveMetadata(
-        {query: '', types: this.searchType_, maxResults: 100},
-        results => {
+        {query: '', types: this.searchType_, maxResults: 100}, results => {
           if (this.cancelled_) {
             errorCallback(util.createDOMError(util.FileError.ABORT_ERR));
             return;
@@ -931,25 +930,26 @@
         }
 
         const chunk = entries.slice(i, i + MAX_CHUNK_SIZE);
-        prefetchMetadataQueue.run(((chunk, callbackInner) => {
-          this.prefetchMetadata(chunk, refresh, () => {
-            if (!prefetchMetadataQueue.isCancelled()) {
-              if (this.scanCancelled_) {
-                prefetchMetadataQueue.cancel();
-              }
-            }
+        prefetchMetadataQueue.run(
+            ((chunk, callbackInner) => {
+              this.prefetchMetadata(chunk, refresh, () => {
+                if (!prefetchMetadataQueue.isCancelled()) {
+                  if (this.scanCancelled_) {
+                    prefetchMetadataQueue.cancel();
+                  }
+                }
 
-            // Checks if this is the last task.
-            if (prefetchMetadataQueue.getWaitingTasksCount() === 0 &&
-                prefetchMetadataQueue.getRunningTasksCount() === 1) {
-              // |callbackOuter| in |finish| must be called before
-              // |callbackInner|, to prevent double-calling.
-              finish();
-            }
+                // Checks if this is the last task.
+                if (prefetchMetadataQueue.getWaitingTasksCount() === 0 &&
+                    prefetchMetadataQueue.getRunningTasksCount() === 1) {
+                  // |callbackOuter| in |finish| must be called before
+                  // |callbackInner|, to prevent double-calling.
+                  finish();
+                }
 
-            callbackInner();
-          });
-        }).bind(null, chunk));
+                callbackInner();
+              });
+            }).bind(null, chunk));
       }
     });
   }
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 a3147c8bf..767e989 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -26,7 +26,8 @@
     singleSelection, fileFilter, metadataModel, volumeManager,
     fileOperationManager) {
   this.fileListSelection_ = singleSelection ?
-      new FileListSingleSelectionModel() : new FileListSelectionModel();
+      new FileListSingleSelectionModel() :
+      new FileListSelectionModel();
 
   this.runningScan_ = null;
   this.pendingScan_ = null;
@@ -40,12 +41,12 @@
   this.ignoreCurrentDirectoryDeletion_ = false;
 
   this.directoryChangeQueue_ = new AsyncUtil.Queue();
-  this.rescanAggregator_ = new AsyncUtil.Aggregator(
-      this.rescanSoon.bind(this, true), 500);
+  this.rescanAggregator_ =
+      new AsyncUtil.Aggregator(this.rescanSoon.bind(this, true), 500);
 
   this.fileFilter_ = fileFilter;
-  this.fileFilter_.addEventListener('changed',
-                                    this.onFilterChanged_.bind(this));
+  this.fileFilter_.addEventListener(
+      'changed', this.onFilterChanged_.bind(this));
 
   this.currentFileListContext_ =
       new FileListContext(fileFilter, metadataModel, volumeManager);
@@ -70,11 +71,9 @@
    */
   this.fileWatcher_ = new FileWatcher();
   this.fileWatcher_.addEventListener(
-      'watcher-directory-changed',
-      this.onWatcherDirectoryChanged_.bind(this));
+      'watcher-directory-changed', this.onWatcherDirectoryChanged_.bind(this));
   util.addEventListenerToBackgroundComponent(
-      fileOperationManager,
-      'entries-changed',
+      fileOperationManager, 'entries-changed',
       this.onEntriesChanged_.bind(this));
 
   /** @private {string} */
@@ -223,31 +222,32 @@
  */
 DirectoryModel.prototype.updateSelectionAndPublishEvent_ =
     (selection, updateFunc) => {
-  // Begin change.
-  selection.beginChange();
+      // Begin change.
+      selection.beginChange();
 
-  // If dispatchNeeded is true, we should ensure the change event is
-  // dispatched.
-  let dispatchNeeded = updateFunc();
+      // If dispatchNeeded is true, we should ensure the change event is
+      // dispatched.
+      let dispatchNeeded = updateFunc();
 
-  // Check if the change event is dispatched in the endChange function
-  // or not.
-  const eventDispatched = () => {
-    dispatchNeeded = false;
-  };
-  selection.addEventListener('change', eventDispatched);
-  selection.endChange();
-  selection.removeEventListener('change', eventDispatched);
+      // Check if the change event is dispatched in the endChange function
+      // or not.
+      const eventDispatched = () => {
+        dispatchNeeded = false;
+      };
+      selection.addEventListener('change', eventDispatched);
+      selection.endChange();
+      selection.removeEventListener('change', eventDispatched);
 
-  // If the change event have been already dispatched, dispatchNeeded is false.
-  if (dispatchNeeded) {
-    const event = new Event('change');
-    // The selection status (selected or not) is not changed because
-    // this event is caused by the change of selected item.
-    event.changes = [];
-    selection.dispatchEvent(event);
-  }
-};
+      // If the change event have been already dispatched, dispatchNeeded is
+      // false.
+      if (dispatchNeeded) {
+        const event = new Event('change');
+        // The selection status (selected or not) is not changed because
+        // this event is caused by the change of selected item.
+        event.changes = [];
+        selection.dispatchEvent(event);
+      }
+    };
 
 /**
  * Sets to ignore current directory deletion. This method is used to prevent
@@ -270,8 +270,7 @@
   if (!this.ignoreCurrentDirectoryDeletion_) {
     // If the change is deletion of currentDir, move up to its parent directory.
     directoryEntry.getDirectory(
-        directoryEntry.fullPath, {create: false}, () => {},
-        () => {
+        directoryEntry.fullPath, {create: false}, () => {}, () => {
           const volumeInfo =
               this.volumeManager_.getVolumeInfo(assert(directoryEntry));
           if (volumeInfo) {
@@ -293,17 +292,20 @@
       }
     });
 
-    util.URLsToEntries(addedOrUpdatedFileUrls).then(result => {
-      deletedFileUrls = deletedFileUrls.concat(result.failureUrls);
+    util.URLsToEntries(addedOrUpdatedFileUrls)
+        .then(result => {
+          deletedFileUrls = deletedFileUrls.concat(result.failureUrls);
 
-      // Passing the resolved entries and failed URLs as the removed files.
-      // The URLs are removed files and they chan't be resolved.
-      this.partialUpdate_(result.entries, deletedFileUrls);
-    }).catch(error => {
-      console.error('Error in proceeding the changed event.', error,
-                    'Fallback to force-refresh');
-      this.rescanAggregator_.run();
-    });
+          // Passing the resolved entries and failed URLs as the removed files.
+          // The URLs are removed files and they chan't be resolved.
+          this.partialUpdate_(result.entries, deletedFileUrls);
+        })
+        .catch(error => {
+          console.error(
+              'Error in proceeding the changed event.', error,
+              'Fallback to force-refresh');
+          this.rescanAggregator_.run();
+        });
   } else {
     // Invokes force refresh if the detailed information isn't provided.
     // This can occur very frequently (e.g. when copying files into Downlaods)
@@ -388,7 +390,8 @@
 DirectoryModel.prototype.getLeadEntry_ = function() {
   const index = this.fileListSelection_.leadIndex;
   return index >= 0 ?
-      /** @type {Entry} */ (this.getFileList().item(index)) : null;
+      /** @type {Entry} */ (this.getFileList().item(index)) :
+      null;
 };
 
 /**
@@ -495,9 +498,8 @@
     }
   };
 
-  this.scan_(dirContents,
-             refresh,
-             successCallback, () => {}, () => {}, () => {});
+  this.scan_(
+      dirContents, refresh, successCallback, () => {}, () => {}, () => {});
 };
 
 /**
@@ -599,8 +601,9 @@
   // Clear the table, and start scanning.
   cr.dispatchSimpleEvent(this, 'scan-started');
   fileList.splice(0, fileList.length);
-  this.scan_(this.currentDirContents_, false,
-             onDone, onFailed, onUpdated, onCancelled);
+  this.scan_(
+      this.currentDirContents_, false, onDone, onFailed, onUpdated,
+      onCancelled);
 };
 
 /**
@@ -609,8 +612,8 @@
  * @param {Array<string>} removedUrls URLs of removed files.
  * @private
  */
-DirectoryModel.prototype.partialUpdate_ =
-    function(changedEntries, removedUrls) {
+DirectoryModel.prototype.partialUpdate_ = function(
+    changedEntries, removedUrls) {
   // This update should be included in the current running update.
   if (this.pendingScan_) {
     return;
@@ -620,8 +623,8 @@
     // Do update after the current scan is finished.
     const previousScan = this.runningScan_;
     const onPreviousScanCompleted = () => {
-      previousScan.removeEventListener('scan-completed',
-                                       onPreviousScanCompleted);
+      previousScan.removeEventListener(
+          'scan-completed', onPreviousScanCompleted);
       // Run the update asynchronously.
       Promise.resolve().then(() => {
         this.partialUpdate_(changedEntries, removedUrls);
@@ -634,11 +637,9 @@
   const onFinish = () => {
     this.runningScan_ = null;
 
-    this.currentDirContents_.removeEventListener(
-        'scan-completed', onCompleted);
+    this.currentDirContents_.removeEventListener('scan-completed', onCompleted);
     this.currentDirContents_.removeEventListener('scan-failed', onFailure);
-    this.currentDirContents_.removeEventListener(
-        'scan-cancelled', onCancelled);
+    this.currentDirContents_.removeEventListener('scan-cancelled', onCancelled);
   };
 
   const onCompleted = () => {
@@ -677,9 +678,8 @@
  * @private
  */
 DirectoryModel.prototype.scan_ = function(
-    dirContents,
-    refresh,
-    successCallback, failureCallback, updatedCallback, cancelledCallback) {
+    dirContents, refresh, successCallback, failureCallback, updatedCallback,
+    cancelledCallback) {
   const self = this;
 
   /**
@@ -708,9 +708,8 @@
 
     // Record metric for Downloads directory.
     if (!dirContents.isSearch()) {
-      const locationInfo =
-          this.volumeManager_.getLocationInfo(
-              assert(dirContents.getDirectoryEntry()));
+      const locationInfo = this.volumeManager_.getLocationInfo(
+          assert(dirContents.getDirectoryEntry()));
       const volumeInfo = locationInfo && locationInfo.volumeInfo;
       if (volumeInfo &&
           volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DOWNLOADS &&
@@ -767,7 +766,8 @@
  * @private
  */
 DirectoryModel.prototype.replaceDirectoryContents_ = function(dirContents) {
-  console.assert(this.currentDirContents_ !== dirContents,
+  console.assert(
+      this.currentDirContents_ !== dirContents,
       'Give directory contents instance must be different from current one.');
   cr.dispatchSimpleEvent(this, 'begin-update-files');
   this.updateSelectionAndPublishEvent_(this.fileListSelection_, () => {
@@ -793,8 +793,10 @@
     if (this.fileListSelection_.selectedIndexes.length == 0 &&
         selectedIndices.length != 0) {
       const maxIdx = Math.max.apply(null, selectedIndices);
-      this.selectIndex(Math.min(maxIdx - selectedIndices.length + 2,
-                                this.getFileList().length) - 1);
+      this.selectIndex(
+          Math.min(
+              maxIdx - selectedIndices.length + 2, this.getFileList().length) -
+          1);
       forceChangeEvent = true;
     } else if (isCheckSelectMode) {
       // Otherwise, ensure check select mode is retained if it was previously
@@ -834,24 +836,26 @@
           entries[i].getParent(resolve, reject);
         }));
       }
-      Promise.all(parentPromises).then(parents => {
-        const entriesToAdd = [];
-        for (let i = 0; i < parents.length; i++) {
-          if (!util.isSameEntry(parents[i], this.getCurrentDirEntry())) {
-            continue;
-          }
-          const index = this.findIndexByEntry_(entries[i]);
-          if (index >= 0) {
-            this.getFileList().replaceItem(
-                this.getFileList().item(index), entries[i]);
-          } else {
-            entriesToAdd.push(entries[i]);
-          }
-        }
-        this.partialUpdate_(entriesToAdd, []);
-      }).catch(error => {
-        console.error(error.stack || error);
-      });
+      Promise.all(parentPromises)
+          .then(parents => {
+            const entriesToAdd = [];
+            for (let i = 0; i < parents.length; i++) {
+              if (!util.isSameEntry(parents[i], this.getCurrentDirEntry())) {
+                continue;
+              }
+              const index = this.findIndexByEntry_(entries[i]);
+              if (index >= 0) {
+                this.getFileList().replaceItem(
+                    this.getFileList().item(index), entries[i]);
+              } else {
+                entriesToAdd.push(entries[i]);
+              }
+            }
+            this.partialUpdate_(entriesToAdd, []);
+          })
+          .catch(error => {
+            console.error(error.stack || error);
+          });
       break;
 
     case util.EntryChangedKind.DELETED:
@@ -952,28 +956,28 @@
   const dirContents = this.currentDirContents_;
 
   return new Promise((onFulfilled, onRejected) => {
-    dirContents.prefetchMetadata(
-        [newDirectory], false, onFulfilled);
-  }).then((sequence => {
-    // If current directory has changed during the prefetch, do not try to
-    // select new directory.
-    if (sequence !== this.changeDirectorySequence_) {
-      return Promise.reject();
-    }
+           dirContents.prefetchMetadata([newDirectory], false, onFulfilled);
+         })
+      .then((sequence => {
+              // If current directory has changed during the prefetch, do not
+              // try to select new directory.
+              if (sequence !== this.changeDirectorySequence_) {
+                return Promise.reject();
+              }
 
-    // If target directory is already in the list, just select it.
-    const existing = this.getFileList().slice().filter(e => {
-      return e.name === newDirectory.name;
-    });
-    if (existing.length) {
-      this.selectEntry(newDirectory);
-    } else {
-      this.fileListSelection_.beginChange();
-      this.getFileList().splice(0, 0, newDirectory);
-      this.selectEntry(newDirectory);
-      this.fileListSelection_.endChange();
-    }
-  }).bind(null, this.changeDirectorySequence_));
+              // If target directory is already in the list, just select it.
+              const existing = this.getFileList().slice().filter(e => {
+                return e.name === newDirectory.name;
+              });
+              if (existing.length) {
+                this.selectEntry(newDirectory);
+              } else {
+                this.fileListSelection_.beginChange();
+                this.getFileList().splice(0, 0, newDirectory);
+                this.selectEntry(newDirectory);
+                this.fileListSelection_.endChange();
+              }
+            }).bind(null, this.changeDirectorySequence_));
 };
 
 /**
@@ -1021,9 +1025,9 @@
     this.currentDirContents_.cancelScan();
   }
 
-  this.directoryChangeQueue_.run(((sequence, queueTaskCallback) => {
-    this.fileWatcher_.changeWatchedDirectory(dirEntry)
-        .then(() => {
+  this.directoryChangeQueue_.run(
+      ((sequence, queueTaskCallback) => {
+        this.fileWatcher_.changeWatchedDirectory(dirEntry).then(() => {
           if (this.changeDirectorySequence_ !== sequence) {
             queueTaskCallback();
             return;
@@ -1036,27 +1040,24 @@
             return;
           }
 
-          const previousDirEntry =
-              this.currentDirContents_.getDirectoryEntry();
-          this.clearAndScan_(
-               newDirectoryContents,
-               result => {
-                 // Calls the callback of the method when successful.
-                 if (result && opt_callback) {
-                   opt_callback();
-                 }
+          const previousDirEntry = this.currentDirContents_.getDirectoryEntry();
+          this.clearAndScan_(newDirectoryContents, result => {
+            // Calls the callback of the method when successful.
+            if (result && opt_callback) {
+              opt_callback();
+            }
 
-                 // Notify that the current task of this.directoryChangeQueue_
-                 // is completed.
-                 setTimeout(queueTaskCallback, 0);
-               });
+            // Notify that the current task of this.directoryChangeQueue_
+            // is completed.
+            setTimeout(queueTaskCallback, 0);
+          });
 
           // For tests that open the dialog to empty directories, everything
           // is loaded at this point.
           util.testSendMessage('directory-change-complete');
-          const previousVolumeInfo =
-              previousDirEntry ?
-              this.volumeManager_.getVolumeInfo(previousDirEntry) : null;
+          const previousVolumeInfo = previousDirEntry ?
+              this.volumeManager_.getVolumeInfo(previousDirEntry) :
+              null;
           // VolumeInfo for dirEntry.
           const currentVolumeInfo = this.getCurrentVolumeInfo();
           const event = new Event('directory-changed');
@@ -1065,7 +1066,7 @@
           event.volumeChanged = previousVolumeInfo !== currentVolumeInfo;
           this.dispatchEvent(event);
         });
-  }).bind(null, this.changeDirectorySequence_));
+      }).bind(null, this.changeDirectorySequence_));
 };
 
 /**
@@ -1114,8 +1115,7 @@
 
     start: function() {
       if (!this.active_) {
-        this.dm_.addEventListener('directory-changed',
-                                  this.onDirectoryChange_);
+        this.dm_.addEventListener('directory-changed', this.onDirectoryChange_);
         this.active_ = true;
         this.hasChanged = false;
       }
@@ -1123,8 +1123,8 @@
 
     stop: function() {
       if (this.active_) {
-        this.dm_.removeEventListener('directory-changed',
-                                     this.onDirectoryChange_);
+        this.dm_.removeEventListener(
+            'directory-changed', this.onDirectoryChange_);
         this.active_ = false;
       }
     },
@@ -1281,11 +1281,12 @@
  * @return {DirectoryContents} Directory contents.
  * @private
  */
-DirectoryModel.prototype.createDirectoryContents_ =
-    function(context, entry, opt_query) {
+DirectoryModel.prototype.createDirectoryContents_ = function(
+    context, entry, opt_query) {
   const query = (opt_query || '').trimLeft();
   const locationInfo = this.volumeManager_.getLocationInfo(entry);
-  const canUseDriveSearch = this.volumeManager_.getDriveConnectionState().type !==
+  const canUseDriveSearch =
+      this.volumeManager_.getDriveConnectionState().type !==
           VolumeManagerCommon.DriveConnectionType.OFFLINE &&
       (locationInfo && locationInfo.isDriveBased);
 
@@ -1347,8 +1348,7 @@
     }
     return DirectoryContents.createForDriveMetadataSearch(
         context,
-        /** @type {!FakeEntry} */ (entry),
-        searchType);
+        /** @type {!FakeEntry} */ (entry), searchType);
   }
   // Local fetch or search.
   return DirectoryContents.createForDirectory(
@@ -1383,9 +1383,8 @@
  *     gets cleared.
  * TODO(olege): Change callbacks to events.
  */
-DirectoryModel.prototype.search = function(query,
-                                           onSearchRescan,
-                                           onClearSearch) {
+DirectoryModel.prototype.search = function(
+    query, onSearchRescan, onClearSearch) {
   this.lastSearchQuery_ = query;
   this.clearSearch_();
   const currentDirEntry = this.getCurrentDirEntry();
@@ -1395,38 +1394,36 @@
   }
 
   this.changeDirectorySequence_++;
-  this.directoryChangeQueue_.run(((sequence, callback) => {
-    if (this.changeDirectorySequence_ !== sequence) {
-      callback();
-      return;
-    }
+  this.directoryChangeQueue_.run(
+      ((sequence, callback) => {
+        if (this.changeDirectorySequence_ !== sequence) {
+          callback();
+          return;
+        }
 
-    if (!(query || '').trimLeft()) {
-      if (this.isSearching()) {
+        if (!(query || '').trimLeft()) {
+          if (this.isSearching()) {
+            const newDirContents = this.createDirectoryContents_(
+                this.currentFileListContext_, assert(currentDirEntry));
+            this.clearAndScan_(newDirContents, callback);
+          } else {
+            callback();
+          }
+          return;
+        }
+
         const newDirContents = this.createDirectoryContents_(
-            this.currentFileListContext_,
-            assert(currentDirEntry));
-        this.clearAndScan_(newDirContents,
-                           callback);
-      } else {
-        callback();
-      }
-      return;
-    }
+            this.currentFileListContext_, assert(currentDirEntry), query);
+        if (!newDirContents) {
+          callback();
+          return;
+        }
 
-    const newDirContents = this.createDirectoryContents_(
-        this.currentFileListContext_, assert(currentDirEntry), query);
-    if (!newDirContents) {
-      callback();
-      return;
-    }
-
-    this.onSearchCompleted_ = onSearchRescan;
-    this.onClearSearch_ = onClearSearch;
-    this.addEventListener('scan-completed', this.onSearchCompleted_);
-    this.clearAndScan_(newDirContents,
-                       callback);
-  }).bind(null, this.changeDirectorySequence_));
+        this.onSearchCompleted_ = onSearchRescan;
+        this.onClearSearch_ = onClearSearch;
+        this.addEventListener('scan-completed', this.onSearchCompleted_);
+        this.clearAndScan_(newDirContents, callback);
+      }).bind(null, this.changeDirectorySequence_));
 };
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/directory_tree_naming_controller.js b/ui/file_manager/file_manager/foreground/js/directory_tree_naming_controller.js
index e25a8847..d28452b 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_tree_naming_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_tree_naming_controller.js
@@ -87,7 +87,6 @@
  */
 DirectoryTreeNamingController.prototype.attachAndStart = function(
     directoryItem, isRemovableRoot, volumeInfo) {
-
   this.isRemovableRoot_ = isRemovableRoot;
   this.volumeInfo_ = this.isRemovableRoot_ ? assert(volumeInfo) : null;
 
@@ -153,13 +152,10 @@
               parentEntry, newName,
               !this.directoryModel_.getFileFilter().isHiddenFilesVisible());
         })
-        .then(
-            this.performRename_.bind(this, entry, newName),
-            errorMessage => {
-              this.alertDialog_.show(
-                  /** @type {string} */ (errorMessage),
-                  this.detach_.bind(this));
-            });
+        .then(this.performRename_.bind(this, entry, newName), errorMessage => {
+          this.alertDialog_.show(
+              /** @type {string} */ (errorMessage), this.detach_.bind(this));
+        });
   }
 };
 
@@ -171,8 +167,8 @@
  */
 DirectoryTreeNamingController.prototype.performRename_ = function(
     entry, newName) {
-  const renamingCurrentDirectory = util.isSameEntry(entry,
-      this.directoryModel_.getCurrentDirEntry());
+  const renamingCurrentDirectory =
+      util.isSameEntry(entry, this.directoryModel_.getCurrentDirEntry());
   if (renamingCurrentDirectory) {
     this.directoryModel_.setIgnoringCurrentDirectoryDeletion(true /* ignore */);
   }
diff --git a/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js b/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js
index a7b450a..e5788c9 100644
--- a/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js
@@ -101,9 +101,7 @@
     const query = this.directoryModel_.getLastSearchQuery();
     let html = '';
     if (query) {
-      html = strf(
-          'SEARCH_NO_MATCHING_FILES_HTML',
-          util.htmlEscape(query));
+      html = strf('SEARCH_NO_MATCHING_FILES_HTML', util.htmlEscape(query));
     } else {
       html = str('EMPTY_FOLDER');
     }
diff --git a/ui/file_manager/file_manager/foreground/js/file_list_model.js b/ui/file_manager/file_manager/foreground/js/file_list_model.js
index 90f1da5..aff8f98 100644
--- a/ui/file_manager/file_manager/foreground/js/file_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/file_list_model.js
@@ -300,8 +300,9 @@
       this.numFiles_++;
     }
 
-    const mimeType = this.metadataModel_.getCache([entry], ['contentMimeType'])[0]
-                       .contentMimeType;
+    const mimeType =
+        this.metadataModel_.getCache([entry], ['contentMimeType'])[0]
+            .contentMimeType;
     if (FileType.isImage(entry, mimeType) || FileType.isRaw(entry, mimeType)) {
       this.numImageFiles_++;
     }
@@ -319,8 +320,9 @@
       this.numFiles_--;
     }
 
-    const mimeType = this.metadataModel_.getCache([entry], ['contentMimeType'])[0]
-                       .contentMimeType;
+    const mimeType =
+        this.metadataModel_.getCache([entry], ['contentMimeType'])[0]
+            .contentMimeType;
     if (FileType.isImage(entry, mimeType) || FileType.isRaw(entry, mimeType)) {
       this.numImageFiles_--;
     }
@@ -441,7 +443,8 @@
       return a.isDirectory === this.isDescendingOrder_ ? 1 : -1;
     }
 
-    const properties = this.metadataModel_.getCache([a, b], ['contentMimeType']);
+    const properties =
+        this.metadataModel_.getCache([a, b], ['contentMimeType']);
     const aType = FileListModel.getFileTypeString(
         FileType.getType(a, properties[0].contentMimeType));
     const bType = FileListModel.getFileTypeString(
diff --git a/ui/file_manager/file_manager/foreground/js/file_list_model_unittest.js b/ui/file_manager/file_manager/foreground/js/file_list_model_unittest.js
index db0c3b8..8909f42 100644
--- a/ui/file_manager/file_manager/foreground/js/file_list_model_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/file_list_model_unittest.js
@@ -65,61 +65,63 @@
 }
 
 function testIsImageDominant() {
-  const fileListModel = new FileListModel(createFakeMetadataModel(TEST_METADATA));
+  const fileListModel =
+      new FileListModel(createFakeMetadataModel(TEST_METADATA));
 
   assertEquals(fileListModel.isImageDominant(), false);
 
   // Adding one image. Image should be dominant in this directory (100%).
-  fileListModel.push({ name: 'c.jpg', isDirectory: false});
+  fileListModel.push({name: 'c.jpg', isDirectory: false});
   assertEquals(fileListModel.isImageDominant(), true);
 
   // Adding a directory shouldn't affect how the image is dominant (still 100%).
-  fileListModel.push({ name: 'tmp_folder', isDirectory: true});
+  fileListModel.push({name: 'tmp_folder', isDirectory: true});
   assertEquals(fileListModel.isImageDominant(), true);
 
   // Adding a non-image file, which will make the images not dominant (50%);
-  fileListModel.push({ name: 'a.txt', isDirectory: false});
+  fileListModel.push({name: 'a.txt', isDirectory: false});
   assertEquals(fileListModel.isImageDominant(), false);
 
   // Adding two image. Now 75%(3/4) files are images. Still not dominant.
-  fileListModel.push({ name: 'c.jpg', isDirectory: false});
-  fileListModel.push({ name: 'c.jpg', isDirectory: false});
+  fileListModel.push({name: 'c.jpg', isDirectory: false});
+  fileListModel.push({name: 'c.jpg', isDirectory: false});
   assertEquals(fileListModel.isImageDominant(), false);
 
   // Adding one more. Now 80%(4/5) files are images. Reached the threshold.
-  fileListModel.push({ name: 'c.jpg', isDirectory: false});
+  fileListModel.push({name: 'c.jpg', isDirectory: false});
   assertEquals(fileListModel.isImageDominant(), true);
 }
 
 function testSortWithFolders() {
-  const fileListModel = new FileListModel(createFakeMetadataModel(TEST_METADATA));
-  fileListModel.push({ name: 'dirA', isDirectory: true });
-  fileListModel.push({ name: 'dirB', isDirectory: true });
-  fileListModel.push({ name: 'a.txt', isDirectory: false });
-  fileListModel.push({ name: 'b.html', isDirectory: false });
-  fileListModel.push({ name: 'c.jpg', isDirectory: false });
+  const fileListModel =
+      new FileListModel(createFakeMetadataModel(TEST_METADATA));
+  fileListModel.push({name: 'dirA', isDirectory: true});
+  fileListModel.push({name: 'dirB', isDirectory: true});
+  fileListModel.push({name: 'a.txt', isDirectory: false});
+  fileListModel.push({name: 'b.html', isDirectory: false});
+  fileListModel.push({name: 'c.jpg', isDirectory: false});
 
   // In following sort tests, note that folders should always be prior to files.
   fileListModel.sort('name', 'asc');
-  assertFileListModelElementNames(fileListModel,
-                                  ['dirA', 'dirB', 'a.txt', 'b.html', 'c.jpg']);
+  assertFileListModelElementNames(
+      fileListModel, ['dirA', 'dirB', 'a.txt', 'b.html', 'c.jpg']);
   fileListModel.sort('name', 'desc');
-  assertFileListModelElementNames(fileListModel,
-                                  ['dirB', 'dirA', 'c.jpg', 'b.html', 'a.txt']);
+  assertFileListModelElementNames(
+      fileListModel, ['dirB', 'dirA', 'c.jpg', 'b.html', 'a.txt']);
   // Sort files by size. Folders should be sorted by their names.
   fileListModel.sort('size', 'asc');
-  assertFileListModelElementNames(fileListModel,
-                                  ['dirA', 'dirB', 'b.html', 'a.txt', 'c.jpg']);
+  assertFileListModelElementNames(
+      fileListModel, ['dirA', 'dirB', 'b.html', 'a.txt', 'c.jpg']);
   fileListModel.sort('size', 'desc');
-  assertFileListModelElementNames(fileListModel,
-                                  ['dirB', 'dirA', 'c.jpg', 'a.txt', 'b.html']);
+  assertFileListModelElementNames(
+      fileListModel, ['dirB', 'dirA', 'c.jpg', 'a.txt', 'b.html']);
   // Sort files by modification. Folders should be sorted by their names.
   fileListModel.sort('modificationTime', 'asc');
-  assertFileListModelElementNames(fileListModel,
-                                  ['dirA', 'dirB', 'c.jpg', 'b.html', 'a.txt']);
+  assertFileListModelElementNames(
+      fileListModel, ['dirA', 'dirB', 'c.jpg', 'b.html', 'a.txt']);
   fileListModel.sort('modificationTime', 'desc');
-  assertFileListModelElementNames(fileListModel,
-                                  ['dirB', 'dirA', 'a.txt', 'b.html', 'c.jpg']);
+  assertFileListModelElementNames(
+      fileListModel, ['dirB', 'dirA', 'a.txt', 'b.html', 'c.jpg']);
 }
 
 function testSplice() {
@@ -138,9 +140,8 @@
     assertEquals(event.newLength, 5);
   });
 
-  fileListModel.splice(2, 1,
-      { name: 'p', isDirectory: false },
-      { name: 'b', isDirectory: false });
+  fileListModel.splice(
+      2, 1, {name: 'p', isDirectory: false}, {name: 'b', isDirectory: false});
   assertFileListModelElementNames(fileListModel, ['a', 'b', 'd', 'p', 'x']);
 }
 
@@ -159,9 +160,8 @@
     assertEquals(event.newLength, 5);
   });
 
-  fileListModel.splice(2, 1,
-      { name: 'p', isDirectory: false },
-      { name: 'b', isDirectory: false });
+  fileListModel.splice(
+      2, 1, {name: 'p', isDirectory: false}, {name: 'b', isDirectory: false});
   // If the sort status is not specified, the original order should be kept.
   // i.e. the 2nd element in the original array, 'x', should be removed, and
   // 'p' and 'b' should be inserted at the position without changing the order.
@@ -204,9 +204,8 @@
     assertEquals(event.newLength, 6);
   });
 
-  fileListModel.splice(2, 0,
-      { name: 'p', isDirectory: false },
-      { name: 'b', isDirectory: false });
-  assertFileListModelElementNames(fileListModel,
-                                  ['a', 'b', 'd', 'n', 'p', 'x']);
+  fileListModel.splice(
+      2, 0, {name: 'p', isDirectory: false}, {name: 'b', isDirectory: false});
+  assertFileListModelElementNames(
+      fileListModel, ['a', 'b', 'd', 'n', 'p', 'x']);
 }
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 6757f16..9c07fc9 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -580,14 +580,10 @@
     assert(this.fileFilter_);
 
     this.scanController_ = new ScanController(
-        this.directoryModel_,
-        this.ui_.listContainer,
-        this.spinnerController_,
-        this.commandHandler_,
-        this.selectionHandler_);
+        this.directoryModel_, this.ui_.listContainer, this.spinnerController_,
+        this.commandHandler_, this.selectionHandler_);
     this.sortMenuController_ = new SortMenuController(
-        this.ui_.sortButton,
-        this.ui_.sortButtonToggleRipple,
+        this.ui_.sortButton, this.ui_.sortButtonToggleRipple,
         assert(this.directoryModel_.getFileList()));
     this.gearMenuController_ = new GearMenuController(
         this.ui_.gearButton, this.ui_.gearButtonToggleRipple, this.ui_.gearMenu,
@@ -597,19 +593,16 @@
         this.ui_.selectionMenuButton,
         util.queryDecoratedElement('#file-context-menu', cr.ui.Menu));
     this.toolbarController_ = new ToolbarController(
-        this.ui_.toolbar,
-        this.ui_.dialogNavigationList,
-        this.ui_.listContainer,
-        assert(this.ui_.locationLine),
-        this.selectionHandler_,
+        this.ui_.toolbar, this.ui_.dialogNavigationList, this.ui_.listContainer,
+        assert(this.ui_.locationLine), this.selectionHandler_,
         this.directoryModel_);
     this.emptyFolderController_ = new EmptyFolderController(
         this.ui_.emptyFolder, this.directoryModel_, this.ui_.alertDialog);
     this.actionsController_ = new ActionsController(
         this.volumeManager_, assert(this.metadataModel_), this.directoryModel_,
         assert(this.folderShortcutsModel_),
-        this.fileBrowserBackground_.driveSyncHandler,
-        this.selectionHandler_, assert(this.ui_));
+        this.fileBrowserBackground_.driveSyncHandler, this.selectionHandler_,
+        assert(this.ui_));
     this.lastModifiedController_ = new LastModifiedController(
         this.ui_.listContainer.table, this.directoryModel_);
 
@@ -628,16 +621,15 @@
         metadataBoxController, this.dialogType, assert(this.volumeManager_));
 
     if (this.dialogType === DialogType.FULL_PAGE) {
-      importer.importEnabled().then(
-          enabled => {
-            if (enabled) {
-              this.importController_ = new importer.ImportController(
-                  new importer.RuntimeControllerEnvironment(
-                      this, assert(this.selectionHandler_)),
-                  assert(this.mediaScanner_), assert(this.mediaImportHandler_),
-                  new importer.RuntimeCommandWidget());
-            }
-          });
+      importer.importEnabled().then(enabled => {
+        if (enabled) {
+          this.importController_ = new importer.ImportController(
+              new importer.RuntimeControllerEnvironment(
+                  this, assert(this.selectionHandler_)),
+              assert(this.mediaScanner_), assert(this.mediaImportHandler_),
+              new importer.RuntimeCommandWidget());
+        }
+      });
     }
 
     assert(this.fileFilter_);
@@ -645,28 +637,19 @@
     assert(this.appStateController_);
     assert(this.taskController_);
     this.mainWindowComponent_ = new MainWindowComponent(
-        this.dialogType,
-        this.ui_,
-        this.volumeManager_,
-        this.directoryModel_,
-        this.fileFilter_,
-        this.selectionHandler_,
-        this.namingController_,
-        this.appStateController_,
-        this.taskController_);
+        this.dialogType, this.ui_, this.volumeManager_, this.directoryModel_,
+        this.fileFilter_, this.selectionHandler_, this.namingController_,
+        this.appStateController_, this.taskController_);
 
     this.initDataTransferOperations_();
 
     this.selectionHandler_.onFileSelectionChanged();
     this.ui_.listContainer.endBatchUpdates();
 
-    this.ui_.initBanners(
-        new Banners(
-            this.directoryModel_,
-            this.volumeManager_,
-            this.document_,
-            // Whether to show any welcome banner.
-            this.dialogType === DialogType.FULL_PAGE));
+    this.ui_.initBanners(new Banners(
+        this.directoryModel_, this.volumeManager_, this.document_,
+        // Whether to show any welcome banner.
+        this.dialogType === DialogType.FULL_PAGE));
 
     this.ui_.attachFilesTooltip();
 
@@ -846,7 +829,8 @@
     } else {
       // Used by the select dialog only.
       const json = location.search ?
-          JSON.parse(decodeURIComponent(location.search.substr(1))) : {};
+          JSON.parse(decodeURIComponent(location.search.substr(1))) :
+          {};
       this.launchParams_ = new LaunchParam(json instanceof Object ? json : {});
     }
 
@@ -862,8 +846,8 @@
   FileManager.prototype.startInitBackgroundPage_ = function() {
     return new Promise(resolve => {
       metrics.startInterval('Load.InitBackgroundPage');
-      chrome.runtime.getBackgroundPage(/** @type {function(Window=)} */ (
-          opt_backgroundPage => {
+      chrome.runtime.getBackgroundPage(
+          /** @type {function(Window=)} */ (opt_backgroundPage => {
             assert(opt_backgroundPage);
             this.backgroundPage_ =
                 /** @type {!BackgroundWindow} */ (opt_backgroundPage);
@@ -879,10 +863,8 @@
                   this.fileBrowserBackground_.fileOperationManager;
               this.mediaImportHandler_ =
                   this.fileBrowserBackground_.mediaImportHandler;
-              this.mediaScanner_ =
-                  this.fileBrowserBackground_.mediaScanner;
-              this.historyLoader_ =
-                  this.fileBrowserBackground_.historyLoader;
+              this.mediaScanner_ = this.fileBrowserBackground_.mediaScanner;
+              this.historyLoader_ = this.fileBrowserBackground_.historyLoader;
               this.crostini_ = this.fileBrowserBackground_.crostini;
               metrics.recordInterval('Load.InitBackgroundPage');
               resolve();
@@ -924,13 +906,14 @@
     // Record stats of dialog types. New values must NOT be inserted into the
     // array enumerating the types. It must be in sync with
     // FileDialogType enum in tools/metrics/histograms/histogram.xml.
-    metrics.recordEnum('Create', this.dialogType,
-        [DialogType.SELECT_FOLDER,
-         DialogType.SELECT_UPLOAD_FOLDER,
-         DialogType.SELECT_SAVEAS_FILE,
-         DialogType.SELECT_OPEN_FILE,
-         DialogType.SELECT_OPEN_MULTI_FILE,
-         DialogType.FULL_PAGE]);
+    metrics.recordEnum('Create', this.dialogType, [
+      DialogType.SELECT_FOLDER,
+      DialogType.SELECT_UPLOAD_FOLDER,
+      DialogType.SELECT_SAVEAS_FILE,
+      DialogType.SELECT_OPEN_FILE,
+      DialogType.SELECT_OPEN_MULTI_FILE,
+      DialogType.FULL_PAGE,
+    ]);
 
     // Create the metadata cache.
     assert(this.volumeManager_);
@@ -964,23 +947,16 @@
 
     const table = queryRequiredElement('.detail-table', dom);
     FileTable.decorate(
-        table,
-        this.metadataModel_,
-        this.volumeManager_,
-        this.historyLoader_,
+        table, this.metadataModel_, this.volumeManager_, this.historyLoader_,
         this.dialogType == DialogType.FULL_PAGE);
     const grid = queryRequiredElement('.thumbnail-grid', dom);
     FileGrid.decorate(
-        grid,
-        this.metadataModel_,
-        this.volumeManager_,
-        this.historyLoader_);
+        grid, this.metadataModel_, this.volumeManager_, this.historyLoader_);
 
     this.addHistoryObserver_();
 
     this.ui_.initAdditionalUI(
-        assertInstanceof(table, FileTable),
-        assertInstanceof(grid, FileGrid),
+        assertInstanceof(table, FileTable), assertInstanceof(grid, FileGrid),
         new LocationLine(
             queryRequiredElement('#location-breadcrumbs', dom),
             this.volumeManager_));
@@ -1022,14 +998,13 @@
     // we want to update grid/list view when it changes.
     this.historyLoader_.addHistoryLoadedListener(
         /**
-        * @param {!importer.ImportHistory} history
-        * @this {FileManager}
-        */
+         * @param {!importer.ImportHistory} history
+         * @this {FileManager}
+         */
         history => {
           this.importHistory_ = history;
           history.addObserver(this.onHistoryChangedBound_);
         });
-
   };
 
   /**
@@ -1044,16 +1019,14 @@
     util.isChildEntry(event.entry, this.getCurrentDirectoryEntry())
         .then(
             /**
-            * @param {boolean} isChild
-            */
+             * @param {boolean} isChild
+             */
             isChild => {
               if (isChild) {
                 this.ui_.listContainer.grid.updateListItemsMetadata(
-                    'import-history',
-                    [event.entry]);
+                    'import-history', [event.entry]);
                 this.ui_.listContainer.table.updateListItemsMetadata(
-                    'import-history',
-                    [event.entry]);
+                    'import-history', [event.entry]);
               }
             });
   };
@@ -1063,8 +1036,7 @@
    * @private
    */
   FileManager.prototype.initFileList_ = function() {
-    const singleSelection =
-        this.dialogType == DialogType.SELECT_OPEN_FILE ||
+    const singleSelection = this.dialogType == DialogType.SELECT_OPEN_FILE ||
         this.dialogType == DialogType.SELECT_FOLDER ||
         this.dialogType == DialogType.SELECT_UPLOAD_FOLDER ||
         this.dialogType == DialogType.SELECT_SAVEAS_FILE;
@@ -1076,8 +1048,8 @@
         singleSelection, this.fileFilter_, this.metadataModel_,
         this.volumeManager_, this.fileOperationManager_);
 
-    this.folderShortcutsModel_ = new FolderShortcutsDataModel(
-        this.volumeManager_);
+    this.folderShortcutsModel_ =
+        new FolderShortcutsDataModel(this.volumeManager_);
 
     assert(this.launchParams_);
     this.selectionHandler_ = new FileSelectionHandler(
@@ -1085,7 +1057,8 @@
         assert(this.ui_.listContainer), assert(this.metadataModel_),
         assert(this.volumeManager_), this.launchParams_.allowedPaths);
 
-    this.directoryModel_.getFileListSelection().addEventListener('change',
+    this.directoryModel_.getFileListSelection().addEventListener(
+        'change',
         this.selectionHandler_.onFileSelectionChanged.bind(
             this.selectionHandler_));
 
@@ -1094,8 +1067,7 @@
     this.initDirectoryTree_();
 
     this.ui_.listContainer.listThumbnailLoader = new ListThumbnailLoader(
-        this.directoryModel_,
-        assert(this.thumbnailModel_),
+        this.directoryModel_, assert(this.thumbnailModel_),
         this.volumeManager_);
     this.ui_.listContainer.dataModel = this.directoryModel_.getFileList();
     this.ui_.listContainer.emptyDataModel =
@@ -1112,9 +1084,7 @@
 
     // Create metadata update controller.
     this.metadataUpdateController_ = new MetadataUpdateController(
-        this.ui_.listContainer,
-        this.directoryModel_,
-        this.metadataModel_,
+        this.ui_.listContainer, this.directoryModel_, this.metadataModel_,
         this.fileMetadataFormatter_);
 
     // Create naming controller.
@@ -1132,34 +1102,24 @@
 
     // Create search controller.
     this.searchController_ = new SearchController(
-        this.ui_.searchBox,
-        assert(this.ui_.locationLine),
-        this.directoryModel_,
-        this.volumeManager_,
-        assert(this.taskController_));
+        this.ui_.searchBox, assert(this.ui_.locationLine), this.directoryModel_,
+        this.volumeManager_, assert(this.taskController_));
 
     // Create directory tree naming controller.
     this.directoryTreeNamingController_ = new DirectoryTreeNamingController(
-        this.directoryModel_,
-        assert(this.ui_.directoryTree),
+        this.directoryModel_, assert(this.ui_.directoryTree),
         this.ui_.alertDialog);
 
     // Create spinner controller.
-    this.spinnerController_ = new SpinnerController(
-        this.ui_.listContainer.spinner);
+    this.spinnerController_ =
+        new SpinnerController(this.ui_.listContainer.spinner);
     this.spinnerController_.blink();
 
     // Create dialog action controller.
     this.dialogActionController_ = new DialogActionController(
-        this.dialogType,
-        this.ui_.dialogFooter,
-        this.directoryModel_,
-        this.metadataModel_,
-        this.volumeManager_,
-        this.fileFilter_,
-        this.namingController_,
-        this.selectionHandler_,
-        this.launchParams_);
+        this.dialogType, this.ui_.dialogFooter, this.directoryModel_,
+        this.metadataModel_, this.volumeManager_, this.fileFilter_,
+        this.namingController_, this.selectionHandler_, this.launchParams_);
   };
 
   /**
@@ -1171,12 +1131,10 @@
     const fakeEntriesVisible =
         this.dialogType !== DialogType.SELECT_SAVEAS_FILE;
     this.navigationUma_ = new NavigationUma(assert(this.volumeManager_));
-    DirectoryTree.decorate(directoryTree,
-                           assert(this.directoryModel_),
-                           assert(this.volumeManager_),
-                           assert(this.metadataModel_),
-                           assert(this.fileOperationManager_),
-                           fakeEntriesVisible);
+    DirectoryTree.decorate(
+        directoryTree, assert(this.directoryModel_),
+        assert(this.volumeManager_), assert(this.metadataModel_),
+        assert(this.fileOperationManager_), fakeEntriesVisible);
     directoryTree.dataModel = new NavigationListModel(
         assert(this.volumeManager_), assert(this.folderShortcutsModel_),
         fakeEntriesVisible &&
@@ -1412,8 +1370,7 @@
     // a file, or in case of a fallback of the current directory, then try to
     // resolve again using the target name.
     queue.run((callback) => {
-      if (selectionEntry ||
-          !nextCurrentDirEntry ||
+      if (selectionEntry || !nextCurrentDirEntry ||
           !this.launchParams_.targetName) {
         callback();
         return;
@@ -1459,9 +1416,7 @@
       }
       // Finish setup current directory.
       this.finishSetupCurrentDirectory_(
-          nextCurrentDirEntry,
-          selectionEntry,
-          this.launchParams_.targetName);
+          nextCurrentDirEntry, selectionEntry, this.launchParams_.targetName);
       callback();
     });
   };
@@ -1526,8 +1481,7 @@
       this.volumeManager_.dispose();
     }
     if (this.fileTransferController_) {
-      for (let i = 0;
-           i < this.fileTransferController_.pendingTaskIds.length;
+      for (let i = 0; i < this.fileTransferController_.pendingTaskIds.length;
            i++) {
         const taskId = this.fileTransferController_.pendingTaskIds[i];
         const item =
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 f2195dff..4ebba5a 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
@@ -48,8 +48,8 @@
   if (element instanceof DirectoryTree) {
     // element is a DirectoryTree.
     return element.selectedItem ? [element.selectedItem.entry] : [];
-  } else if (element instanceof DirectoryItem ||
-             element instanceof ShortcutItem) {
+  } else if (
+      element instanceof DirectoryItem || element instanceof ShortcutItem) {
     // element are sub items in DirectoryTree.
     return element.entry ? [element.entry] : [];
   } else if (element instanceof cr.ui.List) {
@@ -81,8 +81,8 @@
     }
     const parentItem = element.selectedItem.parentItem;
     return parentItem ? parentItem.entry : null;
-  } else if (element instanceof DirectoryItem ||
-             element instanceof ShortcutItem) {
+  } else if (
+      element instanceof DirectoryItem || element instanceof ShortcutItem) {
     return element.parentItem ? element.parentItem.entry : null;
   } else if (element instanceof cr.ui.List) {
     return directoryModel ? directoryModel.getCurrentDirEntry() : null;
@@ -104,8 +104,8 @@
     return element.volumeInfo;
   }
   if (element instanceof ShortcutItem) {
-    return element.entry && fileManager.volumeManager.getVolumeInfo(
-        element.entry);
+    return element.entry &&
+        fileManager.volumeManager.getVolumeInfo(element.entry);
   }
   return null;
 };
@@ -116,8 +116,9 @@
  */
 CommandUtil.getCurrentVolumeInfo = fileManager => {
   const currentDirEntry = fileManager.directoryModel.getCurrentDirEntry();
-  return currentDirEntry ? fileManager.volumeManager.getVolumeInfo(
-      currentDirEntry) : null;
+  return currentDirEntry ?
+      fileManager.volumeManager.getVolumeInfo(currentDirEntry) :
+      null;
 };
 
 /**
@@ -129,8 +130,8 @@
 CommandUtil.getEntryFromNavigationModelItem_ = item => {
   switch (item.type) {
     case NavigationModelItemType.VOLUME:
-      return /** @type {!NavigationModelVolumeItem} */ (
-          item).volumeInfo.displayRoot;
+      return /** @type {!NavigationModelVolumeItem} */ (item)
+          .volumeInfo.displayRoot;
     case NavigationModelItemType.SHORTCUT:
       return /** @type {!NavigationModelShortcutItem} */ (item).entry;
   }
@@ -152,12 +153,13 @@
  * @param {!Event} event Command event to mark.
  * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
  */
-CommandUtil.canExecuteVisibleOnDriveInNormalAppModeOnly = (event, fileManager) => {
-  const enabled = fileManager.directoryModel.isOnDrive() &&
-      !DialogType.isModal(fileManager.dialogType);
-  event.canExecute = enabled;
-  event.command.setHidden(!enabled);
-};
+CommandUtil.canExecuteVisibleOnDriveInNormalAppModeOnly =
+    (event, fileManager) => {
+      const enabled = fileManager.directoryModel.isOnDrive() &&
+          !DialogType.isModal(fileManager.dialogType);
+      event.canExecute = enabled;
+      event.command.setHidden(!enabled);
+    };
 
 /**
  * Sets as the command as always enabled.
@@ -221,8 +223,8 @@
      * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
      */
     canExecute: function(event, fileManager) {
-      event.canExecute = index > 0 &&
-          index <= fileManager.directoryTree.items.length;
+      event.canExecute =
+          index > 0 && index <= fileManager.directoryTree.items.length;
     }
   });
 };
@@ -243,7 +245,7 @@
   if (!selection.entries[0].isDirectory) {
     return null;
   }
-  return /** @type {!DirectoryEntry} */(selection.entries[0]);
+  return /** @type {!DirectoryEntry} */ (selection.entries[0]);
 };
 
 /**
@@ -514,8 +516,8 @@
 CommandHandler.prototype.shouldIgnoreEvents_ = function() {
   // Do not handle commands, when a dialog is shown. Do not use querySelector
   // as it's much slower, and this method is executed often.
-  const dialogs = this.fileManager_.document.getElementsByClassName(
-      'cr-dialog-container');
+  const dialogs =
+      this.fileManager_.document.getElementsByClassName('cr-dialog-container');
   if (dialogs.length !== 0 && dialogs[0].classList.contains('shown')) {
     return true;
   }
@@ -533,8 +535,8 @@
     return;
   }
   const handler = CommandHandler.COMMANDS_[event.command.id];
-  handler.execute.call(/** @type {Command} */ (handler), event,
-                       this.fileManager_);
+  handler.execute.call(
+      /** @type {Command} */ (handler), event, this.fileManager_);
 };
 
 /**
@@ -547,8 +549,8 @@
     return;
   }
   const handler = CommandHandler.COMMANDS_[event.command.id];
-  handler.canExecute.call(/** @type {Command} */ (handler), event,
-                          this.fileManager_);
+  handler.canExecute.call(
+      /** @type {Command} */ (handler), event, this.fileManager_);
 };
 
 /**
@@ -637,10 +639,10 @@
     const volumeType = (event.target instanceof EntryListItem) ?
         entry.rootType :
         volumeInfo.volumeType;
-    event.canExecute = (
-        volumeType === VolumeManagerCommon.VolumeType.ARCHIVE ||
-        volumeType === VolumeManagerCommon.VolumeType.REMOVABLE ||
-        volumeType === VolumeManagerCommon.VolumeType.PROVIDED);
+    event.canExecute =
+        (volumeType === VolumeManagerCommon.VolumeType.ARCHIVE ||
+         volumeType === VolumeManagerCommon.VolumeType.REMOVABLE ||
+         volumeType === VolumeManagerCommon.VolumeType.PROVIDED);
     event.command.setHidden(!event.canExecute);
 
     switch (volumeType) {
@@ -678,8 +680,8 @@
     if (volumeInfo) {
       fileManager.ui.confirmDialog.show(
           loadTimeData.getString('FORMATTING_WARNING'),
-          chrome.fileManagerPrivate.formatVolume.bind(null,
-                                                      volumeInfo.volumeId),
+          chrome.fileManagerPrivate.formatVolume.bind(
+              null, volumeInfo.volumeId),
           null, null);
     }
   },
@@ -810,15 +812,17 @@
     const index = opt_index || 0;
 
     const defaultName = str('DEFAULT_NEW_FOLDER_NAME');
-    const newName = index === 0 ? defaultName :
-        defaultName + ' (' + index + ')';
+    const newName =
+        index === 0 ? defaultName : defaultName + ' (' + index + ')';
 
     return new Promise(parentDirectory.getDirectory.bind(
-        parentDirectory, newName, {create: false})).then(newEntry => {
-      return this.generateNewDirectoryName_(parentDirectory, index + 1);
-    }).catch(() => {
-      return newName;
-    });
+                           parentDirectory, newName, {create: false}))
+        .then(newEntry => {
+          return this.generateNewDirectoryName_(parentDirectory, index + 1);
+        })
+        .catch(() => {
+          return newName;
+        });
   };
 
   /**
@@ -877,8 +881,7 @@
    * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
    */
   canExecute: function(event, fileManager) {
-    event.canExecute =
-        fileManager.getCurrentDirectoryEntry() &&
+    event.canExecute = fileManager.getCurrentDirectoryEntry() &&
         (fileManager.dialogType === DialogType.FULL_PAGE);
   }
 });
@@ -1102,8 +1105,8 @@
             fileManager.directoryModel.getCurrentDirEntry());
 
     // Hide this command if only one folder is selected.
-    event.command.setHidden(!!CommandUtil.getOnlyOneSelectedDirectory(
-        fileManager.getSelection()));
+    event.command.setHidden(
+        !!CommandUtil.getOnlyOneSelectedDirectory(fileManager.getSelection()));
   }
 });
 
@@ -1309,7 +1312,8 @@
     const parentEntry =
         CommandUtil.getParentEntry(renameTarget, fileManager.directoryModel);
     const locationInfo = parentEntry ?
-        fileManager.volumeManager.getLocationInfo(parentEntry) : null;
+        fileManager.volumeManager.getLocationInfo(parentEntry) :
+        null;
     const volumeIsNotReadOnly = !!locationInfo && !locationInfo.isReadOnly;
     event.canExecute = entries.length === 1 && volumeIsNotReadOnly &&
         CommandUtil.hasCapability(entries, 'canRename');
@@ -1558,7 +1562,7 @@
       return;
     }
 
-    event.canExecute =  entries.length === 1;
+    event.canExecute = entries.length === 1;
     event.command.setHidden(false);
   }
 });
@@ -1623,12 +1627,15 @@
    * @param {!CommandHandlerDeps} fileManager
    */
   execute: function(event, fileManager) {
-    const actionsModel = fileManager.actionsController.getActionsModelFor(
-        event.target);
-    const saveForOfflineAction = actionsModel ? actionsModel.getAction(
-        ActionsModel.CommonActionId.SAVE_FOR_OFFLINE) : null;
-    const offlineNotNeededAction = actionsModel ? actionsModel.getAction(
-        ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY) : null;
+    const actionsModel =
+        fileManager.actionsController.getActionsModelFor(event.target);
+    const saveForOfflineAction = actionsModel ?
+        actionsModel.getAction(ActionsModel.CommonActionId.SAVE_FOR_OFFLINE) :
+        null;
+    const offlineNotNeededAction = actionsModel ?
+        actionsModel.getAction(
+            ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY) :
+        null;
     // Saving for offline has a priority if both actions are available.
     const action = saveForOfflineAction || offlineNotNeededAction;
     if (action) {
@@ -1641,12 +1648,15 @@
    * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
    */
   canExecute: function(event, fileManager) {
-    const actionsModel = fileManager.actionsController.getActionsModelFor(
-        event.target);
-    const saveForOfflineAction = actionsModel ? actionsModel.getAction(
-        ActionsModel.CommonActionId.SAVE_FOR_OFFLINE) : null;
-    const offlineNotNeededAction = actionsModel ? actionsModel.getAction(
-        ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY) : null;
+    const actionsModel =
+        fileManager.actionsController.getActionsModelFor(event.target);
+    const saveForOfflineAction = actionsModel ?
+        actionsModel.getAction(ActionsModel.CommonActionId.SAVE_FOR_OFFLINE) :
+        null;
+    const offlineNotNeededAction = actionsModel ?
+        actionsModel.getAction(
+            ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY) :
+        null;
     const action = saveForOfflineAction || offlineNotNeededAction;
 
     event.canExecute = action && action.canExecute();
@@ -1716,7 +1726,8 @@
     }
 
     event.command.setHidden(false);
-    const isOnEligibleLocation = CommandHandler.IS_ZIP_ARCHIVER_PACKER_ENABLED_ ?
+    const isOnEligibleLocation =
+        CommandHandler.IS_ZIP_ARCHIVER_PACKER_ENABLED_ ?
         true :
         !fileManager.directoryModel.isOnDrive() &&
             !fileManager.directoryModel.isOnMTP();
@@ -1739,10 +1750,12 @@
     // To toolbar buttons are always related to the file list, even though the
     // focus is on the navigation list. This assumption will break once we add
     // Share to the context menu on the navigation list. crbug.com/530418
-    const actionsModel = fileManager.actionsController.getActionsModelForContext(
-        ActionsController.Context.FILE_LIST);
-    const action = actionsModel ? actionsModel.getAction(
-        ActionsModel.CommonActionId.SHARE) : null;
+    const actionsModel =
+        fileManager.actionsController.getActionsModelForContext(
+            ActionsController.Context.FILE_LIST);
+    const action = actionsModel ?
+        actionsModel.getAction(ActionsModel.CommonActionId.SHARE) :
+        null;
     if (action) {
       action.execute();
     }
@@ -1752,10 +1765,12 @@
    * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
    */
   canExecute: function(event, fileManager) {
-    const actionsModel = fileManager.actionsController.getActionsModelForContext(
-        ActionsController.Context.FILE_LIST);
-    const action = actionsModel ? actionsModel.getAction(
-        ActionsModel.CommonActionId.SHARE) : null;
+    const actionsModel =
+        fileManager.actionsController.getActionsModelForContext(
+            ActionsController.Context.FILE_LIST);
+    const action = actionsModel ?
+        actionsModel.getAction(ActionsModel.CommonActionId.SHARE) :
+        null;
     event.canExecute = action && action.canExecute();
     // If model is not computed yet, then keep the previous visibility to avoid
     // flickering.
@@ -1946,10 +1961,12 @@
    * @param {!CommandHandlerDeps} fileManager The file manager instance.
    */
   execute: function(event, fileManager) {
-    const actionsModel = fileManager.actionsController.getActionsModelFor(
-        event.target);
-    const action = actionsModel ? actionsModel.getAction(
-        ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT) : null;
+    const actionsModel =
+        fileManager.actionsController.getActionsModelFor(event.target);
+    const action = actionsModel ?
+        actionsModel.getAction(
+            ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT) :
+        null;
     if (action) {
       action.execute();
     }
@@ -1959,10 +1976,12 @@
    * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
    */
   canExecute: function(event, fileManager) {
-    const actionsModel = fileManager.actionsController.getActionsModelFor(
-        event.target);
-    const action = actionsModel ? actionsModel.getAction(
-        ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT) : null;
+    const actionsModel =
+        fileManager.actionsController.getActionsModelFor(event.target);
+    const action = actionsModel ?
+        actionsModel.getAction(
+            ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT) :
+        null;
     event.canExecute = action && action.canExecute();
     if (actionsModel) {
       event.command.setHidden(!action);
@@ -1980,10 +1999,12 @@
    * @param {!CommandHandlerDeps} fileManager The file manager instance.
    */
   execute: function(event, fileManager) {
-    const actionsModel = fileManager.actionsController.getActionsModelFor(
-        event.target);
-    const action = actionsModel ? actionsModel.getAction(
-        ActionsModel.InternalActionId.REMOVE_FOLDER_SHORTCUT) : null;
+    const actionsModel =
+        fileManager.actionsController.getActionsModelFor(event.target);
+    const action = actionsModel ?
+        actionsModel.getAction(
+            ActionsModel.InternalActionId.REMOVE_FOLDER_SHORTCUT) :
+        null;
     if (action) {
       action.execute();
     }
@@ -1993,10 +2014,12 @@
    * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
    */
   canExecute: function(event, fileManager) {
-    const actionsModel = fileManager.actionsController.getActionsModelFor(
-        event.target);
-    const action = actionsModel ? actionsModel.getAction(
-        ActionsModel.InternalActionId.REMOVE_FOLDER_SHORTCUT) : null;
+    const actionsModel =
+        fileManager.actionsController.getActionsModelFor(event.target);
+    const action = actionsModel ?
+        actionsModel.getAction(
+            ActionsModel.InternalActionId.REMOVE_FOLDER_SHORTCUT) :
+        null;
     event.canExecute = action && action.canExecute();
     if (actionsModel) {
       event.command.setHidden(!action);
@@ -2171,14 +2194,13 @@
    * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
    */
   execute: function(event, fileManager) {
-    fileManager.ui.suggestAppsDialog.showProviders(
-        (result, itemId) => {
-          // If a new provider is installed, then launch it so the configuration
-          // dialog is shown (if it's available).
-          if (result === SuggestAppsDialog.Result.SUCCESS) {
-            fileManager.providersModel.requestMount(assert(itemId));
-          }
-        });
+    fileManager.ui.suggestAppsDialog.showProviders((result, itemId) => {
+      // If a new provider is installed, then launch it so the configuration
+      // dialog is shown (if it's available).
+      if (result === SuggestAppsDialog.Result.SUCCESS) {
+        fileManager.providersModel.requestMount(assert(itemId));
+      }
+    });
   },
   canExecute: function(event, fileManager) {
     event.canExecute = fileManager.dialogType === DialogType.FULL_PAGE;
@@ -2295,7 +2317,8 @@
     const volumeInfo = currentDirEntry &&
         fileManager.volumeManager.getVolumeInfo(currentDirEntry);
     event.canExecute = volumeInfo && !volumeInfo.watchable;
-    event.command.setHidden(!event.canExecute ||
+    event.command.setHidden(
+        !event.canExecute ||
         fileManager.directoryModel.getFileListSelection().getCheckSelectMode());
   }
 });
@@ -2312,35 +2335,40 @@
     const entry = fileManager.getSelection().entries[0];
     new Promise((resolve, reject) => {
       entry.file(resolve, reject);
-    }).then(blob => {
-      const fileReader = new FileReader();
-      return new Promise((resolve, reject) => {
-        fileReader.onload = () => {
-          resolve(fileReader.result);
-        };
-        fileReader.onerror = () => {
-          reject(fileReader.error);
-        };
-        fileReader.readAsArrayBuffer(blob);
-      });
-    }).then((/** @type {!ArrayBuffer} */ arrayBuffer) => {
-      return new Promise((resolve, reject) => {
-        chrome.wallpaper.setWallpaper({
-            data: arrayBuffer,
-            layout: chrome.wallpaper.WallpaperLayout.CENTER_CROPPED,
-            filename: 'wallpaper'
-          }, () => {
-            if (chrome.runtime.lastError) {
-              reject(chrome.runtime.lastError);
-            }else{
-              resolve(null);
-            }
+    })
+        .then(blob => {
+          const fileReader = new FileReader();
+          return new Promise((resolve, reject) => {
+            fileReader.onload = () => {
+              resolve(fileReader.result);
+            };
+            fileReader.onerror = () => {
+              reject(fileReader.error);
+            };
+            fileReader.readAsArrayBuffer(blob);
           });
-      });
-    }).catch(() => {
-      fileManager.ui.alertDialog.showHtml(
-          '', str('ERROR_INVALID_WALLPAPER'), null, null, null);
-    });
+        })
+        .then((/** @type {!ArrayBuffer} */ arrayBuffer) => {
+          return new Promise((resolve, reject) => {
+            chrome.wallpaper.setWallpaper(
+                {
+                  data: arrayBuffer,
+                  layout: chrome.wallpaper.WallpaperLayout.CENTER_CROPPED,
+                  filename: 'wallpaper'
+                },
+                () => {
+                  if (chrome.runtime.lastError) {
+                    reject(chrome.runtime.lastError);
+                  } else {
+                    resolve(null);
+                  }
+                });
+          });
+        })
+        .catch(() => {
+          fileManager.ui.alertDialog.showHtml(
+              '', str('ERROR_INVALID_WALLPAPER'), null, null, null);
+        });
   },
   canExecute: function(event, fileManager) {
     const entries = fileManager.getSelection().entries;
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 8d8ce5de..abb09e5 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -173,72 +173,66 @@
  * @param {!Crostini} crostini
  * @return {!Promise<!FileTasks>}
  */
-FileTasks.create = (
-  volumeManager,
-  metadataModel,
-  directoryModel,
-  ui,
-  entries,
-  mimeTypes,
-  taskHistory,
-  namingController,
-  crostini
-) => {
-  const tasksPromise = new Promise(fulfill => {
-    // getFileTasks supports only native entries.
-    entries = entries.filter(util.isNativeEntry);
-    if (entries.length === 0) {
-      fulfill([]);
-      return;
-    }
-    chrome.fileManagerPrivate.getFileTasks(entries, taskItems => {
-      if (chrome.runtime.lastError) {
-        console.error('Failed to fetch file tasks due to: ' +
-            chrome.runtime.lastError.message);
-        Promise.reject();
-        return;
-      }
+FileTasks.create =
+    (volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes,
+     taskHistory, namingController, crostini) => {
+      const tasksPromise = new Promise(fulfill => {
+        // getFileTasks supports only native entries.
+        entries = entries.filter(util.isNativeEntry);
+        if (entries.length === 0) {
+          fulfill([]);
+          return;
+        }
+        chrome.fileManagerPrivate.getFileTasks(entries, taskItems => {
+          if (chrome.runtime.lastError) {
+            console.error(
+                'Failed to fetch file tasks due to: ' +
+                chrome.runtime.lastError.message);
+            Promise.reject();
+            return;
+          }
 
-      // Linux package installation is currently only supported for a single
-      // file which is inside the Linux container, or in a sharable volume.
-      // TODO(timloh): Instead of filtering these out, we probably should show
-      // a dialog with an error message, similar to when attempting to run
-      // Crostini tasks with non-Crostini entries.
-      if (entries.length !== 1 ||
-          !(FileTasks.isCrostiniEntry(entries[0], volumeManager) ||
-            crostini.canSharePath(entries[0], false /* persist */))) {
-        taskItems = taskItems.filter(item => {
-          const taskParts = item.taskId.split('|');
-          const appId = taskParts[0];
-          const taskType = taskParts[1];
-          const actionId = taskParts[2];
-          return !(
-              appId === chrome.runtime.id && taskType === 'app' &&
-              actionId === 'install-linux-package');
+          // Linux package installation is currently only supported for a single
+          // file which is inside the Linux container, or in a shareable volume.
+          // TODO(timloh): Instead of filtering these out, we probably should
+          // show a dialog with an error message, similar to when attempting to
+          // run Crostini tasks with non-Crostini entries.
+          if (entries.length !== 1 ||
+              !(FileTasks.isCrostiniEntry(entries[0], volumeManager) ||
+                crostini.canSharePath(entries[0], false /* persist */))) {
+            taskItems = taskItems.filter(item => {
+              const taskParts = item.taskId.split('|');
+              const appId = taskParts[0];
+              const taskType = taskParts[1];
+              const actionId = taskParts[2];
+              return !(
+                  appId === chrome.runtime.id && taskType === 'app' &&
+                  actionId === 'install-linux-package');
+            });
+          }
+
+          // Filters out Pack with Zip Archiver task because it will be
+          // accessible via 'Zip selection' context menu button
+          taskItems = taskItems.filter(item => {
+            return item.taskId !== FileTasks.ZIP_ARCHIVER_ZIP_TASK_ID &&
+                item.taskId !== FileTasks.ZIP_ARCHIVER_ZIP_USING_TMP_TASK_ID;
+          });
+
+          fulfill(FileTasks.annotateTasks_(assert(taskItems), entries));
         });
-      }
-
-      // Filters out Pack with Zip Archiver task because it will be accessible
-      // via 'Zip selection' context menu button
-      taskItems = taskItems.filter(item => {
-        return item.taskId !== FileTasks.ZIP_ARCHIVER_ZIP_TASK_ID &&
-            item.taskId !== FileTasks.ZIP_ARCHIVER_ZIP_USING_TMP_TASK_ID;
       });
 
-      fulfill(FileTasks.annotateTasks_(assert(taskItems), entries));
-    });
-  });
+      const defaultTaskPromise = tasksPromise.then(tasks => {
+        return FileTasks.getDefaultTask(tasks, taskHistory);
+      });
 
-  const defaultTaskPromise = tasksPromise.then(tasks => {
-    return FileTasks.getDefaultTask(tasks, taskHistory);
-  });
-
-  return Promise.all([tasksPromise, defaultTaskPromise]).then(args => {
-    return new FileTasks(
-        volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes,
-        args[0], args[1], taskHistory, namingController, crostini);
-  });
-};
+      return Promise.all([tasksPromise, defaultTaskPromise]).then(args => {
+        return new FileTasks(
+            volumeManager, metadataModel, directoryModel, ui, entries,
+            mimeTypes, args[0], args[1], taskHistory, namingController,
+            crostini);
+      });
+    };
 
 /**
  * Obtains the task items.
@@ -349,7 +343,10 @@
  * @private
  */
 FileTasks.EXTENSIONS_TO_SKIP_SUGGEST_APPS_ = Object.freeze([
-  '.crdownload', '.dsc', '.inf', '.crx',
+  '.crdownload',
+  '.dsc',
+  '.inf',
+  '.crx',
 ]);
 
 /**
@@ -383,14 +380,15 @@
  * @param {!*} value Enum value.
  * @param {!Array<*>} values Array of valid values.
  */
-FileTasks.recordEnumWithOnlineAndOffline_ = (volumeManager, name, value, values) => {
-  metrics.recordEnum(name, value, values);
-  if (FileTasks.isOffline_(volumeManager)) {
-    metrics.recordEnum(name + '.Offline', value, values);
-  } else {
-    metrics.recordEnum(name + '.Online', value, values);
-  }
-};
+FileTasks.recordEnumWithOnlineAndOffline_ =
+    (volumeManager, name, value, values) => {
+      metrics.recordEnum(name, value, values);
+      if (FileTasks.isOffline_(volumeManager)) {
+        metrics.recordEnum(name + '.Offline', value, values);
+      } else {
+        metrics.recordEnum(name + '.Online', value, values);
+      }
+    };
 
 /**
  * Records trial of opening file grouped by extensions.
@@ -741,8 +739,7 @@
   // a task picker to ask the user to choose one.
   if (nonGenericTasks.length >= 2) {
     this.showTaskPicker(
-        this.ui_.defaultTaskPicker, str('OPEN_WITH_BUTTON_LABEL'),
-        '', task => {
+        this.ui_.defaultTaskPicker, str('OPEN_WITH_BUTTON_LABEL'), '', task => {
           this.execute(task);
         }, FileTasks.TaskPickerType.OpenWith);
     return;
@@ -918,12 +915,11 @@
     return okEntriesNum === props.length;
   };
 
-  const containsDriveEntries =
-      this.entries_.some(entry => {
-        const volumeInfo = this.volumeManager_.getVolumeInfo(entry);
-        return volumeInfo && volumeInfo.volumeType ===
-            VolumeManagerCommon.VolumeType.DRIVE;
-      });
+  const containsDriveEntries = this.entries_.some(entry => {
+    const volumeInfo = this.volumeManager_.getVolumeInfo(entry);
+    return volumeInfo &&
+        volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE;
+  });
 
   // Availability is not checked for non-Drive files, as availableOffline, nor
   // availableWhenMetered are not exposed for other types of volumes at this
@@ -937,8 +933,8 @@
       VolumeManagerCommon.DriveConnectionType.OFFLINE;
 
   if (isDriveOffline) {
-    this.metadataModel_.get(this.entries_, ['availableOffline', 'hosted']).then(
-        props => {
+    this.metadataModel_.get(this.entries_, ['availableOffline', 'hosted'])
+        .then(props => {
           if (areAll(this.entries_, props, 'availableOffline')) {
             callback();
             return;
@@ -952,12 +948,11 @@
                           'HOSTED_OFFLINE_MESSAGE' :
                           'HOSTED_OFFLINE_MESSAGE_PLURAL') :
                   loadTimeData.getStringF(
-                      this.entries_.length === 1 ?
-                          'OFFLINE_MESSAGE' :
-                          'OFFLINE_MESSAGE_PLURAL',
+                      this.entries_.length === 1 ? 'OFFLINE_MESSAGE' :
+                                                   'OFFLINE_MESSAGE_PLURAL',
                       loadTimeData.getString('OFFLINE_COLUMN_LABEL')),
               null, null, null);
-    });
+        });
     return;
   }
 
@@ -980,9 +975,8 @@
           }
           this.ui_.confirmDialog.show(
               loadTimeData.getStringF(
-                  this.entries_.length === 1 ?
-                      'CONFIRM_MOBILE_DATA_USE' :
-                      'CONFIRM_MOBILE_DATA_USE_PLURAL',
+                  this.entries_.length === 1 ? 'CONFIRM_MOBILE_DATA_USE' :
+                                               'CONFIRM_MOBILE_DATA_USE_PLURAL',
                   util.bytesToString(sizeToDownload)),
               callback, null, null);
         });
@@ -1035,36 +1029,31 @@
   const urls = util.entriesToURLs(this.entries_);
   for (let index = 0; index < urls.length; ++index) {
     // TODO(mtomasz): Pass Entry instead of URL.
-    this.volumeManager_.mountArchive(
-        urls[index],
-        volumeInfo => {
-          if (tracker.hasChanged) {
+    this.volumeManager_.mountArchive(urls[index], volumeInfo => {
+      if (tracker.hasChanged) {
+        tracker.stop();
+        return;
+      }
+      volumeInfo.resolveDisplayRoot(
+          displayRoot => {
+            if (tracker.hasChanged) {
+              tracker.stop();
+              return;
+            }
+            this.directoryModel_.changeDirectoryEntry(displayRoot);
+          },
+          () => {
+            console.warn('Failed to resolve the display root after mounting.');
             tracker.stop();
-            return;
-          }
-          volumeInfo.resolveDisplayRoot(
-              displayRoot => {
-                if (tracker.hasChanged) {
-                  tracker.stop();
-                  return;
-                }
-                this.directoryModel_.changeDirectoryEntry(displayRoot);
-              },
-              () => {
-                console.warn(
-                    'Failed to resolve the display root after mounting.');
-                tracker.stop();
-              });
-        },
-        ((url, error) => {
-          tracker.stop();
-          const path = util.extractFilePath(url);
-          const namePos = path.lastIndexOf('/');
-          this.ui_.alertDialog.show(
-              strf('ARCHIVE_MOUNT_FAILED', path.substr(namePos + 1), error),
-              null,
-              null);
-        }).bind(null, urls[index]));
+          });
+    }, ((url, error) => {
+         tracker.stop();
+         const path = util.extractFilePath(url);
+         const namePos = path.lastIndexOf('/');
+         this.ui_.alertDialog.show(
+             strf('ARCHIVE_MOUNT_FAILED', path.substr(namePos + 1), error),
+             null, null);
+       }).bind(null, urls[index]));
   }
 };
 
@@ -1239,8 +1228,8 @@
   for (let index = 0; index < tasks.length; index++) {
     const task = tasks[index];
     if (task === this.defaultTask_) {
-      const title = task.title + ' ' +
-                  loadTimeData.getString('DEFAULT_TASK_LABEL');
+      const title =
+          task.title + ' ' + loadTimeData.getString('DEFAULT_TASK_LABEL');
       items.push(this.createCombobuttonItem_(task, title, true, true));
     } else {
       items.push(this.createCombobuttonItem_(task));
@@ -1294,18 +1283,19 @@
  *     list.
  * @private
  */
-FileTasks.prototype.createCombobuttonItem_ = (task, opt_title, opt_bold, opt_isDefault) => {
-  return {
-    type: FileTasks.TaskMenuButtonItemType.RunTask,
-    label: opt_title || task.label || task.title,
-    iconUrl: task.iconUrl || '',
-    iconType: task.iconType || '',
-    task: task,
-    bold: opt_bold || false,
-    isDefault: opt_isDefault || false,
-    isGenericFileHandler: /** @type {boolean} */ (task.isGenericFileHandler)
-  };
-};
+FileTasks.prototype.createCombobuttonItem_ =
+    (task, opt_title, opt_bold, opt_isDefault) => {
+      return {
+        type: FileTasks.TaskMenuButtonItemType.RunTask,
+        label: opt_title || task.label || task.title,
+        iconUrl: task.iconUrl || '',
+        iconType: task.iconType || '',
+        task: task,
+        bold: opt_bold || false,
+        isDefault: opt_isDefault || false,
+        isGenericFileHandler: /** @type {boolean} */ (task.isGenericFileHandler)
+      };
+    };
 
 /**
  * Shows modal task picker dialog with currently available list of tasks.
@@ -1336,13 +1326,9 @@
     }
   }
 
-  taskDialog.showDefaultTaskDialog(
-      title,
-      message,
-      items, defaultIdx,
-      item => {
-        onSuccess(item.task);
-      });
+  taskDialog.showDefaultTaskDialog(title, message, items, defaultIdx, item => {
+    onSuccess(item.task);
+  });
 };
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
index 0eed63b..c745ca8 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
@@ -215,8 +215,10 @@
   const mockFileSystem = new MockFileSystem('volumeId');
   const mockEntry = new MockFileEntry(mockFileSystem, '/test.exe');
 
-  reportPromise(showHtmlOfAlertDialogIsCalled(
-      [mockEntry], 'test.exe', 'NO_TASK_FOR_EXECUTABLE'), callback);
+  reportPromise(
+      showHtmlOfAlertDialogIsCalled(
+          [mockEntry], 'test.exe', 'NO_TASK_FOR_EXECUTABLE'),
+      callback);
 }
 
 /**
@@ -226,8 +228,9 @@
   const mockFileSystem = new MockFileSystem('volumeId');
   const mockEntry = new MockFileEntry(mockFileSystem, '/test.dmg');
 
-  reportPromise(showHtmlOfAlertDialogIsCalled(
-      [mockEntry], 'test.dmg', 'NO_TASK_FOR_DMG'), callback);
+  reportPromise(
+      showHtmlOfAlertDialogIsCalled([mockEntry], 'test.dmg', 'NO_TASK_FOR_DMG'),
+      callback);
 }
 
 /**
@@ -237,8 +240,10 @@
   const mockFileSystem = new MockFileSystem('volumeId');
   const mockEntry = new MockFileEntry(mockFileSystem, '/test.crx');
 
-  reportPromise(showHtmlOfAlertDialogIsCalled(
-      [mockEntry], 'NO_TASK_FOR_CRX_TITLE', 'NO_TASK_FOR_CRX'), callback);
+  reportPromise(
+      showHtmlOfAlertDialogIsCalled(
+          [mockEntry], 'NO_TASK_FOR_CRX_TITLE', 'NO_TASK_FOR_CRX'),
+      callback);
 }
 
 /**
@@ -248,8 +253,9 @@
   const mockFileSystem = new MockFileSystem('volumeId');
   const mockEntry = new MockFileEntry(mockFileSystem, '/test.rtf');
 
-  reportPromise(openSuggestAppsDialogIsCalled(
-      [mockEntry], ['application/rtf']), callback);
+  reportPromise(
+      openSuggestAppsDialogIsCalled([mockEntry], ['application/rtf']),
+      callback);
 }
 
 /**
@@ -281,8 +287,7 @@
             [mockEntry], ['application/rtf'], mockTaskHistory,
             fileManager.namingController, fileManager.crostini)
         .then(tasks => {
-          tasks.openSuggestAppsDialog(
-              () => {}, () => {}, () => {});
+          tasks.openSuggestAppsDialog(() => {}, () => {}, () => {});
         });
   });
 
@@ -396,10 +401,11 @@
   });
 
   let executedTask = null;
-  window.chrome.fileManagerPrivate.executeTask = (taskId, entries, onViewFiles) => {
-    executedTask = taskId;
-    onViewFiles('success');
-  };
+  window.chrome.fileManagerPrivate.executeTask =
+      (taskId, entries, onViewFiles) => {
+        executedTask = taskId;
+        onViewFiles('success');
+      };
 
   const mockFileSystem = new MockFileSystem('volumeId');
   const mockEntry = new MockFileEntry(mockFileSystem, '/test.tiff');
@@ -467,10 +473,11 @@
   });
 
   let executedTask = null;
-  window.chrome.fileManagerPrivate.executeTask = (taskId, entries, onViewFiles) => {
-    executedTask = taskId;
-    onViewFiles('success');
-  };
+  window.chrome.fileManagerPrivate.executeTask =
+      (taskId, entries, onViewFiles) => {
+        executedTask = taskId;
+        onViewFiles('success');
+      };
 
   const mockFileSystem = new MockFileSystem('volumeId');
   const mockEntry = new MockFileEntry(mockFileSystem, '/test.zip');
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
index 0d3bd11..947da5a 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -377,10 +377,12 @@
  */
 FileTransferController.URLsToEntriesWithAccess = urls => {
   return new Promise((resolve, reject) => {
-    chrome.fileManagerPrivate.grantAccess(urls, resolve.bind(null, undefined));
-  }).then(() => {
-    return util.URLsToEntries(urls);
-  });
+           chrome.fileManagerPrivate.grantAccess(
+               urls, resolve.bind(null, undefined));
+         })
+      .then(() => {
+        return util.URLsToEntries(urls);
+      });
 };
 
 /**
@@ -406,15 +408,15 @@
  *     accetps files (putting it into the current directory).
  * @private
  */
-FileTransferController.prototype.attachFileListDropTarget_ =
-    function(list, opt_onlyIntoDirectories) {
-  list.addEventListener('dragover', this.onDragOver_.bind(this,
-      !!opt_onlyIntoDirectories, list));
-  list.addEventListener('dragenter',
-      this.onDragEnterFileList_.bind(this, list));
+FileTransferController.prototype.attachFileListDropTarget_ = function(
+    list, opt_onlyIntoDirectories) {
+  list.addEventListener(
+      'dragover', this.onDragOver_.bind(this, !!opt_onlyIntoDirectories, list));
+  list.addEventListener(
+      'dragenter', this.onDragEnterFileList_.bind(this, list));
   list.addEventListener('dragleave', this.onDragLeave_.bind(this, list));
-  list.addEventListener('drop',
-      this.onDrop_.bind(this, !!opt_onlyIntoDirectories));
+  list.addEventListener(
+      'drop', this.onDrop_.bind(this, !!opt_onlyIntoDirectories));
 };
 
 /**
@@ -433,22 +435,19 @@
  * @private
  */
 FileTransferController.prototype.attachCopyPasteHandlers_ = function() {
-  this.document_.addEventListener('beforecopy',
-                                  this.onBeforeCutOrCopy_.bind(
-                                      this, false /* not move operation */));
-  this.document_.addEventListener('copy',
-                                  this.onCutOrCopy_.bind(
-                                      this, false /* not move operation */));
-  this.document_.addEventListener('beforecut',
-                                  this.onBeforeCutOrCopy_.bind(
-                                      this, true /* move operation */));
-  this.document_.addEventListener('cut',
-                                  this.onCutOrCopy_.bind(
-                                      this, true /* move operation */));
-  this.document_.addEventListener('beforepaste',
-                                  this.onBeforePaste_.bind(this));
-  this.document_.addEventListener('paste',
-                                  this.onPaste_.bind(this));
+  this.document_.addEventListener(
+      'beforecopy',
+      this.onBeforeCutOrCopy_.bind(this, false /* not move operation */));
+  this.document_.addEventListener(
+      'copy', this.onCutOrCopy_.bind(this, false /* not move operation */));
+  this.document_.addEventListener(
+      'beforecut',
+      this.onBeforeCutOrCopy_.bind(this, true /* move operation */));
+  this.document_.addEventListener(
+      'cut', this.onCutOrCopy_.bind(this, true /* move operation */));
+  this.document_.addEventListener(
+      'beforepaste', this.onBeforePaste_.bind(this));
+  this.document_.addEventListener('paste', this.onPaste_.bind(this));
 };
 
 /**
@@ -473,11 +472,11 @@
     return;
   }
 
-  this.appendCutOrCopyInfo_(clipboardData, effectAllowed, volumeInfo,
+  this.appendCutOrCopyInfo_(
+      clipboardData, effectAllowed, volumeInfo,
       this.selectionHandler_.selection.entries,
       !this.selectionHandler_.isAvailable());
-  this.appendUriList_(clipboardData,
-      this.selectionHandler_.selection.entries);
+  this.appendUriList_(clipboardData, this.selectionHandler_.selection.entries);
 };
 
 /**
@@ -490,27 +489,23 @@
  * @param {boolean} missingFileContents
  * @private
  */
-FileTransferController.prototype.appendCutOrCopyInfo_ = (
-  clipboardData,
-  effectAllowed,
-  sourceVolumeInfo,
-  entries,
-  missingFileContents
-) => {
-  // Tag to check it's filemanager data.
-  clipboardData.setData('fs/tag', 'filemanager-data');
-  clipboardData.setData('fs/sourceRootURL',
-                       sourceVolumeInfo.fileSystem.root.toURL());
+FileTransferController.prototype.appendCutOrCopyInfo_ =
+    (clipboardData, effectAllowed, sourceVolumeInfo, entries,
+     missingFileContents) => {
+      // Tag to check it's filemanager data.
+      clipboardData.setData('fs/tag', 'filemanager-data');
+      clipboardData.setData(
+          'fs/sourceRootURL', sourceVolumeInfo.fileSystem.root.toURL());
 
-  const sourceURLs = util.entriesToURLs(entries);
-  clipboardData.setData('fs/sources', sourceURLs.join('\n'));
+      const sourceURLs = util.entriesToURLs(entries);
+      clipboardData.setData('fs/sources', sourceURLs.join('\n'));
 
-  clipboardData.effectAllowed = effectAllowed;
-  clipboardData.setData('fs/effectallowed', effectAllowed);
+      clipboardData.effectAllowed = effectAllowed;
+      clipboardData.setData('fs/effectallowed', effectAllowed);
 
-  clipboardData.setData('fs/missingFileContents',
-      missingFileContents.toString());
-};
+      clipboardData.setData(
+          'fs/missingFileContents', missingFileContents.toString());
+    };
 
 /**
  * Appends uri-list of |entries| to |clipboardData|.
@@ -569,28 +564,29 @@
  * @return {string} URL or an empty string (if unknown).
  * @private
  */
-FileTransferController.prototype.getSourceRootURL_ = (clipboardData, dragAndDropData) => {
-  const sourceRootURL = clipboardData.getData('fs/sourceRootURL');
-  if (sourceRootURL) {
-    return sourceRootURL;
-  }
+FileTransferController.prototype.getSourceRootURL_ =
+    (clipboardData, dragAndDropData) => {
+      const sourceRootURL = clipboardData.getData('fs/sourceRootURL');
+      if (sourceRootURL) {
+        return sourceRootURL;
+      }
 
-  // |clipboardData| in protected mode.
-  if (dragAndDropData) {
-    return dragAndDropData.sourceRootURL;
-  }
+      // |clipboardData| in protected mode.
+      if (dragAndDropData) {
+        return dragAndDropData.sourceRootURL;
+      }
 
-  // Unknown source.
-  return '';
-};
+      // Unknown source.
+      return '';
+    };
 
 /**
  * @param {!ClipboardData} clipboardData DataTransfer object from the event.
  * @return {boolean} Returns true when missing some file contents.
  * @private
  */
-FileTransferController.prototype.isMissingFileContents_ =
-    function(clipboardData) {
+FileTransferController.prototype.isMissingFileContents_ = function(
+    clipboardData) {
   let data = clipboardData.getData('fs/missingFileContents');
   if (!data) {
     // |clipboardData| in protected mode.
@@ -610,8 +606,8 @@
  *    that need to share.
  * @private
  */
-FileTransferController.prototype.getMultiProfileShareEntries_ =
-    function(entries) {
+FileTransferController.prototype.getMultiProfileShareEntries_ = function(
+    entries) {
   // Utility function to concat arrays.
   const concatArrays = arrays => {
     return Array.prototype.concat.apply([], arrays);
@@ -635,16 +631,17 @@
   // Check all file entries and keeps only those need sharing operation.
   const processFileEntries = entries => {
     return new Promise(callback => {
-      // Do not use metadata cache here because the urls come from the different
-      // profile.
-      chrome.fileManagerPrivate.getEntryProperties(
-          entries, ['hosted', 'sharedWithMe'], callback);
-    }).then(metadatas => {
-      return entries.filter((entry, i) => {
-        const metadata = metadatas[i];
-        return metadata && metadata.hosted && !metadata.sharedWithMe;
-      });
-    });
+             // Do not use metadata cache here because the urls come from the
+             // different profile.
+             chrome.fileManagerPrivate.getEntryProperties(
+                 entries, ['hosted', 'sharedWithMe'], callback);
+           })
+        .then(metadatas => {
+          return entries.filter((entry, i) => {
+            const metadata = metadatas[i];
+            return metadata && metadata.hosted && !metadata.sharedWithMe;
+          });
+        });
   };
 
   // Check child entries.
@@ -655,21 +652,21 @@
   // Read entries from DirectoryReader and call processEntries for the chunk
   // of entries.
   const readEntries = reader => {
-    return new Promise(reader.readEntries.bind(reader)).then(
-        entries => {
-          if (entries.length > 0) {
-            return Promise.all(
-                [processEntries(entries), readEntries(reader)]).
-                then(concatArrays);
-          } else {
-            return [];
-          }
-        },
-        error => {
-          console.warn(
-              'Error happens while reading directory.', error);
-          return [];
-        });
+    return new Promise(reader.readEntries.bind(reader))
+        .then(
+            entries => {
+              if (entries.length > 0) {
+                return Promise
+                    .all([processEntries(entries), readEntries(reader)])
+                    .then(concatArrays);
+              } else {
+                return [];
+              }
+            },
+            error => {
+              console.warn('Error happens while reading directory.', error);
+              return [];
+            });
   };
 
   // Filter entries that is owned by the current user, and call
@@ -689,11 +686,13 @@
 FileTransferController.prototype.preparePaste = function(
     clipboardData, opt_destinationEntry, opt_effect) {
   const sourceURLs = clipboardData.getData('fs/sources') ?
-      clipboardData.getData('fs/sources').split('\n') : [];
+      clipboardData.getData('fs/sources').split('\n') :
+      [];
   // effectAllowed set in copy/paste handlers stay uninitialized. DnD handlers
   // work fine.
   const effectAllowed = clipboardData.effectAllowed !== 'uninitialized' ?
-      clipboardData.effectAllowed : clipboardData.getData('fs/effectallowed');
+      clipboardData.effectAllowed :
+      clipboardData.getData('fs/effectallowed');
   const destinationEntry = opt_destinationEntry ||
       /** @type {DirectoryEntry} */ (this.directoryModel_.getCurrentDirEntry());
   const toMove = util.isDropEffectAllowed(effectAllowed, 'move') &&
@@ -796,59 +795,59 @@
 
   FileTransferController.URLsToEntriesWithAccess(sourceURLs)
       .then(/**
-   * @param {Object} result
-   */
-  result => {
-    failureUrls = result.failureUrls;
-    // The promise is not rejected, so it's safe to not remove the
-    // early progress center item here.
-    return this.fileOperationManager_.filterSameDirectoryEntry(
-        result.entries, destinationEntry, toMove);
-  })
+             * @param {Object} result
+             */
+            result => {
+              failureUrls = result.failureUrls;
+              // The promise is not rejected, so it's safe to not remove the
+              // early progress center item here.
+              return this.fileOperationManager_.filterSameDirectoryEntry(
+                  result.entries, destinationEntry, toMove);
+            })
       .then(/**
-   * @param {!Array<Entry>} filteredEntries
-   * @return {!Promise<Array<Entry>>}
-   */
-  filteredEntries => {
-    entries = filteredEntries;
-    if (entries.length === 0) {
-      return Promise.reject('ABORT');
-    }
+             * @param {!Array<Entry>} filteredEntries
+             * @return {!Promise<Array<Entry>>}
+             */
+            filteredEntries => {
+              entries = filteredEntries;
+              if (entries.length === 0) {
+                return Promise.reject('ABORT');
+              }
 
-    this.pendingTaskIds.push(taskId);
-    const item = new ProgressCenterItem();
-    item.id = taskId;
-    if (toMove) {
-      item.type = ProgressItemType.MOVE;
-      if (entries.length === 1) {
-        item.message = strf('MOVE_FILE_NAME', entries[0].name);
-      } else {
-        item.message = strf('MOVE_ITEMS_REMAINING', entries.length);
-      }
-    } else {
-      item.type = ProgressItemType.COPY;
-      if (entries.length === 1) {
-        item.message = strf('COPY_FILE_NAME', entries[0].name);
-      } else {
-        item.message = strf('COPY_ITEMS_REMAINING', entries.length);
-      }
-    }
-    this.progressCenter_.updateItem(item);
-    // Check if cross share is needed or not.
-    return this.getMultiProfileShareEntries_(entries);
-  })
+              this.pendingTaskIds.push(taskId);
+              const item = new ProgressCenterItem();
+              item.id = taskId;
+              if (toMove) {
+                item.type = ProgressItemType.MOVE;
+                if (entries.length === 1) {
+                  item.message = strf('MOVE_FILE_NAME', entries[0].name);
+                } else {
+                  item.message = strf('MOVE_ITEMS_REMAINING', entries.length);
+                }
+              } else {
+                item.type = ProgressItemType.COPY;
+                if (entries.length === 1) {
+                  item.message = strf('COPY_FILE_NAME', entries[0].name);
+                } else {
+                  item.message = strf('COPY_ITEMS_REMAINING', entries.length);
+                }
+              }
+              this.progressCenter_.updateItem(item);
+              // Check if cross share is needed or not.
+              return this.getMultiProfileShareEntries_(entries);
+            })
       .then(/**
-   * @param {Array<Entry>} inShareEntries
-   * @return {!Promise<Array<Entry>>|!Promise<null>}
-   */
-  inShareEntries => {
-    shareEntries = inShareEntries;
-    if (shareEntries.length === 0) {
-      return Promise.resolve(null);
-    }
-    return this.multiProfileShareDialog_.showMultiProfileShareDialog(
-        shareEntries.length > 1);
-  })
+             * @param {Array<Entry>} inShareEntries
+             * @return {!Promise<Array<Entry>>|!Promise<null>}
+             */
+            inShareEntries => {
+              shareEntries = inShareEntries;
+              if (shareEntries.length === 0) {
+                return Promise.resolve(null);
+              }
+              return this.multiProfileShareDialog_.showMultiProfileShareDialog(
+                  shareEntries.length > 1);
+            })
       .then(
           /**
            * @param {?string} dialogResult
@@ -869,8 +868,7 @@
               }
               return new Promise(fulfill => {
                        chrome.fileManagerPrivate.requestDriveShare(
-                           shareEntries[index], assert(dialogResult),
-                           () => {
+                           shareEntries[index], assert(dialogResult), () => {
                              // TODO(hirono): Check chrome.runtime.lastError
                              // here.
                              fulfill();
@@ -881,28 +879,27 @@
             return requestDriveShare(0);
           })
       .then(() => {
-    // Start the pasting operation.
-    this.fileOperationManager_.paste(
-        entries, destinationEntry, toMove, taskId);
-    this.pendingTaskIds.splice(
-        this.pendingTaskIds.indexOf(taskId), 1);
+        // Start the pasting operation.
+        this.fileOperationManager_.paste(
+            entries, destinationEntry, toMove, taskId);
+        this.pendingTaskIds.splice(this.pendingTaskIds.indexOf(taskId), 1);
 
-    // Publish source not found error item.
-    for (let i = 0; i < failureUrls.length; i++) {
-      const fileName =
-          decodeURIComponent(failureUrls[i].replace(/^.+\//, ''));
-      const item = new ProgressCenterItem();
-      item.id = 'source-not-found-' + this.sourceNotFoundErrorCount_;
-      if (toMove) {
-        item.message = strf('MOVE_SOURCE_NOT_FOUND_ERROR', fileName);
-      } else {
-        item.message = strf('COPY_SOURCE_NOT_FOUND_ERROR', fileName);
-      }
-      item.state = ProgressItemState.ERROR;
-      this.progressCenter_.updateItem(item);
-      this.sourceNotFoundErrorCount_++;
-    }
-  })
+        // Publish source not found error item.
+        for (let i = 0; i < failureUrls.length; i++) {
+          const fileName =
+              decodeURIComponent(failureUrls[i].replace(/^.+\//, ''));
+          const item = new ProgressCenterItem();
+          item.id = 'source-not-found-' + this.sourceNotFoundErrorCount_;
+          if (toMove) {
+            item.message = strf('MOVE_SOURCE_NOT_FOUND_ERROR', fileName);
+          } else {
+            item.message = strf('COPY_SOURCE_NOT_FOUND_ERROR', fileName);
+          }
+          item.state = ProgressItemState.ERROR;
+          this.progressCenter_.updateItem(item);
+          this.sourceNotFoundErrorCount_++;
+        }
+      })
       .catch(error => {
         if (error !== 'ABORT') {
           console.error(error.stack ? error.stack : error);
@@ -978,15 +975,10 @@
     const srcHeight = Math.min(canvas.height * minScale, thumbnailImage.height);
 
     const context = canvas.getContext('2d');
-    context.drawImage(thumbnailImage,
-                      (thumbnailImage.width - srcWidth) / 2,
-                      (thumbnailImage.height - srcHeight) / 2,
-                      srcWidth,
-                      srcHeight,
-                      0,
-                      0,
-                      canvas.width,
-                      canvas.height);
+    context.drawImage(
+        thumbnailImage, (thumbnailImage.width - srcWidth) / 2,
+        (thumbnailImage.height - srcHeight) / 2, srcWidth, srcHeight, 0, 0,
+        canvas.width, canvas.height);
     contents.classList.add('for-image');
     contents.appendChild(canvas);
     return container;
@@ -1105,8 +1097,8 @@
  * @param {Event} event A dragover event of DOM.
  * @private
  */
-FileTransferController.prototype.onDragOver_ =
-    function(onlyIntoDirectories, list, event) {
+FileTransferController.prototype.onDragOver_ = function(
+    onlyIntoDirectories, list, event) {
   event.preventDefault();
   let entry = this.destinationEntry_;
   if (!entry && !onlyIntoDirectories) {
@@ -1118,7 +1110,7 @@
   event.preventDefault();
   const label = effectAndLabel.getLabel();
   if (!this.dropLabel_) {
-    this.dropLabel_ = document.querySelector("div#drop-label");
+    this.dropLabel_ = document.querySelector('div#drop-label');
   }
   if (label) {
     this.dropLabel_.innerText = label;
@@ -1211,8 +1203,8 @@
   if (onlyIntoDirectories && !this.dropTarget_) {
     return;
   }
-  const destinationEntry = this.destinationEntry_ ||
-                         this.directoryModel_.getCurrentDirEntry();
+  const destinationEntry =
+      this.destinationEntry_ || this.directoryModel_.getCurrentDirEntry();
   if (!this.canPasteOrDrop_(event.dataTransfer, destinationEntry)) {
     return;
   }
@@ -1346,8 +1338,7 @@
  * @private
  */
 FileTransferController.prototype.onCutOrCopy_ = function(isMove, event) {
-  if (!this.isDocumentWideEvent_() ||
-      !this.canCutOrCopy_(isMove)) {
+  if (!this.isDocumentWideEvent_() || !this.canCutOrCopy_(isMove)) {
     return;
   }
 
@@ -1396,8 +1387,8 @@
       this.volumeManager_.getDriveConnectionState().type ===
           VolumeManagerCommon.DriveConnectionType.OFFLINE;
 
-  this.appendCutOrCopyInfo_(clipboardData, effectAllowed, volumeInfo, [entry],
-      missingFileContents);
+  this.appendCutOrCopyInfo_(
+      clipboardData, effectAllowed, volumeInfo, [entry], missingFileContents);
 };
 
 /**
@@ -1447,8 +1438,8 @@
       return false;
     }
 
-    const metadata = this.metadataModel_.getCache(
-        [entry], ['canCopy', 'canDelete']);
+    const metadata =
+        this.metadataModel_.getCache([entry], ['canCopy', 'canDelete']);
     assert(metadata.length === 1);
 
     if (!isMove) {
@@ -1476,7 +1467,7 @@
     return false;
   }
 
-  return isMove ? this.canCutOrDrag_() : this.canCopyOrDrag_() ;
+  return isMove ? this.canCutOrDrag_() : this.canCopyOrDrag_();
 };
 
 /**
@@ -1564,8 +1555,9 @@
     return;
   }
   // queryCommandEnabled returns true if event.defaultPrevented is true.
-  if (this.canPasteOrDrop_(assert(event.clipboardData),
-                           this.directoryModel_.getCurrentDirEntry())) {
+  if (this.canPasteOrDrop_(
+          assert(event.clipboardData),
+          this.directoryModel_.getCurrentDirEntry())) {
     event.preventDefault();
   }
 };
@@ -1634,8 +1626,8 @@
   // should be used.
   let result;
   this.simulateCommand_('paste', event => {
-    result = this.canPasteOrDrop_(
-        assert(event.clipboardData), destinationEntry);
+    result =
+        this.canPasteOrDrop_(assert(event.clipboardData), destinationEntry);
   });
   return result;
 };
@@ -1771,14 +1763,14 @@
     }
     if (destinationLocationInfo.volumeInfo &&
         destinationLocationInfo.volumeInfo.isReadOnlyRemovableDevice) {
-      return new DropEffectAndLabel(DropEffectType.NONE,
-                                    strf('DEVICE_WRITE_PROTECTED'));
+      return new DropEffectAndLabel(
+          DropEffectType.NONE, strf('DEVICE_WRITE_PROTECTED'));
     }
     // The disk device is not write-protected but read-only.
     // Currently, the only remaining possibility is that write access to
     // removable drives is restricted by device policy.
-    return new DropEffectAndLabel(DropEffectType.NONE,
-                                  strf('DEVICE_ACCESS_RESTRICTED'));
+    return new DropEffectAndLabel(
+        DropEffectType.NONE, strf('DEVICE_ACCESS_RESTRICTED'));
   }
   const destinationMetadata =
       this.metadataModel_.getCache([destinationEntry], ['canAddChildren']);
diff --git a/ui/file_manager/file_manager/foreground/js/file_watcher.js b/ui/file_manager/file_manager/foreground/js/file_watcher.js
index 6522e29..a393db2b 100644
--- a/ui/file_manager/file_manager/foreground/js/file_watcher.js
+++ b/ui/file_manager/file_manager/foreground/js/file_watcher.js
@@ -59,8 +59,7 @@
       // When watched directory is deleted by the change in parent directory,
       // notify it as watcher directory changed.
       this.watchedDirectoryEntry_.getDirectory(
-          this.watchedDirectoryEntry_.fullPath, {create: false}, null,
-          () => {
+          this.watchedDirectoryEntry_.fullPath, {create: false}, null, () => {
             fireWatcherDirectoryChanged(null);
           });
     }
@@ -95,10 +94,10 @@
       // Release the watched directory.
       if (this.watchedDirectoryEntry_) {
         chrome.fileManagerPrivate.removeFileWatch(
-            this.watchedDirectoryEntry_,
-            result => {
+            this.watchedDirectoryEntry_, result => {
               if (chrome.runtime.lastError) {
-                console.error('Failed to remove the watcher because of: ' +
+                console.error(
+                    'Failed to remove the watcher because of: ' +
                     chrome.runtime.lastError.message);
               }
               // Even on error reset the watcher locally, so at least the
@@ -126,22 +125,19 @@
     const setEntryClosure = () => {
       // Run the tasks in the queue to avoid races.
       this.queue_.run(callback => {
-        chrome.fileManagerPrivate.addFileWatch(
-            entry,
-            result => {
-              if (chrome.runtime.lastError) {
-                // Most probably setting the watcher is not supported on the
-                // file system type.
-                console.info('File watchers not supported for: ' +
-                    entry.toURL());
-                this.watchedDirectoryEntry_ = null;
-                fulfill();
-              } else {
-                this.watchedDirectoryEntry_ = assert(entry);
-                fulfill();
-              }
-              callback();
-            });
+        chrome.fileManagerPrivate.addFileWatch(entry, result => {
+          if (chrome.runtime.lastError) {
+            // Most probably setting the watcher is not supported on the
+            // file system type.
+            console.info('File watchers not supported for: ' + entry.toURL());
+            this.watchedDirectoryEntry_ = null;
+            fulfill();
+          } else {
+            this.watchedDirectoryEntry_ = assert(entry);
+            fulfill();
+          }
+          callback();
+        });
       });
     };
 
diff --git a/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js b/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
index e94d7cf..eed06c0f 100644
--- a/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
+++ b/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
@@ -148,24 +148,24 @@
       const group = new AsyncUtil.Group();
       list.forEach(function(path) {
         group.add(((path, callback) => {
-          const url =
-              this.lastDriveRootURL_ && this.convertStoredPathToUrl_(path);
-          if (url && volumeInfo) {
-            window.webkitResolveLocalFileSystemURL(
-                url,
-                entry => {
-                  onResolveSuccess(path, entry);
-                  callback();
-                },
-                () => {
-                  onResolveFailure(path, url);
-                  callback();
-                });
-          } else {
-            onResolveFailure(path, url);
-            callback();
-          }
-        }).bind(null, path));
+                    const url = this.lastDriveRootURL_ &&
+                        this.convertStoredPathToUrl_(path);
+                    if (url && volumeInfo) {
+                      window.webkitResolveLocalFileSystemURL(
+                          url,
+                          entry => {
+                            onResolveSuccess(path, entry);
+                            callback();
+                          },
+                          () => {
+                            onResolveFailure(path, url);
+                            callback();
+                          });
+                    } else {
+                      onResolveFailure(path, url);
+                      callback();
+                    }
+                  }).bind(null, path));
       }, this);
 
       // Save the model after finishing.
@@ -198,7 +198,8 @@
     this.queue_.run(callback => {
       chrome.storage.sync.get(FolderShortcutsDataModel.NAME, value => {
         if (chrome.runtime.lastError) {
-          console.error('Failed to load shortcut paths from chrome.storage: ' +
+          console.error(
+              'Failed to load shortcut paths from chrome.storage: ' +
               chrome.runtime.lastError.message);
           callback();
           return;
@@ -341,8 +342,7 @@
       addedIndex = this.length;
     }
 
-    this.firePermutedEvent_(
-        this.calculatePermutation_(oldArray, this.array_));
+    this.firePermutedEvent_(this.calculatePermutation_(oldArray, this.array_));
     return addedIndex;
   },
 
@@ -411,12 +411,12 @@
 
     // TODO(mtomasz): Migrate to URL.
     const paths = this.array_
-                    .map(entry => {
-                      return entry.toURL();
-                    })
-                    .map(this.convertUrlToStoredPath_.bind(this))
-                    .concat(Object.keys(this.pendingPaths_))
-                    .concat(Object.keys(this.unresolvablePaths_));
+                      .map(entry => {
+                        return entry.toURL();
+                      })
+                      .map(this.convertUrlToStoredPath_.bind(this))
+                      .concat(Object.keys(this.pendingPaths_))
+                      .concat(Object.keys(this.unresolvablePaths_));
 
     const prefs = {};
     prefs[FolderShortcutsDataModel.NAME] = paths;
@@ -519,8 +519,8 @@
       console.warn(path + ' is neither a drive mount path nor a stored path.');
       return null;
     }
-    return this.lastDriveRootURL_ + encodeURIComponent(
-        path.substr(STORED_DRIVE_MOUNT_PATH.length));
+    return this.lastDriveRootURL_ +
+        encodeURIComponent(path.substr(STORED_DRIVE_MOUNT_PATH.length));
   },
 
   /**
@@ -539,7 +539,7 @@
       return null;
     }
 
-    return STORED_DRIVE_MOUNT_PATH + '/' + decodeURIComponent(
-        url.substr(this.lastDriveRootURL_.length));
+    return STORED_DRIVE_MOUNT_PATH + '/' +
+        decodeURIComponent(url.substr(this.lastDriveRootURL_.length));
   },
 };
diff --git a/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js b/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js
index da44d96b..48ca63b 100644
--- a/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js
@@ -72,7 +72,7 @@
  */
 GearMenuController.prototype.onShowGearMenu_ = function() {
   this.toggleRipple_.activated = true;
-  this.refreshRemainingSpace_(false);  /* Without loading caption. */
+  this.refreshRemainingSpace_(false); /* Without loading caption. */
 
   // Update view of drive-related settings.
   this.commandHandler_.updateAvailability();
@@ -154,9 +154,12 @@
     return;
   }
 
-  this.gearMenu_.setSpaceInfo(new Promise(fulfill => {
-    chrome.fileManagerPrivate.getSizeStats(currentVolumeInfo.volumeId, fulfill);
-  }), true);
+  this.gearMenu_.setSpaceInfo(
+      new Promise(fulfill => {
+        chrome.fileManagerPrivate.getSizeStats(
+            currentVolumeInfo.volumeId, fulfill);
+      }),
+      true);
 };
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/import_controller.js b/ui/file_manager/file_manager/foreground/js/import_controller.js
index 0db814a..8d1a3b01 100644
--- a/ui/file_manager/file_manager/foreground/js/import_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/import_controller.js
@@ -32,7 +32,6 @@
  */
 importer.ImportController = function(
     environment, scanner, importRunner, commandWidget) {
-
   /** @private {!importer.ControllerEnvironment} */
   this.environment_ = environment;
 
@@ -78,14 +77,11 @@
   const listener = this.onScanEvent_.bind(this);
   this.scanner_.addObserver(listener);
   // Remove the observer when the foreground window is closed.
-  window.addEventListener(
-      'pagehide',
-      () => {
-        this.scanner_.removeObserver(listener);
-      });
+  window.addEventListener('pagehide', () => {
+    this.scanner_.removeObserver(listener);
+  });
 
-  this.environment_.addWindowCloseListener(
-      this.onWindowClosing_.bind(this));
+  this.environment_.addWindowCloseListener(this.onWindowClosing_.bind(this));
 
   this.environment_.addVolumeUnmountListener(
       this.onVolumeUnmounted_.bind(this));
@@ -96,14 +92,13 @@
   this.environment_.addSelectionChangedListener(
       this.onSelectionChanged_.bind(this));
 
-  this.commandWidget_.addClickListener(
-      this.onClick_.bind(this));
+  this.commandWidget_.addClickListener(this.onClick_.bind(this));
 
   this.storage_.get(importer.Setting.HAS_COMPLETED_IMPORT, false)
       .then(
           /**
-          * @param {boolean} importCompleted If so, we hide the banner
-          */
+           * @param {boolean} importCompleted If so, we hide the banner
+           */
           importCompleted => {
             this.commandWidget_.setDetailsBannerVisible(!importCompleted);
           });
@@ -233,8 +228,8 @@
  * @private
  */
 importer.ImportController.prototype.finalizeActiveImport_ = function() {
-  console.assert(!!this.activeImport_,
-      'Cannot finish import when none is running.');
+  console.assert(
+      !!this.activeImport_, 'Cannot finish import when none is running.');
   this.previousImport_ = this.activeImport_;
   this.activeImport_ = null;
 };
@@ -243,8 +238,7 @@
  * Handles button clicks emenating from the panel or toolbar.
  * @param {!importer.ClickSource} source
  */
-importer.ImportController.prototype.onClick_ =
-     function(source) {
+importer.ImportController.prototype.onClick_ = function(source) {
   switch (source) {
     case importer.ClickSource.MAIN:
       if (this.lastActivityState_ === importer.ActivityState.READY) {
@@ -284,7 +278,8 @@
  * @private
  */
 importer.ImportController.prototype.startImportTask_ = function() {
-  console.assert(!this.activeImport_,
+  console.assert(
+      !this.activeImport_,
       'Cannot execute while an import task is already active.');
 
   const scan = this.scanManager_.getActiveScan();
@@ -292,15 +287,10 @@
 
   const startDate = new Date();
   const importTask = this.importRunner_.importFromScanResult(
-      scan,
-      importer.Destination.GOOGLE_DRIVE,
+      scan, importer.Destination.GOOGLE_DRIVE,
       this.environment_.getImportDestination(startDate));
 
-  this.activeImport_ = {
-    scan: scan,
-    task: importTask,
-    started: startDate
-  };
+  this.activeImport_ = {scan: scan, task: importTask, started: startDate};
   const taskFinished = this.onImportFinished_.bind(this, importTask);
   importTask.whenFinished.then(taskFinished).catch(taskFinished);
 };
@@ -402,43 +392,42 @@
             VolumeManagerCommon.VolumeType.DRIVE),
       ])
       .then(/** @param {Array<number>} availableSpace in bytes */
-  availableSpace => {
-    // TODO(smckay): We might want to disqualify some small amount of
-    // local storage in this calculation on the assumption that we
-    // don't want to completely max out storage...even though synced
-    // files will eventually be evicted from the cache.
-    if (availableSpace[0] < opt_scan.getStatistics().sizeBytes) {
-      // Doesn't fit in local space.
-      this.updateUi_(
-          importer.ActivityState.INSUFFICIENT_LOCAL_SPACE, opt_scan,
-          availableSpace[0]);
-      return;
-    }
-    if (availableSpace[1] !== -1 &&
-        availableSpace[1] < opt_scan.getStatistics().sizeBytes) {
-      // Could retrieve cloud quota and doesn't fit.
-      this.updateUi_(
-          importer.ActivityState.INSUFFICIENT_CLOUD_SPACE, opt_scan,
-          availableSpace[1]);
-      return;
-    }
+            availableSpace => {
+              // TODO(smckay): We might want to disqualify some small amount of
+              // local storage in this calculation on the assumption that we
+              // don't want to completely max out storage...even though synced
+              // files will eventually be evicted from the cache.
+              if (availableSpace[0] < opt_scan.getStatistics().sizeBytes) {
+                // Doesn't fit in local space.
+                this.updateUi_(
+                    importer.ActivityState.INSUFFICIENT_LOCAL_SPACE, opt_scan,
+                    availableSpace[0]);
+                return;
+              }
+              if (availableSpace[1] !== -1 &&
+                  availableSpace[1] < opt_scan.getStatistics().sizeBytes) {
+                // Could retrieve cloud quota and doesn't fit.
+                this.updateUi_(
+                    importer.ActivityState.INSUFFICIENT_CLOUD_SPACE, opt_scan,
+                    availableSpace[1]);
+                return;
+              }
 
-    // Enough space available!
-    this.updateUi_(
-        importer.ActivityState.READY,  // to import...
-        opt_scan);
-    if (this.isRightAfterPluggingMedia_) {
-      this.isRightAfterPluggingMedia_ = false;
-      this.commandWidget_.setDetailsVisible(true);
-    }
-  })
+              // Enough space available!
+              this.updateUi_(
+                  importer.ActivityState.READY,  // to import...
+                  opt_scan);
+              if (this.isRightAfterPluggingMedia_) {
+                this.isRightAfterPluggingMedia_ = false;
+                this.commandWidget_.setDetailsVisible(true);
+              }
+            })
       .catch(error => {
-               // If an error occurs, it will appear to scan forever - hide the
-               // cloud backup option in that case.
-               importer.getLogger().catcher('import-controller-check-state')(
-                   error);
-               this.updateUi_(importer.ActivityState.HIDDEN);
-             });
+        // If an error occurs, it will appear to scan forever - hide the
+        // cloud backup option in that case.
+        importer.getLogger().catcher('import-controller-check-state')(error);
+        this.updateUi_(importer.ActivityState.HIDDEN);
+      });
 };
 
 /**
@@ -458,8 +447,7 @@
  * @return {boolean} true if the current directory is scan eligible.
  * @private
  */
-importer.ImportController.prototype.isCurrentDirectoryScannable_ =
-    function() {
+importer.ImportController.prototype.isCurrentDirectoryScannable_ = function() {
   const directory = this.environment_.getCurrentDirectory();
   return !!directory &&
       importer.isMediaDirectory(directory, this.environment_.volumeManager);
@@ -547,14 +535,11 @@
  * @struct
  */
 importer.RuntimeCommandWidget = function() {
-
   /** @private {HTMLElement} */
   this.detailsPanel_ = /** @type {HTMLElement} */ (
       document.querySelector('#cloud-import-details'));
   this.detailsPanel_.addEventListener(
-      'transitionend',
-      this.onDetailsTransitionEnd_.bind(this),
-      false);
+      'transitionend', this.onDetailsTransitionEnd_.bind(this), false);
 
   // Any clicks on document outside of the details panel
   // result in the panel being hidden.
@@ -571,21 +556,21 @@
   this.comboButton_ = getRequiredElement('cloud-import-combo-button');
 
   /** @private {!Element} */
-  this.mainButton_ = queryRequiredElement(
-      '#cloud-import-button', this.comboButton_);
-  this.mainButton_.onclick = this.onButtonClicked_.bind(
-      this, importer.ClickSource.MAIN);
+  this.mainButton_ =
+      queryRequiredElement('#cloud-import-button', this.comboButton_);
+  this.mainButton_.onclick =
+      this.onButtonClicked_.bind(this, importer.ClickSource.MAIN);
 
   /** @private {!PaperRipple}*/
   this.mainButtonRipple_ =
-      /** @type {!PaperRipple} */ (queryRequiredElement(
-          '.ripples > paper-ripple', this.comboButton_));
+      /** @type {!PaperRipple} */ (
+          queryRequiredElement('.ripples > paper-ripple', this.comboButton_));
 
   /** @private {Element} */
-  this.sideButton_ = queryRequiredElement(
-      '#cloud-import-details-button', this.comboButton_);
-  this.sideButton_.onclick = this.onButtonClicked_.bind(
-      this, importer.ClickSource.SIDE);
+  this.sideButton_ =
+      queryRequiredElement('#cloud-import-details-button', this.comboButton_);
+  this.sideButton_.onclick =
+      this.onButtonClicked_.bind(this, importer.ClickSource.SIDE);
 
   /** @private {!FilesToggleRipple} */
   this.sideButtonRipple_ =
@@ -595,24 +580,23 @@
   /** @private {Element} */
   this.importButton_ =
       document.querySelector('#cloud-import-details paper-button.import');
-  this.importButton_.onclick = this.onButtonClicked_.bind(
-      this, importer.ClickSource.IMPORT);
+  this.importButton_.onclick =
+      this.onButtonClicked_.bind(this, importer.ClickSource.IMPORT);
 
   /** @private {Element} */
   this.cancelButton_ =
       document.querySelector('#cloud-import-details paper-button.cancel');
-  this.cancelButton_.onclick = this.onButtonClicked_.bind(
-      this, importer.ClickSource.CANCEL);
+  this.cancelButton_.onclick =
+      this.onButtonClicked_.bind(this, importer.ClickSource.CANCEL);
 
   /** @private {Element} */
   this.statusContent_ =
       document.querySelector('#cloud-import-details .status .content');
-  this.statusContent_.onclick = this.onButtonClicked_.bind(
-      this, importer.ClickSource.DESTINATION);
+  this.statusContent_.onclick =
+      this.onButtonClicked_.bind(this, importer.ClickSource.DESTINATION);
 
   /** @private {Element} */
-  this.toolbarIcon_ =
-      document.querySelector('#cloud-import-button iron-icon');
+  this.toolbarIcon_ = document.querySelector('#cloud-import-button iron-icon');
   this.statusIcon_ =
       document.querySelector('#cloud-import-details .status iron-icon');
 
@@ -656,9 +640,8 @@
  * @param {!HTMLElement} element
  * @param {number} timeout In milliseconds.
  */
-importer.RuntimeCommandWidget.ensureTransitionEndEvent =
-    (element, timeout) => {
-    let fired = false;
+importer.RuntimeCommandWidget.ensureTransitionEndEvent = (element, timeout) => {
+  let fired = false;
   element.addEventListener('transitionend', function f(e) {
     element.removeEventListener('transitionend', f);
     fired = true;
@@ -672,8 +655,7 @@
 };
 
 /** @override */
-importer.RuntimeCommandWidget.prototype.addClickListener =
-    function(listener) {
+importer.RuntimeCommandWidget.prototype.addClickListener = function(listener) {
   this.clickListener_ = listener;
 };
 
@@ -682,8 +664,8 @@
  * @param {Event} event Click event.
  * @private
  */
-importer.RuntimeCommandWidget.prototype.onButtonClicked_ =
-    function(source, event) {
+importer.RuntimeCommandWidget.prototype.onButtonClicked_ = function(
+    source, event) {
   console.assert(!!this.clickListener_, 'Listener not set.');
 
   // Clear focus from the toolbar button after it is clicked.
@@ -727,8 +709,8 @@
 };
 
 /** @override */
-importer.RuntimeCommandWidget.prototype.setDetailsBannerVisible =
-    function(visible) {
+importer.RuntimeCommandWidget.prototype.setDetailsBannerVisible = function(
+    visible) {
   this.detailsBanner_.hidden = !visible;
 };
 
@@ -765,14 +747,12 @@
     this.detailsPanel_.className = 'hidden';
     // transition duration is 200ms. Let's wait for 400ms.
     importer.RuntimeCommandWidget.ensureTransitionEndEvent(
-        /** @type {!HTMLElement} */ (this.detailsPanel_),
-        400);
+        /** @type {!HTMLElement} */ (this.detailsPanel_), 400);
   }
 };
 
 /** @private */
-importer.RuntimeCommandWidget.prototype.onDetailsTransitionEnd_ =
-    function() {
+importer.RuntimeCommandWidget.prototype.onDetailsTransitionEnd_ = function() {
   if (this.detailsPanel_.className === 'hidden') {
     // if we simply make the panel invisible (via opacity)
     // it'll still be sitting there grabing mouse events
@@ -782,8 +762,7 @@
 };
 
 /** @private */
-importer.RuntimeCommandWidget.prototype.onDetailsFocusLost_ =
-    function() {
+importer.RuntimeCommandWidget.prototype.onDetailsFocusLost_ = function() {
   this.setDetailsVisible(false);
 };
 
@@ -796,11 +775,11 @@
  */
 importer.RuntimeCommandWidget.prototype.updateTabindexOfAnchors_ =
     (root, newTabIndex) => {
-  const anchors = root.querySelectorAll('a');
-  anchors.forEach(element => {
-    element.tabIndex = newTabIndex;
-  });
-};
+      const anchors = root.querySelectorAll('a');
+      anchors.forEach(element => {
+        element.tabIndex = newTabIndex;
+      });
+    };
 
 /** @override */
 importer.RuntimeCommandWidget.prototype.update = function(
@@ -816,7 +795,7 @@
       photosText = '';
     }
   }
-  switch(activityState) {
+  switch (activityState) {
     case importer.ActivityState.HIDDEN:
       this.setDetailsVisible(false);
 
@@ -877,10 +856,9 @@
       break;
 
     case importer.ActivityState.NO_MEDIA:
-      this.mainButton_.setAttribute('aria-label', str(
-          'CLOUD_IMPORT_TOOLTIP_NO_MEDIA'));
-      this.statusContent_.innerHTML = str(
-          'CLOUD_IMPORT_STATUS_NO_MEDIA');
+      this.mainButton_.setAttribute(
+          'aria-label', str('CLOUD_IMPORT_TOOLTIP_NO_MEDIA'));
+      this.statusContent_.innerHTML = str('CLOUD_IMPORT_STATUS_NO_MEDIA');
 
       this.comboButton_.hidden = false;
       this.importButton_.hidden = true;
@@ -911,8 +889,8 @@
     case importer.ActivityState.SCANNING:
       console.assert(!!opt_scan, 'Scan not defined, but is required.');
 
-      this.mainButton_.setAttribute('aria-label', str(
-          'CLOUD_IMPORT_TOOLTIP_SCANNING'));
+      this.mainButton_.setAttribute(
+          'aria-label', str('CLOUD_IMPORT_TOOLTIP_SCANNING'));
       this.statusContent_.innerHTML =
           strf('CLOUD_IMPORT_STATUS_SCANNING', photosText);
 
@@ -949,7 +927,6 @@
  * @param {!importer.MediaScanner} scanner
  */
 importer.ScanManager = function(environment, scanner) {
-
   /** @private {!importer.ControllerEnvironment} */
   this.environment_ = environment;
 
@@ -1033,7 +1010,8 @@
  * @return {!importer.ScanResult}
  */
 importer.ScanManager.prototype.getSelectionScan = function(entries, mode) {
-  console.assert(!this.selectionScan_,
+  console.assert(
+      !this.selectionScan_,
       'Cannot create new selection scan with another in the cache.');
   this.selectionScan_ = this.scanner_.scanFiles(entries, mode);
   return this.selectionScan_;
@@ -1191,8 +1169,7 @@
 };
 
 /** @override */
-importer.RuntimeControllerEnvironment.prototype.getSelection =
-    function() {
+importer.RuntimeControllerEnvironment.prototype.getSelection = function() {
   return this.fileManager_.getSelection().entries;
 };
 
@@ -1203,14 +1180,14 @@
 };
 
 /** @override */
-importer.RuntimeControllerEnvironment.prototype.setCurrentDirectory =
-    function(entry) {
+importer.RuntimeControllerEnvironment.prototype.setCurrentDirectory = function(
+    entry) {
   this.fileManager_.directoryModel.activateDirectoryEntry(entry);
 };
 
 /** @override */
-importer.RuntimeControllerEnvironment.prototype.getVolumeInfo =
-    function(entry) {
+importer.RuntimeControllerEnvironment.prototype.getVolumeInfo = function(
+    entry) {
   return this.fileManager_.volumeManager.getVolumeInfo(entry);
 };
 
@@ -1230,59 +1207,56 @@
   const volumeInfo = assert(
       this.fileManager_.volumeManager.getCurrentProfileVolumeInfo(volumeType));
   return new Promise((resolve, reject) => {
-    chrome.fileManagerPrivate.getSizeStats(
-        volumeInfo.volumeId, stats => {
-          if (chrome.runtime.lastError) {
-            reject(
-                'Failed to ascertain available free space: ' +
-                chrome.runtime.lastError.message);
-            return;
-          }
-          if (!stats) {
-            resolve(-1);
-          }
-          resolve(stats.remainingSize);
-        });
+    chrome.fileManagerPrivate.getSizeStats(volumeInfo.volumeId, stats => {
+      if (chrome.runtime.lastError) {
+        reject(
+            'Failed to ascertain available free space: ' +
+            chrome.runtime.lastError.message);
+        return;
+      }
+      if (!stats) {
+        resolve(-1);
+      }
+      resolve(stats.remainingSize);
+    });
   });
 };
 
 /** @override */
 importer.RuntimeControllerEnvironment.prototype.addWindowCloseListener =
     listener => {
-  window.addEventListener('pagehide', listener);
-};
+      window.addEventListener('pagehide', listener);
+    };
 
 /** @override */
 importer.RuntimeControllerEnvironment.prototype.addVolumeUnmountListener =
     listener => {
-  // TODO(smckay): remove listeners when the page is torn down.
-  chrome.fileManagerPrivate.onMountCompleted.addListener(
-      /**
-       * @param {!chrome.fileManagerPrivate.MountCompletedEvent} event
-       * @this {importer.RuntimeControllerEnvironment}
-       */
-      event => {
-        if (event.eventType === 'unmount') {
-          listener(event.volumeMetadata.volumeId);
-        }
-      });
-};
+      // TODO(smckay): remove listeners when the page is torn down.
+      chrome.fileManagerPrivate.onMountCompleted.addListener(
+          /**
+           * @param {!chrome.fileManagerPrivate.MountCompletedEvent} event
+           * @this {importer.RuntimeControllerEnvironment}
+           */
+          event => {
+            if (event.eventType === 'unmount') {
+              listener(event.volumeMetadata.volumeId);
+            }
+          });
+    };
 
 /** @override */
 importer.RuntimeControllerEnvironment.prototype.addDirectoryChangedListener =
     function(listener) {
   // TODO(smckay): remove listeners when the page is torn down.
   this.fileManager_.directoryModel.addEventListener(
-      'directory-changed',
-      listener);
+      'directory-changed', listener);
 };
 
 /** @override */
 importer.RuntimeControllerEnvironment.prototype.addSelectionChangedListener =
     function(listener) {
   this.selectionHandler_.addEventListener(
-      FileSelectionHandler.EventType.CHANGE_THROTTLED,
-      listener);
+      FileSelectionHandler.EventType.CHANGE_THROTTLED, listener);
 };
 
 /**
@@ -1292,8 +1266,8 @@
  * @param {!DirectoryEntry} directory
  * @private
  */
-importer.RuntimeControllerEnvironment.prototype.revealDirectory_ =
-    function(directory) {
+importer.RuntimeControllerEnvironment.prototype.revealDirectory_ = function(
+    directory) {
   this.fileManager_.backgroundPage.launcher.launchFileManager(
       {currentDirectoryURL: directory.toURL()},
       /* App ID */ undefined);
@@ -1315,16 +1289,13 @@
  * @return {!Promise<!DirectoryEntry>}
  * @private
  */
-importer.RuntimeControllerEnvironment.prototype.demandCloudFolder_ =
-    root => {
+importer.RuntimeControllerEnvironment.prototype.demandCloudFolder_ = root => {
   return importer.demandChildDirectory(
-      root,
-      str('CLOUD_IMPORT_DESTINATION_FOLDER'));
+      root, str('CLOUD_IMPORT_DESTINATION_FOLDER'));
 };
 
 /** @override */
-importer.RuntimeControllerEnvironment.prototype.showImportRoot =
-    function() {
+importer.RuntimeControllerEnvironment.prototype.showImportRoot = function() {
   return this.getDriveRoot_()
       .then(this.demandCloudFolder_.bind(this))
       .then(this.revealDirectory_.bind(this))
@@ -1332,8 +1303,8 @@
 };
 
 /** @override */
-importer.RuntimeControllerEnvironment.prototype.getImportDestination =
-    function(date) {
+importer.RuntimeControllerEnvironment.prototype.getImportDestination = function(
+    date) {
   return this.getDriveRoot_()
       .then(this.demandCloudFolder_.bind(this))
       .then(
@@ -1343,8 +1314,7 @@
            */
           root => {
             return importer.demandChildDirectory(
-                root,
-                importer.getDirectoryNameForDate(date));
+                root, importer.getDirectoryNameForDate(date));
           })
       .catch(importer.getLogger().catcher('import-destination-provision'));
 };
diff --git a/ui/file_manager/file_manager/foreground/js/import_controller_unittest.js b/ui/file_manager/file_manager/foreground/js/import_controller_unittest.js
index efadacd..0f8a41a 100644
--- a/ui/file_manager/file_manager/foreground/js/import_controller_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/import_controller_unittest.js
@@ -84,8 +84,7 @@
 
 function testVolumeUnmount_InvalidatesScans(callback) {
   const controller = createController(
-      VolumeManagerCommon.VolumeType.MTP,
-      'mtp-volume',
+      VolumeManagerCommon.VolumeType.MTP, 'mtp-volume',
       [
         '/DCIM/',
         '/DCIM/photos0/',
@@ -93,7 +92,7 @@
         '/DCIM/photos0/IMG00002.jpg',
         '/DCIM/photos1/',
         '/DCIM/photos1/IMG00001.jpg',
-        '/DCIM/photos1/IMG00003.jpg'
+        '/DCIM/photos1/IMG00003.jpg',
       ],
       '/DCIM');
 
@@ -101,31 +100,31 @@
   assert(dcim);
 
   environment.directoryChangedListener(EMPTY_EVENT);
-  const promise = widget.updateResolver.promise.then(
-      () => {
-        // Reset the promise so we can wait on a second widget update.
-        widget.resetPromises();
-        environment.setCurrentDirectory(nonDcimDirectory);
-        environment.simulateUnmount();
+  const promise = widget.updateResolver.promise
+                      .then(() => {
+                        // Reset the promise so we can wait on a second widget
+                        // update.
+                        widget.resetPromises();
+                        environment.setCurrentDirectory(nonDcimDirectory);
+                        environment.simulateUnmount();
 
-        dcim = /** @type {!DirectoryEntry} */ (dcim);
-        environment.setCurrentDirectory(dcim);
-        environment.directoryChangedListener(EMPTY_EVENT);
-        // Return the new promise, so subsequent "thens" only
-        // fire once the widget has been updated again.
-        return widget.updateResolver.promise;
-      }).then(
-          () => {
-            mediaScanner.assertScanCount(2);
-          });
+                        dcim = /** @type {!DirectoryEntry} */ (dcim);
+                        environment.setCurrentDirectory(dcim);
+                        environment.directoryChangedListener(EMPTY_EVENT);
+                        // Return the new promise, so subsequent "thens" only
+                        // fire once the widget has been updated again.
+                        return widget.updateResolver.promise;
+                      })
+                      .then(() => {
+                        mediaScanner.assertScanCount(2);
+                      });
 
   reportPromise(promise, callback);
 }
 
 function testDirectoryChange_TriggersUpdate(callback) {
   const controller = createController(
-      VolumeManagerCommon.VolumeType.MTP,
-      'mtp-volume',
+      VolumeManagerCommon.VolumeType.MTP, 'mtp-volume',
       [
         '/DCIM/',
         '/DCIM/photos0/',
@@ -139,8 +138,7 @@
 
 function testDirectoryChange_CancelsScan(callback) {
   const controller = createController(
-      VolumeManagerCommon.VolumeType.MTP,
-      'mtp-volume',
+      VolumeManagerCommon.VolumeType.MTP, 'mtp-volume',
       [
         '/DCIM/',
         '/DCIM/photos0/',
@@ -148,30 +146,30 @@
         '/DCIM/photos0/IMG00002.jpg',
         '/DCIM/photos1/',
         '/DCIM/photos1/IMG00001.jpg',
-        '/DCIM/photos1/IMG00003.jpg'
+        '/DCIM/photos1/IMG00003.jpg',
       ],
       '/DCIM');
 
   environment.directoryChangedListener(EMPTY_EVENT);
-  const promise = widget.updateResolver.promise.then(
-      () => {
-        // Reset the promise so we can wait on a second widget update.
-        widget.resetPromises();
-        environment.setCurrentDirectory(nonDcimDirectory);
-        environment.directoryChangedListener(EMPTY_EVENT);
-      }).then(
-          () => {
-            mediaScanner.assertScanCount(1);
-            mediaScanner.assertLastScanCanceled();
-          });
+  const promise = widget.updateResolver.promise
+                      .then(() => {
+                        // Reset the promise so we can wait on a second widget
+                        // update.
+                        widget.resetPromises();
+                        environment.setCurrentDirectory(nonDcimDirectory);
+                        environment.directoryChangedListener(EMPTY_EVENT);
+                      })
+                      .then(() => {
+                        mediaScanner.assertScanCount(1);
+                        mediaScanner.assertLastScanCanceled();
+                      });
 
   reportPromise(promise, callback);
 }
 
 function testWindowClose_CancelsScan(callback) {
   const controller = createController(
-      VolumeManagerCommon.VolumeType.MTP,
-      'mtp-volume',
+      VolumeManagerCommon.VolumeType.MTP, 'mtp-volume',
       [
         '/DCIM/',
         '/DCIM/photos0/',
@@ -179,29 +177,29 @@
         '/DCIM/photos0/IMG00002.jpg',
         '/DCIM/photos1/',
         '/DCIM/photos1/IMG00001.jpg',
-        '/DCIM/photos1/IMG00003.jpg'
+        '/DCIM/photos1/IMG00003.jpg',
       ],
       '/DCIM');
 
   environment.directoryChangedListener(EMPTY_EVENT);
-  const promise = widget.updateResolver.promise.then(
-      () => {
-        // Reset the promise so we can wait on a second widget update.
-        widget.resetPromises();
-        environment.windowCloseListener();
-      }).then(
-          () => {
-            mediaScanner.assertScanCount(1);
-            mediaScanner.assertLastScanCanceled();
-          });
+  const promise = widget.updateResolver.promise
+                      .then(() => {
+                        // Reset the promise so we can wait on a second widget
+                        // update.
+                        widget.resetPromises();
+                        environment.windowCloseListener();
+                      })
+                      .then(() => {
+                        mediaScanner.assertScanCount(1);
+                        mediaScanner.assertLastScanCanceled();
+                      });
 
   reportPromise(promise, callback);
 }
 
 function testDirectoryChange_DetailsPanelVisibility_InitialChangeDir(callback) {
   const controller = createController(
-      VolumeManagerCommon.VolumeType.MTP,
-      'mtp-volume',
+      VolumeManagerCommon.VolumeType.MTP, 'mtp-volume',
       [
         '/DCIM/',
         '/DCIM/photos0/',
@@ -222,25 +220,26 @@
   environment.directoryChangedListener(event);
   assertFalse(widget.detailsVisible);
 
-  const promise = widget.updateResolver.promise.then(() => {
-    // "scanning..."
-    assertFalse(widget.detailsVisible);
-    widget.resetPromises();
-    mediaScanner.finalizeScans();
-    return widget.updateResolver.promise;
-  }).then(() => {
-    // "ready to update"
-    // Details should pop up.
-    assertTrue(widget.detailsVisible);
-  });
+  const promise = widget.updateResolver.promise
+                      .then(() => {
+                        // "scanning..."
+                        assertFalse(widget.detailsVisible);
+                        widget.resetPromises();
+                        mediaScanner.finalizeScans();
+                        return widget.updateResolver.promise;
+                      })
+                      .then(() => {
+                        // "ready to update"
+                        // Details should pop up.
+                        assertTrue(widget.detailsVisible);
+                      });
 
   reportPromise(promise, callback);
 }
 
 function testDirectoryChange_DetailsPanelVisibility_SubsequentChangeDir() {
   const controller = createController(
-      VolumeManagerCommon.VolumeType.MTP,
-      'mtp-volume',
+      VolumeManagerCommon.VolumeType.MTP, 'mtp-volume',
       [
         '/DCIM/',
         '/DCIM/photos0/',
@@ -249,9 +248,8 @@
       '/DCIM');
 
   const event = new Event('directory-changed');
-  event.newDirEntry = new MockDirectoryEntry(
-      new MockFileSystem('testFs'),
-      '/DCIM/');
+  event.newDirEntry =
+      new MockDirectoryEntry(new MockFileSystem('testFs'), '/DCIM/');
 
   // Any previous dir at all will skip the new window logic.
   event.previousDirEntry = event.newDirEntry;
@@ -262,8 +260,7 @@
 
 function testSelectionChange_TriggersUpdate(callback) {
   const controller = createController(
-      VolumeManagerCommon.VolumeType.MTP,
-      'mtp-volume',
+      VolumeManagerCommon.VolumeType.MTP, 'mtp-volume',
       [
         '/DCIM/',
         '/DCIM/photos0/',
@@ -285,8 +282,7 @@
 
 function testFinalizeScans_TriggersUpdate(callback) {
   const controller = createController(
-      VolumeManagerCommon.VolumeType.MTP,
-      'mtp-volume',
+      VolumeManagerCommon.VolumeType.MTP, 'mtp-volume',
       [
         '/DCIM/',
         '/DCIM/photos0/',
@@ -310,8 +306,7 @@
 
 function testClickDestination_ShowsRootPriorToImport(callback) {
   const controller = createController(
-      VolumeManagerCommon.VolumeType.MTP,
-      'mtp-volume',
+      VolumeManagerCommon.VolumeType.MTP, 'mtp-volume',
       [
         '/DCIM/',
         '/DCIM/photos0/',
@@ -325,23 +320,19 @@
 }
 
 function testClickDestination_ShowsDestinationAfterImportStarted(callback) {
-  const promise = startImport(importer.ClickSource.MAIN)
-      .then(
-          () => {
-            return mediaImporter.importResolver.promise.then(
-                () => {
-                  widget.click(importer.ClickSource.DESTINATION);
-                  return environment.showImportDestinationResolver.promise;
-                });
-          });
+  const promise = startImport(importer.ClickSource.MAIN).then(() => {
+    return mediaImporter.importResolver.promise.then(() => {
+      widget.click(importer.ClickSource.DESTINATION);
+      return environment.showImportDestinationResolver.promise;
+    });
+  });
 
   reportPromise(promise, callback);
 }
 
 function startImport(clickSource) {
   const controller = createController(
-      VolumeManagerCommon.VolumeType.MTP,
-      'mtp-volume',
+      VolumeManagerCommon.VolumeType.MTP, 'mtp-volume',
       [
         '/DCIM/',
         '/DCIM/photos0/',
@@ -360,17 +351,15 @@
   // First we need to force the controller into a scanning state.
   environment.directoryChangedListener(EMPTY_EVENT);
 
-  return widget.updateResolver.promise.then(
-      () => {
-        widget.resetPromises();
-        mediaScanner.finalizeScans();
-        return widget.updateResolver.promise.then(
-            () => {
-              widget.resetPromises();
-              widget.click(clickSource);
-              return mediaImporter.importResolver.promise;
-            });
-      });
+  return widget.updateResolver.promise.then(() => {
+    widget.resetPromises();
+    mediaScanner.finalizeScans();
+    return widget.updateResolver.promise.then(() => {
+      widget.resetPromises();
+      widget.click(clickSource);
+      return mediaImporter.importResolver.promise;
+    });
+  });
 }
 
 /**
@@ -543,26 +532,26 @@
 };
 
 /** @override */
-TestControllerEnvironment.prototype.addWindowCloseListener =
-    function(listener) {
+TestControllerEnvironment.prototype.addWindowCloseListener = function(
+    listener) {
   this.windowCloseListener = listener;
 };
 
 /** @override */
-TestControllerEnvironment.prototype.addVolumeUnmountListener =
-    function(listener) {
+TestControllerEnvironment.prototype.addVolumeUnmountListener = function(
+    listener) {
   this.volumeUnmountListener = listener;
 };
 
 /** @override */
-TestControllerEnvironment.prototype.addDirectoryChangedListener =
-    function(listener) {
+TestControllerEnvironment.prototype.addDirectoryChangedListener = function(
+    listener) {
   this.directoryChangedListener = listener;
 };
 
 /** @override */
-TestControllerEnvironment.prototype.addSelectionChangedListener =
-    function(listener) {
+TestControllerEnvironment.prototype.addSelectionChangedListener = function(
+    listener) {
   this.selectionChangedListener = listener;
 };
 
diff --git a/ui/file_manager/file_manager/foreground/js/launch_param.js b/ui/file_manager/file_manager/foreground/js/launch_param.js
index 17990ee..8dc6ee2d 100644
--- a/ui/file_manager/file_manager/foreground/js/launch_param.js
+++ b/ui/file_manager/file_manager/foreground/js/launch_param.js
@@ -33,7 +33,8 @@
    * @const
    */
   this.currentDirectoryURL = unformatted['currentDirectoryURL'] ?
-      unformatted['currentDirectoryURL'] : '';
+      unformatted['currentDirectoryURL'] :
+      '';
 
   /**
    * @type {string}
@@ -72,8 +73,7 @@
    * @type {!SuggestAppDialogState}
    * @const
    */
-  this.suggestAppsDialogState =
-      unformatted['suggestAppsDialogState'] ?
+  this.suggestAppsDialogState = unformatted['suggestAppsDialogState'] ?
       unformatted['suggestAppsDialogState'] :
       {
         overrideCwsContainerUrlForTest: '',
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 37fa07c..0198861f 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
@@ -120,9 +120,9 @@
  * @return {number} Number of prefetch requests.
  * @private
  */
-ListThumbnailLoader.prototype.getNumOfPrefetch_ = function () {
+ListThumbnailLoader.prototype.getNumOfPrefetch_ = function() {
   switch (/** @type {?ListThumbnailLoader.VolumeType} */
-      (this.currentVolumeType_)) {
+          (this.currentVolumeType_)) {
     case VolumeManagerCommon.VolumeType.MTP:
       return 0;
     case ListThumbnailLoader.TEST_VOLUME_TYPE:
@@ -140,7 +140,7 @@
  */
 ListThumbnailLoader.prototype.getNumOfMaxActiveTasks_ = function() {
   switch (/** @type {?ListThumbnailLoader.VolumeType} */
-      (this.currentVolumeType_)) {
+          (this.currentVolumeType_)) {
     case VolumeManagerCommon.VolumeType.MTP:
       return 1;
     case ListThumbnailLoader.TEST_VOLUME_TYPE:
@@ -258,8 +258,7 @@
 
   // If the entry is a directory, already in cache as valid or fetching, skip.
   const thumbnail = this.cache_.get(entry.toURL());
-  if (entry.isDirectory ||
-      (thumbnail && !thumbnail.outdated) ||
+  if (entry.isDirectory || (thumbnail && !thumbnail.outdated) ||
       this.active_[entry.toURL()]) {
     this.cursor_++;
     this.continue_();
@@ -421,53 +420,59 @@
  */
 ListThumbnailLoader.Task.prototype.fetch = function() {
   let ioError = false;
-  return this.thumbnailModel_.get([this.entry_]).then(metadatas => {
-    // When it failed to read exif header with an IO error, do not generate
-    // thumbnail at this time since it may success in the second try. If it
-    // failed to read at 0 byte, it would be an IO error.
-    if (metadatas[0].thumbnail.urlError &&
-        metadatas[0].thumbnail.urlError.errorDescription ===
-            'Error: Unexpected EOF @0') {
-      ioError = true;
-      return Promise.reject();
-    }
-    return metadatas[0];
-  }).then(metadata => {
-    const loadTargets = [
-      ThumbnailLoader.LoadTarget.CONTENT_METADATA,
-      ThumbnailLoader.LoadTarget.EXTERNAL_METADATA
-    ];
+  return this.thumbnailModel_.get([this.entry_])
+      .then(metadatas => {
+        // When it failed to read exif header with an IO error, do not generate
+        // thumbnail at this time since it may success in the second try. If it
+        // failed to read at 0 byte, it would be an IO error.
+        if (metadatas[0].thumbnail.urlError &&
+            metadatas[0].thumbnail.urlError.errorDescription ===
+                'Error: Unexpected EOF @0') {
+          ioError = true;
+          return Promise.reject();
+        }
+        return metadatas[0];
+      })
+      .then(metadata => {
+        const loadTargets = [
+          ThumbnailLoader.LoadTarget.CONTENT_METADATA,
+          ThumbnailLoader.LoadTarget.EXTERNAL_METADATA
+        ];
 
-    // If the file is on a provided file system which is based on network, then
-    // don't generate thumbnails from file entry, as it could cause very high
-    // network traffic.
-    const volumeInfo = this.volumeManager_.getVolumeInfo(this.entry_);
-    if (volumeInfo && (volumeInfo.volumeType !==
-        VolumeManagerCommon.VolumeType.PROVIDED ||
-        volumeInfo.source !== VolumeManagerCommon.Source.NETWORK)) {
-      loadTargets.push(ThumbnailLoader.LoadTarget.FILE_ENTRY);
-    }
+        // If the file is on a provided file system which is based on network,
+        // then don't generate thumbnails from file entry, as it could cause
+        // very high network traffic.
+        const volumeInfo = this.volumeManager_.getVolumeInfo(this.entry_);
+        if (volumeInfo &&
+            (volumeInfo.volumeType !==
+                 VolumeManagerCommon.VolumeType.PROVIDED ||
+             volumeInfo.source !== VolumeManagerCommon.Source.NETWORK)) {
+          loadTargets.push(ThumbnailLoader.LoadTarget.FILE_ENTRY);
+        }
 
-    return new this.thumbnailLoaderConstructor_(
-        this.entry_, ThumbnailLoader.LoaderType.IMAGE, metadata,
-        undefined /* opt_mediaType */, loadTargets)
-        .loadAsDataUrl(ThumbnailLoader.FillMode.OVER_FILL);
-  }).then(result => {
-    return new ListThumbnailLoader.ThumbnailData(
-        this.entry_.toURL(), result.data, result.width, result.height);
-  }).catch(() => {
-    // If an error happens during generating of a thumbnail, then return
-    // an empty object, so we don't retry the thumbnail over and over
-    // again.
-    const thumbnailData = new ListThumbnailLoader.ThumbnailData(
-          this.entry_.toURL(), null, null, null);
-    if (ioError) {
-      // If fetching a thumbnail from EXIF fails due to an IO error, then try to
-      // refetch it in the future, but not earlier than in 3 second.
-      setTimeout(() => {
-        thumbnailData.outdated = true;
-      }, ListThumbnailLoader.Task.EXIF_IO_ERROR_DELAY);
-    }
-    return thumbnailData;
-  });
+        return new this
+            .thumbnailLoaderConstructor_(
+                this.entry_, ThumbnailLoader.LoaderType.IMAGE, metadata,
+                undefined /* opt_mediaType */, loadTargets)
+            .loadAsDataUrl(ThumbnailLoader.FillMode.OVER_FILL);
+      })
+      .then(result => {
+        return new ListThumbnailLoader.ThumbnailData(
+            this.entry_.toURL(), result.data, result.width, result.height);
+      })
+      .catch(() => {
+        // If an error happens during generating of a thumbnail, then return
+        // an empty object, so we don't retry the thumbnail over and over
+        // again.
+        const thumbnailData = new ListThumbnailLoader.ThumbnailData(
+            this.entry_.toURL(), null, null, null);
+        if (ioError) {
+          // If fetching a thumbnail from EXIF fails due to an IO error, then
+          // try to refetch it in the future, but not earlier than in 3 second.
+          setTimeout(() => {
+            thumbnailData.outdated = true;
+          }, ListThumbnailLoader.Task.EXIF_IO_ERROR_DELAY);
+        }
+        return thumbnailData;
+      });
 };
diff --git a/ui/message_center/views/message_view_context_menu_controller.cc b/ui/message_center/views/message_view_context_menu_controller.cc
index 6d738fc..8b043ca 100644
--- a/ui/message_center/views/message_view_context_menu_controller.cc
+++ b/ui/message_center/views/message_view_context_menu_controller.cc
@@ -46,7 +46,7 @@
 
   menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(), NULL,
                           gfx::Rect(point, gfx::Size()),
-                          views::MENU_ANCHOR_TOPRIGHT, source_type);
+                          views::MenuAnchorPosition::kTopRight, source_type);
 }
 
 void MessageViewContextMenuController::OnMenuClosed() {
diff --git a/ui/ozone/common/linux/gbm_device.h b/ui/ozone/common/linux/gbm_device.h
index 29d9e0a..26402f15 100644
--- a/ui/ozone/common/linux/gbm_device.h
+++ b/ui/ozone/common/linux/gbm_device.h
@@ -5,13 +5,14 @@
 #ifndef UI_OZONE_COMMON_LINUX_GBM_DEVICE_H_
 #define UI_OZONE_COMMON_LINUX_GBM_DEVICE_H_
 
+#include <gbm.h>
+#include <memory>
+
 #include "base/files/file.h"
 #include "base/macros.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_pixmap_handle.h"
 
-#include <gbm.h>
-
 namespace ui {
 
 class GbmBuffer;
diff --git a/ui/ozone/common/linux/gbm_wrapper.cc b/ui/ozone/common/linux/gbm_wrapper.cc
index ce05d29..a3313f14 100644
--- a/ui/ozone/common/linux/gbm_wrapper.cc
+++ b/ui/ozone/common/linux/gbm_wrapper.cc
@@ -5,10 +5,8 @@
 #include "ui/ozone/common/linux/gbm_wrapper.h"
 
 #include <gbm.h>
-#if !defined(MINIGBM)
-#include <fcntl.h>
-#include <xf86drm.h>
-#endif
+#include <memory>
+#include <utility>
 
 #include "base/posix/eintr_wrapper.h"
 #include "third_party/skia/include/core/SkSurface.h"
@@ -17,6 +15,11 @@
 #include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/common/linux/gbm_device.h"
 
+#if !defined(MINIGBM)
+#include <fcntl.h>
+#include <xf86drm.h>
+#endif
+
 namespace gbm_wrapper {
 
 namespace {
diff --git a/ui/ozone/common/stub_client_native_pixmap_factory.cc b/ui/ozone/common/stub_client_native_pixmap_factory.cc
index f5b33302..15be9b4 100644
--- a/ui/ozone/common/stub_client_native_pixmap_factory.cc
+++ b/ui/ozone/common/stub_client_native_pixmap_factory.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/macros.h"
 #include "ui/gfx/client_native_pixmap_factory.h"
 
diff --git a/ui/ozone/common/stub_overlay_manager.cc b/ui/ozone/common/stub_overlay_manager.cc
index fd15b4e..3717c71 100644
--- a/ui/ozone/common/stub_overlay_manager.cc
+++ b/ui/ozone/common/stub_overlay_manager.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "ui/ozone/common/stub_overlay_manager.h"
+
+#include <memory>
+
 #include "ui/ozone/public/overlay_candidates_ozone.h"
 
 namespace ui {
diff --git a/ui/ozone/common/stub_overlay_manager.h b/ui/ozone/common/stub_overlay_manager.h
index 48b37770..77199b7 100644
--- a/ui/ozone/common/stub_overlay_manager.h
+++ b/ui/ozone/common/stub_overlay_manager.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_COMMON_STUB_OVERLAY_MANAGER_H_
 #define UI_OZONE_COMMON_STUB_OVERLAY_MANAGER_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "ui/ozone/public/overlay_manager_ozone.h"
 
diff --git a/ui/ozone/demo/demo_window.cc b/ui/ozone/demo/demo_window.cc
index f376744..d21fe30 100644
--- a/ui/ozone/demo/demo_window.cc
+++ b/ui/ozone/demo/demo_window.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/demo/demo_window.h"
 
+#include <utility>
+
 #include "base/threading/thread_task_runner_handle.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/dom/dom_code.h"
diff --git a/ui/ozone/demo/demo_window.h b/ui/ozone/demo/demo_window.h
index a0be6aea..9987837 100644
--- a/ui/ozone/demo/demo_window.h
+++ b/ui/ozone/demo/demo_window.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_DEMO_DEMO_WINDOW_H_
 #define UI_OZONE_DEMO_DEMO_WINDOW_H_
 
+#include <memory>
+
 #include "base/memory/weak_ptr.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
diff --git a/ui/ozone/demo/gl_renderer.cc b/ui/ozone/demo/gl_renderer.cc
index cb285e9..b23df5d 100644
--- a/ui/ozone/demo/gl_renderer.cc
+++ b/ui/ozone/demo/gl_renderer.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/demo/gl_renderer.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/ui/ozone/demo/gl_renderer.h b/ui/ozone/demo/gl_renderer.h
index f0b638c1..38c9ec3 100644
--- a/ui/ozone/demo/gl_renderer.h
+++ b/ui/ozone/demo/gl_renderer.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_DEMO_GL_RENDERER_H_
 #define UI_OZONE_DEMO_GL_RENDERER_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/ui/ozone/demo/ozone_demo.cc b/ui/ozone/demo/ozone_demo.cc
index c27f416..1ca0578c 100644
--- a/ui/ozone/demo/ozone_demo.cc
+++ b/ui/ozone/demo/ozone_demo.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <iostream>
+#include <memory>
 
 #include "base/at_exit.h"
 #include "base/command_line.h"
diff --git a/ui/ozone/demo/renderer_factory.h b/ui/ozone/demo/renderer_factory.h
index a39a3b4..e2fc9a6 100644
--- a/ui/ozone/demo/renderer_factory.h
+++ b/ui/ozone/demo/renderer_factory.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_DEMO_RENDERER_FACTORY_H_
 #define UI_OZONE_DEMO_RENDERER_FACTORY_H_
 
+#include <memory>
+
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
 
diff --git a/ui/ozone/demo/simple_renderer_factory.cc b/ui/ozone/demo/simple_renderer_factory.cc
index 043583c..8537ed0 100644
--- a/ui/ozone/demo/simple_renderer_factory.cc
+++ b/ui/ozone/demo/simple_renderer_factory.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/demo/simple_renderer_factory.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/command_line.h"
 #include "ui/gl/gl_surface.h"
diff --git a/ui/ozone/demo/simple_renderer_factory.h b/ui/ozone/demo/simple_renderer_factory.h
index c28a2ab..3e4e04e 100644
--- a/ui/ozone/demo/simple_renderer_factory.h
+++ b/ui/ozone/demo/simple_renderer_factory.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_DEMO_SIMPLE_RENDERER_FACTORY_H_
 #define UI_OZONE_DEMO_SIMPLE_RENDERER_FACTORY_H_
 
+#include <memory>
+
 #include "gpu/vulkan/buildflags.h"
 #include "ui/ozone/demo/renderer_factory.h"
 #include "ui/ozone/public/ozone_gpu_test_helper.h"
diff --git a/ui/ozone/demo/skia/skia_demo.cc b/ui/ozone/demo/skia/skia_demo.cc
index 98ac14f..053eead 100644
--- a/ui/ozone/demo/skia/skia_demo.cc
+++ b/ui/ozone/demo/skia/skia_demo.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <iostream>
+#include <memory>
 
 #include "base/at_exit.h"
 #include "base/command_line.h"
diff --git a/ui/ozone/demo/skia/skia_gl_renderer.cc b/ui/ozone/demo/skia/skia_gl_renderer.cc
index ad3b596..69b3851 100644
--- a/ui/ozone/demo/skia/skia_gl_renderer.cc
+++ b/ui/ozone/demo/skia/skia_gl_renderer.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/demo/skia/skia_gl_renderer.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/location.h"
diff --git a/ui/ozone/demo/skia/skia_gl_renderer.h b/ui/ozone/demo/skia/skia_gl_renderer.h
index 9419a25..15b818c 100644
--- a/ui/ozone/demo/skia/skia_gl_renderer.h
+++ b/ui/ozone/demo/skia/skia_gl_renderer.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_DEMO_SKIA_SKIA_GL_RENDERER_H_
 #define UI_OZONE_DEMO_SKIA_SKIA_GL_RENDERER_H_
 
+#include <memory>
+
 #include "base/containers/queue.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
diff --git a/ui/ozone/demo/skia/skia_renderer_factory.cc b/ui/ozone/demo/skia/skia_renderer_factory.cc
index b1037fc..f6062b87b 100644
--- a/ui/ozone/demo/skia/skia_renderer_factory.cc
+++ b/ui/ozone/demo/skia/skia_renderer_factory.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/demo/skia/skia_renderer_factory.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/command_line.h"
 #include "ui/gl/gl_surface.h"
diff --git a/ui/ozone/demo/skia/skia_renderer_factory.h b/ui/ozone/demo/skia/skia_renderer_factory.h
index bd14c35..524bbea7 100644
--- a/ui/ozone/demo/skia/skia_renderer_factory.h
+++ b/ui/ozone/demo/skia/skia_renderer_factory.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_DEMO_SKIA_SKIA_RENDERER_FACTORY_H_
 #define UI_OZONE_DEMO_SKIA_SKIA_RENDERER_FACTORY_H_
 
+#include <memory>
+
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/ozone/demo/renderer_factory.h"
diff --git a/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc b/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
index ad361f1..91ff3c6a 100644
--- a/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
+++ b/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
@@ -5,6 +5,8 @@
 #include "ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h"
 
 #include <stddef.h>
+#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
diff --git a/ui/ozone/demo/software_renderer.cc b/ui/ozone/demo/software_renderer.cc
index 232cc67..44e6330 100644
--- a/ui/ozone/demo/software_renderer.cc
+++ b/ui/ozone/demo/software_renderer.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/demo/software_renderer.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/skia/include/core/SkCanvas.h"
diff --git a/ui/ozone/demo/surfaceless_gl_renderer.cc b/ui/ozone/demo/surfaceless_gl_renderer.cc
index 4974172..7c7751f4 100644
--- a/ui/ozone/demo/surfaceless_gl_renderer.cc
+++ b/ui/ozone/demo/surfaceless_gl_renderer.cc
@@ -5,6 +5,8 @@
 #include "ui/ozone/demo/surfaceless_gl_renderer.h"
 
 #include <stddef.h>
+#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
diff --git a/ui/ozone/demo/vulkan_overlay_renderer.cc b/ui/ozone/demo/vulkan_overlay_renderer.cc
index 5a544c5..ef9edb3 100644
--- a/ui/ozone/demo/vulkan_overlay_renderer.cc
+++ b/ui/ozone/demo/vulkan_overlay_renderer.cc
@@ -5,6 +5,8 @@
 #include "ui/ozone/demo/vulkan_overlay_renderer.h"
 
 #include <vulkan/vulkan.h>
+#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/location.h"
diff --git a/ui/ozone/demo/vulkan_overlay_renderer.h b/ui/ozone/demo/vulkan_overlay_renderer.h
index cc06e66c..c0e4d9a9 100644
--- a/ui/ozone/demo/vulkan_overlay_renderer.h
+++ b/ui/ozone/demo/vulkan_overlay_renderer.h
@@ -6,6 +6,7 @@
 #define UI_OZONE_DEMO_VULKAN_OVERLAY_RENDERER_H_
 
 #include <vulkan/vulkan.h>
+#include <memory>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
diff --git a/ui/ozone/demo/vulkan_renderer.cc b/ui/ozone/demo/vulkan_renderer.cc
index 80dc756..106a88c 100644
--- a/ui/ozone/demo/vulkan_renderer.cc
+++ b/ui/ozone/demo/vulkan_renderer.cc
@@ -5,6 +5,8 @@
 #include "ui/ozone/demo/vulkan_renderer.h"
 
 #include <vulkan/vulkan.h>
+#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/location.h"
diff --git a/ui/ozone/demo/vulkan_renderer.h b/ui/ozone/demo/vulkan_renderer.h
index 9432932..b340f14b 100644
--- a/ui/ozone/demo/vulkan_renderer.h
+++ b/ui/ozone/demo/vulkan_renderer.h
@@ -6,6 +6,7 @@
 #define UI_OZONE_DEMO_VULKAN_RENDERER_H_
 
 #include <vulkan/vulkan.h>
+#include <memory>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
diff --git a/ui/ozone/demo/window_manager.cc b/ui/ozone/demo/window_manager.cc
index 219e907..ffea585 100644
--- a/ui/ozone/demo/window_manager.cc
+++ b/ui/ozone/demo/window_manager.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/demo/window_manager.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/ui/ozone/demo/window_manager.h b/ui/ozone/demo/window_manager.h
index ae96df0b..a31b01d 100644
--- a/ui/ozone/demo/window_manager.h
+++ b/ui/ozone/demo/window_manager.h
@@ -5,6 +5,7 @@
 #ifndef UI_OZONE_DEMO_WINDOW_MANAGER_H_
 #define UI_OZONE_DEMO_WINDOW_MANAGER_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/callback.h"
diff --git a/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc b/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
index 532b040..f66e5e9 100644
--- a/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
+++ b/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include <stdint.h>
-
 #include <memory>
 
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc b/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
index 60c79d0..36fc30b 100644
--- a/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
+++ b/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/cast/client_native_pixmap_factory_cast.h"
 
+#include <memory>
+
 #include "base/logging.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/client_native_pixmap.h"
diff --git a/ui/ozone/platform/cast/gl_ozone_egl_cast.cc b/ui/ozone/platform/cast/gl_ozone_egl_cast.cc
index 6e560e1b..446afea 100644
--- a/ui/ozone/platform/cast/gl_ozone_egl_cast.cc
+++ b/ui/ozone/platform/cast/gl_ozone_egl_cast.cc
@@ -6,7 +6,7 @@
 
 #include <EGL/egl.h>
 #include <dlfcn.h>
-
+#include <memory>
 #include <utility>
 
 #include "base/command_line.h"
diff --git a/ui/ozone/platform/cast/gl_ozone_egl_cast.h b/ui/ozone/platform/cast/gl_ozone_egl_cast.h
index 6a4a1c7..ace0cbc 100644
--- a/ui/ozone/platform/cast/gl_ozone_egl_cast.h
+++ b/ui/ozone/platform/cast/gl_ozone_egl_cast.h
@@ -6,7 +6,6 @@
 #define UI_OZONE_PLATFORM_CAST_GL_OZONE_EGL_CAST_H_
 
 #include <stdint.h>
-
 #include <memory>
 
 #include "base/macros.h"
diff --git a/ui/ozone/platform/cast/gl_surface_cast.cc b/ui/ozone/platform/cast/gl_surface_cast.cc
index 3378fd0..d76bfac 100644
--- a/ui/ozone/platform/cast/gl_surface_cast.cc
+++ b/ui/ozone/platform/cast/gl_surface_cast.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/cast/gl_surface_cast.h"
 
+#include <memory>
 #include <string>
 #include <utility>
 
diff --git a/ui/ozone/platform/cast/gl_surface_cast.h b/ui/ozone/platform/cast/gl_surface_cast.h
index e8d88a6f..e294802 100644
--- a/ui/ozone/platform/cast/gl_surface_cast.h
+++ b/ui/ozone/platform/cast/gl_surface_cast.h
@@ -5,6 +5,7 @@
 #ifndef UI_OZONE_PLATFORM_CAST_GL_SURFACE_CAST_H_
 #define UI_OZONE_PLATFORM_CAST_GL_SURFACE_CAST_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
diff --git a/ui/ozone/platform/cast/overlay_manager_cast.cc b/ui/ozone/platform/cast/overlay_manager_cast.cc
index 6a34f69..940ac23 100644
--- a/ui/ozone/platform/cast/overlay_manager_cast.cc
+++ b/ui/ozone/platform/cast/overlay_manager_cast.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/cast/overlay_manager_cast.h"
 
+#include <memory>
+
 #include "ui/ozone/public/overlay_candidates_ozone.h"
 
 namespace ui {
diff --git a/ui/ozone/platform/cast/ozone_platform_cast.cc b/ui/ozone/platform/cast/ozone_platform_cast.cc
index 594d0e63..5a6d635 100644
--- a/ui/ozone/platform/cast/ozone_platform_cast.cc
+++ b/ui/ozone/platform/cast/ozone_platform_cast.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/cast/ozone_platform_cast.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/command_line.h"
diff --git a/ui/ozone/platform/cast/surface_factory_cast.cc b/ui/ozone/platform/cast/surface_factory_cast.cc
index 3bca913..107e11a 100644
--- a/ui/ozone/platform/cast/surface_factory_cast.cc
+++ b/ui/ozone/platform/cast/surface_factory_cast.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/cast/surface_factory_cast.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/macros.h"
diff --git a/ui/ozone/platform/drm/common/display_types.h b/ui/ozone/platform/drm/common/display_types.h
index da8b5c0..c7cb3ef 100644
--- a/ui/ozone/platform/drm/common/display_types.h
+++ b/ui/ozone/platform/drm/common/display_types.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_DRM_COMMON_DISPLAY_TYPES_H_
 #define UI_OZONE_PLATFORM_DRM_COMMON_DISPLAY_TYPES_H_
 
+#include <memory>
+
 namespace display {
 class DisplaySnapshot;
 }  // namespace display
@@ -16,4 +18,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_DRM_COMMON_DISPLAY_TYPES_H_
\ No newline at end of file
+#endif  // UI_OZONE_PLATFORM_DRM_COMMON_DISPLAY_TYPES_H_
diff --git a/ui/ozone/platform/drm/common/drm_overlay_manager.cc b/ui/ozone/platform/drm/common/drm_overlay_manager.cc
index 959e0bcd3..57cefd0 100644
--- a/ui/ozone/platform/drm/common/drm_overlay_manager.cc
+++ b/ui/ozone/platform/drm/common/drm_overlay_manager.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/drm/common/drm_overlay_manager.h"
 
 #include <algorithm>
+#include <memory>
 #include <utility>
 
 #include "base/trace_event/trace_event.h"
diff --git a/ui/ozone/platform/drm/common/drm_util.cc b/ui/ozone/platform/drm/common/drm_util.cc
index 76a6caf..dd9d0f74 100644
--- a/ui/ozone/platform/drm/common/drm_util.cc
+++ b/ui/ozone/platform/drm/common/drm_util.cc
@@ -11,6 +11,7 @@
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 #include <algorithm>
+#include <memory>
 #include <utility>
 
 #include "base/containers/flat_map.h"
diff --git a/ui/ozone/platform/drm/common/drm_util.h b/ui/ozone/platform/drm/common/drm_util.h
index e70c23a8..c46941ff 100644
--- a/ui/ozone/platform/drm/common/drm_util.h
+++ b/ui/ozone/platform/drm/common/drm_util.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "base/files/file_path.h"
diff --git a/ui/ozone/platform/drm/gpu/crtc_controller.cc b/ui/ozone/platform/drm/gpu/crtc_controller.cc
index aea5c91..d23d0dd6 100644
--- a/ui/ozone/platform/drm/gpu/crtc_controller.cc
+++ b/ui/ozone/platform/drm/gpu/crtc_controller.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
 
+#include <memory>
+
 #include "base/logging.h"
 #include "base/time/time.h"
 #include "ui/gfx/presentation_feedback.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_device.cc b/ui/ozone/platform/drm/gpu/drm_device.cc
index 313bf2df..11b699e 100644
--- a/ui/ozone/platform/drm/gpu/drm_device.cc
+++ b/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -9,6 +9,7 @@
 #include <unistd.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_device.h b/ui/ozone/platform/drm/gpu/drm_device.h
index 1e62f189..d5ef13b 100644
--- a/ui/ozone/platform/drm/gpu/drm_device.h
+++ b/ui/ozone/platform/drm/gpu/drm_device.h
@@ -7,7 +7,7 @@
 
 #include <stddef.h>
 #include <stdint.h>
-
+#include <memory>
 #include <vector>
 
 #include "base/callback.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_device_manager.cc b/ui/ozone/platform/drm/gpu/drm_device_manager.cc
index 6b3214a..5d879fa 100644
--- a/ui/ozone/platform/drm/gpu/drm_device_manager.cc
+++ b/ui/ozone/platform/drm/gpu/drm_device_manager.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/file_descriptor_posix.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_display.cc b/ui/ozone/platform/drm/gpu/drm_display.cc
index f800442..f5bf25f 100644
--- a/ui/ozone/platform/drm/gpu/drm_display.cc
+++ b/ui/ozone/platform/drm/gpu/drm_display.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/drm/gpu/drm_display.h"
 
 #include <xf86drmMode.h>
+#include <memory>
 
 #include "base/stl_util.h"
 #include "ui/display/types/display_snapshot.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_display.h b/ui/ozone/platform/drm/gpu/drm_display.h
index 16f2dae..d0f5911 100644
--- a/ui/ozone/platform/drm/gpu/drm_display.h
+++ b/ui/ozone/platform/drm/gpu/drm_display.h
@@ -7,7 +7,7 @@
 
 #include <stddef.h>
 #include <stdint.h>
-
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_framebuffer.cc b/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
index b632257..e348da1 100644
--- a/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
+++ b/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
 
+#include <utility>
+
 #include "ui/ozone/common/linux/drm_util_linux.h"
 #include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/platform/drm/common/drm_util.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
index 232ae76..8ce4812 100644
--- a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
@@ -5,6 +5,8 @@
 #include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h"
 
 #include <stddef.h>
+#include <memory>
+#include <utility>
 
 #include "ui/display/types/display_mode.h"
 #include "ui/display/types/display_snapshot.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
index 4a7669fa..40d71dea 100644
--- a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
@@ -6,7 +6,6 @@
 #define UI_OZONE_PLATFORM_DRM_GPU_DRM_GPU_DISPLAY_MANAGER_H_
 
 #include <stdint.h>
-
 #include <memory>
 #include <vector>
 
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_plane.cc b/ui/ozone/platform/drm/gpu/drm_overlay_plane.cc
index 87fa16d..72a00b7d 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_plane.cc
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_plane.cc
@@ -5,6 +5,8 @@
 #include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
 
 #include <stddef.h>
+#include <memory>
+#include <utility>
 
 #include "ui/gfx/gpu_fence.h"
 #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_plane.h b/ui/ozone/platform/drm/gpu/drm_overlay_plane.h
index e0dcf10..1e25e55a 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_plane.h
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_plane.h
@@ -5,6 +5,7 @@
 #ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_PLANE_H_
 #define UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_PLANE_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/bind.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc b/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
index ea0947a..d0fe454 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
@@ -5,6 +5,8 @@
 #include "ui/ozone/platform/drm/gpu/drm_overlay_validator.h"
 
 #include <drm_fourcc.h>
+#include <memory>
+#include <utility>
 
 #include "base/files/platform_file.h"
 #include "ui/gfx/geometry/size_conversions.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
index 7aa4285..2f78b21 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
@@ -5,7 +5,6 @@
 #include "ui/ozone/platform/drm/gpu/drm_overlay_validator.h"
 
 #include <drm_fourcc.h>
-
 #include <memory>
 #include <utility>
 
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.cc b/ui/ozone/platform/drm/gpu/drm_thread.cc
index 42cea80..3b53a0d 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/drm/gpu/drm_thread.h"
 
 #include <gbm.h>
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.h b/ui/ozone/platform/drm/gpu/drm_thread.h
index 47f0937..fb9b070c 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.h
+++ b/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -6,7 +6,6 @@
 #define UI_OZONE_PLATFORM_DRM_GPU_DRM_THREAD_H_
 
 #include <stdint.h>
-
 #include <memory>
 
 #include "base/files/file.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc b/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc
index cf65c7bedb..ece302ba 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/drm/gpu/drm_thread_message_proxy.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/task_runner_util.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
index 6b0f4b8..aa18dd98 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_window.cc b/ui/ozone/platform/drm/gpu/drm_window.cc
index c2aadb9..99688b5 100644
--- a/ui/ozone/platform/drm/gpu/drm_window.cc
+++ b/ui/ozone/platform/drm/gpu/drm_window.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include <utility>
 
 #include "base/macros.h"
 #include "base/time/time.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_window.h b/ui/ozone/platform/drm/gpu/drm_window.h
index ad34c45..f0fbdb1 100644
--- a/ui/ozone/platform/drm/gpu/drm_window.h
+++ b/ui/ozone/platform/drm/gpu/drm_window.h
@@ -5,6 +5,7 @@
 #ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_WINDOW_H_
 #define UI_OZONE_PLATFORM_DRM_GPU_DRM_WINDOW_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_window_proxy.cc b/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
index 8f06b91..45ed5b6 100644
--- a/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
+++ b/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "ui/gfx/gpu_fence.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_window_unittest.cc b/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
index 94233bc5..b2a0144 100644
--- a/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
@@ -6,7 +6,6 @@
 
 #include <drm_fourcc.h>
 #include <stdint.h>
-
 #include <memory>
 #include <utility>
 #include <vector>
diff --git a/ui/ozone/platform/drm/gpu/gbm_overlay_surface.cc b/ui/ozone/platform/drm/gpu/gbm_overlay_surface.cc
index d8f6f57..fecf60e5 100644
--- a/ui/ozone/platform/drm/gpu/gbm_overlay_surface.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_overlay_surface.cc
@@ -5,6 +5,8 @@
 #include "ui/ozone/platform/drm/gpu/gbm_overlay_surface.h"
 
 #include <unistd.h>
+#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
diff --git a/ui/ozone/platform/drm/gpu/gbm_pixmap.cc b/ui/ozone/platform/drm/gpu/gbm_pixmap.cc
index 17463810..2d80356 100644
--- a/ui/ozone/platform/drm/gpu/gbm_pixmap.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_pixmap.cc
@@ -5,6 +5,8 @@
 #include "ui/ozone/platform/drm/gpu/gbm_pixmap.h"
 
 #include <gbm.h>
+#include <memory>
+#include <utility>
 
 #include "base/logging.h"
 #include "ui/gfx/gpu_fence.h"
diff --git a/ui/ozone/platform/drm/gpu/gbm_pixmap.h b/ui/ozone/platform/drm/gpu/gbm_pixmap.h
index 6646759..60c856c 100644
--- a/ui/ozone/platform/drm/gpu/gbm_pixmap.h
+++ b/ui/ozone/platform/drm/gpu/gbm_pixmap.h
@@ -5,6 +5,7 @@
 #ifndef UI_OZONE_PLATFORM_DRM_GPU_GBM_BUFFER_H_
 #define UI_OZONE_PLATFORM_DRM_GPU_GBM_BUFFER_H_
 
+#include <memory>
 #include <vector>
 
 #include "ui/gfx/native_pixmap.h"
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
index 55a2d8f..1e4fa9cc 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -5,7 +5,7 @@
 #include "ui/ozone/platform/drm/gpu/gbm_surface_factory.h"
 
 #include <gbm.h>
-
+#include <memory>
 #include <utility>
 
 #include "base/files/file_path.h"
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
index 028a168..5d4c822 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
@@ -6,7 +6,6 @@
 #define UI_OZONE_PLATFORM_DRM_GPU_GBM_SURFACE_FACTORY_H_
 
 #include <stdint.h>
-
 #include <map>
 #include <memory>
 #include <vector>
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 66d000a..67b9843 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/drm/gpu/gbm_surfaceless.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
index 8dbb15c..828f2e44 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -7,6 +7,7 @@
 #include <drm.h>
 #include <string.h>
 #include <xf86drm.h>
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.h b/ui/ozone/platform/drm/gpu/hardware_display_controller.h
index 1031f12..7e6cb787 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_controller.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.h
@@ -8,7 +8,6 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <xf86drmMode.h>
-
 #include <map>
 #include <memory>
 #include <unordered_map>
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc b/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
index 28c210a..d5ba180f3 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
@@ -5,6 +5,8 @@
 #include <drm_fourcc.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/macros.h"
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
index bb8799b..35eb919b 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
@@ -5,8 +5,8 @@
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
 
 #include <drm_fourcc.h>
-
 #include <algorithm>
+#include <memory>
 #include <set>
 #include <utility>
 
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
index 45cd06c..f68e178 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <xf86drmMode.h>
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
index c1868d0f9..ae429e6 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
@@ -7,6 +7,8 @@
 #include <sync/sync.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
+#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/files/platform_file.h"
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
index b319614..c259643 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
@@ -6,6 +6,7 @@
 #define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_ATOMIC_H_
 
 #include <stdint.h>
+#include <memory>
 
 #include "base/macros.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
index 498aec5..136f991 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.cc
@@ -6,6 +6,8 @@
 
 #include <errno.h>
 #include <sync/sync.h>
+#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/posix/eintr_wrapper.h"
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
index a40413f..3843560 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
@@ -6,6 +6,7 @@
 #define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_MANAGER_LEGACY_H_
 
 #include <stdint.h>
+#include <memory>
 
 #include "base/macros.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
index 8c2a3d2..cfd0930 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
@@ -5,8 +5,8 @@
 #include <drm_fourcc.h>
 #include <stdint.h>
 #include <unistd.h>
-
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_device.cc b/ui/ozone/platform/drm/gpu/mock_drm_device.cc
index e9dfffb..38cc4f3 100644
--- a/ui/ozone/platform/drm/gpu/mock_drm_device.cc
+++ b/ui/ozone/platform/drm/gpu/mock_drm_device.cc
@@ -5,6 +5,8 @@
 #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
 
 #include <xf86drm.h>
+#include <memory>
+#include <utility>
 
 #include "base/logging.h"
 #include "base/stl_util.h"
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_device.h b/ui/ozone/platform/drm/gpu/mock_drm_device.h
index 64279da..ab824d5 100644
--- a/ui/ozone/platform/drm/gpu/mock_drm_device.h
+++ b/ui/ozone/platform/drm/gpu/mock_drm_device.h
@@ -8,8 +8,8 @@
 #include <drm_mode.h>
 #include <stddef.h>
 #include <stdint.h>
-
 #include <map>
+#include <memory>
 #include <set>
 #include <vector>
 
diff --git a/ui/ozone/platform/drm/gpu/mock_gbm_device.cc b/ui/ozone/platform/drm/gpu/mock_gbm_device.cc
index 713478e2..20d6f1f 100644
--- a/ui/ozone/platform/drm/gpu/mock_gbm_device.cc
+++ b/ui/ozone/platform/drm/gpu/mock_gbm_device.cc
@@ -6,6 +6,8 @@
 
 #include <drm_fourcc.h>
 #include <xf86drm.h>
+#include <memory>
+#include <utility>
 
 #include "base/logging.h"
 #include "base/numerics/safe_math.h"
diff --git a/ui/ozone/platform/drm/gpu/page_flip_request.cc b/ui/ozone/platform/drm/gpu/page_flip_request.cc
index 7f37668f..b863742b 100644
--- a/ui/ozone/platform/drm/gpu/page_flip_request.cc
+++ b/ui/ozone/platform/drm/gpu/page_flip_request.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/drm/gpu/page_flip_request.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "ui/gfx/presentation_feedback.h"
 
diff --git a/ui/ozone/platform/drm/gpu/proxy_helpers.cc b/ui/ozone/platform/drm/gpu/proxy_helpers.cc
index 72dca98..603b3bc 100644
--- a/ui/ozone/platform/drm/gpu/proxy_helpers.cc
+++ b/ui/ozone/platform/drm/gpu/proxy_helpers.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/drm/gpu/proxy_helpers.h"
 
+#include <utility>
+
 #include "base/synchronization/waitable_event.h"
 
 namespace ui {
diff --git a/ui/ozone/platform/drm/gpu/proxy_helpers.h b/ui/ozone/platform/drm/gpu/proxy_helpers.h
index 8f7c326..b0d8a52 100644
--- a/ui/ozone/platform/drm/gpu/proxy_helpers.h
+++ b/ui/ozone/platform/drm/gpu/proxy_helpers.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_DRM_GPU_PROXY_HELPERS_H_
 #define UI_OZONE_PLATFORM_DRM_GPU_PROXY_HELPERS_H_
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
diff --git a/ui/ozone/platform/drm/gpu/proxy_helpers_unittest.cc b/ui/ozone/platform/drm/gpu/proxy_helpers_unittest.cc
index 9831443..b96b390 100644
--- a/ui/ozone/platform/drm/gpu/proxy_helpers_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/proxy_helpers_unittest.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/platform/drm/gpu/proxy_helpers.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.cc b/ui/ozone/platform/drm/gpu/screen_manager.cc
index 5fe1773..894283b 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager.cc
+++ b/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -5,7 +5,7 @@
 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
 
 #include <xf86drmMode.h>
-
+#include <memory>
 #include <utility>
 
 #include "base/files/platform_file.h"
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.h b/ui/ozone/platform/drm/gpu/screen_manager.h
index e5c2760d..9b1aeb2e 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager.h
+++ b/ui/ozone/platform/drm/gpu/screen_manager.h
@@ -6,7 +6,7 @@
 #define UI_OZONE_PLATFORM_DRM_GPU_SCREEN_MANAGER_H_
 
 #include <stdint.h>
-
+#include <memory>
 #include <unordered_map>
 
 #include "base/macros.h"
diff --git a/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc b/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
index 4deec5b..c4d137db 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
@@ -5,7 +5,7 @@
 #include <drm_fourcc.h>
 #include <stddef.h>
 #include <stdint.h>
-
+#include <memory>
 #include <utility>
 
 #include "base/bind_helpers.h"
diff --git a/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc b/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
index 21e13af..6564a885 100644
--- a/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
+++ b/ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h"
 
+#include <memory>
+
 #include "base/files/file_path.h"
 #include "base/native_library.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
diff --git a/ui/ozone/platform/drm/host/drm_cursor.cc b/ui/ozone/platform/drm/host/drm_cursor.cc
index 3b8e789..8e420a59 100644
--- a/ui/ozone/platform/drm/host/drm_cursor.cc
+++ b/ui/ozone/platform/drm/host/drm_cursor.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/platform/drm/host/drm_cursor.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/trace_event/trace_event.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/ozone/platform/drm/host/drm_window_host.h"
diff --git a/ui/ozone/platform/drm/host/drm_device_connector.cc b/ui/ozone/platform/drm/host/drm_device_connector.cc
index 2da65e7..d207dbe1 100644
--- a/ui/ozone/platform/drm/host/drm_device_connector.cc
+++ b/ui/ozone/platform/drm/host/drm_device_connector.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/drm/host/drm_device_connector.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/system/message_pipe.h"
diff --git a/ui/ozone/platform/drm/host/drm_display_host.cc b/ui/ozone/platform/drm/host/drm_display_host.cc
index 78271ca..a0bcdbc 100644
--- a/ui/ozone/platform/drm/host/drm_display_host.cc
+++ b/ui/ozone/platform/drm/host/drm_display_host.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/platform/drm/host/drm_display_host.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
index d339e42..666b731 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.cc
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -7,7 +7,7 @@
 #include <fcntl.h>
 #include <stddef.h>
 #include <xf86drm.h>
-
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.h b/ui/ozone/platform/drm/host/drm_display_host_manager.h
index 50fc27d9..2d211b0 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.h
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.h
@@ -6,7 +6,6 @@
 #define UI_OZONE_PLATFORM_DRM_HOST_DRM_DISPLAY_HOST_MANAGER_H_
 
 #include <stdint.h>
-
 #include <map>
 #include <memory>
 
diff --git a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
index e4677fb81..4e353fb4 100644
--- a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
+++ b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
 
 #include <stddef.h>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/command_line.h"
diff --git a/ui/ozone/platform/drm/host/drm_native_display_delegate.cc b/ui/ozone/platform/drm/host/drm_native_display_delegate.cc
index 61d507f1..54ecf76 100644
--- a/ui/ozone/platform/drm/host/drm_native_display_delegate.cc
+++ b/ui/ozone/platform/drm/host/drm_native_display_delegate.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/drm/host/drm_native_display_delegate.h"
 
+#include <utility>
+
 #include "ui/display/types/display_snapshot.h"
 #include "ui/display/types/native_display_observer.h"
 #include "ui/ozone/platform/drm/host/drm_display_host.h"
diff --git a/ui/ozone/platform/drm/host/host_cursor_proxy.cc b/ui/ozone/platform/drm/host/host_cursor_proxy.cc
index 2a6e342..766980d 100644
--- a/ui/ozone/platform/drm/host/host_cursor_proxy.cc
+++ b/ui/ozone/platform/drm/host/host_cursor_proxy.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/drm/host/host_cursor_proxy.h"
 
+#include <utility>
+
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/ws/public/mojom/constants.mojom.h"
 #include "ui/ozone/public/gpu_platform_support_host.h"
diff --git a/ui/ozone/platform/drm/host/host_drm_device.cc b/ui/ozone/platform/drm/host/host_drm_device.cc
index a82b7e9c..4ff514f 100644
--- a/ui/ozone/platform/drm/host/host_drm_device.cc
+++ b/ui/ozone/platform/drm/host/host_drm_device.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/platform/drm/host/host_drm_device.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
diff --git a/ui/ozone/platform/drm/host/host_drm_device.h b/ui/ozone/platform/drm/host/host_drm_device.h
index 30f61c1..7c518779 100644
--- a/ui/ozone/platform/drm/host/host_drm_device.h
+++ b/ui/ozone/platform/drm/host/host_drm_device.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_DRM_HOST_HOST_DRM_DEVICE_H_
 #define UI_OZONE_PLATFORM_DRM_HOST_HOST_DRM_DEVICE_H_
 
+#include <memory>
+
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc
index bdaa1a2..858c141 100644
--- a/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -7,7 +7,6 @@
 #include <gbm.h>
 #include <stdlib.h>
 #include <xf86drm.h>
-
 #include <memory>
 #include <utility>
 
diff --git a/ui/ozone/platform/headless/headless_native_display_delegate.cc b/ui/ozone/platform/headless/headless_native_display_delegate.cc
index a4ca1d32..adb1175 100644
--- a/ui/ozone/platform/headless/headless_native_display_delegate.cc
+++ b/ui/ozone/platform/headless/headless_native_display_delegate.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/platform/headless/headless_native_display_delegate.h"
 
+#include <memory>
+#include <utility>
+
 #include "ui/display/types/display_snapshot.h"
 #include "ui/display/types/native_display_observer.h"
 
diff --git a/ui/ozone/platform/headless/headless_native_display_delegate.h b/ui/ozone/platform/headless/headless_native_display_delegate.h
index 37ac5ba..1cd9402a 100644
--- a/ui/ozone/platform/headless/headless_native_display_delegate.h
+++ b/ui/ozone/platform/headless/headless_native_display_delegate.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_HEADLESS_HEADLESS_NATIVE_DISPLAY_DELEGATE_H_
 #define UI_OZONE_PLATFORM_HEADLESS_HEADLESS_NATIVE_DISPLAY_DELEGATE_H_
 
+#include <memory>
+
 #include "base/observer_list.h"
 #include "ui/display/types/native_display_delegate.h"
 
diff --git a/ui/ozone/platform/headless/headless_surface_factory.cc b/ui/ozone/platform/headless/headless_surface_factory.cc
index d1ef15f..3c3a0b75 100644
--- a/ui/ozone/platform/headless/headless_surface_factory.cc
+++ b/ui/ozone/platform/headless/headless_surface_factory.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/headless/headless_surface_factory.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
diff --git a/ui/ozone/platform/headless/ozone_platform_headless.cc b/ui/ozone/platform/headless/ozone_platform_headless.cc
index 3e22233..85279dd 100644
--- a/ui/ozone/platform/headless/ozone_platform_headless.cc
+++ b/ui/ozone/platform/headless/ozone_platform_headless.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/headless/ozone_platform_headless.h"
 
+#include <memory>
+
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
diff --git a/ui/ozone/platform/magma/ozone_platform_magma.cc b/ui/ozone/platform/magma/ozone_platform_magma.cc
index f5467a4..40c6b82 100644
--- a/ui/ozone/platform/magma/ozone_platform_magma.cc
+++ b/ui/ozone/platform/magma/ozone_platform_magma.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/magma/ozone_platform_magma.h"
 
+#include <memory>
+
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
diff --git a/ui/ozone/platform/scenic/scenic_gpu_host.cc b/ui/ozone/platform/scenic/scenic_gpu_host.cc
index 758de96..9e9925e 100644
--- a/ui/ozone/platform/scenic/scenic_gpu_host.cc
+++ b/ui/ozone/platform/scenic/scenic_gpu_host.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/scenic/scenic_gpu_host.h"
 
 #include <inttypes.h>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
diff --git a/ui/ozone/platform/scenic/scenic_surface_factory.cc b/ui/ozone/platform/scenic/scenic_surface_factory.cc
index 8187064..f559780 100644
--- a/ui/ozone/platform/scenic/scenic_surface_factory.cc
+++ b/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/scenic/scenic_surface_factory.h"
 
 #include <lib/zx/event.h>
+#include <memory>
 
 #include "base/bind.h"
 #include "base/fuchsia/fuchsia_logging.h"
diff --git a/ui/ozone/platform/scenic/scenic_window_canvas.cc b/ui/ozone/platform/scenic/scenic_window_canvas.cc
index 1559148..9f8d43e3d 100644
--- a/ui/ozone/platform/scenic/scenic_window_canvas.cc
+++ b/ui/ozone/platform/scenic/scenic_window_canvas.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/scenic/scenic_window_canvas.h"
 
+#include <memory>
+
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/memory/writable_shared_memory_region.h"
diff --git a/ui/ozone/platform/scenic/scenic_window_canvas.h b/ui/ozone/platform/scenic/scenic_window_canvas.h
index f385a96..237e621a 100644
--- a/ui/ozone/platform/scenic/scenic_window_canvas.h
+++ b/ui/ozone/platform/scenic/scenic_window_canvas.h
@@ -6,6 +6,7 @@
 #define UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_CANVAS_H_
 
 #include <lib/ui/scenic/cpp/resources.h>
+#include <memory>
 
 #include "base/macros.h"
 #include "base/memory/shared_memory_mapping.h"
diff --git a/ui/ozone/platform/scenic/scenic_window_manager.cc b/ui/ozone/platform/scenic/scenic_window_manager.cc
index aeabc0ee..da55cee 100644
--- a/ui/ozone/platform/scenic/scenic_window_manager.cc
+++ b/ui/ozone/platform/scenic/scenic_window_manager.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/scenic/scenic_window_manager.h"
 
+#include <memory>
+
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/fuchsia/service_directory_client.h"
 #include "ui/ozone/platform/scenic/ozone_platform_scenic.h"
diff --git a/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc b/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
index 72184009..e82f0b3 100644
--- a/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
+++ b/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
@@ -8,6 +8,7 @@
 #include <lib/ui/scenic/cpp/session.h>
 #include <lib/zx/channel.h>
 #include <vulkan/vulkan.h>
+#include <memory>
 
 #include "base/bind_helpers.h"
 #include "base/files/file_path.h"
diff --git a/ui/ozone/platform/wayland/gl_surface_wayland.cc b/ui/ozone/platform/wayland/gl_surface_wayland.cc
index 5827383e..1c65f6d 100644
--- a/ui/ozone/platform/wayland/gl_surface_wayland.cc
+++ b/ui/ozone/platform/wayland/gl_surface_wayland.cc
@@ -5,7 +5,7 @@
 #include "ui/ozone/platform/wayland/gl_surface_wayland.h"
 
 #include <wayland-egl.h>
-
+#include <memory>
 #include <utility>
 
 #include "third_party/khronos/EGL/egl.h"
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
index c2c1ea08..ca6ccf6 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -7,6 +7,7 @@
 #include <drm_fourcc.h>
 #include <gbm.h>
 #include <xf86drmMode.h>
+#include <memory>
 
 #include "base/files/platform_file.h"
 #include "base/logging.h"
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h
index 3c191cee..3f43538b 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h
+++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h
@@ -5,6 +5,7 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_GPU_GBM_PIXMAP_WAYLAND_H_
 #define UI_OZONE_PLATFORM_WAYLAND_GPU_GBM_PIXMAP_WAYLAND_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/files/scoped_file.h"
diff --git a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
index 175f0b6..49d2938 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/task/post_task.h"
 #include "base/trace_event/trace_event.h"
diff --git a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
index 6870debb..f86dd4b0 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
+++ b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_GPU_GBM_SURFACELESS_WAYLAND_H_
 #define UI_OZONE_PLATFORM_WAYLAND_GPU_GBM_SURFACELESS_WAYLAND_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/gfx/native_widget_types.h"
diff --git a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
index a281d5b..a8fb25a 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/files/scoped_file.h"
diff --git a/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h b/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h
index 2790987..13a8d04 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h
+++ b/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_GPU_WAYLAND_CONNECTION_PROXY_H_
 #define UI_OZONE_PLATFORM_WAYLAND_GPU_WAYLAND_CONNECTION_PROXY_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread_checker.h"
diff --git a/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc b/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
index e92e077..99e8a3e 100644
--- a/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
+++ b/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include <sys/socket.h>
 #include <wayland-server.h>
+#include <memory>
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
diff --git a/ui/ozone/platform/wayland/test/test_wayland_server_thread.h b/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
index 24c00bf5..fddd426d 100644
--- a/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
+++ b/ui/ozone/platform/wayland/test/test_wayland_server_thread.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 #include <vector>
-
 #include <wayland-server-core.h>
 
 #include "base/message_loop/message_pump_libevent.h"
diff --git a/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc b/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc
index f10f9336..117208c 100644
--- a/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc
+++ b/ui/ozone/platform/wayland/wayland_buffer_fuzzer.cc
@@ -8,7 +8,6 @@
 #include <drm_fourcc.h>
 #include <stddef.h>
 #include <stdint.h>
-
 #include <memory>
 #include <vector>
 
diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager.cc b/ui/ozone/platform/wayland/wayland_buffer_manager.cc
index 862989e1..7b0bf9a 100644
--- a/ui/ozone/platform/wayland/wayland_buffer_manager.cc
+++ b/ui/ozone/platform/wayland/wayland_buffer_manager.cc
@@ -7,6 +7,7 @@
 #include <drm_fourcc.h>
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include <presentation-time-client-protocol.h>
+#include <memory>
 
 #include "base/trace_event/trace_event.h"
 #include "ui/ozone/common/linux/drm_util_linux.h"
diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager.h b/ui/ozone/platform/wayland/wayland_buffer_manager.h
index 50e44bb..0c33947e 100644
--- a/ui/ozone/platform/wayland/wayland_buffer_manager.h
+++ b/ui/ozone/platform/wayland/wayland_buffer_manager.h
@@ -6,6 +6,7 @@
 #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_BUFFER_MANAGER_H_
 
 #include <map>
+#include <memory>
 #include <vector>
 
 #include "base/containers/flat_map.h"
diff --git a/ui/ozone/platform/wayland/wayland_connection.cc b/ui/ozone/platform/wayland/wayland_connection.cc
index bbcb18e..ca36a1be 100644
--- a/ui/ozone/platform/wayland/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/wayland_connection.cc
@@ -6,6 +6,7 @@
 
 #include <xdg-shell-unstable-v5-client-protocol.h>
 #include <xdg-shell-unstable-v6-client-protocol.h>
+#include <memory>
 
 #include <algorithm>
 #include <utility>
diff --git a/ui/ozone/platform/wayland/wayland_cursor.cc b/ui/ozone/platform/wayland/wayland_cursor.cc
index 725e70c..deb8641 100644
--- a/ui/ozone/platform/wayland/wayland_cursor.cc
+++ b/ui/ozone/platform/wayland/wayland_cursor.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/platform/wayland/wayland_cursor.h"
 
+#include <memory>
+#include <vector>
+
 #include "base/memory/shared_memory.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/skia_util.h"
diff --git a/ui/ozone/platform/wayland/wayland_data_device.cc b/ui/ozone/platform/wayland/wayland_data_device.cc
index ab5df3f4..dfe42f2 100644
--- a/ui/ozone/platform/wayland/wayland_data_device.cc
+++ b/ui/ozone/platform/wayland/wayland_data_device.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/wayland/wayland_data_device.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/ui/ozone/platform/wayland/wayland_data_device_unittest.cc b/ui/ozone/platform/wayland/wayland_data_device_unittest.cc
index b09b8cb..50c4d7e 100644
--- a/ui/ozone/platform/wayland/wayland_data_device_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_data_device_unittest.cc
@@ -4,6 +4,8 @@
 
 #include <wayland-server.h>
 
+#include <memory>
+
 #include "base/bind.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc b/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc
index 2b8349a..7537f27e 100644
--- a/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc
+++ b/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/wayland/wayland_input_method_context_factory.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "ui/ozone/platform/wayland/wayland_connection.h"
 #include "ui/ozone/platform/wayland/wayland_input_method_context.h"
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_factory.h b/ui/ozone/platform/wayland/wayland_input_method_context_factory.h
index 413f3a4..23bd695 100644
--- a/ui/ozone/platform/wayland/wayland_input_method_context_factory.h
+++ b/ui/ozone/platform/wayland/wayland_input_method_context_factory.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
 #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "ui/base/ime/linux/linux_input_method_context_factory.h"
 
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc b/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc
index 08bf4b7..83ca9f2b 100644
--- a/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <text-input-unstable-v1-server-protocol.h>
 #include <wayland-server.h>
+#include <memory>
 
 #include "mojo/public/cpp/bindings/binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc b/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
index 7d85608..3e7abb0 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <linux/input.h>
 #include <wayland-server.h>
+#include <memory>
 
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/timer/timer.h"
diff --git a/ui/ozone/platform/wayland/wayland_object.h b/ui/ozone/platform/wayland/wayland_object.h
index f7f7fd3..cdae701b 100644
--- a/ui/ozone/platform/wayland/wayland_object.h
+++ b/ui/ozone/platform/wayland/wayland_object.h
@@ -6,7 +6,6 @@
 #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OBJECT_H_
 
 #include <wayland-client-core.h>
-
 #include <memory>
 
 struct wl_buffer;
diff --git a/ui/ozone/platform/wayland/wayland_output_manager.cc b/ui/ozone/platform/wayland/wayland_output_manager.cc
index 992d0c3..a7f6e44 100644
--- a/ui/ozone/platform/wayland/wayland_output_manager.cc
+++ b/ui/ozone/platform/wayland/wayland_output_manager.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/wayland/wayland_output_manager.h"
 
+#include <memory>
+
 #include "ui/ozone/platform/wayland/wayland_connection.h"
 #include "ui/ozone/platform/wayland/wayland_output.h"
 
diff --git a/ui/ozone/platform/wayland/wayland_pointer.h b/ui/ozone/platform/wayland/wayland_pointer.h
index 109d08d..070e0b62 100644
--- a/ui/ozone/platform/wayland/wayland_pointer.h
+++ b/ui/ozone/platform/wayland/wayland_pointer.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_POINTER_H_
 #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_POINTER_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/events/ozone/evdev/event_dispatch_callback.h"
diff --git a/ui/ozone/platform/wayland/wayland_pointer_unittest.cc b/ui/ozone/platform/wayland/wayland_pointer_unittest.cc
index 49dcfe7..3b3aa896 100644
--- a/ui/ozone/platform/wayland/wayland_pointer_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_pointer_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <linux/input.h>
 #include <wayland-server.h>
+#include <memory>
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ui/ozone/platform/wayland/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/wayland_screen_unittest.cc
index a6513be6..e081590a 100644
--- a/ui/ozone/platform/wayland/wayland_screen_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_screen_unittest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include <memory>
-
 #include <wayland-server.h>
 
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory.h b/ui/ozone/platform/wayland/wayland_surface_factory.h
index 2f5ab3a..be0bf798 100644
--- a/ui/ozone/platform/wayland/wayland_surface_factory.h
+++ b/ui/ozone/platform/wayland/wayland_surface_factory.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SURFACE_FACTORY_H_
 #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SURFACE_FACTORY_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc b/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc
index 87861f46..f040c66 100644
--- a/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_surface_factory_unittest.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 <utility>
 
 #include "base/run_loop.h"
diff --git a/ui/ozone/platform/wayland/wayland_test.h b/ui/ozone/platform/wayland/wayland_test.h
index 625d7e60a..2c83f37 100644
--- a/ui/ozone/platform/wayland/wayland_test.h
+++ b/ui/ozone/platform/wayland/wayland_test.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_TEST_H_
 #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_TEST_H_
 
+#include <memory>
+
 #include "base/message_loop/message_loop.h"
 #include "base/test/scoped_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ui/ozone/platform/wayland/wayland_touch_unittest.cc b/ui/ozone/platform/wayland/wayland_touch_unittest.cc
index 831dd903..9a64f9c 100644
--- a/ui/ozone/platform/wayland/wayland_touch_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_touch_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <linux/input.h>
 #include <wayland-server.h>
+#include <memory>
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/wayland_window.cc
index 7b65895..f0ae1a0 100644
--- a/ui/ozone/platform/wayland/wayland_window.cc
+++ b/ui/ozone/platform/wayland/wayland_window.cc
@@ -4,9 +4,8 @@
 
 #include "ui/ozone/platform/wayland/wayland_window.h"
 
-#include <memory>
-
 #include <wayland-client.h>
+#include <memory>
 
 #include "base/bind.h"
 #include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
diff --git a/ui/ozone/platform/wayland/wayland_window.h b/ui/ozone/platform/wayland/wayland_window.h
index 4c7271d..94c3a60 100644
--- a/ui/ozone/platform/wayland/wayland_window.h
+++ b/ui/ozone/platform/wayland/wayland_window.h
@@ -5,6 +5,7 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
 #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
 
+#include <memory>
 #include <set>
 #include <vector>
 
diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc b/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc
index 38b274f..866133e 100644
--- a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc
+++ b/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h"
 
 #include <xdg-shell-unstable-v6-client-protocol.h>
+#include <memory>
 
 #include "ui/events/event_constants.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h b/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h
index 4e43d2dd..cd56eeff 100644
--- a/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h
+++ b/ui/ozone/platform/wayland/xdg_popup_wrapper_v6.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_V6_H_
 #define UI_OZONE_PLATFORM_WAYLAND_XDG_POPUP_WRAPPER_V6_H_
 
+#include <memory>
+
 #include "ui/ozone/platform/wayland/xdg_popup_wrapper.h"
 
 namespace ui {
diff --git a/ui/ozone/platform/windows/ozone_platform_windows.cc b/ui/ozone/platform/windows/ozone_platform_windows.cc
index 8346924..7b0a5982 100644
--- a/ui/ozone/platform/windows/ozone_platform_windows.cc
+++ b/ui/ozone/platform/windows/ozone_platform_windows.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/windows/ozone_platform_windows.h"
 
+#include <memory>
+
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
diff --git a/ui/ozone/platform/x11/x11_screen_ozone.h b/ui/ozone/platform/x11/x11_screen_ozone.h
index cd16a1c9..5acf82a2 100644
--- a/ui/ozone/platform/x11/x11_screen_ozone.h
+++ b/ui/ozone/platform/x11/x11_screen_ozone.h
@@ -5,6 +5,7 @@
 #ifndef UI_OZONE_PLATFORM_X11_X11_SCREEN_OZONE_H_
 #define UI_OZONE_PLATFORM_X11_X11_SCREEN_OZONE_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
diff --git a/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc b/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc
index 6086f084..250da19 100644
--- a/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc
+++ b/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/x11/x11_screen_ozone.h"
 
+#include <memory>
+
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/display.h"
 
diff --git a/ui/ozone/platform/x11/x11_surface_factory.cc b/ui/ozone/platform/x11/x11_surface_factory.cc
index 74aa63ce..6011ca12 100644
--- a/ui/ozone/platform/x11/x11_surface_factory.cc
+++ b/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/x11/x11_surface_factory.h"
 
+#include <memory>
+
 #include "gpu/vulkan/buildflags.h"
 #include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_types.h"
diff --git a/ui/ozone/platform/x11/x11_window_ozone_unittest.cc b/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
index 2a74570..2484f518 100644
--- a/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
+++ b/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/platform/x11/x11_window_ozone.h"
 
+#include <memory>
+
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ui/ozone/platform_object_internal.h b/ui/ozone/platform_object_internal.h
index bcf1b46..c548931c 100644
--- a/ui/ozone/platform_object_internal.h
+++ b/ui/ozone/platform_object_internal.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_OBJECT_INTERNAL_H_
 #define UI_OZONE_PLATFORM_OBJECT_INTERNAL_H_
 
+#include <memory>
+
 #include "base/memory/ptr_util.h"
 #include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform_constructor_list.h"
diff --git a/ui/ozone/public/client_native_pixmap_factory_ozone.cc b/ui/ozone/public/client_native_pixmap_factory_ozone.cc
index 7d6428b..c118a31 100644
--- a/ui/ozone/public/client_native_pixmap_factory_ozone.cc
+++ b/ui/ozone/public/client_native_pixmap_factory_ozone.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
 
+#include <memory>
+
 #include "base/trace_event/trace_event.h"
 #include "ui/ozone/platform_object.h"
 #include "ui/ozone/platform_selection.h"
diff --git a/ui/ozone/public/client_native_pixmap_factory_ozone.h b/ui/ozone/public/client_native_pixmap_factory_ozone.h
index 744e868a..a152589 100644
--- a/ui/ozone/public/client_native_pixmap_factory_ozone.h
+++ b/ui/ozone/public/client_native_pixmap_factory_ozone.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PUBLIC_CLIENT_NATIVE_PIXMAP_FACTORY_OZONE_H_
 #define UI_OZONE_PUBLIC_CLIENT_NATIVE_PIXMAP_FACTORY_OZONE_H_
 
+#include <memory>
+
 #include "ui/gfx/client_native_pixmap_factory.h"
 #include "ui/ozone/ozone_export.h"
 
diff --git a/ui/ozone/public/input_controller.cc b/ui/ozone/public/input_controller.cc
index 4ba1521c..daacfbb44 100644
--- a/ui/ozone/public/input_controller.cc
+++ b/ui/ozone/public/input_controller.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/public/input_controller.h"
 
+#include <memory>
+
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/macros.h"
diff --git a/ui/ozone/public/overlay_plane.cc b/ui/ozone/public/overlay_plane.cc
index ddc0abbb..35cd261 100644
--- a/ui/ozone/public/overlay_plane.cc
+++ b/ui/ozone/public/overlay_plane.cc
@@ -4,6 +4,8 @@
 
 #include "ui/ozone/public/overlay_plane.h"
 
+#include <memory>
+
 namespace ui {
 
 OverlayPlane::OverlayPlane() {}
diff --git a/ui/ozone/public/overlay_plane.h b/ui/ozone/public/overlay_plane.h
index c1b5e8d2..9689177 100644
--- a/ui/ozone/public/overlay_plane.h
+++ b/ui/ozone/public/overlay_plane.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PUBLIC_OVERLAY_PLANE_H_
 #define UI_OZONE_PUBLIC_OVERLAY_PLANE_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/ui/ozone/public/ozone_platform.cc b/ui/ozone/public/ozone_platform.cc
index e3c40bec..787f3fa 100644
--- a/ui/ozone/public/ozone_platform.cc
+++ b/ui/ozone/public/ozone_platform.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/public/ozone_platform.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/logging.h"
diff --git a/ui/ozone/public/surface_factory_ozone.cc b/ui/ozone/public/surface_factory_ozone.cc
index a12ec48..faa7bb6 100644
--- a/ui/ozone/public/surface_factory_ozone.cc
+++ b/ui/ozone/public/surface_factory_ozone.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/public/surface_factory_ozone.h"
 
 #include <stdlib.h>
+#include <memory>
 
 #include "base/command_line.h"
 #include "gpu/vulkan/buildflags.h"
diff --git a/ui/ozone/public/surface_factory_ozone.h b/ui/ozone/public/surface_factory_ozone.h
index 6ac0ea49..16758eb 100644
--- a/ui/ozone/public/surface_factory_ozone.h
+++ b/ui/ozone/public/surface_factory_ozone.h
@@ -6,7 +6,6 @@
 #define UI_OZONE_PUBLIC_SURFACE_FACTORY_OZONE_H_
 
 #include <stdint.h>
-
 #include <memory>
 #include <vector>
 
diff --git a/ui/ozone/public/swap_completion_callback.h b/ui/ozone/public/swap_completion_callback.h
index c5be525..367e306 100644
--- a/ui/ozone/public/swap_completion_callback.h
+++ b/ui/ozone/public/swap_completion_callback.h
@@ -6,6 +6,7 @@
 #define UI_OZONE_PUBLIC_SWAP_COMPLETION_CALLBACK_H_
 
 #include <memory>
+
 #include "base/callback.h"
 #include "ui/gfx/swap_result.h"
 
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
index 9fc8f31..899aaa0c 100644
--- a/ui/views/controls/combobox/combobox.cc
+++ b/ui/views/controls/combobox/combobox.cc
@@ -633,8 +633,8 @@
         base::BindRepeating(&Combobox::OnMenuClosed, base::Unretained(this),
                             original_state));
   }
-  menu_runner_->RunMenuAt(GetWidget(), nullptr, bounds, MENU_ANCHOR_TOPLEFT,
-                          source_type);
+  menu_runner_->RunMenuAt(GetWidget(), nullptr, bounds,
+                          MenuAnchorPosition::kTopLeft, source_type);
 }
 
 void Combobox::OnMenuClosed(Button::ButtonState original_button_state) {
diff --git a/ui/views/controls/editable_combobox/editable_combobox.cc b/ui/views/controls/editable_combobox/editable_combobox.cc
index b30fd95c..1e58fb4c 100644
--- a/ui/views/controls/editable_combobox/editable_combobox.cc
+++ b/ui/views/controls/editable_combobox/editable_combobox.cc
@@ -350,8 +350,8 @@
       menu_model_.get(), MenuRunner::EDITABLE_COMBOBOX,
       base::BindRepeating(&EditableCombobox::OnMenuClosed,
                           base::Unretained(this)));
-  menu_runner_->RunMenuAt(GetWidget(), nullptr, bounds, MENU_ANCHOR_TOPLEFT,
-                          source_type);
+  menu_runner_->RunMenuAt(GetWidget(), nullptr, bounds,
+                          MenuAnchorPosition::kTopLeft, source_type);
 }
 
 }  // namespace views
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index fe30059d..09c24be 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -656,7 +656,7 @@
       MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU);
   context_menu_runner_->RunMenuAt(GetWidget(), nullptr,
                                   gfx::Rect(point, gfx::Size()),
-                                  MENU_ANCHOR_TOPLEFT, source_type);
+                                  MenuAnchorPosition::kTopLeft, source_type);
 }
 
 bool Label::GetWordLookupDataAtPoint(const gfx::Point& point,
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 6ae1820..c7aa2fec 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -408,7 +408,7 @@
     : item(nullptr),
       hot_button(nullptr),
       submenu_open(false),
-      anchor(MENU_ANCHOR_TOPLEFT),
+      anchor(MenuAnchorPosition::kTopLeft),
       context_menu(false) {}
 
 MenuController::State::State(const State& other) = default;
@@ -1595,11 +1595,11 @@
   pending_state_.initial_bounds = bounds;
 
   // Reverse anchor position for RTL languages.
-  if (base::i18n::IsRTL() &&
-      (position == MENU_ANCHOR_TOPRIGHT || position == MENU_ANCHOR_TOPLEFT)) {
-    pending_state_.anchor = position == MENU_ANCHOR_TOPRIGHT
-                                ? MENU_ANCHOR_TOPLEFT
-                                : MENU_ANCHOR_TOPRIGHT;
+  if (base::i18n::IsRTL() && (position == MenuAnchorPosition::kTopRight ||
+                              position == MenuAnchorPosition::kTopLeft)) {
+    pending_state_.anchor = position == MenuAnchorPosition::kTopRight
+                                ? MenuAnchorPosition::kTopLeft
+                                : MenuAnchorPosition::kTopRight;
   } else {
     pending_state_.anchor = position;
   }
@@ -2210,20 +2210,20 @@
     const int vertically_centered =
         anchor_bounds.y() + (anchor_bounds.height() - menu_bounds.height()) / 2;
 
-    if (state_.anchor == MENU_ANCHOR_TOPRIGHT) {
+    if (state_.anchor == MenuAnchorPosition::kTopRight) {
       // Move the menu so that its right edge is aligned with the anchor
       // bounds right edge.
       menu_bounds.set_x(anchor_bounds.right() - menu_bounds.width());
-    } else if (state_.anchor == MENU_ANCHOR_BOTTOMCENTER) {
+    } else if (state_.anchor == MenuAnchorPosition::kBottomCenter) {
       // Try to fit the menu above the anchor bounds. If it doesn't fit, place
       // it below.
       menu_bounds.set_x(horizontally_centered);
       menu_bounds.set_y(above_anchor - kTouchYPadding);
       if (menu_bounds.y() < monitor_bounds.y())
         menu_bounds.set_y(anchor_bounds.y() + kTouchYPadding);
-    } else if (state_.anchor == MENU_ANCHOR_FIXED_BOTTOMCENTER) {
+    } else if (state_.anchor == MenuAnchorPosition::kFixedBottomCenter) {
       menu_bounds.set_x(horizontally_centered);
-    } else if (state_.anchor == MENU_ANCHOR_FIXED_SIDECENTER) {
+    } else if (state_.anchor == MenuAnchorPosition::kSideCenter) {
       menu_bounds.set_y(vertically_centered);
     }
 
@@ -2265,7 +2265,7 @@
       const int right_of_anchor = anchor_bounds.right();
 
       menu_bounds.set_y(monitor_bounds.bottom() - menu_bounds.height());
-      if (state_.anchor == MENU_ANCHOR_TOPLEFT) {
+      if (state_.anchor == MenuAnchorPosition::kTopLeft) {
         // Prefer menu to right of anchor bounds but move it to left if it
         // doesn't fit.
         menu_bounds.set_x(right_of_anchor);
@@ -2330,19 +2330,19 @@
       int max_height = monitor_bounds.height();
       // In case of bubbles, the maximum width is limited by the space
       // between the display corner and the target area + the tip size.
-      if (state_.anchor == MENU_ANCHOR_BUBBLE_LEFT) {
+      if (state_.anchor == MenuAnchorPosition::kBubbleLeft) {
         max_width =
             anchor_bounds.x() - monitor_bounds.x() + kBubbleTipSizeLeftRight;
-      } else if (state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT) {
+      } else if (state_.anchor == MenuAnchorPosition::kBubbleRight) {
         max_width = monitor_bounds.right() - anchor_bounds.right() +
                     kBubbleTipSizeLeftRight;
-      } else if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE) {
+      } else if (state_.anchor == MenuAnchorPosition::kBubbleAbove) {
         max_height =
             anchor_bounds.y() - monitor_bounds.y() + kBubbleTipSizeTopBottom;
-      } else if (state_.anchor == MENU_ANCHOR_BUBBLE_BELOW) {
+      } else if (state_.anchor == MenuAnchorPosition::kBubbleBelow) {
         max_height = monitor_bounds.bottom() - anchor_bounds.bottom() +
                      kBubbleTipSizeTopBottom;
-      } else if (state_.anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE) {
+      } else if (state_.anchor == MenuAnchorPosition::kBubbleTouchableAbove) {
         // Don't consider |border_and_shadow_insets| because when the max size
         // is enforced, the scroll view is shown and the md shadows are not
         // applied.
@@ -2360,9 +2360,9 @@
     menu_size.set_width(std::min(
         menu_size.width(), item->GetDelegate()->GetMaxWidthForMenu(item)));
 
-    if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE ||
-        state_.anchor == MENU_ANCHOR_BUBBLE_BELOW) {
-      if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE)
+    if (state_.anchor == MenuAnchorPosition::kBubbleAbove ||
+        state_.anchor == MenuAnchorPosition::kBubbleBelow) {
+      if (state_.anchor == MenuAnchorPosition::kBubbleAbove)
         y = anchor_bounds.y() - menu_size.height() + kBubbleTipSizeTopBottom;
       else
         y = anchor_bounds.bottom() - kBubbleTipSizeTopBottom;
@@ -2373,9 +2373,9 @@
                              monitor_bounds.right() - menu_size.width());
       submenu->GetScrollViewContainer()->SetBubbleArrowOffset(
           menu_size.width() / 2 - x + x_old);
-    } else if (state_.anchor == MENU_ANCHOR_BUBBLE_LEFT ||
-               state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT) {
-      if (state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT)
+    } else if (state_.anchor == MenuAnchorPosition::kBubbleLeft ||
+               state_.anchor == MenuAnchorPosition::kBubbleRight) {
+      if (state_.anchor == MenuAnchorPosition::kBubbleRight)
         x = anchor_bounds.right() - kBubbleTipSizeLeftRight;
       else
         x = anchor_bounds.x() - menu_size.width() + kBubbleTipSizeLeftRight;
@@ -2386,7 +2386,7 @@
                              monitor_bounds.bottom() - menu_size.height());
       submenu->GetScrollViewContainer()->SetBubbleArrowOffset(
           menu_size.height() / 2 - y + y_old);
-    } else if (state_.anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE) {
+    } else if (state_.anchor == MenuAnchorPosition::kBubbleTouchableAbove) {
       // Align the left edges of the menu and anchor, and the bottom of the menu
       // with the top of the anchor.
       x = std::max(monitor_bounds.x(),
@@ -2405,7 +2405,7 @@
         y = anchor_bounds.bottom() - border_and_shadow_insets.top() +
             menu_config.touchable_anchor_offset;
       }
-    } else if (state_.anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT) {
+    } else if (state_.anchor == MenuAnchorPosition::kBubbleTouchableLeft) {
       // Align the right of the menu with the left of the anchor, and the top of
       // the menu with the top of the anchor.
       x = anchor_bounds.x() - menu_size.width() +
@@ -2425,7 +2425,7 @@
         if (y < monitor_bounds.y())
           y = monitor_bounds.y();
       }
-    } else if (state_.anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT) {
+    } else if (state_.anchor == MenuAnchorPosition::kBubbleTouchableRight) {
       // Align the left of the menu with the right of the anchor, and the top of
       // the menu with the top of the anchor.
       x = anchor_bounds.right() - border_and_shadow_insets.left() +
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc
index c1ac0e8..1d369d1 100644
--- a/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -312,7 +312,7 @@
   gfx::Rect anchor_bounds = gfx::Rect(500, 500, 10, 10);
   gfx::Rect monitor_bounds = gfx::Rect(0, 0, 1000, 1000);
   gfx::Size menu_size = gfx::Size(100, 100);
-  MenuAnchorPosition menu_anchor = MENU_ANCHOR_TOPLEFT;
+  MenuAnchorPosition menu_anchor = MenuAnchorPosition::kTopLeft;
   MenuItemView::MenuPosition menu_position = MenuItemView::POSITION_BEST_FIT;
 };
 
@@ -800,7 +800,7 @@
   event_generator()->ReleaseTouchId(0);
 
   menu_controller()->Run(owner(), nullptr, menu_item(), gfx::Rect(),
-                         MENU_ANCHOR_TOPLEFT, false, false);
+                         MenuAnchorPosition::kTopLeft, false, false);
 
   MenuControllerTest::ReleaseTouchId(1);
   TestAsyncEscapeKey();
@@ -1173,7 +1173,7 @@
 
   MenuController* controller = menu_controller();
   controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
-                  MENU_ANCHOR_TOPLEFT, false, false);
+                  MenuAnchorPosition::kTopLeft, false, false);
 
   // |button2| should stay in hot-tracked state but menu controller should not
   // track it anymore (preventing resetting hot-tracked state when changing
@@ -1200,7 +1200,7 @@
 
   MenuController* controller = menu_controller();
   controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
-                  MENU_ANCHOR_TOPLEFT, false, false);
+                  MenuAnchorPosition::kTopLeft, false, false);
   TestMenuControllerDelegate* delegate = menu_controller_delegate();
   EXPECT_EQ(0, delegate->on_menu_closed_called());
 
@@ -1221,7 +1221,7 @@
   MenuController* controller = menu_controller();
 
   controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
-                  MENU_ANCHOR_TOPLEFT, false, false);
+                  MenuAnchorPosition::kTopLeft, false, false);
   TestMenuControllerDelegate* delegate = menu_controller_delegate();
   EXPECT_EQ(0, delegate->on_menu_closed_called());
 
@@ -1246,7 +1246,7 @@
   EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate());
 
   controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
-                  MENU_ANCHOR_TOPLEFT, false, false);
+                  MenuAnchorPosition::kTopLeft, false, false);
 
   controller->CancelAll();
   EXPECT_EQ(delegate, GetCurrentDelegate());
@@ -1361,7 +1361,7 @@
   // Nested run
   controller->AddNestedDelegate(nested_delegate.get());
   controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
-                  MENU_ANCHOR_TOPLEFT, false, false);
+                  MenuAnchorPosition::kTopLeft, false, false);
 
   controller->CancelAll();
   EXPECT_EQ(1, delegate->on_menu_closed_called());
@@ -1374,7 +1374,7 @@
   MenuController* controller = menu_controller();
   MenuItemView* item = menu_item();
   controller->Run(owner(), nullptr, item, gfx::Rect(),
-                  MENU_ANCHOR_FIXED_BOTTOMCENTER, false, false);
+                  MenuAnchorPosition::kFixedBottomCenter, false, false);
   SubmenuView* sub_menu = item->GetSubmenu();
   sub_menu->ShowAt(owner(), gfx::Rect(0, 0, 100, 100), true);
 
@@ -1456,8 +1456,8 @@
   EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate());
 
   MenuItemView* item = menu_item();
-  controller->Run(owner(), nullptr, item, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                  false, false);
+  controller->Run(owner(), nullptr, item, gfx::Rect(),
+                  MenuAnchorPosition::kTopLeft, false, false);
 
   // Show a sub menu to target with a pointer selection. However have the event
   // occur outside of the bounds of the entire menu.
@@ -1524,8 +1524,8 @@
   EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate());
 
   MenuItemView* item = menu_item();
-  controller->Run(owner(), nullptr, item, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                  false, false);
+  controller->Run(owner(), nullptr, item, gfx::Rect(),
+                  MenuAnchorPosition::kTopLeft, false, false);
 
   // Show a sub menu to target with a pointer selection. However have the event
   // occur outside of the bounds of the entire menu.
@@ -1561,8 +1561,8 @@
   EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate());
 
   MenuItemView* item = menu_item();
-  controller->Run(owner(), nullptr, item, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                  false, false);
+  controller->Run(owner(), nullptr, item, gfx::Rect(),
+                  MenuAnchorPosition::kTopLeft, false, false);
 
   // Show a sub menu to target with a tap event.
   SubmenuView* sub_menu = item->GetSubmenu();
@@ -1664,7 +1664,7 @@
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   // Fits on both sides, prefer left -> placed left.
-  options.menu_anchor = MENU_ANCHOR_TOPRIGHT;
+  options.menu_anchor = MenuAnchorPosition::kTopRight;
   options.anchor_bounds = gfx::Rect(options.menu_size.width(),
                                     options.menu_size.height() / 2, 0, 0);
   options.monitor_bounds =
@@ -1693,13 +1693,13 @@
   MenuBoundsOptions options;
   gfx::Rect expected;
 
-  options.menu_anchor = MENU_ANCHOR_TOPLEFT;
+  options.menu_anchor = MenuAnchorPosition::kTopLeft;
   expected =
       gfx::Rect(options.anchor_bounds.x(), options.anchor_bounds.bottom(),
                 options.menu_size.width(), options.menu_size.height());
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
-  options.menu_anchor = MENU_ANCHOR_TOPRIGHT;
+  options.menu_anchor = MenuAnchorPosition::kTopRight;
   expected =
       gfx::Rect(options.anchor_bounds.right() - options.menu_size.width(),
                 options.anchor_bounds.bottom(), options.menu_size.width(),
@@ -1707,7 +1707,7 @@
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   // Menu will be placed above or below with an offset.
-  options.menu_anchor = MENU_ANCHOR_BOTTOMCENTER;
+  options.menu_anchor = MenuAnchorPosition::kBottomCenter;
   const int kTouchYPadding = 15;
 
   // Menu fits above -> placed above.
@@ -1729,7 +1729,7 @@
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   // Assumes anchor bounds is at the bottom of screen.
-  options.menu_anchor = MENU_ANCHOR_FIXED_BOTTOMCENTER;
+  options.menu_anchor = MenuAnchorPosition::kFixedBottomCenter;
   options.anchor_bounds =
       gfx::Rect(options.menu_size.width(), options.menu_size.height(), 0, 0);
   options.monitor_bounds = gfx::Rect(0, 0, options.menu_size.width() * 2,
@@ -1742,7 +1742,7 @@
   EXPECT_EQ(expected, CalculateMenuBounds(options));
 
   // Assumes anchor bounds is on left/right edge of screen.
-  options.menu_anchor = MENU_ANCHOR_FIXED_SIDECENTER;
+  options.menu_anchor = MenuAnchorPosition::kSideCenter;
   options.monitor_bounds = gfx::Rect(0, 0, options.menu_size.width(),
                                      options.menu_size.height() * 2);
   options.anchor_bounds =
@@ -1794,16 +1794,16 @@
 
 // Test that menus show up on screen with non-zero sized anchors.
 TEST_F(MenuControllerTest, TestMenuFitsOnScreen) {
-  TestMenuFitsOnScreen(MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE);
-  TestMenuFitsOnScreen(MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT);
-  TestMenuFitsOnScreen(MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT);
+  TestMenuFitsOnScreen(MenuAnchorPosition::kBubbleTouchableAbove);
+  TestMenuFitsOnScreen(MenuAnchorPosition::kBubbleTouchableLeft);
+  TestMenuFitsOnScreen(MenuAnchorPosition::kBubbleTouchableRight);
 }
 
 // Test that menus show up on screen with zero sized anchors.
 TEST_F(MenuControllerTest, TestMenuFitsOnScreenSmallAnchor) {
-  TestMenuFitsOnScreenSmallAnchor(MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE);
-  TestMenuFitsOnScreenSmallAnchor(MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT);
-  TestMenuFitsOnScreenSmallAnchor(MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT);
+  TestMenuFitsOnScreenSmallAnchor(MenuAnchorPosition::kBubbleTouchableAbove);
+  TestMenuFitsOnScreenSmallAnchor(MenuAnchorPosition::kBubbleTouchableLeft);
+  TestMenuFitsOnScreenSmallAnchor(MenuAnchorPosition::kBubbleTouchableRight);
 }
 
 // Test that a menu that was originally drawn below the anchor does not get
@@ -1857,7 +1857,7 @@
   gfx::Point location(item_size.width() / 2, item_size.height() / 2);
   GetRootWindow(owner())->MoveCursorTo(location);
   menu_controller()->Run(owner(), nullptr, menu_item.get(), gfx::Rect(),
-                         MENU_ANCHOR_TOPLEFT, false, false);
+                         MenuAnchorPosition::kTopLeft, false, false);
 
   EXPECT_EQ(0, pending_state_item()->GetCommand());
 
@@ -1883,7 +1883,7 @@
   ExitMenuRun();
   MenuController* controller = menu_controller();
   controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
-                  MENU_ANCHOR_TOPLEFT, false, false);
+                  MenuAnchorPosition::kTopLeft, false, false);
   EXPECT_EQ(MenuController::EXIT_NONE, controller->exit_type());
   ui::CancelModeEvent cancel_event;
   event_generator()->Dispatch(&cancel_event);
@@ -1902,7 +1902,7 @@
   ExitMenuRun();
   MenuController* controller = menu_controller();
   controller->Run(nullptr, nullptr, menu_item(), gfx::Rect(),
-                  MENU_ANCHOR_TOPLEFT, false, false);
+                  MenuAnchorPosition::kTopLeft, false, false);
 }
 
 // Tests that if a MenuController is destroying during drag/drop, and another
@@ -1940,7 +1940,7 @@
   ExitMenuRun();
   MenuController* controller = menu_controller();
   controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
-                  MENU_ANCHOR_TOPLEFT, false, false);
+                  MenuAnchorPosition::kTopLeft, false, false);
   TestDestroyedDuringViewsRelease();
 }
 
@@ -1992,8 +1992,8 @@
       std::make_unique<TestMenuControllerDelegate>();
   controller->AddNestedDelegate(nested_controller_delegate_1.get());
   controller->Run(owner(), nullptr, nested_menu_item_1.get(),
-                  gfx::Rect(150, 50, 100, 100), MENU_ANCHOR_TOPLEFT, true,
-                  false);
+                  gfx::Rect(150, 50, 100, 100), MenuAnchorPosition::kTopLeft,
+                  true, false);
 
   SubmenuView* nested_menu_submenu = nested_menu_item_1->GetSubmenu();
   nested_menu_submenu->SetBounds(0, 0, 100, 100);
@@ -2043,8 +2043,8 @@
       std::make_unique<TestMenuControllerDelegate>();
   controller->AddNestedDelegate(nested_controller_delegate_2.get());
   controller->Run(owner(), nullptr, nested_menu_item_2.get(),
-                  gfx::Rect(150, 50, 100, 100), MENU_ANCHOR_TOPLEFT, true,
-                  false);
+                  gfx::Rect(150, 50, 100, 100), MenuAnchorPosition::kTopLeft,
+                  true, false);
 
   // The escape key should only close the nested menu. SelectByChar should not
   // crash.
@@ -2113,7 +2113,7 @@
   canceling_view->SetBoundsRect(item->bounds());
 
   controller->Run(owner(), nullptr, item.get(), item->bounds(),
-                  MENU_ANCHOR_TOPLEFT, false, false);
+                  MenuAnchorPosition::kTopLeft, false, false);
   sub_menu->ShowAt(owner(), item->bounds(), true);
 
   // Simulate a mouse press in the middle of the |closing_widget|.
@@ -2314,7 +2314,7 @@
 
   MenuController* controller = menu_controller();
   controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
-                  MENU_ANCHOR_TOPLEFT, false, false);
+                  MenuAnchorPosition::kTopLeft, false, false);
   TestMenuControllerDelegate* delegate = menu_controller_delegate();
   EXPECT_EQ(0, delegate->on_menu_closed_called());
 
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index 74d5bca..ffd40f6 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -220,13 +220,13 @@
 
 // static
 bool MenuItemView::IsBubble(MenuAnchorPosition anchor) {
-  return anchor == MENU_ANCHOR_BUBBLE_LEFT ||
-         anchor == MENU_ANCHOR_BUBBLE_RIGHT ||
-         anchor == MENU_ANCHOR_BUBBLE_ABOVE ||
-         anchor == MENU_ANCHOR_BUBBLE_BELOW ||
-         anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE ||
-         anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT ||
-         anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT;
+  return anchor == MenuAnchorPosition::kBubbleLeft ||
+         anchor == MenuAnchorPosition::kBubbleRight ||
+         anchor == MenuAnchorPosition::kBubbleAbove ||
+         anchor == MenuAnchorPosition::kBubbleBelow ||
+         anchor == MenuAnchorPosition::kBubbleTouchableAbove ||
+         anchor == MenuAnchorPosition::kBubbleTouchableLeft ||
+         anchor == MenuAnchorPosition::kBubbleTouchableRight;
 }
 
 // static
diff --git a/ui/views/controls/menu/menu_item_view_unittest.cc b/ui/views/controls/menu/menu_item_view_unittest.cc
index 792f2bd..5ab6170 100644
--- a/ui/views/controls/menu/menu_item_view_unittest.cc
+++ b/ui/views/controls/menu/menu_item_view_unittest.cc
@@ -316,7 +316,8 @@
   AddItem("Minor text and icon", base::ASCIIToUTF16("minor text"),
           &views::kMenuCheckIcon);
 
-  menu_runner()->RunMenuAt(widget(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+  menu_runner()->RunMenuAt(widget(), nullptr, gfx::Rect(),
+                           MenuAnchorPosition::kTopLeft,
                            ui::MENU_SOURCE_KEYBOARD);
 
   SkBitmap bitmap;
diff --git a/ui/views/controls/menu/menu_runner.cc b/ui/views/controls/menu/menu_runner.cc
index b0a2f3d..a34f7ae 100644
--- a/ui/views/controls/menu/menu_runner.cc
+++ b/ui/views/controls/menu/menu_runner.cc
@@ -58,11 +58,11 @@
       case ui::MENU_SOURCE_NONE:
       case ui::MENU_SOURCE_KEYBOARD:
       case ui::MENU_SOURCE_MOUSE:
-        anchor = MENU_ANCHOR_TOPLEFT;
+        anchor = MenuAnchorPosition::kTopLeft;
         break;
       case ui::MENU_SOURCE_TOUCH:
       case ui::MENU_SOURCE_TOUCH_EDIT_MENU:
-        anchor = MENU_ANCHOR_BOTTOMCENTER;
+        anchor = MenuAnchorPosition::kBottomCenter;
         break;
       default:
         break;
diff --git a/ui/views/controls/menu/menu_runner_cocoa_unittest.mm b/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
index 4f9dd1e..f6e98da 100644
--- a/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
+++ b/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
@@ -148,8 +148,8 @@
                          base::Unretained(this), std::move(callback)));
     }
 
-    runner_->RunMenuAt(parent_, nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                       MenuRunner::CONTEXT_MENU);
+    runner_->RunMenuAt(parent_, nullptr, gfx::Rect(),
+                       MenuAnchorPosition::kTopLeft, MenuRunner::CONTEXT_MENU);
     MaybeRunAsync();
   }
 
@@ -168,7 +168,7 @@
       menu_->set_menu_open_callback(std::move(callback));
     }
 
-    runner_->RunMenuAt(parent_, nullptr, anchor, MENU_ANCHOR_TOPLEFT,
+    runner_->RunMenuAt(parent_, nullptr, anchor, MenuAnchorPosition::kTopLeft,
                        MenuRunner::COMBOBOX);
     MaybeRunAsync();
   }
diff --git a/ui/views/controls/menu/menu_runner_impl_cocoa.mm b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
index 8743751..9fe4eca 100644
--- a/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -74,7 +74,8 @@
   // When the actual menu width is larger than the anchor, right alignment
   // should be respected.
   if (actual_menu_width > rect.size.width &&
-      position == views::MENU_ANCHOR_TOPRIGHT && !base::i18n::IsRTL()) {
+      position == views::MenuAnchorPosition::kTopRight &&
+      !base::i18n::IsRTL()) {
     int width_diff = actual_menu_width - rect.size.width;
     rect.origin.x -= width_diff;
   }
diff --git a/ui/views/controls/menu/menu_runner_unittest.cc b/ui/views/controls/menu/menu_runner_unittest.cc
index 7c5a7ac..9e4e124 100644
--- a/ui/views/controls/menu/menu_runner_unittest.cc
+++ b/ui/views/controls/menu/menu_runner_unittest.cc
@@ -129,7 +129,7 @@
 TEST_F(MenuRunnerTest, AsynchronousRun) {
   InitMenuRunner(0);
   MenuRunner* runner = menu_runner();
-  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MenuAnchorPosition::kTopLeft,
                     ui::MENU_SOURCE_NONE);
   EXPECT_TRUE(runner->IsRunning());
 
@@ -145,7 +145,7 @@
 TEST_F(MenuRunnerTest, AsynchronousKeyEventHandling) {
   InitMenuRunner(0);
   MenuRunner* runner = menu_runner();
-  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MenuAnchorPosition::kTopLeft,
                     ui::MENU_SOURCE_NONE);
   EXPECT_TRUE(runner->IsRunning());
 
@@ -166,7 +166,7 @@
   views::test::DisableMenuClosureAnimations();
   InitMenuRunner(0);
   MenuRunner* runner = menu_runner();
-  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MenuAnchorPosition::kTopLeft,
                     ui::MENU_SOURCE_NONE);
   EXPECT_TRUE(runner->IsRunning());
 
@@ -190,7 +190,7 @@
   views::test::DisableMenuClosureAnimations();
   InitMenuRunner(0);
   MenuRunner* runner = menu_runner();
-  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MenuAnchorPosition::kTopLeft,
                     ui::MENU_SOURCE_NONE);
   EXPECT_TRUE(runner->IsRunning());
 
@@ -212,8 +212,8 @@
 
   InitMenuRunner(MenuRunner::HAS_MNEMONICS | MenuRunner::SHOULD_SHOW_MNEMONICS);
 
-  menu_runner()->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                           ui::MENU_SOURCE_NONE);
+  menu_runner()->RunMenuAt(owner(), nullptr, gfx::Rect(),
+                           MenuAnchorPosition::kTopLeft, ui::MENU_SOURCE_NONE);
 
   EXPECT_TRUE(menu_item_view()->show_mnemonics());
 }
@@ -224,8 +224,8 @@
 
   InitMenuRunner(MenuRunner::HAS_MNEMONICS);
 
-  menu_runner()->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                           ui::MENU_SOURCE_NONE);
+  menu_runner()->RunMenuAt(owner(), nullptr, gfx::Rect(),
+                           MenuAnchorPosition::kTopLeft, ui::MENU_SOURCE_NONE);
 
   EXPECT_FALSE(menu_item_view()->show_mnemonics());
 }
@@ -248,7 +248,7 @@
   menu_item_view()->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("One Two"));
 
   MenuRunner* runner = menu_runner();
-  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MenuAnchorPosition::kTopLeft,
                     ui::MENU_SOURCE_NONE);
   EXPECT_TRUE(runner->IsRunning());
 
@@ -291,7 +291,7 @@
   InitMenuRunner(0);
 
   MenuRunner* runner = menu_runner();
-  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MenuAnchorPosition::kTopLeft,
                     ui::MENU_SOURCE_NONE);
   EXPECT_TRUE(runner->IsRunning());
 
@@ -315,7 +315,7 @@
 TEST_F(MenuRunnerTest, NestingDuringDrag) {
   InitMenuRunner(MenuRunner::FOR_DROP);
   MenuRunner* runner = menu_runner();
-  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+  runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MenuAnchorPosition::kTopLeft,
                     ui::MENU_SOURCE_NONE);
   EXPECT_TRUE(runner->IsRunning());
 
@@ -323,8 +323,8 @@
   MenuItemView* nested_menu = new MenuItemView(nested_delegate.get());
   std::unique_ptr<MenuRunner> nested_runner(
       new MenuRunner(nested_menu, MenuRunner::IS_NESTED));
-  nested_runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                           ui::MENU_SOURCE_NONE);
+  nested_runner->RunMenuAt(owner(), nullptr, gfx::Rect(),
+                           MenuAnchorPosition::kTopLeft, ui::MENU_SOURCE_NONE);
   EXPECT_TRUE(nested_runner->IsRunning());
   EXPECT_FALSE(runner->IsRunning());
   TestMenuDelegate* delegate = menu_delegate();
@@ -345,8 +345,8 @@
   // ui::EventHandler:
   void OnMouseEvent(ui::MouseEvent* event) override {
     if (event->type() == ui::ET_MOUSE_PRESSED) {
-      runner_->RunMenuAt(owner_, nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                         ui::MENU_SOURCE_NONE);
+      runner_->RunMenuAt(owner_, nullptr, gfx::Rect(),
+                         MenuAnchorPosition::kTopLeft, ui::MENU_SOURCE_NONE);
       event->SetHandled();
     }
   }
@@ -490,7 +490,8 @@
 TEST_F(MenuRunnerImplTest, NestedMenuRunnersDestroyedOutOfOrder) {
   internal::MenuRunnerImpl* menu_runner =
       new internal::MenuRunnerImpl(menu_item_view());
-  menu_runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT, 0);
+  menu_runner->RunMenuAt(owner(), nullptr, gfx::Rect(),
+                         MenuAnchorPosition::kTopLeft, 0);
 
   std::unique_ptr<TestMenuDelegate> menu_delegate2(new TestMenuDelegate);
   MenuItemView* menu_item_view2 = new MenuItemView(menu_delegate2.get());
@@ -498,8 +499,8 @@
 
   internal::MenuRunnerImpl* menu_runner2 =
       new internal::MenuRunnerImpl(menu_item_view2);
-  menu_runner2->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                          MenuRunner::IS_NESTED);
+  menu_runner2->RunMenuAt(owner(), nullptr, gfx::Rect(),
+                          MenuAnchorPosition::kTopLeft, MenuRunner::IS_NESTED);
 
   // Hide the controller so we can test out of order destruction.
   MenuControllerTestApi menu_controller;
@@ -521,7 +522,8 @@
 TEST_F(MenuRunnerImplTest, MenuRunnerDestroyedWithNoActiveController) {
   internal::MenuRunnerImpl* menu_runner =
       new internal::MenuRunnerImpl(menu_item_view());
-  menu_runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT, 0);
+  menu_runner->RunMenuAt(owner(), nullptr, gfx::Rect(),
+                         MenuAnchorPosition::kTopLeft, 0);
 
   // Hide the menu, and clear its item selection state.
   MenuControllerTestApi menu_controller;
@@ -534,8 +536,8 @@
 
   internal::MenuRunnerImpl* menu_runner2 =
       new internal::MenuRunnerImpl(menu_item_view2);
-  menu_runner2->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
-                          MenuRunner::FOR_DROP);
+  menu_runner2->RunMenuAt(owner(), nullptr, gfx::Rect(),
+                          MenuAnchorPosition::kTopLeft, MenuRunner::FOR_DROP);
 
   EXPECT_NE(menu_controller.controller(), MenuController::GetActiveInstance());
   menu_controller.SetShowing(true);
@@ -595,7 +597,8 @@
 TEST_F(MenuRunnerDestructionTest, MenuRunnerDestroyedDuringReleaseRef) {
   internal::MenuRunnerImpl* menu_runner =
       new internal::MenuRunnerImpl(menu_item_view());
-  menu_runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT, 0);
+  menu_runner->RunMenuAt(owner(), nullptr, gfx::Rect(),
+                         MenuAnchorPosition::kTopLeft, 0);
 
   views_delegate()->set_menu_runner(menu_runner);
 
diff --git a/ui/views/controls/menu/menu_scroll_view_container.cc b/ui/views/controls/menu/menu_scroll_view_container.cc
index 43752f5..17d6d7d3 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -357,17 +357,17 @@
 BubbleBorder::Arrow MenuScrollViewContainer::BubbleBorderTypeFromAnchor(
     MenuAnchorPosition anchor) {
   switch (anchor) {
-    case MENU_ANCHOR_BUBBLE_LEFT:
+    case MenuAnchorPosition::kBubbleLeft:
       return BubbleBorder::RIGHT_CENTER;
-    case MENU_ANCHOR_BUBBLE_RIGHT:
+    case MenuAnchorPosition::kBubbleRight:
       return BubbleBorder::LEFT_CENTER;
-    case MENU_ANCHOR_BUBBLE_ABOVE:
+    case MenuAnchorPosition::kBubbleAbove:
       return BubbleBorder::BOTTOM_CENTER;
-    case MENU_ANCHOR_BUBBLE_BELOW:
+    case MenuAnchorPosition::kBubbleBelow:
       return BubbleBorder::TOP_CENTER;
-    case MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE:
-    case MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT:
-    case MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT:
+    case MenuAnchorPosition::kBubbleTouchableAbove:
+    case MenuAnchorPosition::kBubbleTouchableLeft:
+    case MenuAnchorPosition::kBubbleTouchableRight:
       return BubbleBorder::FLOAT;
     default:
       return BubbleBorder::NONE;
diff --git a/ui/views/controls/menu/menu_types.h b/ui/views/controls/menu/menu_types.h
index d8419e6..c61b976 100644
--- a/ui/views/controls/menu/menu_types.h
+++ b/ui/views/controls/menu/menu_types.h
@@ -11,21 +11,19 @@
 // position will be used if base::i18n:IsRTL() is true. The BUBBLE flags are
 // used when the menu should get enclosed by a bubble. The Fixed flags are
 // used for the menus that have a fixed anchor position.
-enum MenuAnchorPosition {
-  MENU_ANCHOR_TOPLEFT,
-  MENU_ANCHOR_TOPRIGHT,
-  MENU_ANCHOR_BOTTOMCENTER,
-  MENU_ANCHOR_FIXED_BOTTOMCENTER,
-  MENU_ANCHOR_FIXED_SIDECENTER,
-  MENU_ANCHOR_BUBBLE_LEFT,
-  MENU_ANCHOR_BUBBLE_RIGHT,
-  MENU_ANCHOR_BUBBLE_ABOVE,
-  MENU_ANCHOR_BUBBLE_BELOW,
-  MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE,
-  MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT,
-  MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT,
-  // Keep this the last item.
-  MENU_ANCHOR_POSITION_LAST
+enum class MenuAnchorPosition {
+  kTopLeft,
+  kTopRight,
+  kBottomCenter,
+  kFixedBottomCenter,
+  kSideCenter,
+  kBubbleLeft,
+  kBubbleRight,
+  kBubbleAbove,
+  kBubbleBelow,
+  kBubbleTouchableAbove,
+  kBubbleTouchableLeft,
+  kBubbleTouchableRight,
 };
 
 }  // namespace views
diff --git a/ui/views/controls/scrollbar/base_scroll_bar.cc b/ui/views/controls/scrollbar/base_scroll_bar.cc
index c33458c..bb31c72d 100644
--- a/ui/views/controls/scrollbar/base_scroll_bar.cc
+++ b/ui/views/controls/scrollbar/base_scroll_bar.cc
@@ -301,7 +301,7 @@
       menu_model_.get(),
       MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU);
   menu_runner_->RunMenuAt(GetWidget(), nullptr, gfx::Rect(p, gfx::Size()),
-                          MENU_ANCHOR_TOPLEFT, source_type);
+                          MenuAnchorPosition::kTopLeft, source_type);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 4a793b66..38095214 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -1196,7 +1196,7 @@
   UpdateContextMenu();
   context_menu_runner_->RunMenuAt(GetWidget(), nullptr,
                                   gfx::Rect(point, gfx::Size()),
-                                  MENU_ANCHOR_TOPLEFT, source_type);
+                                  MenuAnchorPosition::kTopLeft, source_type);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/examples/checkbox_example.cc b/ui/views/examples/checkbox_example.cc
index d7f9670..422dd37 100644
--- a/ui/views/examples/checkbox_example.cc
+++ b/ui/views/examples/checkbox_example.cc
@@ -13,8 +13,7 @@
 namespace views {
 namespace examples {
 
-CheckboxExample::CheckboxExample() : ExampleBase("Checkbox"), count_(0) {
-}
+CheckboxExample::CheckboxExample() : ExampleBase("Checkbox") {}
 
 CheckboxExample::~CheckboxExample() = default;
 
diff --git a/ui/views/examples/checkbox_example.h b/ui/views/examples/checkbox_example.h
index 9e10134..2a88f5ad 100644
--- a/ui/views/examples/checkbox_example.h
+++ b/ui/views/examples/checkbox_example.h
@@ -29,9 +29,9 @@
   void ButtonPressed(Button* sender, const ui::Event& event) override;
 
   // The only control in this test.
-  Checkbox* button_;
+  Checkbox* button_ = nullptr;
 
-  int count_;
+  int count_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(CheckboxExample);
 };
diff --git a/ui/views/examples/label_example.cc b/ui/views/examples/label_example.cc
index 108d29e..ba39175 100644
--- a/ui/views/examples/label_example.cc
+++ b/ui/views/examples/label_example.cc
@@ -56,14 +56,7 @@
 
 }  // namespace
 
-LabelExample::LabelExample()
-    : ExampleBase("Label"),
-      textfield_(nullptr),
-      alignment_(nullptr),
-      elide_behavior_(nullptr),
-      multiline_(nullptr),
-      shadows_(nullptr),
-      custom_label_(nullptr) {}
+LabelExample::LabelExample() : ExampleBase("Label") {}
 
 LabelExample::~LabelExample() = default;
 
diff --git a/ui/views/examples/label_example.h b/ui/views/examples/label_example.h
index da35611..a6c67e6 100644
--- a/ui/views/examples/label_example.h
+++ b/ui/views/examples/label_example.h
@@ -50,15 +50,15 @@
                          const char** strings,
                          int count);
 
-  Textfield* textfield_;
-  Combobox* alignment_;
-  Combobox* elide_behavior_;
-  Checkbox* multiline_;
-  Checkbox* shadows_;
-  Checkbox* selectable_;
-  Label* custom_label_;
+   Textfield* textfield_ = nullptr;
+   Combobox* alignment_ = nullptr;
+   Combobox* elide_behavior_ = nullptr;
+   Checkbox* multiline_ = nullptr;
+   Checkbox* shadows_ = nullptr;
+   Checkbox* selectable_ = nullptr;
+   Label* custom_label_ = nullptr;
 
-  DISALLOW_COPY_AND_ASSIGN(LabelExample);
+   DISALLOW_COPY_AND_ASSIGN(LabelExample);
 };
 
 }  // namespace examples
diff --git a/ui/views/examples/menu_example.cc b/ui/views/examples/menu_example.cc
index 289affcd..7a8c555 100644
--- a/ui/views/examples/menu_example.cc
+++ b/ui/views/examples/menu_example.cc
@@ -52,7 +52,7 @@
 
   std::unique_ptr<ui::SimpleMenuModel> submenu_;
   std::set<int> checked_fruits_;
-  int current_encoding_command_id_;
+  int current_encoding_command_id_ = COMMAND_SELECT_ASCII;
 
   DISALLOW_COPY_AND_ASSIGN(ExampleMenuModel);
 };
@@ -78,9 +78,7 @@
 
 // ExampleMenuModel ---------------------------------------------------------
 
-ExampleMenuModel::ExampleMenuModel()
-    : ui::SimpleMenuModel(this),
-      current_encoding_command_id_(COMMAND_SELECT_ASCII) {
+ExampleMenuModel::ExampleMenuModel() : ui::SimpleMenuModel(this) {
   AddItem(COMMAND_DO_SOMETHING, ASCIIToUTF16("Do Something"));
   AddSeparator(ui::NORMAL_SEPARATOR);
   AddRadioItem(COMMAND_SELECT_ASCII, ASCIIToUTF16("ASCII"),
@@ -183,8 +181,8 @@
       std::make_unique<MenuRunner>(GetMenuModel(), MenuRunner::HAS_MNEMONICS);
 
   menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(), this,
-                          gfx::Rect(point, gfx::Size()), MENU_ANCHOR_TOPRIGHT,
-                          ui::MENU_SOURCE_NONE);
+                          gfx::Rect(point, gfx::Size()),
+                          MenuAnchorPosition::kTopRight, ui::MENU_SOURCE_NONE);
 }
 
 ui::SimpleMenuModel* ExampleMenuButton::GetMenuModel() {
diff --git a/ui/views/examples/multiline_example.cc b/ui/views/examples/multiline_example.cc
index e77367a..3517a36 100644
--- a/ui/views/examples/multiline_example.cc
+++ b/ui/views/examples/multiline_example.cc
@@ -121,13 +121,7 @@
   DISALLOW_COPY_AND_ASSIGN(RenderTextView);
 };
 
-MultilineExample::MultilineExample()
-    : ExampleBase("Multiline RenderText"),
-      render_text_view_(nullptr),
-      label_(nullptr),
-      textfield_(nullptr),
-      label_checkbox_(nullptr),
-      elision_checkbox_(nullptr) {}
+MultilineExample::MultilineExample() : ExampleBase("Multiline RenderText") {}
 
 MultilineExample::~MultilineExample() = default;
 
diff --git a/ui/views/examples/multiline_example.h b/ui/views/examples/multiline_example.h
index 4bb5b61f..7bcdbe9 100644
--- a/ui/views/examples/multiline_example.h
+++ b/ui/views/examples/multiline_example.h
@@ -38,15 +38,15 @@
   void ContentsChanged(Textfield* sender,
                        const base::string16& new_contents) override;
 
-  RenderTextView* render_text_view_;
-  Label* label_;
-  Textfield* textfield_;
+  RenderTextView* render_text_view_ = nullptr;
+  Label* label_ = nullptr;
+  Textfield* textfield_ = nullptr;
 
   // Checkbox to enable and disable text rendering in |label_|.
-  Checkbox* label_checkbox_;
+  Checkbox* label_checkbox_ = nullptr;
 
   // Checkbox to toggle text elision in |render_text_view_|.
-  Checkbox* elision_checkbox_;
+  Checkbox* elision_checkbox_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(MultilineExample);
 };
diff --git a/ui/views/examples/progress_bar_example.cc b/ui/views/examples/progress_bar_example.cc
index 8fe33df..27d48ba 100644
--- a/ui/views/examples/progress_bar_example.cc
+++ b/ui/views/examples/progress_bar_example.cc
@@ -25,12 +25,7 @@
 namespace views {
 namespace examples {
 
-ProgressBarExample::ProgressBarExample()
-    : ExampleBase("Progress Bar"),
-      minus_button_(nullptr),
-      plus_button_(nullptr),
-      progress_bar_(nullptr),
-      current_percent_(0.0) {}
+ProgressBarExample::ProgressBarExample() : ExampleBase("Progress Bar") {}
 
 ProgressBarExample::~ProgressBarExample() = default;
 
diff --git a/ui/views/examples/progress_bar_example.h b/ui/views/examples/progress_bar_example.h
index bf5fd90..a38751bd 100644
--- a/ui/views/examples/progress_bar_example.h
+++ b/ui/views/examples/progress_bar_example.h
@@ -27,10 +27,10 @@
   // ButtonListener:
   void ButtonPressed(Button* button, const ui::Event& event) override;
 
-  Button* minus_button_;
-  Button* plus_button_;
-  ProgressBar* progress_bar_;
-  double current_percent_;
+  Button* minus_button_ = nullptr;
+  Button* plus_button_ = nullptr;
+  ProgressBar* progress_bar_ = nullptr;
+  double current_percent_ = 0.0;
 
   DISALLOW_COPY_AND_ASSIGN(ProgressBarExample);
 };
diff --git a/ui/views/examples/slider_example.cc b/ui/views/examples/slider_example.cc
index 0509e85..edc6f84 100644
--- a/ui/views/examples/slider_example.cc
+++ b/ui/views/examples/slider_example.cc
@@ -15,8 +15,7 @@
 namespace views {
 namespace examples {
 
-SliderExample::SliderExample()
-    : ExampleBase("Slider"), slider_(nullptr), label_(nullptr) {}
+SliderExample::SliderExample() : ExampleBase("Slider") {}
 
 SliderExample::~SliderExample() = default;
 
diff --git a/ui/views/examples/slider_example.h b/ui/views/examples/slider_example.h
index 7f339d9a..4f7f57c 100644
--- a/ui/views/examples/slider_example.h
+++ b/ui/views/examples/slider_example.h
@@ -30,8 +30,8 @@
                           float old_value,
                           SliderChangeReason reason) override;
 
-  Slider* slider_;
-  Label* label_;
+  Slider* slider_ = nullptr;
+  Label* label_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(SliderExample);
 };
diff --git a/ui/views/examples/table_example.cc b/ui/views/examples/table_example.cc
index 72985b1..0a763f0 100644
--- a/ui/views/examples/table_example.cc
+++ b/ui/views/examples/table_example.cc
@@ -32,7 +32,7 @@
 
 }  // namespace
 
-TableExample::TableExample() : ExampleBase("Table"), table_(nullptr) {}
+TableExample::TableExample() : ExampleBase("Table") {}
 
 TableExample::~TableExample() {
   // Delete the view before the model.
diff --git a/ui/views/examples/table_example.h b/ui/views/examples/table_example.h
index 604b49f..36b443c 100644
--- a/ui/views/examples/table_example.h
+++ b/ui/views/examples/table_example.h
@@ -58,12 +58,12 @@
 
  private:
   // The table to be tested.
-  TableView* table_;
+  TableView* table_ = nullptr;
 
-  Checkbox* column1_visible_checkbox_;
-  Checkbox* column2_visible_checkbox_;
-  Checkbox* column3_visible_checkbox_;
-  Checkbox* column4_visible_checkbox_;
+  Checkbox* column1_visible_checkbox_ = nullptr;
+  Checkbox* column2_visible_checkbox_ = nullptr;
+  Checkbox* column3_visible_checkbox_ = nullptr;
+  Checkbox* column4_visible_checkbox_ = nullptr;
 
   SkBitmap icon1_;
   SkBitmap icon2_;
diff --git a/ui/views/examples/text_example.cc b/ui/views/examples/text_example.cc
index b999289..f1cb5f5 100644
--- a/ui/views/examples/text_example.cc
+++ b/ui/views/examples/text_example.cc
@@ -76,11 +76,7 @@
 // TextExample's content view, which draws stylized string.
 class TextExample::TextExampleView : public View {
  public:
-  TextExampleView()
-    : text_(base::ASCIIToUTF16(kShortText)),
-      flags_(0),
-      elide_(gfx::NO_ELIDE) {
-  }
+  TextExampleView() : text_(base::ASCIIToUTF16(kShortText)) {}
 
   void OnPaint(gfx::Canvas* canvas) override {
     View::OnPaint(canvas);
@@ -121,10 +117,10 @@
   base::string16 text_;
 
   // Text flags for passing to |DrawStringRect()|.
-  int flags_;
+  int flags_ = 0;
 
   // The eliding, fading, or truncating behavior.
-  gfx::ElideBehavior elide_;
+  gfx::ElideBehavior elide_ = gfx::NO_ELIDE;
 
   DISALLOW_COPY_AND_ASSIGN(TextExampleView);
 };
diff --git a/ui/views/examples/textfield_example.cc b/ui/views/examples/textfield_example.cc
index 7b4f353..b7a0290 100644
--- a/ui/views/examples/textfield_example.cc
+++ b/ui/views/examples/textfield_example.cc
@@ -23,19 +23,7 @@
 namespace views {
 namespace examples {
 
-TextfieldExample::TextfieldExample()
-    : ExampleBase("Textfield"),
-      name_(nullptr),
-      password_(nullptr),
-      disabled_(nullptr),
-      read_only_(nullptr),
-      invalid_(nullptr),
-      rtl_(nullptr),
-      show_password_(nullptr),
-      clear_all_(nullptr),
-      append_(nullptr),
-      set_(nullptr),
-      set_style_(nullptr) {}
+TextfieldExample::TextfieldExample() : ExampleBase("Textfield") {}
 
 TextfieldExample::~TextfieldExample() = default;
 
diff --git a/ui/views/examples/textfield_example.h b/ui/views/examples/textfield_example.h
index b2b5fd4a..9ea0144 100644
--- a/ui/views/examples/textfield_example.h
+++ b/ui/views/examples/textfield_example.h
@@ -42,20 +42,20 @@
   void ButtonPressed(Button* sender, const ui::Event& event) override;
 
   // Textfields for name and password.
-  Textfield* name_;
-  Textfield* password_;
-  Textfield* disabled_;
-  Textfield* read_only_;
-  Textfield* invalid_;
-  Textfield* rtl_;
+  Textfield* name_ = nullptr;
+  Textfield* password_ = nullptr;
+  Textfield* disabled_ = nullptr;
+  Textfield* read_only_ = nullptr;
+  Textfield* invalid_ = nullptr;
+  Textfield* rtl_ = nullptr;
 
   // Various buttons to control textfield.
-  LabelButton* show_password_;
-  LabelButton* set_background_;
-  LabelButton* clear_all_;
-  LabelButton* append_;
-  LabelButton* set_;
-  LabelButton* set_style_;
+  LabelButton* show_password_ = nullptr;
+  LabelButton* set_background_ = nullptr;
+  LabelButton* clear_all_ = nullptr;
+  LabelButton* append_ = nullptr;
+  LabelButton* set_ = nullptr;
+  LabelButton* set_style_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(TextfieldExample);
 };
diff --git a/ui/views/examples/throbber_example.cc b/ui/views/examples/throbber_example.cc
index 87a88f1..845ad359 100644
--- a/ui/views/examples/throbber_example.cc
+++ b/ui/views/examples/throbber_example.cc
@@ -16,7 +16,7 @@
 
 class ThrobberView : public View {
  public:
-  ThrobberView() : throbber_(new Throbber()), is_checked_(false) {
+  ThrobberView() : throbber_(new Throbber()) {
     AddChildView(throbber_);
     throbber_->Start();
   }
@@ -49,7 +49,7 @@
 
  private:
   Throbber* throbber_;
-  bool is_checked_;
+  bool is_checked_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(ThrobberView);
 };
diff --git a/ui/views/examples/toggle_button_example.cc b/ui/views/examples/toggle_button_example.cc
index 07da23c..adf5d9e 100644
--- a/ui/views/examples/toggle_button_example.cc
+++ b/ui/views/examples/toggle_button_example.cc
@@ -13,8 +13,7 @@
 namespace views {
 namespace examples {
 
-ToggleButtonExample::ToggleButtonExample()
-    : ExampleBase("Toggle button"), button_(nullptr), count_(0) {}
+ToggleButtonExample::ToggleButtonExample() : ExampleBase("Toggle button") {}
 
 ToggleButtonExample::~ToggleButtonExample() = default;
 
diff --git a/ui/views/examples/toggle_button_example.h b/ui/views/examples/toggle_button_example.h
index 50c4b9f..90a5891 100644
--- a/ui/views/examples/toggle_button_example.h
+++ b/ui/views/examples/toggle_button_example.h
@@ -29,9 +29,9 @@
   void ButtonPressed(Button* sender, const ui::Event& event) override;
 
   // The only control in this test.
-  ToggleButton* button_;
+  ToggleButton* button_ = nullptr;
 
-  int count_;
+  int count_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(ToggleButtonExample);
 };
diff --git a/ui/views/examples/tree_view_example.cc b/ui/views/examples/tree_view_example.cc
index 114841c94..1ec82dac 100644
--- a/ui/views/examples/tree_view_example.cc
+++ b/ui/views/examples/tree_view_example.cc
@@ -168,7 +168,7 @@
       std::make_unique<MenuRunner>(context_menu_model_.get(), 0);
   context_menu_runner_->RunMenuAt(source->GetWidget(), nullptr,
                                   gfx::Rect(point, gfx::Size()),
-                                  MENU_ANCHOR_TOPLEFT, source_type);
+                                  MenuAnchorPosition::kTopLeft, source_type);
 }
 
 bool TreeViewExample::IsCommandIdChecked(int command_id) const {
diff --git a/ui/views/examples/vector_example.cc b/ui/views/examples/vector_example.cc
index 6d495db..e05e8f6 100644
--- a/ui/views/examples/vector_example.cc
+++ b/ui/views/examples/vector_example.cc
@@ -39,11 +39,7 @@
         color_input_(new Textfield()),
         file_chooser_(new Textfield()),
         file_go_button_(
-            MdTextButton::Create(this, base::ASCIIToUTF16("Render"))),
-        // 36dp is one of the natural sizes for MD icons, and corresponds
-        // roughly to a 32dp usable area.
-        size_(36),
-        color_(SK_ColorRED) {
+            MdTextButton::Create(this, base::ASCIIToUTF16("Render"))) {
     AddChildView(size_input_);
     AddChildView(color_input_);
 
@@ -131,6 +127,11 @@
     Layout();
   }
 
+  // 36dp is one of the natural sizes for MD icons, and corresponds roughly to a
+  // 32dp usable area.
+  int size_ = 36;
+  SkColor color_ = SK_ColorRED;
+
   ImageView* image_view_;
   View* image_view_container_;
   Textfield* size_input_;
@@ -139,9 +140,6 @@
   Button* file_go_button_;
   std::string contents_;
 
-  int size_;
-  SkColor color_;
-
   DISALLOW_COPY_AND_ASSIGN(VectorIconGallery);
 };
 
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js b/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
index 55ce7a8..c23d6435 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
+++ b/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
@@ -388,6 +388,23 @@
 };
 
 /**
+ * Determines whether the provided properties represent a connecting/connected
+ * network.
+ * @param {!CrOnc.NetworkProperties|undefined} properties
+ * @return {boolean} Whether the properties provided indicate that the network
+ *     is connecting or connected.
+ */
+CrOnc.isConnectingOrConnected = function(properties) {
+  if (!properties) {
+    return false;
+  }
+
+  const connectionState = properties.ConnectionState;
+  return connectionState == CrOnc.ConnectionState.CONNECTED ||
+      connectionState == CrOnc.ConnectionState.CONNECTING;
+};
+
+/**
  * Gets the SignalStrength value from |properties| based on properties.Type.
  * @param {!CrOnc.NetworkProperties|!CrOnc.NetworkStateProperties|undefined}
  *     properties The ONC network properties or state properties.