diff --git a/DEPS b/DEPS
index c27725f..64343446d 100644
--- a/DEPS
+++ b/DEPS
@@ -138,11 +138,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': '64a5b671b9c01de6103209764206fdc221be5181',
+  'skia_revision': 'b9416caa367a770e55935916e135572c2461ca37',
   # 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': '6a51e6131f7ffe6afb8cd98d27faaa2af54037b5',
+  'v8_revision': 'eca9f8c887e111480522a0477522b0d5fdbc7095',
   # 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.
@@ -150,15 +150,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': '13ac9422cf189cef255bc00627f05bddffa070f0',
+  'angle_revision': '85fef1bc62f851a4de91408cfafa570dbacf544f',
   # 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': 'f9411ce30f132dbcb297a533525000a788b7c951',
+  'swiftshader_revision': 'df84b9466cfd59992e09f1d04bb0453060f3aa0f',
   # 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': 'd8ae8f8120dc8d2e63f98999c19236495519137f',
+  'pdfium_revision': 'd050b35a14af9626b0b08c12c563696cd7ed25e6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -201,7 +201,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': '86a9e51b7ad87e1a1a4fbd1f7abf7e8e19f281bf',
+  'catapult_revision': '727d7ca2730f942dd59a2389f8471d579c8ee95b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -261,7 +261,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_headers_revision': '9cf7c3a7d2d203b1ee35896547b9644e28d9280e',
+  'spv_headers_revision': 'de99d4d834aeb51dd9f099baa285bd44fd04bb3d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -273,7 +273,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '970101a1028dbd2ec46028a2e40ae1a0974de1b3',
+  'dawn_revision': '87ab2f96d93bcf28ce97fa27a0c90f870ec040db',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -807,7 +807,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '491e16e8569b19b2877448ca5ff4817b007f03b1',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'bbe067f8952c0e9f230ab853561d7d59291ac619',
       'condition': 'checkout_linux',
   },
 
@@ -1187,7 +1187,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '07b9e93544271ef4ddea3519b73ac6cda236d3d6',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '6b5210e9dfb6bbf58d62d0010e3369e95cd13085',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1355,7 +1355,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6f0b34abee8dba611c253738d955c59f703c147a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '51db421682d67c9ab78cc029d0aa3b2e94d1f3e0',
+    Var('webrtc_git') + '/src.git' + '@' + 'a7acc4dd8d303310fb1bd2cfafbc032f308b1fbc',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1396,7 +1396,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2fcee1474c0d19c97821c6dcef5d8e21bfb41b9e',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d96cf88529977e65f994d950bddaef85bac305f6',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 1abd2964..803f596 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2269,9 +2269,7 @@
                         'cywang@chromium.org',
                         'vovoy@chromium.org'],
     'crostini': ['crostini-ui@chromium.org'],
-    'cups_printing': ['baileyberro+watch-printers@chromium.org',
-                      'jimmyxgong+watch-printers@chromium.org',
-                      'zentaro+watch-printers@chromium.org'],
+    'cups_printing': ['print-reviews+cups@chromium.org'],
     'custom_proxy': ['lbendig@opera.com',
                      'wdzierzanowski@opera.com'],
     'custom_tabs': ['amalova+watch@chromium.org',
@@ -2508,7 +2506,7 @@
                   'tburkard+watch@chromium.org'],
     'presentation': ['mfoltz+watch@chromium.org'],
     'preview_features': ['chrome-lite-pages+watch@google.com'],
-    'print_preview': ['rbpotter@chromium.org'],
+    'print_preview': ['print-reviews+preview@chromium.org'],
     'push_messaging': ['peter@chromium.org'],
     'reading_list': ['stkhapugin@chromium.org'],
     'remoteplayback': ['mfoltz+watch@chromium.org'],
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index c8786471..81616ef 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1269,7 +1269,6 @@
     "//services/device/public/mojom",
     "//services/media_session/public/mojom",
     "//services/service_manager/public/cpp",
-    "//services/ws/public/cpp/input_devices",
     "//skia",
     "//ui/aura",
     "//ui/events",
@@ -1360,8 +1359,6 @@
     "//services/data_decoder/public/cpp",
     "//services/preferences/public/cpp",
     "//services/service_manager/public/cpp",
-    "//services/ws/public/cpp/input_devices:input_device_controller",
-    "//services/ws/public/mojom/input_devices",
 
     # TODO(msw): Remove this; ash should not depend on blink/webkit.
     "//third_party/blink/public:blink_headers",
@@ -1386,7 +1383,6 @@
     "//ui/events:events_base",
     "//ui/events:gesture_detection",
     "//ui/events/devices",
-    "//ui/events/devices/mojo",
     "//ui/events/ozone:events_ozone",
     "//ui/message_center",
     "//ui/native_theme",
@@ -2207,7 +2203,6 @@
     "//components/viz/test:test_support",
     "//device/bluetooth",
     "//services/device/public/mojom",
-    "//services/ws/public/cpp/input_devices",
     "//skia",
     "//testing/gtest",
     "//ui/accessibility",
diff --git a/ash/DEPS b/ash/DEPS
index fb790b2..865e3259 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -85,20 +85,6 @@
   # InputMethodManager lives in the browser process. Use ImeController.
   "-ui/base/ime/chromeos/input_method_manager.h"
 
-  # ui/events/devices is tied with ozone, which is controlled by mus, and
-  # shouldn't be used by ash.
-  "-ui/events/devices",
-
-  # Enums and supporting classes or observers that are safe (should be moved to
-  # services/ws/public/cpp). http://crbug.com/747544.
-  "+ui/events/devices/device_hotplug_event_observer.h",
-  "+ui/events/devices/input_device.h",
-  "+ui/events/devices/input_device_event_observer.h",
-  "+ui/events/devices/input_device_manager.h",
-  "+ui/events/devices/stylus_state.h",
-  "+ui/events/devices/touch_device_transform.h",
-  "+ui/events/devices/touchscreen_device.h",
-
   # SessionManager/UserManager is not part of ash. Use SessionController.
   "-components/session_manager/core",
   "-components/user_manager/user_manager.h",
diff --git a/ash/accessibility/touch_exploration_manager.h b/ash/accessibility/touch_exploration_manager.h
index 4f11f4e..3cae740 100644
--- a/ash/accessibility/touch_exploration_manager.h
+++ b/ash/accessibility/touch_exploration_manager.h
@@ -11,7 +11,7 @@
 #include "ash/accessibility/touch_accessibility_enabler.h"
 #include "ash/accessibility/touch_exploration_controller.h"
 #include "ash/ash_export.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/shell_observer.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
@@ -40,7 +40,7 @@
       public TouchAccessibilityEnablerDelegate,
       public display::DisplayObserver,
       public ::wm::ActivationChangeObserver,
-      public keyboard::KeyboardControllerObserver,
+      public KeyboardControllerObserver,
       public ShellObserver {
  public:
   explicit TouchExplorationManager(
@@ -86,7 +86,7 @@
   void SetTouchAccessibilityAnchorPoint(const gfx::Point& anchor_point);
 
  private:
-  // keyboard::KeyboardControllerObserver overrides:
+  // KeyboardControllerObserver overrides:
   void OnKeyboardVisibleBoundsChanged(const gfx::Rect& new_bounds) override;
   void OnKeyboardEnabledChanged(bool is_enabled) override;
 
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 90072d1..c9b3642 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -625,8 +625,7 @@
     presenter_.GetView()->OnWallpaperColorsChanged();
 }
 
-void AppListControllerImpl::OnKeyboardVisibilityStateChanged(
-    const bool is_visible) {
+void AppListControllerImpl::OnKeyboardVisibilityChanged(const bool is_visible) {
   onscreen_keyboard_shown_ = is_visible;
   app_list::AppListView* app_list_view = presenter_.GetView();
   if (app_list_view)
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index 21b0240..56d9f4d 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -21,9 +21,9 @@
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/home_screen/home_launcher_gesture_handler_observer.h"
 #include "ash/home_screen/home_screen_delegate.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
 #include "ash/public/cpp/app_list/app_list_controller.h"
 #include "ash/public/cpp/assistant/default_voice_interaction_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/wallpaper_controller_observer.h"
 #include "ash/public/interfaces/voice_interaction_controller.mojom.h"
@@ -56,7 +56,7 @@
       public ash::ShellObserver,
       public OverviewObserver,
       public TabletModeObserver,
-      public keyboard::KeyboardControllerObserver,
+      public KeyboardControllerObserver,
       public WallpaperControllerObserver,
       public DefaultVoiceInteractionObserver,
       public WindowTreeHostManager::Observer,
@@ -222,7 +222,7 @@
   void OnTabletModeEnded() override;
 
   // KeyboardControllerObserver:
-  void OnKeyboardVisibilityStateChanged(bool is_visible) override;
+  void OnKeyboardVisibilityChanged(bool is_visible) override;
 
   // WallpaperControllerObserver:
   void OnWallpaperColorsChanged() override;
diff --git a/ash/app_list/app_list_presenter_delegate_impl.h b/ash/app_list/app_list_presenter_delegate_impl.h
index fe7681a..7c91618 100644
--- a/ash/app_list/app_list_presenter_delegate_impl.h
+++ b/ash/app_list/app_list_presenter_delegate_impl.h
@@ -9,7 +9,6 @@
 
 #include "ash/app_list/presenter/app_list_presenter_delegate.h"
 #include "ash/ash_export.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "ui/display/display_observer.h"
diff --git a/ash/assistant/assistant_ui_controller.cc b/ash/assistant/assistant_ui_controller.cc
index 94372217..11e3bcf 100644
--- a/ash/assistant/assistant_ui_controller.cc
+++ b/ash/assistant/assistant_ui_controller.cc
@@ -480,7 +480,7 @@
                    due_to_interaction);
 }
 
-void AssistantUiController::OnKeyboardWorkspaceOccludedBoundsChanged(
+void AssistantUiController::OnKeyboardOccludedBoundsChanged(
     const gfx::Rect& new_bounds_in_screen) {
   DCHECK(container_view_);
 
@@ -518,7 +518,7 @@
   // inconsistency between normal virtual keyboard and accessibility keyboard in
   // changing the work area (accessibility keyboard will change the display work
   // area but virtual keyboard won't). Display metrics change with keyboard
-  // showing is instead handled by OnKeyboardWorkspaceOccludedBoundsChanged.
+  // showing is instead handled by OnKeyboardOccludedBoundsChanged.
   if (keyboard_workspace_occluded_bounds_.IsEmpty()) {
     aura::Window* root_window =
         container_view_->GetWidget()->GetNativeWindow()->GetRootWindow();
diff --git a/ash/assistant/assistant_ui_controller.h b/ash/assistant/assistant_ui_controller.h
index 1a075bd7..946e89a 100644
--- a/ash/assistant/assistant_ui_controller.h
+++ b/ash/assistant/assistant_ui_controller.h
@@ -18,7 +18,7 @@
 #include "ash/assistant/ui/assistant_view_delegate.h"
 #include "ash/assistant/ui/caption_bar.h"
 #include "ash/highlighter/highlighter_controller.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/timer/timer.h"
@@ -54,7 +54,7 @@
       public AssistantViewDelegateObserver,
       public CaptionBarDelegate,
       public HighlighterController::Observer,
-      public keyboard::KeyboardControllerObserver,
+      public KeyboardControllerObserver,
       public display::DisplayObserver,
       public ui::EventObserver {
  public:
@@ -112,9 +112,8 @@
       base::Optional<AssistantEntryPoint> entry_point,
       base::Optional<AssistantExitPoint> exit_point) override;
 
-  // keyboard::KeyboardControllerObserver:
-  void OnKeyboardWorkspaceOccludedBoundsChanged(
-      const gfx::Rect& new_bounds) override;
+  // KeyboardControllerObserver:
+  void OnKeyboardOccludedBoundsChanged(const gfx::Rect& new_bounds) override;
 
   // display::DisplayObserver:
   void OnDisplayMetricsChanged(const display::Display& display,
diff --git a/ash/components/shortcut_viewer/DEPS b/ash/components/shortcut_viewer/DEPS
index 9083c1ecd..d708fed 100644
--- a/ash/components/shortcut_viewer/DEPS
+++ b/ash/components/shortcut_viewer/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   "+ash/components/strings",
-  "+services/ws/public",
   "+ui/accessibility",
   "+ui/chromeos/events",
   "+ui/chromeos/search_box",
diff --git a/ash/host/ash_window_tree_host_platform.cc b/ash/host/ash_window_tree_host_platform.cc
index f368a97..b6e5209 100644
--- a/ash/host/ash_window_tree_host_platform.cc
+++ b/ash/host/ash_window_tree_host_platform.cc
@@ -13,7 +13,6 @@
 #include "ash/window_factory.h"
 #include "base/feature_list.h"
 #include "base/trace_event/trace_event.h"
-#include "services/ws/public/cpp/input_devices/input_device_controller_client.h"
 #include "ui/aura/null_window_targeter.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host_platform.h"
@@ -24,6 +23,8 @@
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/transform.h"
+#include "ui/ozone/public/input_controller.h"
+#include "ui/ozone/public/ozone_platform.h"
 #include "ui/platform_window/platform_window.h"
 #include "ui/platform_window/platform_window_init_properties.h"
 
@@ -152,13 +153,9 @@
 }
 
 void AshWindowTreeHostPlatform::SetTapToClickPaused(bool state) {
-  ws::InputDeviceControllerClient* input_device_controller_client =
-      Shell::Get()->shell_delegate()->GetInputDeviceControllerClient();
-  if (!input_device_controller_client)
-    return;  // Happens in tests.
-
   // Temporarily pause tap-to-click when the cursor is hidden.
-  input_device_controller_client->SetTapToClickPaused(state);
+  ui::OzonePlatform::GetInstance()->GetInputController()->SetTapToClickPaused(
+      state);
 }
 
 void AshWindowTreeHostPlatform::DispatchEvent(ui::Event* event) {
diff --git a/ash/keyboard/ash_keyboard_controller.cc b/ash/keyboard/ash_keyboard_controller.cc
index 0e603de..2d104039a 100644
--- a/ash/keyboard/ash_keyboard_controller.cc
+++ b/ash/keyboard/ash_keyboard_controller.cc
@@ -4,6 +4,8 @@
 
 #include "ash/keyboard/ash_keyboard_controller.h"
 
+#include <utility>
+
 #include "ash/keyboard/ui/keyboard_controller.h"
 #include "ash/keyboard/ui/keyboard_ui_factory.h"
 #include "ash/keyboard/virtual_keyboard_controller.h"
@@ -80,9 +82,8 @@
   keyboard_controller()->KeyboardContentsLoaded(size);
 }
 
-void AshKeyboardController::GetKeyboardConfig(
-    GetKeyboardConfigCallback callback) {
-  std::move(callback).Run(keyboard_controller_->keyboard_config());
+keyboard::KeyboardConfig AshKeyboardController::GetKeyboardConfig() {
+  return keyboard_controller_->keyboard_config();
 }
 
 void AshKeyboardController::SetKeyboardConfig(
@@ -90,9 +91,8 @@
   keyboard_controller_->UpdateKeyboardConfig(keyboard_config);
 }
 
-void AshKeyboardController::IsKeyboardEnabled(
-    IsKeyboardEnabledCallback callback) {
-  std::move(callback).Run(keyboard_controller_->IsEnabled());
+bool AshKeyboardController::IsKeyboardEnabled() {
+  return keyboard_controller_->IsEnabled();
 }
 
 void AshKeyboardController::SetEnableFlag(KeyboardEnableFlag flag) {
@@ -103,12 +103,9 @@
   keyboard_controller_->ClearEnableFlag(flag);
 }
 
-void AshKeyboardController::GetEnableFlags(GetEnableFlagsCallback callback) {
-  const std::set<keyboard::KeyboardEnableFlag>& keyboard_enable_flags =
-      keyboard_controller_->keyboard_enable_flags();
-  std::vector<keyboard::KeyboardEnableFlag> flags(keyboard_enable_flags.begin(),
-                                                  keyboard_enable_flags.end());
-  std::move(callback).Run(std::move(flags));
+const std::set<keyboard::KeyboardEnableFlag>&
+AshKeyboardController::GetEnableFlags() {
+  return keyboard_controller_->keyboard_enable_flags();
 }
 
 void AshKeyboardController::ReloadKeyboardIfNeeded() {
@@ -122,9 +119,8 @@
   keyboard_controller_->RebuildKeyboardIfEnabled();
 }
 
-void AshKeyboardController::IsKeyboardVisible(
-    IsKeyboardVisibleCallback callback) {
-  std::move(callback).Run(keyboard_controller_->IsKeyboardVisible());
+bool AshKeyboardController::IsKeyboardVisible() {
+  return keyboard_controller_->IsKeyboardVisible();
 }
 
 void AshKeyboardController::ShowKeyboard() {
@@ -174,8 +170,7 @@
   keyboard_controller_->SetDraggableArea(bounds);
 }
 
-void AshKeyboardController::AddObserver(
-    ash::KeyboardControllerObserver* observer) {
+void AshKeyboardController::AddObserver(KeyboardControllerObserver* observer) {
   observers_.AddObserver(observer);
 }
 
@@ -211,13 +206,13 @@
   }
 }
 
-void AshKeyboardController::OnKeyboardConfigChanged() {
-  KeyboardConfig config = keyboard_controller_->keyboard_config();
+void AshKeyboardController::OnKeyboardConfigChanged(
+    const keyboard::KeyboardConfig& config) {
   for (auto& observer : observers_)
     observer.OnKeyboardConfigChanged(config);
 }
 
-void AshKeyboardController::OnKeyboardVisibilityStateChanged(bool is_visible) {
+void AshKeyboardController::OnKeyboardVisibilityChanged(bool is_visible) {
   for (auto& observer : observers_)
     observer.OnKeyboardVisibilityChanged(is_visible);
 }
@@ -227,7 +222,7 @@
   SendOnKeyboardVisibleBoundsChanged(screen_bounds);
 }
 
-void AshKeyboardController::OnKeyboardWorkspaceOccludedBoundsChanged(
+void AshKeyboardController::OnKeyboardOccludedBoundsChanged(
     const gfx::Rect& screen_bounds) {
   DVLOG(1) << "OnKeyboardOccludedBoundsChanged: " << screen_bounds.ToString();
   for (auto& observer : observers_)
@@ -235,12 +230,9 @@
 }
 
 void AshKeyboardController::OnKeyboardEnableFlagsChanged(
-    const std::set<keyboard::KeyboardEnableFlag>& keyboard_enable_flags) {
-  std::vector<keyboard::KeyboardEnableFlag> flags(keyboard_enable_flags.begin(),
-                                                  keyboard_enable_flags.end());
-  for (auto& observer : observers_) {
+    const std::set<keyboard::KeyboardEnableFlag>& flags) {
+  for (auto& observer : observers_)
     observer.OnKeyboardEnableFlagsChanged(flags);
-  }
 }
 
 void AshKeyboardController::OnKeyboardEnabledChanged(bool is_enabled) {
diff --git a/ash/keyboard/ash_keyboard_controller.h b/ash/keyboard/ash_keyboard_controller.h
index 8d42172..6d5cc29d 100644
--- a/ash/keyboard/ash_keyboard_controller.h
+++ b/ash/keyboard/ash_keyboard_controller.h
@@ -6,11 +6,13 @@
 #define ASH_KEYBOARD_ASH_KEYBOARD_CONTROLLER_H_
 
 #include <memory>
+#include <set>
+#include <vector>
 
 #include "ash/ash_export.h"
 #include "ash/keyboard/ui/keyboard_controller.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
 #include "ash/public/cpp/keyboard/keyboard_controller.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/session/session_observer.h"
 #include "base/macros.h"
 #include "base/optional.h"
@@ -34,10 +36,9 @@
 // class. TODO(shend): Consider re-factoring keyboard::KeyboardController so
 // that this can inherit from that class instead. Rename this to
 // KeyboardControllerImpl.
-class ASH_EXPORT AshKeyboardController
-    : public ash::KeyboardController,
-      public keyboard::KeyboardControllerObserver,
-      public SessionObserver {
+class ASH_EXPORT AshKeyboardController : public KeyboardController,
+                                         public KeyboardControllerObserver,
+                                         public SessionObserver {
  public:
   // |session_controller| is expected to outlive AshKeyboardController.
   explicit AshKeyboardController(SessionControllerImpl* session_controller);
@@ -57,16 +58,16 @@
 
   // ash::KeyboardController:
   void KeyboardContentsLoaded(const gfx::Size& size) override;
-  void GetKeyboardConfig(GetKeyboardConfigCallback callback) override;
+  keyboard::KeyboardConfig GetKeyboardConfig() override;
   void SetKeyboardConfig(
       const keyboard::KeyboardConfig& keyboard_config) override;
-  void IsKeyboardEnabled(IsKeyboardEnabledCallback callback) override;
+  bool IsKeyboardEnabled() override;
   void SetEnableFlag(keyboard::KeyboardEnableFlag flag) override;
   void ClearEnableFlag(keyboard::KeyboardEnableFlag flag) override;
-  void GetEnableFlags(GetEnableFlagsCallback callback) override;
+  const std::set<keyboard::KeyboardEnableFlag>& GetEnableFlags() override;
   void ReloadKeyboardIfNeeded() override;
   void RebuildKeyboardIfEnabled() override;
-  void IsKeyboardVisible(IsKeyboardVisibleCallback callback) override;
+  bool IsKeyboardVisible() override;
   void ShowKeyboard() override;
   void HideKeyboard(HideReason reason) override;
   void SetContainerType(keyboard::ContainerType container_type,
@@ -76,7 +77,7 @@
   void SetOccludedBounds(const std::vector<gfx::Rect>& bounds) override;
   void SetHitTestBounds(const std::vector<gfx::Rect>& bounds) override;
   void SetDraggableArea(const gfx::Rect& bounds) override;
-  void AddObserver(ash::KeyboardControllerObserver* observer) override;
+  void AddObserver(KeyboardControllerObserver* observer) override;
 
   // SessionObserver:
   void OnSessionStateChanged(session_manager::SessionState state) override;
@@ -95,21 +96,19 @@
   void OnRootWindowClosing(aura::Window* root_window);
 
  private:
-  // keyboard::KeyboardControllerObserver
-  void OnKeyboardConfigChanged() override;
-  void OnKeyboardVisibilityStateChanged(bool is_visible) override;
+  // KeyboardControllerObserver:
+  void OnKeyboardConfigChanged(const keyboard::KeyboardConfig& config) override;
+  void OnKeyboardVisibilityChanged(bool is_visible) override;
   void OnKeyboardVisibleBoundsChanged(const gfx::Rect& screen_bounds) override;
-  void OnKeyboardWorkspaceOccludedBoundsChanged(
-      const gfx::Rect& screen_bounds) override;
+  void OnKeyboardOccludedBoundsChanged(const gfx::Rect& screen_bounds) override;
   void OnKeyboardEnableFlagsChanged(
-      const std::set<keyboard::KeyboardEnableFlag>& keyboard_enable_flags)
-      override;
+      const std::set<keyboard::KeyboardEnableFlag>& flags) override;
   void OnKeyboardEnabledChanged(bool is_enabled) override;
 
   SessionControllerImpl* session_controller_;  // unowned
   std::unique_ptr<keyboard::KeyboardController> keyboard_controller_;
   std::unique_ptr<VirtualKeyboardController> virtual_keyboard_controller_;
-  base::ObserverList<ash::KeyboardControllerObserver>::Unchecked observers_;
+  base::ObserverList<KeyboardControllerObserver>::Unchecked observers_;
 
   DISALLOW_COPY_AND_ASSIGN(AshKeyboardController);
 };
diff --git a/ash/keyboard/ash_keyboard_controller_unittest.cc b/ash/keyboard/ash_keyboard_controller_unittest.cc
index 9ac42c1..410e1e8 100644
--- a/ash/keyboard/ash_keyboard_controller_unittest.cc
+++ b/ash/keyboard/ash_keyboard_controller_unittest.cc
@@ -5,7 +5,8 @@
 #include "ash/keyboard/ash_keyboard_controller.h"
 
 #include <memory>
-#include <vector>
+#include <set>
+#include <utility>
 
 #include "ash/keyboard/ui/container_behavior.h"
 #include "ash/keyboard/ui/keyboard_controller.h"
@@ -18,6 +19,7 @@
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/scoped_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/window.h"
@@ -30,117 +32,6 @@
 
 namespace {
 
-// TODO(shend): Remove this as AshKeyboardController no longer uses mojo.
-class TestClient {
- public:
-  explicit TestClient()
-      : keyboard_controller_(Shell::Get()->ash_keyboard_controller()) {}
-
-  ~TestClient() = default;
-
-  bool IsKeyboardEnabled() {
-    keyboard_controller_->IsKeyboardEnabled(base::BindOnce(
-        &TestClient::OnIsKeyboardEnabled, base::Unretained(this)));
-    return is_enabled_;
-  }
-
-  void GetKeyboardConfig() {
-    keyboard_controller_->GetKeyboardConfig(base::BindOnce(
-        &TestClient::OnGetKeyboardConfig, base::Unretained(this)));
-  }
-
-  void SetKeyboardConfig(KeyboardConfig config) {
-    keyboard_controller_->SetKeyboardConfig(std::move(config));
-  }
-
-  void SetEnableFlag(KeyboardEnableFlag flag) {
-    keyboard_controller_->SetEnableFlag(flag);
-  }
-
-  void ClearEnableFlag(KeyboardEnableFlag flag) {
-    keyboard_controller_->ClearEnableFlag(flag);
-  }
-
-  std::vector<keyboard::KeyboardEnableFlag> GetEnableFlags() {
-    std::vector<keyboard::KeyboardEnableFlag> enable_flags;
-    base::RunLoop run_loop;
-    keyboard_controller_->GetEnableFlags(base::BindOnce(
-        [](std::vector<keyboard::KeyboardEnableFlag>* enable_flags,
-           base::OnceClosure callback,
-           const std::vector<keyboard::KeyboardEnableFlag>& flags) {
-          *enable_flags = flags;
-          std::move(callback).Run();
-        },
-        &enable_flags, run_loop.QuitClosure()));
-    run_loop.Run();
-    return enable_flags;
-  }
-
-  void RebuildKeyboardIfEnabled() {
-    keyboard_controller_->RebuildKeyboardIfEnabled();
-  }
-
-  bool IsKeyboardVisible() {
-    keyboard_controller_->IsKeyboardVisible(base::BindOnce(
-        &TestClient::OnIsKeyboardVisible, base::Unretained(this)));
-    return is_visible_;
-  }
-
-  void ShowKeyboard() { keyboard_controller_->ShowKeyboard(); }
-
-  void HideKeyboard() { keyboard_controller_->HideKeyboard(HideReason::kUser); }
-
-  bool SetContainerType(keyboard::ContainerType container_type,
-                        const base::Optional<gfx::Rect>& target_bounds) {
-    bool result;
-    base::RunLoop run_loop;
-    keyboard_controller_->SetContainerType(
-        container_type, target_bounds,
-        base::BindOnce(
-            [](bool* result_ptr, base::OnceClosure callback, bool result) {
-              *result_ptr = result;
-              std::move(callback).Run();
-            },
-            &result, run_loop.QuitClosure()));
-    run_loop.Run();
-    return result;
-  }
-
-  void SetKeyboardLocked(bool locked) {
-    keyboard_controller_->SetKeyboardLocked(locked);
-  }
-
-  void SetOccludedBounds(const std::vector<gfx::Rect>& bounds) {
-    keyboard_controller_->SetOccludedBounds(bounds);
-  }
-
-  void SetHitTestBounds(const std::vector<gfx::Rect>& bounds) {
-    keyboard_controller_->SetHitTestBounds(bounds);
-  }
-
-  void SetDraggableArea(const gfx::Rect& bounds) {
-    keyboard_controller_->SetDraggableArea(bounds);
-  }
-
-  int got_keyboard_config_count() const { return got_keyboard_config_count_; }
-  const KeyboardConfig& keyboard_config() const { return keyboard_config_; }
-
- private:
-  void OnIsKeyboardEnabled(bool enabled) { is_enabled_ = enabled; }
-  void OnIsKeyboardVisible(bool visible) { is_visible_ = visible; }
-
-  void OnGetKeyboardConfig(const KeyboardConfig& config) {
-    ++got_keyboard_config_count_;
-    keyboard_config_ = config;
-  }
-
-  KeyboardController* keyboard_controller_ = nullptr;
-  bool is_enabled_ = false;
-  bool is_visible_ = false;
-  int got_keyboard_config_count_ = 0;
-  KeyboardConfig keyboard_config_;
-};
-
 class TestContainerBehavior : public keyboard::ContainerBehavior {
  public:
   TestContainerBehavior() : keyboard::ContainerBehavior(nullptr) {}
@@ -212,116 +103,130 @@
   void SetUp() override {
     AshTestBase::SetUp();
 
-    test_client_ = std::make_unique<TestClient>();
-
-    // Set the initial observer config to the client (default) config.
-    test_observer()->set_config(test_client()->keyboard_config());
+    // Set the initial observer config to the default config.
+    test_observer()->set_config(ash_keyboard_controller()->GetKeyboardConfig());
   }
 
   void TearDown() override {
-    test_client_.reset();
     AshTestBase::TearDown();
   }
 
-  keyboard::KeyboardController* keyboard_controller() {
-    return Shell::Get()->ash_keyboard_controller()->keyboard_controller();
+  AshKeyboardController* ash_keyboard_controller() {
+    return Shell::Get()->ash_keyboard_controller();
   }
-  TestClient* test_client() { return test_client_.get(); }
+  keyboard::KeyboardController* keyboard_controller() {
+    return ash_keyboard_controller()->keyboard_controller();
+  }
   TestKeyboardControllerObserver* test_observer() {
     return ash_test_helper()->test_keyboard_controller_observer();
   }
 
- private:
-  std::unique_ptr<TestClient> test_client_;
+ protected:
+  bool SetContainerType(keyboard::ContainerType container_type,
+                        const base::Optional<gfx::Rect>& target_bounds) {
+    bool result = false;
+    base::RunLoop run_loop;
+    ash_keyboard_controller()->SetContainerType(
+        container_type, target_bounds,
+        base::BindLambdaForTesting([&](bool success) {
+          result = success;
+          run_loop.QuitWhenIdle();
+        }));
+    run_loop.Run();
+    return result;
+  }
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(AshKeyboardControllerTest);
 };
 
 }  // namespace
 
-TEST_F(AshKeyboardControllerTest, GetKeyboardConfig) {
-  test_client()->GetKeyboardConfig();
-  EXPECT_EQ(1, test_client()->got_keyboard_config_count());
-}
-
 TEST_F(AshKeyboardControllerTest, SetKeyboardConfig) {
   // Enable the keyboard so that config changes trigger observer events.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
 
-  test_client()->GetKeyboardConfig();
-  EXPECT_EQ(1, test_client()->got_keyboard_config_count());
-  KeyboardConfig config = test_client()->keyboard_config();
-  // Set the observer config to the client (default) config.
+  ash_keyboard_controller()->GetKeyboardConfig();
+  KeyboardConfig config = ash_keyboard_controller()->GetKeyboardConfig();
+  // Set the observer config to the default config.
   test_observer()->set_config(config);
 
   // Change the keyboard config.
   bool old_auto_complete = config.auto_complete;
   config.auto_complete = !config.auto_complete;
-  test_client()->SetKeyboardConfig(std::move(config));
+  ash_keyboard_controller()->SetKeyboardConfig(std::move(config));
 
   // Test that the config changes.
-  test_client()->GetKeyboardConfig();
-  EXPECT_NE(old_auto_complete, test_client()->keyboard_config().auto_complete);
+  ash_keyboard_controller()->GetKeyboardConfig();
+  EXPECT_NE(old_auto_complete,
+            ash_keyboard_controller()->GetKeyboardConfig().auto_complete);
 
   // Test that the test observer received the change.
   EXPECT_NE(old_auto_complete, test_observer()->config().auto_complete);
 }
 
 TEST_F(AshKeyboardControllerTest, EnableFlags) {
-  EXPECT_FALSE(test_client()->IsKeyboardEnabled());
+  EXPECT_FALSE(ash_keyboard_controller()->IsKeyboardEnabled());
   // Enable the keyboard.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
-  std::vector<keyboard::KeyboardEnableFlag> enable_flags =
-      test_client()->GetEnableFlags();
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
+  std::set<keyboard::KeyboardEnableFlag> enable_flags =
+      ash_keyboard_controller()->GetEnableFlags();
   EXPECT_TRUE(
       base::Contains(enable_flags, KeyboardEnableFlag::kExtensionEnabled));
   EXPECT_EQ(enable_flags, test_observer()->enable_flags());
-  EXPECT_TRUE(test_client()->IsKeyboardEnabled());
+  EXPECT_TRUE(ash_keyboard_controller()->IsKeyboardEnabled());
 
   // Set the enable override to disable the keyboard.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kPolicyDisabled);
-  enable_flags = test_client()->GetEnableFlags();
+  ash_keyboard_controller()->SetEnableFlag(KeyboardEnableFlag::kPolicyDisabled);
+  enable_flags = ash_keyboard_controller()->GetEnableFlags();
   EXPECT_TRUE(
       base::Contains(enable_flags, KeyboardEnableFlag::kExtensionEnabled));
   EXPECT_TRUE(
       base::Contains(enable_flags, KeyboardEnableFlag::kPolicyDisabled));
   EXPECT_EQ(enable_flags, test_observer()->enable_flags());
-  EXPECT_FALSE(test_client()->IsKeyboardEnabled());
+  EXPECT_FALSE(ash_keyboard_controller()->IsKeyboardEnabled());
 
   // Clear the enable override; should enable the keyboard.
-  test_client()->ClearEnableFlag(KeyboardEnableFlag::kPolicyDisabled);
-  enable_flags = test_client()->GetEnableFlags();
+  ash_keyboard_controller()->ClearEnableFlag(
+      KeyboardEnableFlag::kPolicyDisabled);
+  enable_flags = ash_keyboard_controller()->GetEnableFlags();
   EXPECT_TRUE(
       base::Contains(enable_flags, KeyboardEnableFlag::kExtensionEnabled));
   EXPECT_FALSE(
       base::Contains(enable_flags, KeyboardEnableFlag::kPolicyDisabled));
   EXPECT_EQ(enable_flags, test_observer()->enable_flags());
-  EXPECT_TRUE(test_client()->IsKeyboardEnabled());
+  EXPECT_TRUE(ash_keyboard_controller()->IsKeyboardEnabled());
 }
 
 TEST_F(AshKeyboardControllerTest, RebuildKeyboardIfEnabled) {
   EXPECT_EQ(0, test_observer()->destroyed_count());
 
   // Enable the keyboard.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
   EXPECT_EQ(0, test_observer()->destroyed_count());
 
   // Enable the keyboard again; this should not reload the keyboard.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
   EXPECT_EQ(0, test_observer()->destroyed_count());
 
   // Rebuild the keyboard. This should destroy the previous keyboard window.
-  test_client()->RebuildKeyboardIfEnabled();
+  ash_keyboard_controller()->RebuildKeyboardIfEnabled();
   EXPECT_EQ(1, test_observer()->destroyed_count());
 
   // Disable the keyboard. The keyboard window should be destroyed.
-  test_client()->ClearEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->ClearEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
   EXPECT_EQ(2, test_observer()->destroyed_count());
 }
 
 TEST_F(AshKeyboardControllerTest, ShowAndHideKeyboard) {
   // Enable the keyboard. This will create the keyboard window but not show it.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
 
   ASSERT_TRUE(keyboard_controller()->GetKeyboardWindow());
   EXPECT_FALSE(keyboard_controller()->GetKeyboardWindow()->IsVisible());
@@ -329,10 +234,10 @@
   // The keyboard needs to be in a loaded state before being shown.
   ASSERT_TRUE(keyboard::test::WaitUntilLoaded());
 
-  test_client()->ShowKeyboard();
+  ash_keyboard_controller()->ShowKeyboard();
   EXPECT_TRUE(keyboard_controller()->GetKeyboardWindow()->IsVisible());
 
-  test_client()->HideKeyboard();
+  ash_keyboard_controller()->HideKeyboard(HideReason::kUser);
   EXPECT_FALSE(keyboard_controller()->GetKeyboardWindow()->IsVisible());
 
   // TODO(stevenjb): Also use TestKeyboardControllerObserver and
@@ -341,14 +246,15 @@
 
 TEST_F(AshKeyboardControllerTest, SetContainerType) {
   // Enable the keyboard.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
   const auto default_behavior = keyboard::ContainerType::kFullWidth;
   EXPECT_EQ(default_behavior, keyboard_controller()->GetActiveContainerType());
 
   gfx::Rect target_bounds(0, 0, 10, 10);
   // Set the container type to kFloating.
-  EXPECT_TRUE(test_client()->SetContainerType(
-      keyboard::ContainerType::kFloating, target_bounds));
+  EXPECT_TRUE(
+      SetContainerType(keyboard::ContainerType::kFloating, target_bounds));
   EXPECT_EQ(keyboard::ContainerType::kFloating,
             keyboard_controller()->GetActiveContainerType());
   // Ensure that the window size is correct (position is determined by Ash).
@@ -357,23 +263,24 @@
       keyboard_controller()->GetKeyboardWindow()->GetTargetBounds().size());
 
   // Setting the container type to the current type should fail.
-  EXPECT_FALSE(test_client()->SetContainerType(
-      keyboard::ContainerType::kFloating, base::nullopt));
+  EXPECT_FALSE(
+      SetContainerType(keyboard::ContainerType::kFloating, base::nullopt));
   EXPECT_EQ(keyboard::ContainerType::kFloating,
             keyboard_controller()->GetActiveContainerType());
 }
 
 TEST_F(AshKeyboardControllerTest, SetKeyboardLocked) {
   ASSERT_FALSE(keyboard_controller()->keyboard_locked());
-  test_client()->SetKeyboardLocked(true);
+  ash_keyboard_controller()->SetKeyboardLocked(true);
   EXPECT_TRUE(keyboard_controller()->keyboard_locked());
-  test_client()->SetKeyboardLocked(false);
+  ash_keyboard_controller()->SetKeyboardLocked(false);
   EXPECT_FALSE(keyboard_controller()->keyboard_locked());
 }
 
 TEST_F(AshKeyboardControllerTest, SetOccludedBounds) {
   // Enable the keyboard.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
 
   // Override the container behavior.
   auto scoped_behavior = std::make_unique<TestContainerBehavior>();
@@ -382,23 +289,25 @@
       std::move(scoped_behavior));
 
   gfx::Rect bounds(10, 20, 30, 40);
-  test_client()->SetOccludedBounds({bounds});
+  ash_keyboard_controller()->SetOccludedBounds({bounds});
   EXPECT_EQ(bounds, behavior->occluded_bounds());
 }
 
 TEST_F(AshKeyboardControllerTest, SetHitTestBounds) {
   // Enable the keyboard.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
   ASSERT_FALSE(keyboard_controller()->GetKeyboardWindow()->targeter());
 
   // Setting the hit test bounds should set a WindowTargeter.
-  test_client()->SetHitTestBounds({gfx::Rect(10, 20, 30, 40)});
+  ash_keyboard_controller()->SetHitTestBounds({gfx::Rect(10, 20, 30, 40)});
   ASSERT_TRUE(keyboard_controller()->GetKeyboardWindow()->targeter());
 }
 
 TEST_F(AshKeyboardControllerTest, SetDraggableArea) {
   // Enable the keyboard.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
 
   // Override the container behavior.
   auto scoped_behavior = std::make_unique<TestContainerBehavior>();
@@ -407,13 +316,14 @@
       std::move(scoped_behavior));
 
   gfx::Rect bounds(10, 20, 30, 40);
-  test_client()->SetDraggableArea(bounds);
+  ash_keyboard_controller()->SetDraggableArea(bounds);
   EXPECT_EQ(bounds, behavior->draggable_area());
 }
 
 TEST_F(AshKeyboardControllerTest, ChangingSessionRebuildsKeyboard) {
   // Enable the keyboard.
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
 
   // LOGGED_IN_NOT_ACTIVE session state needs to rebuild keyboard for supervised
   // user profile.
@@ -430,7 +340,8 @@
 TEST_F(AshKeyboardControllerTest, VisualBoundsInMultipleDisplays) {
   UpdateDisplay("800x600,1024x768");
 
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
 
   // Show the keyboard in the second display.
   keyboard_controller()->ShowKeyboardInDisplay(
@@ -447,7 +358,8 @@
 TEST_F(AshKeyboardControllerTest, OccludedBoundsInMultipleDisplays) {
   UpdateDisplay("800x600,1024x768");
 
-  test_client()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
+  ash_keyboard_controller()->SetEnableFlag(
+      KeyboardEnableFlag::kExtensionEnabled);
 
   // Show the keyboard in the second display.
   keyboard_controller()->ShowKeyboardInDisplay(
diff --git a/ash/keyboard/ui/BUILD.gn b/ash/keyboard/ui/BUILD.gn
index 9be75ac..457f93d 100644
--- a/ash/keyboard/ui/BUILD.gn
+++ b/ash/keyboard/ui/BUILD.gn
@@ -24,7 +24,6 @@
     "drag_descriptor.h",
     "keyboard_controller.cc",
     "keyboard_controller.h",
-    "keyboard_controller_observer.h",
     "keyboard_event_handler.cc",
     "keyboard_event_handler.h",
     "keyboard_export.h",
@@ -95,6 +94,7 @@
   ]
   deps = [
     ":ui",
+    "//ash/public/cpp",
     "//base",
     "//ui/aura",
     "//ui/aura:test_support",
@@ -149,6 +149,7 @@
     "container_full_width_behavior_unittest.cc",
     "keyboard_controller_unittest.cc",
     "keyboard_event_handler_unittest.cc",
+    "keyboard_ui_model_unittest.cc",
     "keyboard_ukm_recorder_unittest.cc",
     "keyboard_util_unittest.cc",
     "notification_manager_unittest.cc",
diff --git a/ash/keyboard/ui/keyboard_controller.cc b/ash/keyboard/ui/keyboard_controller.cc
index 4fbfb39..4ff5db0c 100644
--- a/ash/keyboard/ui/keyboard_controller.cc
+++ b/ash/keyboard/ui/keyboard_controller.cc
@@ -9,7 +9,6 @@
 #include "ash/keyboard/ui/container_floating_behavior.h"
 #include "ash/keyboard/ui/container_full_width_behavior.h"
 #include "ash/keyboard/ui/display_util.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
 #include "ash/keyboard/ui/keyboard_layout_manager.h"
 #include "ash/keyboard/ui/keyboard_ui.h"
 #include "ash/keyboard/ui/keyboard_ui_factory.h"
@@ -18,6 +17,7 @@
 #include "ash/keyboard/ui/queued_container_type.h"
 #include "ash/keyboard/ui/queued_display_change.h"
 #include "ash/keyboard/ui/shaped_window_targeter.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/public/cpp/keyboard/keyboard_switches.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -203,8 +203,7 @@
 
 void KeyboardController::Shutdown() {
   keyboard_enable_flags_.clear();
-  for (KeyboardControllerObserver& observer : observer_list_)
-    observer.OnKeyboardEnableFlagsChanged(keyboard_enable_flags_);
+  EnableFlagsChanged();
 
   DCHECK(!IsKeyboardEnableRequested());
   DisableKeyboard();
@@ -234,7 +233,7 @@
   LoadKeyboardWindowInBackground();
 
   // Notify observers after the keyboard window has a root window.
-  for (KeyboardControllerObserver& observer : observer_list_)
+  for (auto& observer : observer_list_)
     observer.OnKeyboardEnabledChanged(true);
 }
 
@@ -266,7 +265,7 @@
   ui_.reset();
 
   // Notify observers after |ui_| is reset so that IsEnabled() is false.
-  for (KeyboardControllerObserver& observer : observer_list_)
+  for (auto& observer : observer_list_)
     observer.OnKeyboardEnabledChanged(false);
 }
 
@@ -392,16 +391,18 @@
   EnableKeyboard();
 }
 
-void KeyboardController::AddObserver(KeyboardControllerObserver* observer) {
+void KeyboardController::AddObserver(
+    ash::KeyboardControllerObserver* observer) {
   observer_list_.AddObserver(observer);
 }
 
 bool KeyboardController::HasObserver(
-    KeyboardControllerObserver* observer) const {
+    ash::KeyboardControllerObserver* observer) const {
   return observer_list_.HasObserver(observer);
 }
 
-void KeyboardController::RemoveObserver(KeyboardControllerObserver* observer) {
+void KeyboardController::RemoveObserver(
+    ash::KeyboardControllerObserver* observer) {
   observer_list_.RemoveObserver(observer);
 }
 
@@ -435,8 +436,8 @@
     default:
       break;
   }
-  for (KeyboardControllerObserver& observer : observer_list_)
-    observer.OnKeyboardEnableFlagsChanged(keyboard_enable_flags_);
+
+  EnableFlagsChanged();
 
   UpdateKeyboardAsRequestedBy(flag);
 }
@@ -446,8 +447,7 @@
     return;
 
   keyboard_enable_flags_.erase(flag);
-  for (KeyboardControllerObserver& observer : observer_list_)
-    observer.OnKeyboardEnableFlagsChanged(keyboard_enable_flags_);
+  EnableFlagsChanged();
 
   UpdateKeyboardAsRequestedBy(flag);
 }
@@ -589,7 +589,7 @@
       ui_->HideKeyboardWindow();
       ChangeState(KeyboardUIState::kHidden);
 
-      for (KeyboardControllerObserver& observer : observer_list_)
+      for (auto& observer : observer_list_)
         observer.OnKeyboardHidden(reason == HIDE_REASON_SYSTEM_TEMPORARY);
 
       break;
@@ -915,8 +915,8 @@
 }
 
 void KeyboardController::NotifyKeyboardConfigChanged() {
-  for (KeyboardControllerObserver& observer : observer_list_)
-    observer.OnKeyboardConfigChanged();
+  for (auto& observer : observer_list_)
+    observer.OnKeyboardConfigChanged(keyboard_config_);
 }
 
 void KeyboardController::ChangeState(KeyboardUIState state) {
@@ -1122,4 +1122,9 @@
   keyboard_load_time_logged_ = true;
 }
 
+void KeyboardController::EnableFlagsChanged() {
+  for (auto& observer : observer_list_)
+    observer.OnKeyboardEnableFlagsChanged(keyboard_enable_flags_);
+}
+
 }  // namespace keyboard
diff --git a/ash/keyboard/ui/keyboard_controller.h b/ash/keyboard/ui/keyboard_controller.h
index 7d747d8..fcd5e23d 100644
--- a/ash/keyboard/ui/keyboard_controller.h
+++ b/ash/keyboard/ui/keyboard_controller.h
@@ -37,6 +37,9 @@
 namespace aura {
 class Window;
 }
+namespace ash {
+class KeyboardControllerObserver;
+}
 namespace ui {
 class InputMethod;
 class TextInputClient;
@@ -45,7 +48,6 @@
 namespace keyboard {
 
 class CallbackAnimationObserver;
-class KeyboardControllerObserver;
 class KeyboardUI;
 class KeyboardUIFactory;
 
@@ -101,9 +103,9 @@
   void RebuildKeyboardIfEnabled();
 
   // Management of the observer list.
-  void AddObserver(KeyboardControllerObserver* observer);
-  bool HasObserver(KeyboardControllerObserver* observer) const;
-  void RemoveObserver(KeyboardControllerObserver* observer);
+  void AddObserver(ash::KeyboardControllerObserver* observer);
+  bool HasObserver(ash::KeyboardControllerObserver* observer) const;
+  void RemoveObserver(ash::KeyboardControllerObserver* observer);
 
   // Updates |keyboard_config_| with |config|. Returns |false| if there is no
   // change, otherwise returns true and notifies observers if this is enabled.
@@ -391,6 +393,9 @@
   // keyboard is loaded.
   void MarkKeyboardLoadFinished();
 
+  // Called when the enable flags change. Notifies observers of the change.
+  void EnableFlagsChanged();
+
   std::unique_ptr<KeyboardUIFactory> ui_factory_;
   std::unique_ptr<KeyboardUI> ui_;
   std::unique_ptr<ui::InputMethodKeyboardController>
@@ -419,7 +424,7 @@
   bool keyboard_locked_ = false;
   KeyboardEventHandler event_handler_;
 
-  base::ObserverList<KeyboardControllerObserver>::Unchecked observer_list_;
+  base::ObserverList<ash::KeyboardControllerObserver>::Unchecked observer_list_;
 
   KeyboardUIModel model_;
 
diff --git a/ash/keyboard/ui/keyboard_controller_observer.h b/ash/keyboard/ui/keyboard_controller_observer.h
deleted file mode 100644
index 58c7e02..0000000
--- a/ash/keyboard/ui/keyboard_controller_observer.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_KEYBOARD_UI_KEYBOARD_CONTROLLER_OBSERVER_H_
-#define ASH_KEYBOARD_UI_KEYBOARD_CONTROLLER_OBSERVER_H_
-
-#include <set>
-
-#include "ash/keyboard/ui/keyboard_export.h"
-#include "ash/public/cpp/keyboard/keyboard_types.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace keyboard {
-
-// Describes the various attributes of the keyboard's appearance and usability.
-struct KeyboardStateDescriptor {
-  bool is_visible;
-
-  // The bounds of the keyboard window on the screen.
-  gfx::Rect visual_bounds;
-
-  // The bounds of the area on the screen that is considered "blocked" by the
-  // keyboard. For example, the docked keyboard's occluded bounds is the same as
-  // the visual bounds, but the floating keyboard has no occluded bounds (as the
-  // window is small and moveable).
-  gfx::Rect occluded_bounds_in_screen;
-
-  // The bounds of the area on the screen that is considered "unusable" because
-  // it is blocked by the keyboard. This is used by the accessibility keyboard.
-  gfx::Rect displaced_bounds_in_screen;
-};
-
-// Observers to the KeyboardController are notified of significant events that
-// occur with the keyboard, such as the bounds or visibility changing.
-class KEYBOARD_EXPORT KeyboardControllerObserver {
- public:
-  virtual ~KeyboardControllerObserver() {}
-
-  // Called when the keyboard is shown or hidden (e.g. when user focuses and
-  // unfocuses on a textfield).
-  virtual void OnKeyboardVisibilityStateChanged(bool is_visible) {}
-
-  // Called when the keyboard bounds are changing.
-  virtual void OnKeyboardVisibleBoundsChanged(const gfx::Rect& new_bounds) {}
-
-  // Called when the keyboard bounds have changed in a way that should affect
-  // the usable region of the workspace. The user interface should respond to
-  // this event by moving important elements away from |new_bounds_in_screen|
-  // so that they don't overlap. However, drastic visual changes should be
-  // avoided, as the occluded bounds may change frequently.
-  virtual void OnKeyboardWorkspaceOccludedBoundsChanged(
-      const gfx::Rect& new_bounds_in_screen) {}
-
-  // Called when the keyboard bounds have changed in a way that affects how the
-  // workspace should change to not take up the screen space occupied by the
-  // keyboard. The user interface should respond to this event by moving all
-  // elements away from |new_bounds| so that they don't overlap. Large visual
-  // changes are okay, as the displacing bounds do not change frequently.
-  virtual void OnKeyboardWorkspaceDisplacingBoundsChanged(
-      const gfx::Rect& new_bounds) {}
-
-  // Redundant with other various notification methods. Use this if the state of
-  // multiple properties need to be conveyed simultaneously to observer
-  // implementations without the need to track multiple stateful properties.
-  virtual void OnKeyboardAppearanceChanged(
-      const KeyboardStateDescriptor& state) {}
-
-  // Called when an enable flag affecting the requested enabled state changes.
-  virtual void OnKeyboardEnableFlagsChanged(
-      const std::set<KeyboardEnableFlag>& keyboard_enable_flags) {}
-
-  // Called when the keyboard is enabled or disabled. NOTE: This is called
-  // when Enabled() or Disabled() is called, not when the requested enabled
-  // state (IsEnableRequested) changes.
-  virtual void OnKeyboardEnabledChanged(bool is_enabled) {}
-
-  // Called when the keyboard has been hidden and the hiding animation finished
-  // successfully.
-  // When |is_temporary_hide| is true, this hide is immediately followed by a
-  // show (e.g. when changing to floating keyboard)
-  virtual void OnKeyboardHidden(bool is_temporary_hide) {}
-
-  // Called when the virtual keyboard IME config changed.
-  virtual void OnKeyboardConfigChanged() {}
-};
-
-}  // namespace keyboard
-
-#endif  // ASH_KEYBOARD_UI_KEYBOARD_CONTROLLER_OBSERVER_H_
diff --git a/ash/keyboard/ui/keyboard_controller_unittest.cc b/ash/keyboard/ui/keyboard_controller_unittest.cc
index 8e518743..c483ae7 100644
--- a/ash/keyboard/ui/keyboard_controller_unittest.cc
+++ b/ash/keyboard/ui/keyboard_controller_unittest.cc
@@ -7,13 +7,13 @@
 #include <memory>
 
 #include "ash/keyboard/ui/container_full_width_behavior.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
 #include "ash/keyboard/ui/keyboard_layout_manager.h"
 #include "ash/keyboard/ui/keyboard_ui.h"
 #include "ash/keyboard/ui/keyboard_util.h"
 #include "ash/keyboard/ui/test/keyboard_test_util.h"
 #include "ash/keyboard/ui/test/test_keyboard_layout_delegate.h"
 #include "ash/keyboard/ui/test/test_keyboard_ui_factory.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
@@ -139,7 +139,7 @@
 }  // namespace
 
 class KeyboardControllerTest : public aura::test::AuraTestBase,
-                               public KeyboardControllerObserver {
+                               public ash::KeyboardControllerObserver {
  public:
   KeyboardControllerTest() = default;
   ~KeyboardControllerTest() override = default;
@@ -191,12 +191,11 @@
     visible_bounds_ = new_bounds;
     visible_bounds_number_of_calls_++;
   }
-  void OnKeyboardWorkspaceOccludedBoundsChanged(
-      const gfx::Rect& new_bounds) override {
+  void OnKeyboardOccludedBoundsChanged(const gfx::Rect& new_bounds) override {
     occluding_bounds_ = new_bounds;
     occluding_bounds_number_of_calls_++;
   }
-  void OnKeyboardVisibilityStateChanged(bool is_visible) override {
+  void OnKeyboardVisibilityChanged(bool is_visible) override {
     is_visible_ = is_visible;
     is_visible_number_of_calls_++;
   }
@@ -740,7 +739,7 @@
   EXPECT_TRUE(IsKeyboardDisabled());
 }
 
-class MockKeyboardControllerObserver : public KeyboardControllerObserver {
+class MockKeyboardControllerObserver : public ash::KeyboardControllerObserver {
  public:
   MockKeyboardControllerObserver() = default;
   ~MockKeyboardControllerObserver() override = default;
diff --git a/ash/keyboard/ui/keyboard_ui_model.cc b/ash/keyboard/ui/keyboard_ui_model.cc
index 211c23d..b660514 100644
--- a/ash/keyboard/ui/keyboard_ui_model.cc
+++ b/ash/keyboard/ui/keyboard_ui_model.cc
@@ -4,12 +4,7 @@
 
 #include "ash/keyboard/ui/keyboard_ui_model.h"
 
-#include <set>
-#include <utility>
-
 #include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/no_destructor.h"
 
 namespace keyboard {
 
@@ -18,46 +13,43 @@
 // Returns whether a given state transition is valid.
 // See the design document linked in https://crbug.com/71990.
 bool IsAllowedStateTransition(KeyboardUIState from, KeyboardUIState to) {
-  static const base::NoDestructor<
-      std::set<std::pair<KeyboardUIState, KeyboardUIState>>>
-      kAllowedStateTransition({
-          // The initial ShowKeyboard scenario
-          // INITIAL -> LOADING_EXTENSION -> HIDDEN -> SHOWN.
-          {KeyboardUIState::kInitial, KeyboardUIState::kLoading},
-          {KeyboardUIState::kLoading, KeyboardUIState::kHidden},
-          {KeyboardUIState::kHidden, KeyboardUIState::kShown},
+  using State = KeyboardUIState;
+  switch (GetStateTransitionHash(from, to)) {
+    // The initial ShowKeyboard scenario
+    // INITIAL -> LOADING -> HIDDEN -> SHOWN.
+    case GetStateTransitionHash(State::kInitial, State::kLoading):
+    case GetStateTransitionHash(State::kLoading, State::kHidden):
+    case GetStateTransitionHash(State::kHidden, State::kShown):
 
-          // Hide scenario
-          // SHOWN -> WILL_HIDE -> HIDDEN.
-          {KeyboardUIState::kShown, KeyboardUIState::kWillHide},
-          {KeyboardUIState::kWillHide, KeyboardUIState::kHidden},
+    // Hide scenario
+    // SHOWN -> WILL_HIDE -> HIDDEN.
+    case GetStateTransitionHash(State::kShown, State::kWillHide):
+    case GetStateTransitionHash(State::kWillHide, State::kHidden):
 
-          // Focus transition scenario
-          // SHOWN -> WILL_HIDE -> SHOWN.
-          {KeyboardUIState::kWillHide, KeyboardUIState::kShown},
+    // Focus transition scenario
+    // SHOWN -> WILL_HIDE -> SHOWN.
+    case GetStateTransitionHash(State::kWillHide, State::kShown):
 
-          // HideKeyboard can be called at anytime for example on shutdown.
-          {KeyboardUIState::kShown, KeyboardUIState::kHidden},
+    // HideKeyboard can be called at anytime (for example on shutdown).
+    case GetStateTransitionHash(State::kShown, State::kHidden):
 
-          // Return to INITIAL when keyboard is disabled.
-          {KeyboardUIState::kLoading, KeyboardUIState::kInitial},
-          {KeyboardUIState::kHidden, KeyboardUIState::kInitial},
-      });
-  return kAllowedStateTransition->count(std::make_pair(from, to)) == 1;
+    // Return to INITIAL when keyboard is disabled.
+    case GetStateTransitionHash(State::kLoading, State::kInitial):
+    case GetStateTransitionHash(State::kHidden, State::kInitial):
+      return true;
+    default:
+      return false;
+  }
 }
 
 // Records a state transition for metrics.
 void RecordStateTransition(KeyboardUIState prev, KeyboardUIState next) {
   const bool valid_transition = IsAllowedStateTransition(prev, next);
 
-  // Emit UMA
-  const int transition_record =
-      (valid_transition ? 1 : -1) *
-      (static_cast<int>(prev) * 1000 + static_cast<int>(next));
+  // Use negative hash values to indicate invalid transitions.
+  const int hash = GetStateTransitionHash(prev, next);
   base::UmaHistogramSparse("VirtualKeyboard.ControllerStateTransition",
-                           transition_record);
-  UMA_HISTOGRAM_BOOLEAN("VirtualKeyboard.ControllerStateTransitionIsValid",
-                        valid_transition);
+                           valid_transition ? hash : -hash);
 
   DCHECK(valid_transition) << "State: " << StateToStr(prev) << " -> "
                            << StateToStr(next) << " Unexpected transition";
diff --git a/ash/keyboard/ui/keyboard_ui_model.h b/ash/keyboard/ui/keyboard_ui_model.h
index 84fb147..e9ce0f9 100644
--- a/ash/keyboard/ui/keyboard_ui_model.h
+++ b/ash/keyboard/ui/keyboard_ui_model.h
@@ -38,6 +38,14 @@
 // Returns the string representation of a keyboard UI state.
 std::string StateToStr(KeyboardUIState state);
 
+// Returns a unique hash of a state transition, used for histograms.
+// The hashes correspond to the KeyboardControllerStateTransition entry in
+// tools/metrics/enums.xml.
+constexpr int GetStateTransitionHash(KeyboardUIState prev,
+                                     KeyboardUIState next) {
+  return static_cast<int>(prev) * 1000 + static_cast<int>(next);
+}
+
 // Model for the virtual keyboard UI.
 class KEYBOARD_EXPORT KeyboardUIModel {
  public:
diff --git a/ash/keyboard/ui/keyboard_ui_model_unittest.cc b/ash/keyboard/ui/keyboard_ui_model_unittest.cc
new file mode 100644
index 0000000..86ab381
--- /dev/null
+++ b/ash/keyboard/ui/keyboard_ui_model_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/keyboard/ui/keyboard_ui_model.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace keyboard {
+
+TEST(KeyboardUIModelTest, ChangeToValidStateRecordsPositiveHistogram) {
+  base::HistogramTester histogram_tester;
+
+  KeyboardUIModel model;
+  ASSERT_EQ(KeyboardUIState::kInitial, model.state());
+
+  model.ChangeState(KeyboardUIState::kLoading);
+  histogram_tester.ExpectUniqueSample(
+      "VirtualKeyboard.ControllerStateTransition",
+      GetStateTransitionHash(KeyboardUIState::kInitial,
+                             KeyboardUIState::kLoading),
+      1);
+}
+
+// Test fails DCHECK when the state transition is invalid. This is expected.
+#if !DCHECK_IS_ON()
+TEST(KeyboardUIModelTest, ChangeToInvalidStateRecordsNegativeHistogram) {
+  base::HistogramTester histogram_tester;
+
+  KeyboardUIModel model;
+  ASSERT_EQ(KeyboardUIState::kInitial, model.state());
+
+  model.ChangeState(KeyboardUIState::kShown);
+  histogram_tester.ExpectUniqueSample(
+      "VirtualKeyboard.ControllerStateTransition",
+      -GetStateTransitionHash(KeyboardUIState::kInitial,
+                              KeyboardUIState::kShown),
+      1);
+}
+#endif
+
+}  // namespace keyboard
diff --git a/ash/keyboard/ui/notification_manager.cc b/ash/keyboard/ui/notification_manager.cc
index eaf6660..f2fb7d8 100644
--- a/ash/keyboard/ui/notification_manager.cc
+++ b/ash/keyboard/ui/notification_manager.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "ash/keyboard/ui/notification_manager.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "base/observer_list.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -30,7 +30,7 @@
     bool does_occluded_bounds_affect_layout,
     const gfx::Rect& visual_bounds,
     const gfx::Rect& occluded_bounds,
-    const base::ObserverList<KeyboardControllerObserver>::Unchecked&
+    const base::ObserverList<ash::KeyboardControllerObserver>::Unchecked&
         observers) {
   bool is_visible = !visual_bounds.IsEmpty();
   bool send_visibility_notification =
@@ -48,24 +48,24 @@
       ShouldSendWorkspaceDisplacementBoundsNotification(
           workspace_layout_offset_region);
 
-  KeyboardStateDescriptor state;
+  ash::KeyboardStateDescriptor state;
   state.is_visible = is_visible;
   state.visual_bounds = visual_bounds;
   state.occluded_bounds_in_screen = occluded_bounds;
   state.displaced_bounds_in_screen = workspace_layout_offset_region;
 
-  for (KeyboardControllerObserver& observer : observers) {
+  for (auto& observer : observers) {
     if (send_visibility_notification)
-      observer.OnKeyboardVisibilityStateChanged(is_visible);
+      observer.OnKeyboardVisibilityChanged(is_visible);
 
     if (send_visual_bounds_notification)
       observer.OnKeyboardVisibleBoundsChanged(visual_bounds);
 
     if (send_occluded_bounds_notification)
-      observer.OnKeyboardWorkspaceOccludedBoundsChanged(occluded_bounds);
+      observer.OnKeyboardOccludedBoundsChanged(occluded_bounds);
 
     if (send_displaced_bounds_notification) {
-      observer.OnKeyboardWorkspaceDisplacingBoundsChanged(
+      observer.OnKeyboardDisplacingBoundsChanged(
           workspace_layout_offset_region);
     }
 
diff --git a/ash/keyboard/ui/notification_manager.h b/ash/keyboard/ui/notification_manager.h
index e98d0c7..ee17d3c 100644
--- a/ash/keyboard/ui/notification_manager.h
+++ b/ash/keyboard/ui/notification_manager.h
@@ -9,9 +9,11 @@
 #include "base/observer_list.h"
 #include "ui/gfx/geometry/rect.h"
 
-namespace keyboard {
-
+namespace ash {
 class KeyboardControllerObserver;
+}
+
+namespace keyboard {
 
 template <typename T>
 class ValueNotificationConsolidator {
@@ -41,7 +43,7 @@
       bool does_occluded_bounds_affect_layout,
       const gfx::Rect& visual_bounds,
       const gfx::Rect& occluded_bounds,
-      const base::ObserverList<KeyboardControllerObserver>::Unchecked&
+      const base::ObserverList<ash::KeyboardControllerObserver>::Unchecked&
           observers);
 
   bool ShouldSendVisibilityNotification(bool current_visibility);
diff --git a/ash/keyboard/ui/test/keyboard_test_util.cc b/ash/keyboard/ui/test/keyboard_test_util.cc
index 8b1e48d..8e48c72 100644
--- a/ash/keyboard/ui/test/keyboard_test_util.cc
+++ b/ash/keyboard/ui/test/keyboard_test_util.cc
@@ -5,7 +5,7 @@
 #include "ash/keyboard/ui/test/keyboard_test_util.h"
 
 #include "ash/keyboard/ui/keyboard_controller.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "base/run_loop.h"
 #include "base/time/time.h"
 #include "ui/display/screen.h"
@@ -14,7 +14,7 @@
 
 namespace {
 
-class KeyboardVisibilityChangeWaiter : public KeyboardControllerObserver {
+class KeyboardVisibilityChangeWaiter : public ash::KeyboardControllerObserver {
  public:
   explicit KeyboardVisibilityChangeWaiter(bool wait_until)
       : wait_until_(wait_until) {
@@ -27,7 +27,7 @@
   void Wait() { run_loop_.Run(); }
 
  private:
-  void OnKeyboardVisibilityStateChanged(const bool is_visible) override {
+  void OnKeyboardVisibilityChanged(const bool is_visible) override {
     if (is_visible == wait_until_)
       run_loop_.QuitWhenIdle();
   }
diff --git a/ash/keyboard/ui/test/test_keyboard_controller_observer.h b/ash/keyboard/ui/test/test_keyboard_controller_observer.h
index fd1645e..877b17d 100644
--- a/ash/keyboard/ui/test/test_keyboard_controller_observer.h
+++ b/ash/keyboard/ui/test/test_keyboard_controller_observer.h
@@ -5,12 +5,12 @@
 #ifndef ASH_KEYBOARD_UI_TEST_TEST_KEYBOARD_CONTROLLER_OBSERVER_H_
 #define ASH_KEYBOARD_UI_TEST_TEST_KEYBOARD_CONTROLLER_OBSERVER_H_
 
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 
 namespace keyboard {
 
 // A KeyboardControllerObserver that counts occurrences of events for testing.
-struct TestKeyboardControllerObserver : public KeyboardControllerObserver {
+struct TestKeyboardControllerObserver : public ash::KeyboardControllerObserver {
   TestKeyboardControllerObserver();
   ~TestKeyboardControllerObserver() override;
 
diff --git a/ash/keyboard/virtual_keyboard_controller.h b/ash/keyboard/virtual_keyboard_controller.h
index f56f614..2c64bc8f 100644
--- a/ash/keyboard/virtual_keyboard_controller.h
+++ b/ash/keyboard/virtual_keyboard_controller.h
@@ -9,8 +9,8 @@
 
 #include "ash/ash_export.h"
 #include "ash/bluetooth_devices_observer.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
 #include "ash/keyboard/ui/keyboard_layout_delegate.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/session/session_observer.h"
 #include "ash/wm/tablet_mode/tablet_mode_observer.h"
 #include "base/macros.h"
@@ -27,7 +27,7 @@
     : public TabletModeObserver,
       public ui::InputDeviceEventObserver,
       public keyboard::KeyboardLayoutDelegate,
-      public keyboard::KeyboardControllerObserver,
+      public KeyboardControllerObserver,
       public SessionObserver {
  public:
   VirtualKeyboardController();
@@ -53,7 +53,7 @@
   aura::Window* GetContainerForDisplay(
       const display::Display& display) override;
 
-  // keyboard::KeyboardControllerObserver:
+  // KeyboardControllerObserver:
   void OnKeyboardEnabledChanged(bool is_enabled) override;
   void OnKeyboardHidden(bool is_temporary_hide) override;
 
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index 36208324..62d5ddf 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -1149,7 +1149,7 @@
   }
 }
 
-void LockContentsView::OnKeyboardVisibilityStateChanged(bool is_visible) {
+void LockContentsView::OnKeyboardVisibilityChanged(bool is_visible) {
   if (!primary_big_view_ || keyboard_shown_ == is_visible)
     return;
 
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index 6211b18b..59ceb575 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -12,13 +12,13 @@
 
 #include "ash/ash_export.h"
 #include "ash/keyboard/ui/keyboard_controller.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
 #include "ash/login/ui/lock_screen.h"
 #include "ash/login/ui/login_data_dispatcher.h"
 #include "ash/login/ui/login_display_style.h"
 #include "ash/login/ui/login_error_bubble.h"
 #include "ash/login/ui/login_tooltip_view.h"
 #include "ash/login/ui/non_accessible_view.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/public/cpp/login_types.h"
 #include "ash/public/cpp/system_tray_focus_observer.h"
 #include "ash/session/session_observer.h"
@@ -66,7 +66,7 @@
       public display::DisplayObserver,
       public views::StyledLabelListener,
       public SessionObserver,
-      public keyboard::KeyboardControllerObserver,
+      public KeyboardControllerObserver,
       public chromeos::PowerManagerClient::Observer {
  public:
   // TestApi is used for tests to get internal implementation details.
@@ -189,8 +189,8 @@
   // SessionObserver:
   void OnLockStateChanged(bool locked) override;
 
-  // keyboard::KeyboardControllerObserver:
-  void OnKeyboardVisibilityStateChanged(bool is_visible) override;
+  // KeyboardControllerObserver:
+  void OnKeyboardVisibilityChanged(bool is_visible) override;
 
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 1b9158e7..8dddeeb 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -90,6 +90,7 @@
     "keyboard/keyboard_config.h",
     "keyboard/keyboard_controller.cc",
     "keyboard/keyboard_controller.h",
+    "keyboard/keyboard_controller_observer.h",
     "keyboard/keyboard_switches.cc",
     "keyboard/keyboard_switches.h",
     "keyboard/keyboard_types.h",
diff --git a/ash/public/cpp/keyboard/keyboard_controller.h b/ash/public/cpp/keyboard/keyboard_controller.h
index 79fdf01..6a2de18 100644
--- a/ash/public/cpp/keyboard/keyboard_controller.h
+++ b/ash/public/cpp/keyboard/keyboard_controller.h
@@ -5,6 +5,9 @@
 #ifndef ASH_PUBLIC_CPP_KEYBOARD_KEYBOARD_CONTROLLER_H_
 #define ASH_PUBLIC_CPP_KEYBOARD_KEYBOARD_CONTROLLER_H_
 
+#include <set>
+#include <vector>
+
 #include "ash/public/cpp/ash_public_export.h"
 #include "ash/public/cpp/keyboard/keyboard_config.h"
 #include "ash/public/cpp/keyboard/keyboard_types.h"
@@ -13,6 +16,8 @@
 
 namespace ash {
 
+class KeyboardControllerObserver;
+
 enum class HideReason {
   // Hide requested by an explicit user action.
   kUser,
@@ -22,59 +27,8 @@
   kSystem,
 };
 
-class KeyboardControllerObserver {
- public:
-  virtual ~KeyboardControllerObserver() {}
-
-  // Called when a keyboard enable flag changes.
-  virtual void OnKeyboardEnableFlagsChanged(
-      const std::vector<keyboard::KeyboardEnableFlag>& flags) = 0;
-
-  // Called when the keyboard is enabled or disabled. If ReloadKeyboard() is
-  // called or other code enables the keyboard while already enabled, this will
-  // be called twice, once when the keyboard is disabled and again when it is
-  // re-enabled.
-  virtual void OnKeyboardEnabledChanged(bool is_enabled) = 0;
-
-  // Called when the virtual keyboard configuration changes.
-  virtual void OnKeyboardConfigChanged(
-      const keyboard::KeyboardConfig& config) = 0;
-
-  // Called when the visibility of the virtual keyboard changes, e.g. an input
-  // field is focused or blurred, or the user hides the keyboard.
-  virtual void OnKeyboardVisibilityChanged(bool visible) = 0;
-
-  // Called when the keyboard bounds change. |screen_bounds| is in screen
-  // coordinates.
-  virtual void OnKeyboardVisibleBoundsChanged(
-      const gfx::Rect& screen_bounds) = 0;
-
-  // Called when the keyboard occluded bounds change. |screen_bounds| is in
-  // screen coordinates.
-  virtual void OnKeyboardOccludedBoundsChanged(
-      const gfx::Rect& screen_bounds) = 0;
-
-  // Signals a request to load the keyboard contents. If the contents are
-  // already loaded, requests a reload. Once the contents have loaded,
-  // KeyboardController.KeyboardContentsLoaded is expected to be called by the
-  // client implementation.
-  virtual void OnLoadKeyboardContentsRequested() = 0;
-
-  // Called when the UI has been destroyed so that the client can reset the
-  // embedded contents and handle.
-  virtual void OnKeyboardUIDestroyed() = 0;
-};
-
 class ASH_PUBLIC_EXPORT KeyboardController {
  public:
-  using GetKeyboardConfigCallback =
-      base::OnceCallback<void(const keyboard::KeyboardConfig&)>;
-  using IsKeyboardEnabledCallback = base::OnceCallback<void(bool)>;
-  using GetEnableFlagsCallback = base::OnceCallback<void(
-      const std::vector<keyboard::KeyboardEnableFlag>&)>;
-  using IsKeyboardVisibleCallback = base::OnceCallback<void(bool)>;
-  using SetContainerTypeCallback = base::OnceCallback<void(bool)>;
-
   static KeyboardController* Get();
 
   // Sets the global KeyboardController instance to |this|.
@@ -86,13 +40,13 @@
   virtual void KeyboardContentsLoaded(const gfx::Size& size) = 0;
 
   // Retrieves the current keyboard configuration.
-  virtual void GetKeyboardConfig(GetKeyboardConfigCallback callback) = 0;
+  virtual keyboard::KeyboardConfig GetKeyboardConfig() = 0;
 
   // Sets the current keyboard configuration.
   virtual void SetKeyboardConfig(const keyboard::KeyboardConfig& config) = 0;
 
   // Returns whether the virtual keyboard has been enabled.
-  virtual void IsKeyboardEnabled(IsKeyboardVisibleCallback callback) = 0;
+  virtual bool IsKeyboardEnabled() = 0;
 
   // Sets the provided keyboard enable flag. If the computed enabled state
   // changes, enables or disables the keyboard to match the new state.
@@ -103,7 +57,7 @@
   virtual void ClearEnableFlag(keyboard::KeyboardEnableFlag flag) = 0;
 
   // Gets the current set of keyboard enable flags.
-  virtual void GetEnableFlags(GetEnableFlagsCallback callback) = 0;
+  virtual const std::set<keyboard::KeyboardEnableFlag>& GetEnableFlags() = 0;
 
   // Reloads the virtual keyboard if it is enabled and the URL has changed, e.g.
   // the focus has switched from one type of field to another.
@@ -115,7 +69,7 @@
   virtual void RebuildKeyboardIfEnabled() = 0;
 
   // Returns whether the virtual keyboard is visible.
-  virtual void IsKeyboardVisible(IsKeyboardVisibleCallback callback) = 0;
+  virtual bool IsKeyboardVisible() = 0;
 
   // Shows the virtual keyboard on the current display if it is enabled.
   virtual void ShowKeyboard() = 0;
@@ -126,6 +80,7 @@
   // Sets the keyboard container type. If non empty, |target_bounds| provides
   // the container size. Returns whether the transition succeeded once the
   // container type changes (or fails to change).
+  using SetContainerTypeCallback = base::OnceCallback<void(bool)>;
   virtual void SetContainerType(keyboard::ContainerType container_type,
                                 const base::Optional<gfx::Rect>& target_bounds,
                                 SetContainerTypeCallback callback) = 0;
diff --git a/ash/public/cpp/keyboard/keyboard_controller_observer.h b/ash/public/cpp/keyboard/keyboard_controller_observer.h
new file mode 100644
index 0000000..108dd0c
--- /dev/null
+++ b/ash/public/cpp/keyboard/keyboard_controller_observer.h
@@ -0,0 +1,102 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PUBLIC_CPP_KEYBOARD_KEYBOARD_CONTROLLER_OBSERVER_H_
+#define ASH_PUBLIC_CPP_KEYBOARD_KEYBOARD_CONTROLLER_OBSERVER_H_
+
+#include <set>
+
+#include "ash/public/cpp/ash_public_export.h"
+#include "ash/public/cpp/keyboard/keyboard_config.h"
+#include "ash/public/cpp/keyboard/keyboard_types.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace ash {
+
+// Describes the various attributes of the keyboard's appearance and usability.
+struct KeyboardStateDescriptor {
+  bool is_visible;
+
+  // The bounds of the keyboard window on the screen.
+  gfx::Rect visual_bounds;
+
+  // The bounds of the area on the screen that is considered "blocked" by the
+  // keyboard. For example, the docked keyboard's occluded bounds is the same as
+  // the visual bounds, but the floating keyboard has no occluded bounds (as the
+  // window is small and moveable).
+  gfx::Rect occluded_bounds_in_screen;
+
+  // The bounds of the area on the screen that is considered "unusable" because
+  // it is blocked by the keyboard. This is used by the accessibility keyboard.
+  gfx::Rect displaced_bounds_in_screen;
+};
+
+class ASH_PUBLIC_EXPORT KeyboardControllerObserver {
+ public:
+  // Called when a keyboard enable flag changes.
+  virtual void OnKeyboardEnableFlagsChanged(
+      const std::set<keyboard::KeyboardEnableFlag>& flags) {}
+
+  // Called when the keyboard is enabled or disabled. If ReloadKeyboard() is
+  // called or other code enables the keyboard while already enabled, this will
+  // be called twice, once when the keyboard is disabled and again when it is
+  // re-enabled.
+  virtual void OnKeyboardEnabledChanged(bool is_enabled) {}
+
+  // Called when the virtual keyboard configuration changes.
+  virtual void OnKeyboardConfigChanged(const keyboard::KeyboardConfig& config) {
+  }
+
+  // Called when the visibility of the virtual keyboard changes, e.g. an input
+  // field is focused or blurred, or the user hides the keyboard.
+  virtual void OnKeyboardVisibilityChanged(bool visible) {}
+
+  // Called when the keyboard bounds change. |screen_bounds| is in screen
+  // coordinates.
+  virtual void OnKeyboardVisibleBoundsChanged(const gfx::Rect& screen_bounds) {}
+
+  // Called when the keyboard bounds have changed in a way that should affect
+  // the usable region of the workspace. The user interface should respond to
+  // this event by moving important elements away from |new_bounds_in_screen|
+  // so that they don't overlap. However, drastic visual changes should be
+  // avoided, as the occluded bounds may change frequently.
+  virtual void OnKeyboardOccludedBoundsChanged(const gfx::Rect& screen_bounds) {
+  }
+
+  // Called when the keyboard bounds have changed in a way that affects how the
+  // workspace should change to not take up the screen space occupied by the
+  // keyboard. The user interface should respond to this event by moving all
+  // elements away from |new_bounds| so that they don't overlap. Large visual
+  // changes are okay, as the displacing bounds do not change frequently.
+  virtual void OnKeyboardDisplacingBoundsChanged(const gfx::Rect& new_bounds) {}
+
+  // Redundant with other various notification methods. Use this if the state of
+  // multiple properties need to be conveyed simultaneously to observer
+  // implementations without the need to track multiple stateful properties.
+  virtual void OnKeyboardAppearanceChanged(
+      const KeyboardStateDescriptor& state) {}
+
+  // Signals a request to load the keyboard contents. If the contents are
+  // already loaded, requests a reload. Once the contents have loaded,
+  // KeyboardController.KeyboardContentsLoaded is expected to be called by the
+  // client implementation.
+  virtual void OnLoadKeyboardContentsRequested() {}
+
+  // Called when the UI has been destroyed so that the client can reset the
+  // embedded contents and handle.
+  virtual void OnKeyboardUIDestroyed() {}
+
+  // Called when the keyboard has been hidden and the hiding animation finished
+  // successfully.
+  // When |is_temporary_hide| is true, this hide is immediately followed by a
+  // show (e.g. when changing to floating keyboard)
+  virtual void OnKeyboardHidden(bool is_temporary_hide) {}
+
+ protected:
+  virtual ~KeyboardControllerObserver() = default;
+};
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_KEYBOARD_KEYBOARD_CONTROLLER_OBSERVER_H_
diff --git a/ash/public/cpp/test/test_keyboard_controller_observer.cc b/ash/public/cpp/test/test_keyboard_controller_observer.cc
index 906c147..daeac0d 100644
--- a/ash/public/cpp/test/test_keyboard_controller_observer.cc
+++ b/ash/public/cpp/test/test_keyboard_controller_observer.cc
@@ -17,7 +17,7 @@
 TestKeyboardControllerObserver::~TestKeyboardControllerObserver() = default;
 
 void TestKeyboardControllerObserver::OnKeyboardEnableFlagsChanged(
-    const std::vector<keyboard::KeyboardEnableFlag>& flags) {
+    const std::set<keyboard::KeyboardEnableFlag>& flags) {
   enable_flags_ = flags;
 }
 
diff --git a/ash/public/cpp/test/test_keyboard_controller_observer.h b/ash/public/cpp/test/test_keyboard_controller_observer.h
index e089225..55cab7c 100644
--- a/ash/public/cpp/test/test_keyboard_controller_observer.h
+++ b/ash/public/cpp/test/test_keyboard_controller_observer.h
@@ -5,12 +5,15 @@
 #ifndef ASH_PUBLIC_CPP_TEST_TEST_KEYBOARD_CONTROLLER_OBSERVER_H_
 #define ASH_PUBLIC_CPP_TEST_TEST_KEYBOARD_CONTROLLER_OBSERVER_H_
 
+#include <set>
+
 #include "ash/public/cpp/keyboard/keyboard_config.h"
 #include "ash/public/cpp/keyboard/keyboard_controller.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 
 namespace ash {
 
-// :KeyboardControllerObserver implementation for tests. This class
+// KeyboardControllerObserver implementation for tests. This class
 // implements a test client observer for tests running with the Window Service.
 
 class TestKeyboardControllerObserver : public KeyboardControllerObserver {
@@ -20,7 +23,7 @@
 
   // KeyboardControllerObserver:
   void OnKeyboardEnableFlagsChanged(
-      const std::vector<keyboard::KeyboardEnableFlag>& flags) override;
+      const std::set<keyboard::KeyboardEnableFlag>& flags) override;
   void OnKeyboardEnabledChanged(bool enabled) override;
   void OnKeyboardConfigChanged(const keyboard::KeyboardConfig& config) override;
   void OnKeyboardVisibilityChanged(bool visible) override;
@@ -31,14 +34,14 @@
 
   const keyboard::KeyboardConfig& config() const { return config_; }
   void set_config(const keyboard::KeyboardConfig& config) { config_ = config; }
-  const std::vector<keyboard::KeyboardEnableFlag>& enable_flags() const {
+  const std::set<keyboard::KeyboardEnableFlag>& enable_flags() const {
     return enable_flags_;
   }
   int destroyed_count() const { return destroyed_count_; }
 
  private:
   KeyboardController* controller_;
-  std::vector<keyboard::KeyboardEnableFlag> enable_flags_;
+  std::set<keyboard::KeyboardEnableFlag> enable_flags_;
   keyboard::KeyboardConfig config_;
   int destroyed_count_ = 0;
 
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc
index 3289c1c4..937c7cb 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -8,7 +8,7 @@
 
 #include "ash/animation/animation_change_type.h"
 #include "ash/app_list/app_list_controller_impl.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/public/cpp/shelf_item_delegate.h"
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/public/cpp/shell_window_ids.h"
@@ -330,17 +330,17 @@
 }
 
 void Shelf::SetVirtualKeyboardBoundsForTesting(const gfx::Rect& bounds) {
-  keyboard::KeyboardStateDescriptor state;
+  KeyboardStateDescriptor state;
   state.is_visible = !bounds.IsEmpty();
   state.visual_bounds = bounds;
   state.occluded_bounds_in_screen = bounds;
   state.displaced_bounds_in_screen = gfx::Rect();
   WorkAreaInsets* work_area_insets = GetWorkAreaInsets();
-  work_area_insets->OnKeyboardVisibilityStateChanged(state.is_visible);
+  work_area_insets->OnKeyboardVisibilityChanged(state.is_visible);
   work_area_insets->OnKeyboardVisibleBoundsChanged(state.visual_bounds);
-  work_area_insets->OnKeyboardWorkspaceOccludedBoundsChanged(
+  work_area_insets->OnKeyboardOccludedBoundsChanged(
       state.occluded_bounds_in_screen);
-  work_area_insets->OnKeyboardWorkspaceDisplacingBoundsChanged(
+  work_area_insets->OnKeyboardDisplacingBoundsChanged(
       state.displaced_bounds_in_screen);
   work_area_insets->OnKeyboardAppearanceChanged(state);
 }
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 6121aed..c2961d33 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -19,11 +19,11 @@
 #include "ash/home_screen/home_screen_controller.h"
 #include "ash/home_screen/home_screen_delegate.h"
 #include "ash/keyboard/ui/keyboard_controller.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
 #include "ash/keyboard/ui/keyboard_ui.h"
 #include "ash/keyboard/ui/keyboard_util.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/public/cpp/shelf_item.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/test/shell_test_api.h"
@@ -3092,13 +3092,13 @@
                               bool is_locked,
                               const gfx::Rect& bounds_in_screen) {
     WorkAreaInsets* work_area_insets = GetPrimaryWorkAreaInsets();
-    keyboard::KeyboardStateDescriptor state;
+    KeyboardStateDescriptor state;
     state.visual_bounds = bounds_in_screen;
     state.occluded_bounds_in_screen = bounds_in_screen;
     state.displaced_bounds_in_screen =
         is_locked ? bounds_in_screen : gfx::Rect();
     state.is_visible = !bounds_in_screen.IsEmpty();
-    work_area_insets->OnKeyboardVisibilityStateChanged(state.is_visible);
+    work_area_insets->OnKeyboardVisibilityChanged(state.is_visible);
     work_area_insets->OnKeyboardAppearanceChanged(state);
   }
 
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 838caeb1..8579c51 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -29,10 +29,5 @@
   return new DefaultAccessibilityDelegate;
 }
 
-ws::InputDeviceControllerClient*
-ShellDelegateImpl::GetInputDeviceControllerClient() {
-  return nullptr;
-}
-
 }  // namespace shell
 }  // namespace ash
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h
index ebeecb1..d772fd9f 100644
--- a/ash/shell/shell_delegate_impl.h
+++ b/ash/shell/shell_delegate_impl.h
@@ -23,7 +23,6 @@
   bool CanShowWindowForUser(const aura::Window* window) const override;
   std::unique_ptr<ScreenshotDelegate> CreateScreenshotDelegate() override;
   AccessibilityDelegate* CreateAccessibilityDelegate() override;
-  ws::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ShellDelegateImpl);
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index 27618b5..17ce0d5 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -16,10 +16,6 @@
 class Window;
 }
 
-namespace ws {
-class InputDeviceControllerClient;
-}
-
 namespace ash {
 
 class AccessibilityDelegate;
@@ -42,9 +38,6 @@
   virtual AccessibilityDelegate* CreateAccessibilityDelegate() = 0;
 
   virtual void OpenKeyboardShortcutHelpPage() const {}
-
-  // Creator of Shell owns this; it's assumed this outlives Shell.
-  virtual ws::InputDeviceControllerClient* GetInputDeviceControllerClient() = 0;
 };
 
 }  // namespace ash
diff --git a/ash/system/ime_menu/ime_menu_tray.h b/ash/system/ime_menu/ime_menu_tray.h
index 06d5e1d..4837368 100644
--- a/ash/system/ime_menu/ime_menu_tray.h
+++ b/ash/system/ime_menu/ime_menu_tray.h
@@ -6,7 +6,7 @@
 #define ASH_SYSTEM_IME_MENU_IME_MENU_TRAY_H_
 
 #include "ash/ash_export.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/public/interfaces/ime_controller.mojom.h"
 #include "ash/public/interfaces/ime_info.mojom.h"
 #include "ash/system/ime/ime_observer.h"
@@ -32,7 +32,7 @@
 // for emoji, handwriting, and voice.
 class ASH_EXPORT ImeMenuTray : public TrayBackgroundView,
                                public IMEObserver,
-                               public keyboard::KeyboardControllerObserver,
+                               public KeyboardControllerObserver,
                                public VirtualKeyboardObserver {
  public:
   explicit ImeMenuTray(Shelf* shelf);
@@ -72,7 +72,7 @@
   bool ShouldEnableExtraKeyboardAccessibility() override;
   void HideBubble(const TrayBubbleView* bubble_view) override;
 
-  // keyboard::KeyboardControllerObserver:
+  // KeyboardControllerObserver:
   void OnKeyboardHidden(bool is_temporary_hide) override;
 
   // VirtualKeyboardObserver:
diff --git a/ash/system/toast/toast_overlay.cc b/ash/system/toast/toast_overlay.cc
index 685dbf4..1dd42fb0 100644
--- a/ash/system/toast/toast_overlay.cc
+++ b/ash/system/toast/toast_overlay.cc
@@ -302,7 +302,7 @@
     delegate_->OnClosed();
 }
 
-void ToastOverlay::OnKeyboardWorkspaceOccludedBoundsChanged(
+void ToastOverlay::OnKeyboardOccludedBoundsChanged(
     const gfx::Rect& new_bounds_in_screen) {
   // TODO(https://crbug.com/943446): Observe changes in user work area bounds
   // directly instead of listening for keyboard bounds changes.
diff --git a/ash/system/toast/toast_overlay.h b/ash/system/toast/toast_overlay.h
index d26b1e0..dd44ff18 100644
--- a/ash/system/toast/toast_overlay.h
+++ b/ash/system/toast/toast_overlay.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "ash/ash_export.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "base/optional.h"
 #include "base/strings/string16.h"
 #include "ui/compositor/layer_animation_observer.h"
@@ -31,7 +31,7 @@
 class ToastOverlayButton;
 
 class ASH_EXPORT ToastOverlay : public ui::ImplicitAnimationObserver,
-                                public keyboard::KeyboardControllerObserver {
+                                public KeyboardControllerObserver {
  public:
   class ASH_EXPORT Delegate {
    public:
@@ -71,9 +71,8 @@
   void OnImplicitAnimationsScheduled() override;
   void OnImplicitAnimationsCompleted() override;
 
-  // keyboard::KeyboardControllerObserver:
-  void OnKeyboardWorkspaceOccludedBoundsChanged(
-      const gfx::Rect& new_bounds) override;
+  // KeyboardControllerObserver:
+  void OnKeyboardOccludedBoundsChanged(const gfx::Rect& new_bounds) override;
 
   views::Widget* widget_for_testing();
   ToastOverlayButton* dismiss_button_for_testing();
diff --git a/ash/system/virtual_keyboard/virtual_keyboard_tray.cc b/ash/system/virtual_keyboard/virtual_keyboard_tray.cc
index 3266ad0..185cc85 100644
--- a/ash/system/virtual_keyboard/virtual_keyboard_tray.cc
+++ b/ash/system/virtual_keyboard/virtual_keyboard_tray.cc
@@ -95,8 +95,7 @@
   UpdateIconVisibility();
 }
 
-void VirtualKeyboardTray::OnKeyboardVisibilityStateChanged(
-    const bool is_visible) {
+void VirtualKeyboardTray::OnKeyboardVisibilityChanged(const bool is_visible) {
   SetIsActive(is_visible);
 }
 
diff --git a/ash/system/virtual_keyboard/virtual_keyboard_tray.h b/ash/system/virtual_keyboard/virtual_keyboard_tray.h
index 3d0c2c5..4258105 100644
--- a/ash/system/virtual_keyboard/virtual_keyboard_tray.h
+++ b/ash/system/virtual_keyboard/virtual_keyboard_tray.h
@@ -6,7 +6,7 @@
 #define ASH_SYSTEM_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_TRAY_H_
 
 #include "ash/accessibility/accessibility_observer.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/session/session_observer.h"
 #include "ash/shell_observer.h"
 #include "ash/system/tray/tray_background_view.h"
@@ -21,7 +21,7 @@
 // TODO(sky): make this visible on non-chromeos platforms.
 class VirtualKeyboardTray : public TrayBackgroundView,
                             public AccessibilityObserver,
-                            public keyboard::KeyboardControllerObserver,
+                            public KeyboardControllerObserver,
                             public ShellObserver,
                             public SessionObserver {
  public:
@@ -37,8 +37,8 @@
   // AccessibilityObserver:
   void OnAccessibilityStatusChanged() override;
 
-  // keyboard::KeyboardControllerObserver:
-  void OnKeyboardVisibilityStateChanged(bool is_visible) override;
+  // KeyboardControllerObserver:
+  void OnKeyboardVisibilityChanged(bool is_visible) override;
 
   // SessionObserver:
   void OnSessionStateChanged(session_manager::SessionState state) override;
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc
index bc1b67f3a..6fc9007 100644
--- a/ash/test_shell_delegate.cc
+++ b/ash/test_shell_delegate.cc
@@ -29,9 +29,4 @@
   return new DefaultAccessibilityDelegate;
 }
 
-ws::InputDeviceControllerClient*
-TestShellDelegate::GetInputDeviceControllerClient() {
-  return nullptr;
-}
-
 }  // namespace ash
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h
index f0604f8..c332ec9 100644
--- a/ash/test_shell_delegate.h
+++ b/ash/test_shell_delegate.h
@@ -21,7 +21,6 @@
   bool CanShowWindowForUser(const aura::Window* window) const override;
   std::unique_ptr<ScreenshotDelegate> CreateScreenshotDelegate() override;
   AccessibilityDelegate* CreateAccessibilityDelegate() override;
-  ws::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestShellDelegate);
diff --git a/ash/touch/touch_devices_controller.cc b/ash/touch/touch_devices_controller.cc
index 161ca3c..2e1d531 100644
--- a/ash/touch/touch_devices_controller.cc
+++ b/ash/touch/touch_devices_controller.cc
@@ -17,35 +17,14 @@
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
-#include "services/ws/public/cpp/input_devices/input_device_controller_client.h"
+#include "ui/ozone/public/input_controller.h"
+#include "ui/ozone/public/ozone_platform.h"
 #include "ui/wm/core/cursor_manager.h"
 
 namespace ash {
 
 namespace {
 
-void OnSetTouchpadEnabledDone(bool enabled, bool succeeded) {
-  // Don't log here, |succeeded| is only true if there is a touchpad *and* the
-  // value changed. In other words |succeeded| is false when not on device or
-  // the value was already at the value specified. Neither of these are
-  // interesting failures.
-  if (!succeeded)
-    return;
-
-  ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
-  if (!cursor_manager)
-    return;
-
-  if (enabled)
-    cursor_manager->ShowCursor();
-  else
-    cursor_manager->HideCursor();
-}
-
-ws::InputDeviceControllerClient* GetInputDeviceControllerClient() {
-  return Shell::Get()->shell_delegate()->GetInputDeviceControllerClient();
-}
-
 PrefService* GetActivePrefService() {
   return Shell::Get()->session_controller()->GetActivePrefService();
 }
@@ -182,30 +161,36 @@
 
   UMA_HISTOGRAM_BOOLEAN("Touchpad.TapDragging.Changed", enabled);
 
-  if (!GetInputDeviceControllerClient())
-    return;  // Happens in tests.
-
-  GetInputDeviceControllerClient()->SetTapDragging(enabled);
+  ui::OzonePlatform::GetInstance()->GetInputController()->SetTapDragging(
+      enabled);
 }
 
 void TouchDevicesController::UpdateTouchpadEnabled() {
-  if (!GetInputDeviceControllerClient())
-    return;  // Happens in tests.
-
   bool enabled = GetTouchpadEnabled(TouchDeviceEnabledSource::GLOBAL) &&
                  GetTouchpadEnabled(TouchDeviceEnabledSource::USER_PREF);
+  ui::InputController* input_controller =
+      ui::OzonePlatform::GetInstance()->GetInputController();
+  const bool old_value = input_controller->IsInternalTouchpadEnabled();
+  input_controller->SetInternalTouchpadEnabled(enabled);
+  if (old_value == input_controller->IsInternalTouchpadEnabled())
+    return;  // Value didn't actually change.
 
-  GetInputDeviceControllerClient()->SetInternalTouchpadEnabled(
-      enabled, base::BindRepeating(&OnSetTouchpadEnabledDone, enabled));
+  ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
+  if (!cursor_manager)
+    return;
+
+  if (enabled)
+    cursor_manager->ShowCursor();
+  else
+    cursor_manager->HideCursor();
 }
 
 void TouchDevicesController::UpdateTouchscreenEnabled() {
-  if (!GetInputDeviceControllerClient())
-    return;  // Happens in tests.
-
-  GetInputDeviceControllerClient()->SetTouchscreensEnabled(
-      GetTouchscreenEnabled(TouchDeviceEnabledSource::GLOBAL) &&
-      GetTouchscreenEnabled(TouchDeviceEnabledSource::USER_PREF));
+  ui::OzonePlatform::GetInstance()
+      ->GetInputController()
+      ->SetTouchscreensEnabled(
+          GetTouchscreenEnabled(TouchDeviceEnabledSource::GLOBAL) &&
+          GetTouchscreenEnabled(TouchDeviceEnabledSource::USER_PREF));
 }
 
 }  // namespace ash
diff --git a/ash/wm/always_on_top_controller_unittest.cc b/ash/wm/always_on_top_controller_unittest.cc
index 8714958..8117a9e 100644
--- a/ash/wm/always_on_top_controller_unittest.cc
+++ b/ash/wm/always_on_top_controller_unittest.cc
@@ -45,10 +45,9 @@
 
   ~TestLayoutManager() override = default;
 
-  void OnKeyboardWorkspaceDisplacingBoundsChanged(
-      const gfx::Rect& bounds) override {
+  void OnKeyboardDisplacingBoundsChanged(const gfx::Rect& bounds) override {
     keyboard_bounds_changed_ = true;
-    WorkspaceLayoutManager::OnKeyboardWorkspaceDisplacingBoundsChanged(bounds);
+    WorkspaceLayoutManager::OnKeyboardDisplacingBoundsChanged(bounds);
   }
 
   bool keyboard_bounds_changed() const { return keyboard_bounds_changed_; }
diff --git a/ash/wm/client_controlled_state.cc b/ash/wm/client_controlled_state.cc
index 82f9d54..6bad8bc 100644
--- a/ash/wm/client_controlled_state.cc
+++ b/ash/wm/client_controlled_state.cc
@@ -214,6 +214,14 @@
             break;
         }
         next_bounds_change_animation_type_ = kAnimationNone;
+
+        // For PIP, restore bounds is used to specify the ideal position.
+        // Usually this value is set in completeDrag, but for the initial
+        // position, we need to set it here.
+        if (window_state->IsPip() &&
+            window_state->GetRestoreBoundsInParent().IsEmpty())
+          window_state->SetRestoreBoundsInParent(bounds);
+
       } else if (!window_state->IsPinned()) {
         // TODO(oshima): Define behavior for pinned app.
         bounds_change_animation_duration_ = set_bounds_event->duration();
diff --git a/ash/wm/client_controlled_state_unittest.cc b/ash/wm/client_controlled_state_unittest.cc
index 5c9c1b3..b006a72 100644
--- a/ash/wm/client_controlled_state_unittest.cc
+++ b/ash/wm/client_controlled_state_unittest.cc
@@ -565,5 +565,20 @@
   EXPECT_EQ(gfx::Rect(475, 0, 100, 200), delegate()->requested_bounds());
 }
 
+TEST_F(ClientControlledStateTest, HandleBoundsEventsUpdatesPipRestoreBounds) {
+  state()->EnterNextState(window_state(), ash::WindowStateType::kPip);
+
+  EXPECT_TRUE(window_state()->IsPip());
+
+  state()->set_bounds_locally(true);
+  wm::SetBoundsEvent event(gfx::Rect(0, 0, 50, 50));
+  window_state()->OnWMEvent(&event);
+  state()->set_bounds_locally(false);
+
+  EXPECT_TRUE(window_state()->HasRestoreBounds());
+  EXPECT_EQ(gfx::Rect(0, 0, 50, 50),
+            window_state()->GetRestoreBoundsInParent());
+}
+
 }  // namespace wm
 }  // namespace ash
diff --git a/ash/wm/lock_layout_manager.cc b/ash/wm/lock_layout_manager.cc
index 9dd55075..d2375f2 100644
--- a/ash/wm/lock_layout_manager.cc
+++ b/ash/wm/lock_layout_manager.cc
@@ -114,7 +114,7 @@
   AdjustWindowsForWorkAreaChange(&event);
 }
 
-void LockLayoutManager::OnKeyboardWorkspaceOccludedBoundsChanged(
+void LockLayoutManager::OnKeyboardOccludedBoundsChanged(
     const gfx::Rect& new_bounds_in_screen) {
   OnWindowResized();
 }
diff --git a/ash/wm/lock_layout_manager.h b/ash/wm/lock_layout_manager.h
index 23849da..99512a8 100644
--- a/ash/wm/lock_layout_manager.h
+++ b/ash/wm/lock_layout_manager.h
@@ -7,7 +7,7 @@
 
 #include "ash/ash_export.h"
 #include "ash/keyboard/ui/keyboard_controller.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/shelf/shelf_observer.h"
 #include "ash/shell_observer.h"
 #include "ash/wm/wm_snap_to_pixel_layout_manager.h"
@@ -36,12 +36,11 @@
 // virtual keyboard changes inner workspace of each WebContents.
 // For all windows in LockScreenContainer default wm::WindowState is replaced
 // with LockWindowState.
-class ASH_EXPORT LockLayoutManager
-    : public wm::WmSnapToPixelLayoutManager,
-      public aura::WindowObserver,
-      public ShellObserver,
-      public ShelfObserver,
-      public keyboard::KeyboardControllerObserver {
+class ASH_EXPORT LockLayoutManager : public wm::WmSnapToPixelLayoutManager,
+                                     public aura::WindowObserver,
+                                     public ShellObserver,
+                                     public ShelfObserver,
+                                     public KeyboardControllerObserver {
  public:
   LockLayoutManager(aura::Window* window, Shelf* shelf);
   ~LockLayoutManager() override;
@@ -66,9 +65,8 @@
   // ShelfObserver:
   void WillChangeVisibilityState(ShelfVisibilityState visibility) override;
 
-  // keyboard::KeyboardControllerObserver overrides:
-  void OnKeyboardWorkspaceOccludedBoundsChanged(
-      const gfx::Rect& new_bounds) override;
+  // KeyboardControllerObserver overrides:
+  void OnKeyboardOccludedBoundsChanged(const gfx::Rect& new_bounds) override;
 
  protected:
   // Adjusts the bounds of all managed windows when the display area changes.
diff --git a/ash/wm/system_modal_container_layout_manager.cc b/ash/wm/system_modal_container_layout_manager.cc
index 897223b..c835c0b 100644
--- a/ash/wm/system_modal_container_layout_manager.cc
+++ b/ash/wm/system_modal_container_layout_manager.cc
@@ -134,9 +134,8 @@
 // SystemModalContainerLayoutManager, Keyboard::KeyboardControllerObserver
 // implementation:
 
-void SystemModalContainerLayoutManager::
-    OnKeyboardWorkspaceOccludedBoundsChanged(
-        const gfx::Rect& new_bounds_in_screen) {
+void SystemModalContainerLayoutManager::OnKeyboardOccludedBoundsChanged(
+    const gfx::Rect& new_bounds_in_screen) {
   PositionDialogsAfterWorkAreaResize();
 }
 
diff --git a/ash/wm/system_modal_container_layout_manager.h b/ash/wm/system_modal_container_layout_manager.h
index 7937803..af3c5fe 100644
--- a/ash/wm/system_modal_container_layout_manager.h
+++ b/ash/wm/system_modal_container_layout_manager.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "ash/ash_export.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/wm/wm_snap_to_pixel_layout_manager.h"
 #include "base/macros.h"
 #include "ui/aura/window_observer.h"
@@ -28,7 +28,7 @@
 class ASH_EXPORT SystemModalContainerLayoutManager
     : public wm::WmSnapToPixelLayoutManager,
       public aura::WindowObserver,
-      public keyboard::KeyboardControllerObserver {
+      public KeyboardControllerObserver {
  public:
   explicit SystemModalContainerLayoutManager(aura::Window* container);
   ~SystemModalContainerLayoutManager() override;
@@ -49,9 +49,8 @@
                                const void* key,
                                intptr_t old) override;
 
-  // Overridden from keyboard::KeyboardControllerObserver:
-  void OnKeyboardWorkspaceOccludedBoundsChanged(
-      const gfx::Rect& new_bounds) override;
+  // Overridden from KeyboardControllerObserver:
+  void OnKeyboardOccludedBoundsChanged(const gfx::Rect& new_bounds) override;
 
   // True if the window is either contained by the top most modal window,
   // or contained by its transient children.
diff --git a/ash/wm/tablet_mode/internal_input_devices_event_blocker.cc b/ash/wm/tablet_mode/internal_input_devices_event_blocker.cc
index b0b51a79..c787d75d 100644
--- a/ash/wm/tablet_mode/internal_input_devices_event_blocker.cc
+++ b/ash/wm/tablet_mode/internal_input_devices_event_blocker.cc
@@ -7,21 +7,14 @@
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/touch/touch_devices_controller.h"
-#include "services/ws/public/cpp/input_devices/input_device_controller_client.h"
 #include "ui/events/devices/input_device.h"
 #include "ui/events/devices/input_device_manager.h"
 #include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/ozone/public/input_controller.h"
+#include "ui/ozone/public/ozone_platform.h"
 
 namespace ash {
 
-namespace {
-
-ws::InputDeviceControllerClient* GetInputDeviceControllerClient() {
-  return Shell::Get()->shell_delegate()->GetInputDeviceControllerClient();
-}
-
-}  // namespace
-
 InternalInputDevicesEventBlocker::InternalInputDevicesEventBlocker() {
   ui::InputDeviceManager::GetInstance()->AddObserver(this);
 }
@@ -86,22 +79,23 @@
   if (should_be_blocked == is_keyboard_blocked_)
     return;
 
-  // Block or unblock the internal keyboard. Note InputDeviceControllerClient
-  // may be null in tests.
-  if (HasInternalKeyboard() && GetInputDeviceControllerClient()) {
-    std::vector<ui::DomCode> allowed_keys;
-    if (should_be_blocked) {
-      // Only allow the acccessible keys present on the side of some devices to
-      // continue working if the internal keyboard events should be blocked.
-      allowed_keys.push_back(ui::DomCode::VOLUME_DOWN);
-      allowed_keys.push_back(ui::DomCode::VOLUME_UP);
-      allowed_keys.push_back(ui::DomCode::POWER);
-    }
-    GetInputDeviceControllerClient()->SetInternalKeyboardFilter(
-        should_be_blocked, allowed_keys);
-    is_keyboard_blocked_ = should_be_blocked;
-    VLOG(1) << "Internal keyboard is blocked: " << is_keyboard_blocked_;
+  if (!HasInternalKeyboard())
+    return;
+
+  // Block or unblock the internal keyboard.
+  ui::InputController* input_controller =
+      ui::OzonePlatform::GetInstance()->GetInputController();
+  std::vector<ui::DomCode> allowed_keys;
+  if (should_be_blocked) {
+    // Only allow the acccessible keys present on the side of some devices to
+    // continue working if the internal keyboard events should be blocked.
+    allowed_keys.push_back(ui::DomCode::VOLUME_DOWN);
+    allowed_keys.push_back(ui::DomCode::VOLUME_UP);
+    allowed_keys.push_back(ui::DomCode::POWER);
   }
+  input_controller->SetInternalKeyboardFilter(should_be_blocked, allowed_keys);
+  is_keyboard_blocked_ = should_be_blocked;
+  VLOG(1) << "Internal keyboard is blocked: " << is_keyboard_blocked_;
 }
 
 }  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index 19fe5719..76639c2 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -50,18 +50,18 @@
 namespace {
 
 // The hinge angle at which to enter tablet mode.
-const float kEnterTabletModeAngle = 200.0f;
+constexpr float kEnterTabletModeAngle = 200.0f;
 
 // The angle at which to exit tablet mode, this is specifically less than the
 // angle to enter tablet mode to prevent rapid toggling when near the angle.
-const float kExitTabletModeAngle = 160.0f;
+constexpr float kExitTabletModeAngle = 160.0f;
 
 // Defines a range for which accelerometer readings are considered accurate.
 // When the lid is near open (or near closed) the accelerometer readings may be
 // inaccurate and a lid that is fully open may appear to be near closed (and
 // vice versa).
-const float kMinStableAngle = 20.0f;
-const float kMaxStableAngle = 340.0f;
+constexpr float kMinStableAngle = 20.0f;
+constexpr float kMaxStableAngle = 340.0f;
 
 // The time duration to consider an unstable lid angle to be valid. This is used
 // to prevent entering tablet mode if an erroneous accelerometer reading makes
@@ -78,15 +78,15 @@
 // smoothed over time in order to reduce this noise.
 // This is the minimum acceleration parallel to the hinge under which to begin
 // smoothing in m/s^2.
-const float kHingeVerticalSmoothingStart = 7.0f;
+constexpr float kHingeVerticalSmoothingStart = 7.0f;
 // This is the maximum acceleration parallel to the hinge under which smoothing
 // will incorporate new acceleration values, in m/s^2.
-const float kHingeVerticalSmoothingMaximum = 8.7f;
+constexpr float kHingeVerticalSmoothingMaximum = 8.7f;
 
 // The maximum deviation between the magnitude of the two accelerometers under
 // which to detect hinge angle in m/s^2. These accelerometers are attached to
 // the same physical device and so should be under the same acceleration.
-const float kNoisyMagnitudeDeviation = 1.0f;
+constexpr float kNoisyMagnitudeDeviation = 1.0f;
 
 // Interval between calls to RecordLidAngle().
 constexpr base::TimeDelta kRecordLidAngleInterval =
@@ -203,7 +203,7 @@
 constexpr char TabletModeController::kLidAngleHistogramName[];
 
 TabletModeController::TabletModeController()
-    : event_blocker_(new InternalInputDevicesEventBlocker),
+    : event_blocker_(std::make_unique<InternalInputDevicesEventBlocker>()),
       tablet_mode_usage_interval_start_time_(base::Time::Now()),
       tick_clock_(base::DefaultTickClock::GetInstance()) {
   Shell::Get()->AddShellObserver(this);
@@ -911,7 +911,7 @@
 }
 
 void TabletModeController::FinishInitTabletMode() {
-  tablet_mode_window_manager_.reset(new TabletModeWindowManager());
+  tablet_mode_window_manager_ = std::make_unique<TabletModeWindowManager>();
   tablet_mode_window_manager_->Init();
 
   base::RecordAction(base::UserMetricsAction("Touchview_Enabled"));
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
index 4595d50..3d05a3f9 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -115,6 +115,8 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedObserveWindowAnimation);
 };
 
+TabletModeWindowManager::TabletModeWindowManager() = default;
+
 TabletModeWindowManager::~TabletModeWindowManager() = default;
 
 // static
@@ -195,6 +197,11 @@
     window_state_map_.erase(it);
 }
 
+void TabletModeWindowManager::SetIgnoreWmEventsForExit() {
+  for (auto& pair : window_state_map_)
+    pair.second->set_ignore_wm_events(true);
+}
+
 void TabletModeWindowManager::OnOverviewModeEndingAnimationComplete(
     bool canceled) {
   if (canceled)
@@ -254,7 +261,7 @@
   } else {
     // If a known window gets destroyed we need to remove all knowledge about
     // it.
-    ForgetWindow(window, true /* destroyed */);
+    ForgetWindow(window, /*destroyed=*/true);
   }
 }
 
@@ -416,13 +423,6 @@
   }
 }
 
-void TabletModeWindowManager::SetIgnoreWmEventsForExit() {
-  for (auto& pair : window_state_map_)
-    pair.second->set_ignore_wm_events(true);
-}
-
-TabletModeWindowManager::TabletModeWindowManager() = default;
-
 WindowStateType TabletModeWindowManager::GetDesktopWindowStateType(
     aura::Window* window) const {
   auto iter = window_state_map_.find(window);
@@ -522,13 +522,12 @@
   DCHECK(!IsTrackingWindow(window));
   window->AddObserver(this);
 
-  // We create and remember a tablet mode state which will attach itself to
-  // the provided state object. First set the map to point to a null object
-  // because on creating a TabletModeWindowState will check to see if |window|
-  // is being tracked by |this|, and we want that to return true.
-  window_state_map_.emplace(window, nullptr);
-  window_state_map_[window] = new TabletModeWindowState(
-      window, this, snap, animate_bounds_on_attach, entering_tablet_mode);
+  // Create and remember a tablet mode state which will attach itself to the
+  // provided state object.
+  window_state_map_.emplace(
+      window,
+      new TabletModeWindowState(window, this, snap, animate_bounds_on_attach,
+                                entering_tablet_mode));
 }
 
 void TabletModeWindowManager::ForgetWindow(aura::Window* window,
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.h b/ash/wm/tablet_mode/tablet_mode_window_manager.h
index 780b8bf..42cec9a 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.h
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.h
@@ -47,7 +47,9 @@
                                            public ShellObserver,
                                            public SessionObserver {
  public:
-  // This should only be deleted by the creator (TabletModeController).
+  // This should only be created or deleted by the creator
+  // (TabletModeController).
+  TabletModeWindowManager();
   ~TabletModeWindowManager() override;
 
   static aura::Window* GetTopWindow();
@@ -74,6 +76,9 @@
   // Called from a window state object when it gets destroyed.
   void WindowStateDestroyed(aura::Window* window);
 
+  // Tell all managing windows not to handle WM events.
+  void SetIgnoreWmEventsForExit();
+
   // OverviewObserver:
   void OnOverviewModeEndingAnimationComplete(bool canceled) override;
 
@@ -99,15 +104,6 @@
   // SessionObserver:
   void OnActiveUserSessionChanged(const AccountId& account_id) override;
 
-  // Tell all managing windows not to handle WM events.
-  void SetIgnoreWmEventsForExit();
-
- protected:
-  friend class TabletModeController;
-
-  // The object should only be created by TabletModeController.
-  TabletModeWindowManager();
-
  private:
   using WindowToState = std::map<aura::Window*, TabletModeWindowState*>;
 
diff --git a/ash/wm/work_area_insets.cc b/ash/wm/work_area_insets.cc
index 8fc729f..f8f567f 100644
--- a/ash/wm/work_area_insets.cc
+++ b/ash/wm/work_area_insets.cc
@@ -102,7 +102,7 @@
 }
 
 void WorkAreaInsets::OnKeyboardAppearanceChanged(
-    const keyboard::KeyboardStateDescriptor& state) {
+    const KeyboardStateDescriptor& state) {
   aura::Window* window = root_window_controller_->GetRootWindow();
 
   keyboard_occluded_bounds_ = state.occluded_bounds_in_screen;
@@ -112,7 +112,7 @@
   Shell::Get()->NotifyUserWorkAreaInsetsChanged(window);
 }
 
-void WorkAreaInsets::OnKeyboardVisibilityStateChanged(const bool is_visible) {
+void WorkAreaInsets::OnKeyboardVisibilityChanged(const bool is_visible) {
   // On login screen if keyboard has been just hidden, update bounds just once
   // but ignore work area insets since shelf overlaps with login window.
   if (Shell::Get()->session_controller()->IsUserSessionBlocked() &&
diff --git a/ash/wm/work_area_insets.h b/ash/wm/work_area_insets.h
index ff8ace8..d6563e0 100644
--- a/ash/wm/work_area_insets.h
+++ b/ash/wm/work_area_insets.h
@@ -6,7 +6,7 @@
 #define ASH_WM_WORK_AREA_INSETS_H_
 
 #include "ash/ash_export.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "base/macros.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
@@ -26,7 +26,7 @@
 // WorkAreaInsets class caches information about persistent system elements to
 // avoid frequent recalculations. It gathers work area related computations and
 // provides single interface to query work area details.
-class ASH_EXPORT WorkAreaInsets : public keyboard::KeyboardControllerObserver {
+class ASH_EXPORT WorkAreaInsets : public KeyboardControllerObserver {
  public:
   // Returns work area parameters associated with the given |window|.
   static WorkAreaInsets* ForWindow(const aura::Window* window);
@@ -79,10 +79,10 @@
   void SetShelfBoundsAndInsets(const gfx::Rect& bounds,
                                const gfx::Insets& insets);
 
-  // keyboard::KeyboardControllerObserver:
+  // KeyboardControllerObserver:
   void OnKeyboardAppearanceChanged(
-      const keyboard::KeyboardStateDescriptor& state) override;
-  void OnKeyboardVisibilityStateChanged(bool is_visible) override;
+      const KeyboardStateDescriptor& state) override;
+  void OnKeyboardVisibilityChanged(bool is_visible) override;
 
  private:
   // Updates cached values of work area bounds and insets.
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index ac1941a8..fa25925 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -10,7 +10,7 @@
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/autoclick/autoclick_controller.h"
 #include "ash/keyboard/ui/keyboard_controller.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/root_window_controller.h"
@@ -213,7 +213,7 @@
 }
 
 //////////////////////////////////////////////////////////////////////////////
-// WorkspaceLayoutManager, keyboard::KeyboardControllerObserver implementation:
+// WorkspaceLayoutManager, ash::KeyboardControllerObserver implementation:
 
 void WorkspaceLayoutManager::OnKeyboardVisibleBoundsChanged(
     const gfx::Rect& new_bounds) {
@@ -223,7 +223,7 @@
     NotifySystemUiAreaChanged();
 }
 
-void WorkspaceLayoutManager::OnKeyboardWorkspaceDisplacingBoundsChanged(
+void WorkspaceLayoutManager::OnKeyboardDisplacingBoundsChanged(
     const gfx::Rect& new_bounds_in_screen) {
   aura::Window* window = wm::GetActiveWindow();
   if (!window)
diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h
index 19292323..540a6b2 100644
--- a/ash/wm/workspace/workspace_layout_manager.h
+++ b/ash/wm/workspace/workspace_layout_manager.h
@@ -9,7 +9,7 @@
 #include <set>
 
 #include "ash/ash_export.h"
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/shelf/shelf_observer.h"
 #include "ash/shell_observer.h"
 #include "ash/wm/window_state_observer.h"
@@ -32,15 +32,14 @@
 }
 
 // LayoutManager used on the window created for a workspace.
-class ASH_EXPORT WorkspaceLayoutManager
-    : public aura::LayoutManager,
-      public aura::WindowObserver,
-      public ::wm::ActivationChangeObserver,
-      public keyboard::KeyboardControllerObserver,
-      public display::DisplayObserver,
-      public ShellObserver,
-      public wm::WindowStateObserver,
-      public ShelfObserver {
+class ASH_EXPORT WorkspaceLayoutManager : public aura::LayoutManager,
+                                          public aura::WindowObserver,
+                                          public ::wm::ActivationChangeObserver,
+                                          public KeyboardControllerObserver,
+                                          public display::DisplayObserver,
+                                          public ShellObserver,
+                                          public wm::WindowStateObserver,
+                                          public ShelfObserver {
  public:
   // |window| is the container for this layout manager.
   explicit WorkspaceLayoutManager(aura::Window* window);
@@ -87,10 +86,9 @@
       aura::Window* gained_active,
       aura::Window* lost_active) override;
 
-  // keyboard::KeyboardControllerObserver:
+  // KeyboardControllerObserver:
   void OnKeyboardVisibleBoundsChanged(const gfx::Rect& new_bounds) override;
-  void OnKeyboardWorkspaceDisplacingBoundsChanged(
-      const gfx::Rect& new_bounds) override;
+  void OnKeyboardDisplacingBoundsChanged(const gfx::Rect& new_bounds) override;
 
   // WindowStateObserver:
   void OnPostWindowStateTypeChange(wm::WindowState* window_state,
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 75b08b7..232cfd1 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -1638,8 +1638,7 @@
   }
 
   void ShowKeyboard() {
-    layout_manager_->OnKeyboardWorkspaceDisplacingBoundsChanged(
-        keyboard_bounds_);
+    layout_manager_->OnKeyboardDisplacingBoundsChanged(keyboard_bounds_);
     restore_work_area_insets_ = GetPrimaryDisplay().GetWorkAreaInsets();
     Shell::Get()->SetDisplayWorkAreaInsets(
         Shell::GetPrimaryRootWindow(),
@@ -1649,7 +1648,7 @@
   void HideKeyboard() {
     Shell::Get()->SetDisplayWorkAreaInsets(Shell::GetPrimaryRootWindow(),
                                            restore_work_area_insets_);
-    layout_manager_->OnKeyboardWorkspaceDisplacingBoundsChanged(gfx::Rect());
+    layout_manager_->OnKeyboardDisplacingBoundsChanged(gfx::Rect());
   }
 
   // Initializes the keyboard bounds using the bottom half of the work area.
diff --git a/chrome/VERSION b/chrome/VERSION
index 55f74ea..cc6cebc 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=77
 MINOR=0
-BUILD=3824
+BUILD=3825
 PATCH=0
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 1615b8a..e4254cf 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1557,6 +1557,7 @@
   "java/src/org/chromium/chrome/browser/tabmodel/document/AsyncTabCreationParams.java",
   "java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java",
   "java/src/org/chromium/chrome/browser/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java",
+  "java/src/org/chromium/chrome/browser/tab_activity_glue/TabDelegateFactoryImpl.java",
   "java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java",
   "java/src/org/chromium/chrome/browser/tasks/EngagementTimeUtil.java",
   "java/src/org/chromium/chrome/browser/tasks/JourneyManager.java",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java
index 94ba7a3..52f6037 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java
@@ -357,7 +357,8 @@
 
     @Nullable
     TabListMediator.TabActionListener getCreateGroupButtonOnClickListener(Tab tab) {
-        if (!ableToCreateGroup(tab)) return null;
+        if (!ableToCreateGroup(tab) || FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled())
+            return null;
 
         return tabId -> {
             Tab parentTab = TabModelUtils.getTabById(mTabModelSelector.getCurrentModel(), tabId);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
index f70cea2c..a12fd4f8 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
@@ -98,16 +98,15 @@
 
             @Override
             public void didSelectTab(Tab tab, int type, int lastId) {
-                if (type == TabSelectionType.FROM_USER)
+                if (type == TabSelectionType.FROM_USER) {
                     // Cancel the zooming into tab grid card animation.
                     mModel.set(TabGridSheetProperties.ANIMATION_SOURCE_RECT, null);
                     mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, false);
+                }
             }
 
             @Override
             public void willCloseTab(Tab tab, boolean animate) {
-                updateDialog();
-                updateGridTabSwitcher();
                 List<Tab> relatedTabs = getRelatedTabs(tab.getId());
                 // If current tab is closed and tab group is not empty, hand over ID of the next
                 // tab in the group to mCurrentTabId.
@@ -115,6 +114,8 @@
                 if (tab.getId() == mCurrentTabId) {
                     mCurrentTabId = relatedTabs.get(0).getId();
                 }
+                updateDialog();
+                updateGridTabSwitcher();
             }
         };
         mTabModelSelector.getTabModelFilterProvider().addTabModelFilterObserver(mTabModelObserver);
@@ -134,9 +135,11 @@
                             .getCurrentTabModelFilter();
             int index = filter.indexOf(
                     TabModelUtils.getTabById(mTabModelSelector.getCurrentModel(), tabId));
-            Rect rect = mAnimationOriginProvider.getAnimationOriginRect(index);
+            if (mAnimationOriginProvider != null) {
+                Rect rect = mAnimationOriginProvider.getAnimationOriginRect(index);
+                mModel.set(TabGridSheetProperties.ANIMATION_SOURCE_RECT, rect);
+            }
             updateDialog();
-            mModel.set(TabGridSheetProperties.ANIMATION_SOURCE_RECT, rect);
             mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, true);
         } else {
             mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, false);
@@ -154,7 +157,9 @@
     }
 
     private void updateGridTabSwitcher() {
-        if (!mModel.get(TabGridSheetProperties.IS_DIALOG_VISIBLE)) return;
+        if (!mModel.get(TabGridSheetProperties.IS_DIALOG_VISIBLE)
+                || mGridTabSwitcherResetHandler == null)
+            return;
         mGridTabSwitcherResetHandler.resetWithTabList(
                 mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(), false);
     }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java
index 69f09c7a..a0fc983 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java
@@ -46,6 +46,7 @@
     private ScrimView.ScrimParams mScrimParams;
     private View mBlockView;
     private Animator mCurrentAnimator;
+    private ObjectAnimator mBasicFadeIn;
     private ObjectAnimator mBasicFadeOut;
     private AnimatorSet mShowDialogAnimation;
     private AnimatorSet mHideDialogAnimation;
@@ -99,9 +100,14 @@
     }
 
     private void prepareAnimation() {
+        mBasicFadeIn = ObjectAnimator.ofFloat(mDialogContainerView, View.ALPHA, 0f, 1f);
+        mBasicFadeIn.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE);
+        mBasicFadeIn.setDuration(DIALOG_ANIMATION_DURATION);
+
         mBasicFadeOut = ObjectAnimator.ofFloat(mDialogContainerView, View.ALPHA, 1f, 0f);
         mBasicFadeOut.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
         mBasicFadeOut.setDuration(DIALOG_ANIMATION_DURATION);
+
         mShowDialogAnimationListener = new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -124,6 +130,11 @@
         // mHideDialogAnimation and play basic fade out instead of zooming back to corresponding tab
         // grid card.
         if (rect == null) {
+            mShowDialogAnimation = new AnimatorSet();
+            mShowDialogAnimation.play(mBasicFadeIn);
+            mShowDialogAnimation.removeAllListeners();
+            mShowDialogAnimation.addListener(mShowDialogAnimationListener);
+
             mHideDialogAnimation = new AnimatorSet();
             mHideDialogAnimation.play(mBasicFadeOut);
             mHideDialogAnimation.removeAllListeners();
@@ -159,6 +170,7 @@
                 .with(showMoveYAnimator)
                 .with(showScaleXAnimator)
                 .with(showScaleYAnimator);
+        mShowDialogAnimation.removeAllListeners();
         mShowDialogAnimation.addListener(mShowDialogAnimationListener);
 
         final ObjectAnimator hideMoveYAnimator =
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 a025adef..72d51a7 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
@@ -23,6 +23,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tasks.tabgroup.TabGroupModelFilter;
 import org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.ui.modelutil.PropertyModel;
 
@@ -40,6 +41,7 @@
     private final PropertyModel mTabStripToolbarModel;
     private final ThemeColorProvider mThemeColorProvider;
     private TabGridSheetCoordinator mTabGridSheetCoordinator;
+    private TabGridDialogCoordinator mTabGridDialogCoordinator;
     private TabListCoordinator mTabStripCoordinator;
     private TabGroupUiMediator mMediator;
     private TabStripToolbarCoordinator mTabStripToolbarCoordinator;
@@ -79,9 +81,20 @@
                 mTabStripToolbarCoordinator.getTabListContainerView(), null, true,
                 R.layout.tab_list_recycler_view_layout, COMPONENT_NAME);
 
-        mTabGridSheetCoordinator =
-                new TabGridSheetCoordinator(mContext, activity.getBottomSheetController(),
-                        tabModelSelector, tabContentManager, activity, mThemeColorProvider);
+        if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled()) {
+            // TODO(yuezhanggg): find a way to enable interactions between grid tab switcher and the
+            // dialog here.
+            mTabGridSheetCoordinator = null;
+
+            mTabGridDialogCoordinator = new TabGridDialogCoordinator(mContext, tabModelSelector,
+                    tabContentManager, activity, activity.getCompositorViewHolder(), null, null);
+        } else {
+            mTabGridSheetCoordinator =
+                    new TabGridSheetCoordinator(mContext, activity.getBottomSheetController(),
+                            tabModelSelector, tabContentManager, activity, mThemeColorProvider);
+
+            mTabGridDialogCoordinator = null;
+        }
 
         mMediator = new TabGroupUiMediator(visibilityController, this, mTabStripToolbarModel,
                 tabModelSelector, activity,
@@ -92,7 +105,7 @@
 
     /**
      * Handles a reset event originated from {@link TabGroupUiMediator}
-     * when the bottom sheet is collapsed.
+     * when the bottom sheet is collapsed or the dialog is hidden.
      *
      * @param tabs List of Tabs to reset.
      */
@@ -103,13 +116,17 @@
 
     /**
      * Handles a reset event originated from {@link TabGroupUiMediator}
-     * when the bottom sheet is expanded.
+     * when the bottom sheet is expanded or the dialog is shown.
      *
      * @param tabs List of Tabs to reset.
      */
     @Override
-    public void resetSheetWithListOfTabs(List<Tab> tabs) {
-        mTabGridSheetCoordinator.resetWithListOfTabs(tabs);
+    public void resetGridWithListOfTabs(List<Tab> tabs) {
+        if (mTabGridDialogCoordinator == null) {
+            mTabGridSheetCoordinator.resetWithListOfTabs(tabs);
+        } else {
+            mTabGridDialogCoordinator.resetWithListOfTabs(tabs);
+        }
     }
 
     /**
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
index dee69c376..19a80b3 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
@@ -39,7 +39,7 @@
     interface ResetHandler {
         /**
          * Handles a reset event originated from {@link TabGroupUiMediator}
-         * when the bottom sheet is collapsed.
+         * when the bottom sheet is collapsed or the dialog is hidden.
          *
          * @param tabs List of Tabs to reset.
          */
@@ -47,11 +47,11 @@
 
         /**
          * Handles a reset event originated from {@link TabGroupUiMediator}
-         * when the bottom sheet is expanded.
+         * when the bottom sheet is expanded or the dialog is shown.
          *
          * @param tabs List of Tabs to reset.
          */
-        void resetSheetWithListOfTabs(List<Tab> tabs);
+        void resetGridWithListOfTabs(List<Tab> tabs);
     }
 
     private final PropertyModel mToolbarPropertyModel;
@@ -176,7 +176,7 @@
         mToolbarPropertyModel.set(TabStripToolbarViewProperties.EXPAND_CLICK_LISTENER, view -> {
             Tab currentTab = mTabModelSelector.getCurrentTab();
             if (currentTab == null) return;
-            mResetHandler.resetSheetWithListOfTabs(getRelatedTabsForId(currentTab.getId()));
+            mResetHandler.resetGridWithListOfTabs(getRelatedTabsForId(currentTab.getId()));
             RecordUserAction.record("TabGroup.ExpandedFromStrip");
         });
         mToolbarPropertyModel.set(TabStripToolbarViewProperties.ADD_CLICK_LISTENER, view -> {
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java
index de50cb6..9a6a5c6 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedLoggingBridge.java
@@ -208,6 +208,7 @@
 
     @Override
     public void onPietFrameRenderingEvent(List<Integer> pietErrorCodes) {
+        if (mNativeFeedLoggingBridge == 0) return;
         int[] pietErrorCodesArray = new int[pietErrorCodes.size()];
         for (int i = 0; i < pietErrorCodes.size(); ++i) {
             pietErrorCodesArray[i] = pietErrorCodes.get(i);
@@ -217,12 +218,18 @@
 
     @Override
     public void onVisualElementClicked(ElementLoggingData data, int elementType) {
-        // TODO(https://crbug.com/924739): Implementation.
+        if (mNativeFeedLoggingBridge == 0) return;
+        nativeOnVisualElementClicked(mNativeFeedLoggingBridge, elementType,
+                data.getPositionInStream(),
+                TimeUnit.SECONDS.toMillis(data.getTimeContentBecameAvailable()));
     }
 
     @Override
     public void onVisualElementViewed(ElementLoggingData data, int elementType) {
-        // TODO(https://crbug.com/924739): Implementation.
+        if (mNativeFeedLoggingBridge == 0) return;
+        nativeOnVisualElementViewed(mNativeFeedLoggingBridge, elementType,
+                data.getPositionInStream(),
+                TimeUnit.SECONDS.toMillis(data.getTimeContentBecameAvailable()));
     }
 
     @Override
@@ -393,6 +400,10 @@
             long nativeFeedLoggingBridge, long spinnerShownTimeMs, int spinnerType);
     private native void nativeOnPietFrameRenderingEvent(
             long nativeFeedLoggingBridge, int[] pietErrorCodes);
+    private native void nativeOnVisualElementClicked(long nativeFeedLoggingBridge, int elementType,
+            int position, long timeContentBecameAvailableMs);
+    private native void nativeOnVisualElementViewed(long nativeFeedLoggingBridge, int elementType,
+            int position, long timeContentBecameAvailableMs);
     private native void nativeOnInternalError(long nativeFeedLoggingBridge, int internalError);
     private native void nativeOnTokenCompleted(
             long nativeFeedLoggingBridge, boolean wasSynthetic, int contentCount, int tokenCount);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index ebe13e40..657c16a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -123,6 +123,7 @@
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate;
+import org.chromium.chrome.browser.tab_activity_glue.TabDelegateFactoryImpl;
 import org.chromium.chrome.browser.tabbed_mode.TabbedAppMenuPropertiesDelegate;
 import org.chromium.chrome.browser.tabbed_mode.TabbedRootUiCoordinator;
 import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
@@ -448,7 +449,11 @@
         }
     }
 
-    private class TabbedModeTabDelegateFactory extends TabDelegateFactory {
+    private class TabbedModeTabDelegateFactory extends TabDelegateFactoryImpl {
+        private TabbedModeTabDelegateFactory() {
+            super(ChromeTabbedActivity.this);
+        }
+
         @Override
         public void createBrowserControlsState(Tab tab) {
             TabBrowserControlsState.create(tab,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
index 6e1f7608..6f59e20a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.browser.tab.TabBuilder;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabState;
+import org.chromium.chrome.browser.tab_activity_glue.TabDelegateFactoryImpl;
 import org.chromium.chrome.browser.tabmodel.SingleTabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -114,7 +115,7 @@
      * @return {@link TabDelegateFactory} to be used while creating the associated {@link Tab}.
      */
     protected TabDelegateFactory createTabDelegateFactory() {
-        return new TabDelegateFactory();
+        return new TabDelegateFactoryImpl(this);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
index 2f88199..8aebfd5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
@@ -249,7 +249,7 @@
             mLastOnDownTimeStamp = time;
 
             if (shouldIgnoreTouchInput()) return;
-            if (mNavigationEnabled) mNavigationHandler.onDown();
+            if (mNavigationHandler != null) mNavigationHandler.onDown();
             mStacks.get(getTabStackIndex()).onDown(time);
         }
 
@@ -262,7 +262,7 @@
         public void drag(float x, float y, float dx, float dy, float tx, float ty) {
             if (shouldIgnoreTouchInput()) return;
 
-            if (mNavigationEnabled) {
+            if (mNavigationHandler != null) {
                 mNavigationHandler.onScroll(mLastOnDownX * mDpToPx, -dx * mDpToPx, -dy * mDpToPx,
                         x * mDpToPx, y * mDpToPx);
                 if (mNavigationHandler.isActive()) {
@@ -355,7 +355,7 @@
         private void onUpOrCancel(long time) {
             if (shouldIgnoreTouchInput()) return;
 
-            if (mNavigationEnabled && mNavigationHandler.isActive()) {
+            if (mNavigationHandler != null && mNavigationHandler.isActive()) {
                 mNavigationHandler.onTouchEvent(MotionEvent.ACTION_UP);
             }
             cancelDragTabs(time);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
index ae58803..0bda3b8c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
@@ -50,7 +50,7 @@
  * by a {@link CustomTabActivity}.
  */
 @ActivityScope
-public class CustomTabDelegateFactory extends TabDelegateFactory {
+public class CustomTabDelegateFactory implements TabDelegateFactory {
     /**
      * A custom external navigation delegate that forbids the intent picker from showing up.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index d996efa4..4690468 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -7,6 +7,7 @@
 import android.app.Activity;
 import android.app.SearchManager;
 import android.content.Intent;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.support.v4.app.ActivityOptionsCompat;
 import android.text.TextUtils;
@@ -22,8 +23,10 @@
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.WindowDelegate;
+import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
 import org.chromium.chrome.browser.customtabs.CustomTabsConnection;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
 import org.chromium.chrome.browser.init.AsyncInitializationActivity;
 import org.chromium.chrome.browser.init.SingleWindowKeyboardVisibilityDelegate;
 import org.chromium.chrome.browser.locale.LocaleManager;
@@ -34,10 +37,12 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabBuilder;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
+import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid;
 import org.chromium.chrome.browser.tabmodel.TabLaunchType;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.components.url_formatter.UrlFormatter;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.ContentUrlConstants;
 import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
 import org.chromium.ui.base.ActivityWindowAndroid;
@@ -171,8 +176,47 @@
                        .setWindow(getWindowAndroid())
                        .setLaunchType(TabLaunchType.FROM_EXTERNAL_APP)
                        .build();
-        mTab.initialize(WebContentsFactory.createWebContents(false, false),
-                new TabDelegateFactory(), false, null, false);
+        TabDelegateFactory factory = new TabDelegateFactory() {
+            @Override
+            public TabWebContentsDelegateAndroid createWebContentsDelegate(Tab tab) {
+                return new TabWebContentsDelegateAndroid(tab) {
+                    @Override
+                    protected boolean shouldResumeRequestsForCreatedWindow() {
+                        return false;
+                    }
+
+                    @Override
+                    protected boolean addNewContents(WebContents sourceWebContents,
+                            WebContents webContents, int disposition, Rect initialPosition,
+                            boolean userGesture) {
+                        return false;
+                    }
+
+                    @Override
+                    protected void setOverlayMode(boolean useOverlayMode) {}
+                };
+            }
+
+            @Override
+            public ExternalNavigationHandler createExternalNavigationHandler(Tab tab) {
+                return null;
+            }
+
+            @Override
+            public ContextMenuPopulator createContextMenuPopulator(Tab tab) {
+                return null;
+            }
+
+            @Override
+            public boolean canShowAppBanners() {
+                return false;
+            }
+
+            @Override
+            public void createBrowserControlsState(Tab tab) {}
+        };
+        mTab.initialize(
+                WebContentsFactory.createWebContents(false, false), factory, false, null, false);
         mTab.loadUrl(new LoadUrlParams(ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL));
 
         mSearchBoxDataProvider.onNativeLibraryReady(mTab);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
index 3f83208..fc98d94 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -14,7 +14,4 @@
     "+ui/android/java/src/org/chromium/ui/base",
     "+ui/android/java/src/org/chromium/ui/mojom",
   ],
-  'TabDelegateFactory\.java': [
-    "+chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue",
-  ]
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 8fa6394..3588d08b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -865,11 +865,11 @@
 
             if (tabState != null) restoreFieldsFromState(tabState);
 
-            mDelegateFactory = delegateFactory;
             initializeNative();
 
             RevenueStats.getInstance().tabCreated(this);
 
+            mDelegateFactory = delegateFactory;
             mDelegateFactory.createBrowserControlsState(this);
 
             // If there is a frozen WebContents state or a pending lazy load, don't create a new
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuPopulator.java
index 977044b..8329944 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuPopulator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuPopulator.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.tab;
 
 import android.content.Context;
+import android.support.annotation.Nullable;
 import android.util.Pair;
 import android.view.ContextMenu;
 
@@ -20,6 +21,7 @@
  * A simple wrapper around a {@link ContextMenuPopulator} to handle observer notification.
  */
 public class TabContextMenuPopulator implements ContextMenuPopulator {
+    @Nullable
     private final ContextMenuPopulator mPopulator;
     private final Tab mTab;
 
@@ -36,7 +38,9 @@
 
     @Override
     public void onDestroy() {
-        mPopulator.onDestroy();
+        // |mPopulator| can be null for activities that do not use context menu. Following
+        // methods are not called, but |onDestroy| is.
+        if (mPopulator != null) mPopulator.onDestroy();
     }
 
     @Override
@@ -55,4 +59,4 @@
     public boolean onItemSelected(ContextMenuHelper helper, ContextMenuParams params, int itemId) {
         return mPopulator.onItemSelected(helper, params, itemId);
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java
index 72f5f4a3..6d81f42 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java
@@ -4,26 +4,21 @@
 
 package org.chromium.chrome.browser.tab;
 
-import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
 import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
-import org.chromium.chrome.browser.tab_activity_glue.ActivityTabWebContentsDelegateAndroid;
 import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid;
 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
 
 /**
- * A factory class to create {@link Tab} related delegates.
- * TODO(jinsukkim): Turn this into an interface.
+ * An interface for factory to create {@link Tab} related delegates.
  */
-public class TabDelegateFactory {
+public interface TabDelegateFactory {
     /**
      * Creates the {@link WebContentsDelegateAndroid} the tab will be initialized with.
      * @param tab The associated {@link Tab}.
      * @return The {@link WebContentsDelegateAndroid} to be used for this tab.
      */
-    public TabWebContentsDelegateAndroid createWebContentsDelegate(Tab tab) {
-        return new ActivityTabWebContentsDelegateAndroid(tab, tab.getActivity());
-    }
+    TabWebContentsDelegateAndroid createWebContentsDelegate(Tab tab);
 
     /**
      * Creates the {@link ExternalNavigationHandler} the tab will use for its
@@ -31,38 +26,24 @@
      * @param tab The associated {@link Tab}.
      * @return The {@link ExternalNavigationHandler} to be used for this tab.
      */
-
-    public ExternalNavigationHandler createExternalNavigationHandler(Tab tab) {
-        return new ExternalNavigationHandler(tab);
-    }
+    ExternalNavigationHandler createExternalNavigationHandler(Tab tab);
 
     /**
      * Creates the {@link ContextMenuPopulator} the tab will be initialized with.
      * @param tab The associated {@link Tab}.
      * @return The {@link ContextMenuPopulator} to be used for this tab.
      */
-    public ContextMenuPopulator createContextMenuPopulator(Tab tab) {
-        return new ChromeContextMenuPopulator(new TabContextMenuItemDelegate(tab),
-                ChromeContextMenuPopulator.ContextMenuMode.NORMAL);
-    }
+    ContextMenuPopulator createContextMenuPopulator(Tab tab);
 
     /**
      * Return true if app banners are to be permitted in this tab. May need to be overridden.
      * @return true if app banners are permitted, and false otherwise.
      */
-    public boolean canShowAppBanners() {
-        return true;
-    }
+    boolean canShowAppBanners();
 
     /**
      * Creates the {@link BrowserControlsVisibilityDelegate} the tab will be initialized with.
      * @param tab The associated {@link Tab}.
      */
-    public void createBrowserControlsState(Tab tab) {
-        TabBrowserControlsState.create(tab, new TabStateBrowserControlsVisibilityDelegate(tab));
-    }
-
-    public TabDelegateFactory createNewTabDelegateFactory() {
-        return new TabDelegateFactory();
-    }
+    void createBrowserControlsState(Tab tab);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
index 48eaf0bc..6e3d9fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
@@ -196,6 +196,16 @@
     @CalledByNative
     protected abstract boolean shouldResumeRequestsForCreatedWindow();
 
+    /**
+     * Creates a new tab with the already-created WebContents. The tab for the added
+     * contents should be reparented correctly when this method returns.
+     * @param sourceWebContents Source WebContents from which the new one is created.
+     * @param webContents Newly created WebContents object.
+     * @param disposition WindowOpenDisposition indicating how the tab should be created.
+     * @param initialPosition Initial position of the content to be created.
+     * @param userGesture {@code true} if opened by user gesture.
+     * @return {@code true} if new tab was created successfully with a give WebContents.
+     */
     @CalledByNative
     protected abstract boolean addNewContents(WebContents sourceWebContents,
             WebContents webContents, int disposition, Rect initialPosition, boolean userGesture);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java
index 18d0d0ce..0eb3868 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java
@@ -128,7 +128,7 @@
     }
 
     @Override
-    public boolean addNewContents(WebContents sourceWebContents, WebContents webContents,
+    protected boolean addNewContents(WebContents sourceWebContents, WebContents webContents,
             int disposition, Rect initialPosition, boolean userGesture) {
         assert mWebContentsUrlMapping.containsKey(webContents);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/TabDelegateFactoryImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/TabDelegateFactoryImpl.java
new file mode 100644
index 0000000..4c207de
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/TabDelegateFactoryImpl.java
@@ -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.
+
+package org.chromium.chrome.browser.tab_activity_glue;
+
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
+import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabBrowserControlsState;
+import org.chromium.chrome.browser.tab.TabContextMenuItemDelegate;
+import org.chromium.chrome.browser.tab.TabDelegateFactory;
+import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate;
+import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid;
+
+/**
+ * A default implementation of {@link TabDelegateFactory}.
+ */
+public class TabDelegateFactoryImpl implements TabDelegateFactory {
+    private final ChromeActivity mActivity;
+
+    public TabDelegateFactoryImpl(ChromeActivity activity) {
+        mActivity = activity;
+    }
+
+    @Override
+    public TabWebContentsDelegateAndroid createWebContentsDelegate(Tab tab) {
+        return new ActivityTabWebContentsDelegateAndroid(tab, mActivity);
+    }
+
+    @Override
+    public ExternalNavigationHandler createExternalNavigationHandler(Tab tab) {
+        return new ExternalNavigationHandler(tab);
+    }
+
+    @Override
+    public ContextMenuPopulator createContextMenuPopulator(Tab tab) {
+        return new ChromeContextMenuPopulator(new TabContextMenuItemDelegate(tab),
+                ChromeContextMenuPopulator.ContextMenuMode.NORMAL);
+    }
+
+    @Override
+    public boolean canShowAppBanners() {
+        return true;
+    }
+
+    @Override
+    public void createBrowserControlsState(Tab tab) {
+        TabBrowserControlsState.create(tab, new TabStateBrowserControlsVisibilityDelegate(tab));
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
index 99ec101..2b552d04 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.browser.tab.TabParentIntent;
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tab.TabState;
+import org.chromium.chrome.browser.tab_activity_glue.TabDelegateFactoryImpl;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.components.url_formatter.UrlFormatter;
 import org.chromium.content_public.browser.LoadUrlParams;
@@ -359,8 +360,8 @@
     /**
      * @return The default tab delegate factory to be used if creating new tabs w/o parents.
      */
-    public TabDelegateFactory createDefaultTabDelegateFactory() {
-        return new TabDelegateFactory();
+    protected TabDelegateFactory createDefaultTabDelegateFactory() {
+        return new TabDelegateFactoryImpl(mActivity);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java
index 2f49768d..241cc89 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid;
 import org.chromium.chrome.browser.tab_activity_glue.ActivityTabWebContentsDelegateAndroid;
+import org.chromium.chrome.browser.tab_activity_glue.TabDelegateFactoryImpl;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.webapk.lib.client.WebApkNavigationClient;
 
@@ -27,7 +28,7 @@
  * A {@link TabDelegateFactory} class to be used in all {@link Tab} instances owned by a
  * {@link SingleTabActivity}.
  */
-public class WebappDelegateFactory extends TabDelegateFactory {
+public class WebappDelegateFactory extends TabDelegateFactoryImpl {
     private static class WebappWebContentsDelegateAndroid
             extends ActivityTabWebContentsDelegateAndroid {
         private final WebappActivity mActivity;
@@ -92,6 +93,7 @@
     private final WebappActivity mActivity;
 
     public WebappDelegateFactory(WebappActivity activity) {
+        super(activity);
         mActivity = activity;
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
index ba308bc..328a5fd8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
@@ -20,6 +20,7 @@
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.tab_activity_glue.TabDelegateFactoryImpl;
 import org.chromium.chrome.browser.tabmodel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabSelectionType;
 import org.chromium.chrome.test.ChromeActivityTestRule;
@@ -74,7 +75,8 @@
                                     .setWindow(mActivityTestRule.getActivity().getWindowAndroid())
                                     .setLaunchType(TabLaunchType.FROM_LONGPRESS_BACKGROUND)
                                     .build();
-                bgTab.initialize(null, new TabDelegateFactory(), true, null, false);
+                bgTab.initialize(null, new TabDelegateFactoryImpl(mActivityTestRule.getActivity()),
+                        true, null, false);
                 return bgTab;
             }
         });
@@ -119,7 +121,8 @@
                                     .setWindow(mActivityTestRule.getActivity().getWindowAndroid())
                                     .setLaunchType(TabLaunchType.FROM_LONGPRESS_BACKGROUND)
                                     .build();
-                bgTab.initialize(null, new TabDelegateFactory(), true, null, false);
+                bgTab.initialize(null, new TabDelegateFactoryImpl(mActivityTestRule.getActivity()),
+                        true, null, false);
                 bgTab.loadUrl(new LoadUrlParams(mTestUrl));
                 bgTab.show(TabSelectionType.FROM_USER);
                 return bgTab;
@@ -137,7 +140,8 @@
                                     .setWindow(mActivityTestRule.getActivity().getWindowAndroid())
                                     .setLaunchType(TabLaunchType.FROM_LONGPRESS_BACKGROUND)
                                     .build();
-                bgTab.initialize(null, new TabDelegateFactory(), true, null, false);
+                bgTab.initialize(null, new TabDelegateFactoryImpl(mActivityTestRule.getActivity()),
+                        true, null, false);
                 bgTab.loadUrl(new LoadUrlParams(mTestUrl));
                 // Simulate the renderer being killed by the OS.
                 ChromeTabUtils.simulateRendererKilledForTesting(bgTab, false);
@@ -157,7 +161,8 @@
                                     .setWindow(mActivityTestRule.getActivity().getWindowAndroid())
                                     .setLaunchType(TabLaunchType.FROM_LONGPRESS_BACKGROUND)
                                     .build();
-                bgTab.initialize(null, new TabDelegateFactory(), true, null, false);
+                bgTab.initialize(null, new TabDelegateFactoryImpl(mActivityTestRule.getActivity()),
+                        true, null, false);
                 bgTab.show(TabSelectionType.FROM_USER);
                 return bgTab;
             }
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index 338daf2..83ceb0a2 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -626,7 +626,6 @@
       "//chromeos/services/ime/public/cpp:manifest",
       "//chromeos/services/network_config/public/cpp:manifest",
       "//chromeos/services/secure_channel/public/cpp:manifest",
-      "//services/ws/public/mojom/input_devices",
     ]
   }
 
diff --git a/chrome/app/DEPS b/chrome/app/DEPS
index 13bf73a..291ba12 100644
--- a/chrome/app/DEPS
+++ b/chrome/app/DEPS
@@ -37,7 +37,6 @@
   "+sandbox",
   "+services/preferences/public",
   "+services/service_manager/public",
-  "+services/ws/public",
   "+third_party/breakpad/breakpad",
   "+third_party/crashpad/crashpad",
 ]
@@ -68,7 +67,6 @@
     "+services/identity",
     "+services/image_annotation/public",
     "+services/resource_coordinator/public",
-    "+services/ws/common",
     "+third_party/blink/public/mojom",
   ],
   "chrome_content_gpu_overlay_manifest\.cc": [
diff --git a/chrome/app/builtin_service_manifests.cc b/chrome/app/builtin_service_manifests.cc
index 03f0652..170afd5 100644
--- a/chrome/app/builtin_service_manifests.cc
+++ b/chrome/app/builtin_service_manifests.cc
@@ -30,7 +30,6 @@
 #include "chromeos/services/ime/public/cpp/manifest.h"
 #include "chromeos/services/network_config/public/cpp/manifest.h"
 #include "chromeos/services/secure_channel/public/cpp/manifest.h"
-#include "services/ws/public/mojom/input_devices/input_device_controller.mojom.h"
 #endif
 
 #if defined(OS_MACOSX)
@@ -97,12 +96,6 @@
 #endif
                               spellcheck::mojom::SpellCheckHost,
                               startup_metric_utils::mojom::StartupMetricHost>())
-#if defined(OS_CHROMEOS)
-        // Only used in the classic Ash case.
-        .ExposeCapability("input_device_controller",
-                          service_manager::Manifest::InterfaceList<
-                              ws::mojom::InputDeviceController>())
-#endif
         .RequireCapability(chrome::mojom::kRendererServiceName, "browser")
         .Build()
   };
diff --git a/chrome/app/vector_icons/send_tab_to_self.icon b/chrome/app/vector_icons/send_tab_to_self.icon
index a303c736..1c7966a 100644
--- a/chrome/app/vector_icons/send_tab_to_self.icon
+++ b/chrome/app/vector_icons/send_tab_to_self.icon
@@ -3,40 +3,32 @@
 // found in the LICENSE file.
 
 CANVAS_DIMENSIONS, 16,
-MOVE_TO, 0, 0,
-R_H_LINE_TO, 16,
-R_V_LINE_TO, 16,
+MOVE_TO, 2.5f, 4.21f,
+R_H_LINE_TO, 11.25f,
+V_LINE_TO, 3,
+H_LINE_TO, 2.5f,
+R_CUBIC_TO, -0.69f, 0, -1.25f, 0.54f, -1.25f, 1.21f,
+R_V_LINE_TO, 6.63f,
 H_LINE_TO, 0,
+R_V_LINE_TO, 1.81f,
+R_H_LINE_TO, 8.75f,
+R_V_LINE_TO, -1.81f,
+H_LINE_TO, 2.5f,
+R_V_LINE_TO, -6.63f,
 CLOSE,
-MOVE_TO, 3.4f, 4.41f,
-R_H_LINE_TO, 10.8f,
-V_LINE_TO, 3.25f,
-H_LINE_TO, 3.4f,
-R_CUBIC_TO, -0.66f, 0, -1.2f, 0.52f, -1.2f, 1.16f,
-R_V_LINE_TO, 6.36f,
-H_LINE_TO, 1,
-R_V_LINE_TO, 1.74f,
-R_H_LINE_TO, 8.4f,
-R_V_LINE_TO, -1.74f,
-R_H_LINE_TO, -6,
+R_MOVE_TO, 11.88f, 1.21f,
+R_H_LINE_TO, -3.75f,
+R_ARC_TO, 0.62f, 0.62f, 0, 0, 0, -0.62f, 0.6f,
+R_V_LINE_TO, 6.03f,
+R_CUBIC_TO, 0, 0.33f, 0.28f, 0.6f, 0.63f, 0.6f,
+R_H_LINE_TO, 3.75f,
+ARC_TO, 0.62f, 0.62f, 0, 0, 0, 15, 12.04f,
+V_LINE_TO, 6.01f,
+R_ARC_TO, 0.62f, 0.62f, 0, 0, 0, -0.62f, -0.6f,
 CLOSE,
-R_MOVE_TO, 11.4f, 1.16f,
-R_H_LINE_TO, -3.6f,
-R_CUBIC_TO, -0.33f, 0, -0.6f, 0.26f, -0.6f, 0.58f,
-R_V_LINE_TO, 5.79f,
-R_CUBIC_TO, 0, 0.32f, 0.27f, 0.58f, 0.6f, 0.58f,
-R_H_LINE_TO, 3.6f,
-R_CUBIC_TO, 0.33f, 0, 0.6f, -0.26f, 0.6f, -0.58f,
-V_LINE_TO, 6.14f,
-R_ARC_TO, 0.59f, 0.59f, 0, 0, 0, -0.6f, -0.58f,
-CLOSE,
-R_MOVE_TO, -0.6f, 5.21f,
-R_H_LINE_TO, -2.4f,
-R_V_LINE_TO, -4.05f,
-R_H_LINE_TO, 2.4f,
-CLOSE,
-MOVE_TO, 0, 0,
-R_H_LINE_TO, 16,
-R_V_LINE_TO, 16,
-H_LINE_TO, 0,
+R_MOVE_TO, -0.62f, 5.42f,
+R_H_LINE_TO, -2.5f,
+V_LINE_TO, 6.62f,
+R_H_LINE_TO, 2.5f,
+R_V_LINE_TO, 4.22f,
 CLOSE
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e23e995..acfd23a8 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3521,8 +3521,6 @@
       "//chromeos/strings",
       "//components/services/font:lib",
       "//components/services/font/public/interfaces",
-      "//services/ws/public/cpp/input_devices",
-      "//services/ws/public/cpp/input_devices:input_device_controller",
       "//ui/ozone",
     ]
     allow_circular_includes_from += [ "//chrome/browser/chromeos" ]
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 51703a5..84b5578 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -93,7 +93,6 @@
   "+services/video_capture/public",
   "+services/viz/public",
   "+services/viz/privileged",
-  "+services/ws/public",
   "+skia/ext",
   "+third_party/boringssl/src/include",
   "+third_party/crashpad",
diff --git a/chrome/browser/android/feed/feed_logging_bridge.cc b/chrome/browser/android/feed/feed_logging_bridge.cc
index 2a206f4..b0cda75 100644
--- a/chrome/browser/android/feed/feed_logging_bridge.cc
+++ b/chrome/browser/android/feed/feed_logging_bridge.cc
@@ -171,6 +171,28 @@
   feed_logging_metrics_->OnPietFrameRenderingEvent(std::move(piet_error_codes));
 }
 
+void FeedLoggingBridge::OnVisualElementClicked(
+    JNIEnv* j_env,
+    const base::android::JavaRef<jobject>& j_this,
+    const jint j_element_type,
+    const jint j_position,
+    const jlong j_timeContentBecameAvailableMs) {
+  feed_logging_metrics_->OnVisualElementClicked(
+      j_element_type, j_position,
+      base::Time::FromJavaTime(j_timeContentBecameAvailableMs));
+}
+
+void FeedLoggingBridge::OnVisualElementViewed(
+    JNIEnv* j_env,
+    const base::android::JavaRef<jobject>& j_this,
+    const jint j_element_type,
+    const jint j_position,
+    const jlong j_timeContentBecameAvailableMs) {
+  feed_logging_metrics_->OnVisualElementViewed(
+      j_element_type, j_position,
+      base::Time::FromJavaTime(j_timeContentBecameAvailableMs));
+}
+
 void FeedLoggingBridge::OnInternalError(JNIEnv* j_env,
                                         const JavaRef<jobject>& j_this,
                                         const jint j_internal_error) {
diff --git a/chrome/browser/android/feed/feed_logging_bridge.h b/chrome/browser/android/feed/feed_logging_bridge.h
index cbf8a1bb..abe7bd93 100644
--- a/chrome/browser/android/feed/feed_logging_bridge.h
+++ b/chrome/browser/android/feed/feed_logging_bridge.h
@@ -102,6 +102,18 @@
       const base::android::JavaRef<jobject>& j_this,
       const base::android::JavaRef<jintArray>& j_piet_error_codes);
 
+  void OnVisualElementClicked(JNIEnv* j_env,
+                              const base::android::JavaRef<jobject>& j_this,
+                              const jint j_element_type,
+                              const jint j_position,
+                              const jlong j_timeContentBecameAvailableMs);
+
+  void OnVisualElementViewed(JNIEnv* j_env,
+                             const base::android::JavaRef<jobject>& j_this,
+                             const jint j_element_type,
+                             const jint j_position,
+                             const jlong j_timeContentBecameAvailableMs);
+
   void OnInternalError(JNIEnv* j_env,
                        const base::android::JavaRef<jobject>& j_this,
                        const jint j_internal_error);
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index 0d2301a..9fa0c4b 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -210,6 +210,20 @@
   observer_list_.RemoveObserver(observer);
 }
 
+void AppBannerManager::MigrateObserverListForTesting(
+    content::WebContents* web_contents) {
+  AppBannerManager* existing_manager = FromWebContents(web_contents);
+  for (Observer& observer : existing_manager->observer_list_)
+    observer.ObserveAppBannerManager(this);
+  DCHECK(existing_manager->observer_list_.begin() ==
+         existing_manager->observer_list_.end())
+      << "Old observer list must be empty after transfer to test instance.";
+}
+
+bool AppBannerManager::IsPromptAvailableForTesting() const {
+  return binding_.is_bound();
+}
+
 AppBannerManager::AppBannerManager(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
       SiteEngagementObserver(SiteEngagementService::Get(
@@ -489,16 +503,6 @@
     observer.OnInstallableWebAppStatusUpdated();
 }
 
-void AppBannerManager::MigrateObserverListForTesting(
-    content::WebContents* web_contents) {
-  AppBannerManager* existing_manager = FromWebContents(web_contents);
-  for (Observer& observer : existing_manager->observer_list_)
-    observer.ObserveAppBannerManager(this);
-  DCHECK(existing_manager->observer_list_.begin() ==
-         existing_manager->observer_list_.end())
-      << "Old observer list must be empty after transfer to test instance.";
-}
-
 void AppBannerManager::Stop(InstallableStatusCode code) {
   ReportStatus(code);
 
diff --git a/chrome/browser/banners/app_banner_manager.h b/chrome/browser/banners/app_banner_manager.h
index 38304c03..67a9638 100644
--- a/chrome/browser/banners/app_banner_manager.h
+++ b/chrome/browser/banners/app_banner_manager.h
@@ -152,7 +152,8 @@
   // performs logging related to the app installation. Appinstalled event is
   // redundant for the beforeinstallprompt event's promise being resolved, but
   // is required by the install event spec.
-  void OnInstall(bool is_native, blink::WebDisplayMode display);
+  // This is virtual for testing.
+  virtual void OnInstall(bool is_native, blink::WebDisplayMode display);
 
   // Sends a message to the renderer that the user accepted the banner.
   void SendBannerAccepted();
@@ -163,6 +164,17 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
+  virtual base::WeakPtr<AppBannerManager> GetWeakPtr() = 0;
+
+  // Used by test subclasses that replace the existing AppBannerManager
+  // instance. The observer list must be transferred over to avoid dangling
+  // pointers in the observers.
+  void MigrateObserverListForTesting(content::WebContents* web_contents);
+
+  // Returns whether the site can call "event.prompt()" to prompt the user to
+  // install the site.
+  bool IsPromptAvailableForTesting() const;
+
  protected:
   explicit AppBannerManager(content::WebContents* web_contents);
   ~AppBannerManager() override;
@@ -189,7 +201,6 @@
   // alerting websites that a banner is about to be created.
   virtual std::string GetBannerType();
 
-  virtual base::WeakPtr<AppBannerManager> GetWeakPtr() = 0;
   virtual void InvalidateWeakPtrs() = 0;
 
   // Returns true if |has_sufficient_engagement_| is true or
@@ -296,11 +307,6 @@
   State state() const { return state_; }
   bool IsRunning() const;
 
-  // Used by test subclasses that replace the existing AppBannerManager
-  // instance. The observer list must be transferred over to avoid dangling
-  // pointers in the observers.
-  void MigrateObserverListForTesting(content::WebContents* web_contents);
-
   // The URL for which the banner check is being conducted.
   GURL validated_url_;
 
diff --git a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
index 68c1804..9c4f757 100644
--- a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
+++ b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
@@ -12,15 +12,20 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/banners/app_banner_manager_browsertest_base.h"
 #include "chrome/browser/banners/app_banner_manager_desktop.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/page_action/page_action_icon_container.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
@@ -37,11 +42,14 @@
 
   static FakeAppBannerManagerDesktop* CreateForWebContents(
       content::WebContents* web_contents) {
-    web_contents->SetUserData(
-        UserDataKey(),
-        std::make_unique<FakeAppBannerManagerDesktop>(web_contents));
-    return static_cast<FakeAppBannerManagerDesktop*>(
-        web_contents->GetUserData(UserDataKey()));
+    auto banner_manager =
+        std::make_unique<FakeAppBannerManagerDesktop>(web_contents);
+    banner_manager->MigrateObserverListForTesting(web_contents);
+
+    FakeAppBannerManagerDesktop* result = banner_manager.get();
+    web_contents->SetUserData(FakeAppBannerManagerDesktop::UserDataKey(),
+                              std::move(banner_manager));
+    return result;
   }
 
   // Configures a callback to be invoked when the app banner flow finishes.
@@ -49,7 +57,19 @@
 
   State state() { return AppBannerManager::state(); }
 
+  void AwaitAppInstall() {
+    base::RunLoop loop;
+    on_install_ = loop.QuitClosure();
+    loop.Run();
+  }
+
  protected:
+  void OnInstall(bool is_native, blink::WebDisplayMode display) override {
+    AppBannerManager::OnInstall(is_native, display);
+    if (on_install_)
+      std::move(on_install_).Run();
+  }
+
   void OnFinished() {
     if (on_done_) {
       base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
@@ -74,6 +94,7 @@
 
  private:
   base::OnceClosure on_done_;
+  base::OnceClosure on_install_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeAppBannerManagerDesktop);
 };
@@ -224,3 +245,65 @@
     EXPECT_TRUE(callback_called);
   }
 }
+
+IN_PROC_BROWSER_TEST_F(AppBannerManagerDesktopBrowserTest,
+                       InstallPromptAfterUserMenuInstall) {
+  // TODO(https://crbug.com/915043): Fix this test for the unified install
+  // codepath. This fails under unified install because the menu install path
+  // relies on extensions::TabHelper to call AppBannerManager::OnInstall which
+  // is no longer the case under unified install. This will be fixed in a follow
+  // up patch when AppBannerManager calls OnInstall by itself via
+  // AppRegistrarObserver::OnWebAppInstalled().
+  if (base::FeatureList::IsEnabled(features::kDesktopPWAsUnifiedInstall))
+    return;
+
+  FakeAppBannerManagerDesktop* manager =
+      FakeAppBannerManagerDesktop::CreateForWebContents(
+          browser()->tab_strip_model()->GetActiveWebContents());
+
+  {
+    base::RunLoop run_loop;
+    manager->PrepareDone(run_loop.QuitClosure());
+
+    ui_test_utils::NavigateToURL(browser(),
+                                 GetBannerURLWithAction("stash_event"));
+    run_loop.Run();
+    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+  }
+
+  // Install the app via the menu instead of the banner.
+  chrome::SetAutoAcceptPWAInstallConfirmationForTesting(true);
+  browser()->command_controller()->ExecuteCommand(IDC_INSTALL_PWA);
+  manager->AwaitAppInstall();
+  chrome::SetAutoAcceptPWAInstallConfirmationForTesting(false);
+
+  EXPECT_FALSE(manager->IsPromptAvailableForTesting());
+}
+
+IN_PROC_BROWSER_TEST_F(AppBannerManagerDesktopBrowserTest,
+                       InstallPromptAfterUserOmniboxInstall) {
+  FakeAppBannerManagerDesktop* manager =
+      FakeAppBannerManagerDesktop::CreateForWebContents(
+          browser()->tab_strip_model()->GetActiveWebContents());
+
+  {
+    base::RunLoop run_loop;
+    manager->PrepareDone(run_loop.QuitClosure());
+
+    ui_test_utils::NavigateToURL(browser(),
+                                 GetBannerURLWithAction("stash_event"));
+    run_loop.Run();
+    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+  }
+
+  // Install the app via the menu instead of the banner.
+  chrome::SetAutoAcceptPWAInstallConfirmationForTesting(true);
+  browser()
+      ->window()
+      ->GetOmniboxPageActionIconContainer()
+      ->ExecutePageActionIconForTesting(PageActionIconType::kPwaInstall);
+  manager->AwaitAppInstall();
+  chrome::SetAutoAcceptPWAInstallConfirmationForTesting(false);
+
+  EXPECT_FALSE(manager->IsPromptAvailableForTesting());
+}
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc
index 9c32d6d..c78ed1b 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.cc
+++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -43,8 +43,6 @@
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "services/service_manager/public/cpp/service.h"
-#include "services/ws/public/cpp/input_devices/input_device_controller.h"
-#include "services/ws/public/cpp/input_devices/input_device_controller_client.h"
 
 BrowserProcessPlatformPart::BrowserProcessPlatformPart()
     : created_profile_helper_(false),
@@ -215,17 +213,6 @@
   system_clock_.reset();
 }
 
-ws::InputDeviceControllerClient*
-BrowserProcessPlatformPart::GetInputDeviceControllerClient() {
-  if (!input_device_controller_client_) {
-    input_device_controller_client_ =
-        std::make_unique<ws::InputDeviceControllerClient>(
-            content::ServiceManagerConnection::GetForProcess()->GetConnector(),
-            chromeos::kChromeServiceName);
-  }
-  return input_device_controller_client_.get();
-}
-
 void BrowserProcessPlatformPart::CreateProfileHelper() {
   DCHECK(!created_profile_helper_ && !profile_helper_);
   created_profile_helper_ = true;
diff --git a/chrome/browser/browser_process_platform_part_chromeos.h b/chrome/browser/browser_process_platform_part_chromeos.h
index 5ca39f9..67a4d39 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.h
+++ b/chrome/browser/browser_process_platform_part_chromeos.h
@@ -41,10 +41,6 @@
 class BrowserPolicyConnectorChromeOS;
 }
 
-namespace ws {
-class InputDeviceControllerClient;
-}
-
 class ScopedKeepAlive;
 
 class BrowserProcessPlatformPart : public BrowserProcessPlatformPartBase {
@@ -124,8 +120,6 @@
   chromeos::system::SystemClock* GetSystemClock();
   void DestroySystemClock();
 
-  ws::InputDeviceControllerClient* GetInputDeviceControllerClient();
-
   chromeos::AccountManagerFactory* GetAccountManagerFactory();
 
  private:
@@ -167,11 +161,6 @@
   std::unique_ptr<chromeos::KerberosCredentialsManager>
       kerberos_credentials_manager_;
 
-#if defined(USE_OZONE)
-  std::unique_ptr<ws::InputDeviceControllerClient>
-      input_device_controller_client_;
-#endif
-
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(BrowserProcessPlatformPart);
diff --git a/chrome/browser/chrome_service.cc b/chrome/browser/chrome_service.cc
index dec6c1e..a1719f0 100644
--- a/chrome/browser/chrome_service.cc
+++ b/chrome/browser/chrome_service.cc
@@ -22,9 +22,6 @@
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_binding.h"
 
-#if defined(OS_CHROMEOS)
-#include "services/ws/public/cpp/input_devices/input_device_controller.h"
-#endif
 #if BUILDFLAG(ENABLE_SPELLCHECK)
 #include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h"
 #if BUILDFLAG(HAS_SPELLCHECK_PANEL)
@@ -39,9 +36,6 @@
         base::CreateSingleThreadTaskRunnerWithTraits(
             {content::BrowserThread::UI});
 
-#if defined(OS_CHROMEOS)
-    input_device_controller_.AddInterface(&registry_, ui_task_runner);
-#endif
     registry_.AddInterface(base::BindRepeating(
         &startup_metric_utils::StartupMetricHostImpl::Create));
 #if BUILDFLAG(ENABLE_SPELLCHECK)
@@ -109,10 +103,6 @@
       const service_manager::BindSourceInfo&>
       registry_with_source_info_;
 
-#if defined(OS_CHROMEOS)
-  ws::InputDeviceController input_device_controller_;
-#endif
-
   DISALLOW_COPY_AND_ASSIGN(IOThreadContext);
 };
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 901d057..701de951 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -239,7 +239,6 @@
     "//services/preferences/public/mojom",
     "//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
     "//services/service_manager/public/cpp",
-    "//services/ws/public/cpp/input_devices",
     "//skia",
     "//storage/browser",
     "//storage/common",
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS
index 64789cf..d388eba 100644
--- a/chrome/browser/chromeos/DEPS
+++ b/chrome/browser/chromeos/DEPS
@@ -19,10 +19,6 @@
   "+services/network",
   "+services/tracing/public",
   "+services/viz/public/interfaces",
-  # Chromeos should not use ozone directly, it must go through mojo as ozone
-  # does not run in process in mus.
-  "-ui/ozone/public",
-  "+ui/ozone/public/ozone_switches.h",
 
   # keyboard::KeyboardController only exists in ash and should not be accessed
   # directly from src/chrome. Use ChromeKeyboardControllerClient instead.
diff --git a/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc b/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
index 372c4382..2e20692 100644
--- a/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
+++ b/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
@@ -33,7 +33,6 @@
 #include "net/cert/x509_certificate.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
-#include "services/network/cert_verifier_with_trust_anchors.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -108,41 +107,12 @@
     },
 };
 
-// Weak ptr to network::CertVerifierWithTrustAnchors - object is freed in test
-// destructor once we've ensured the profile has been shut down.
-network::CertVerifierWithTrustAnchors* g_policy_cert_verifier_for_factory =
-    NULL;
-
 std::unique_ptr<KeyedService> TestPolicyCertServiceFactory(
     content::BrowserContext* context) {
   return policy::PolicyCertService::CreateForTesting(
-      kUsers[0], g_policy_cert_verifier_for_factory,
-      user_manager::UserManager::Get());
+      kUsers[0], user_manager::UserManager::Get());
 }
 
-class MockCertVerifyProc : public net::CertVerifyProc {
- public:
-  MockCertVerifyProc() = default;
-
-  // net::CertVerifyProc implementation
-  bool SupportsAdditionalTrustAnchors() const override { return true; }
-
- protected:
-  ~MockCertVerifyProc() override = default;
-
- private:
-  int VerifyInternal(net::X509Certificate* cert,
-                     const std::string& hostname,
-                     const std::string& ocsp_response,
-                     const std::string& sct_list,
-                     int flags,
-                     net::CRLSet* crl_set,
-                     const net::CertificateList& additional_trust_anchors,
-                     net::CertVerifyResult* result) override {
-    return net::ERR_FAILED;
-  }
-};
-
 }  // namespace
 
 class MultiProfileUserControllerTest
@@ -184,9 +154,6 @@
   }
 
   void TearDown() override {
-    // Clear our cached pointer to the network::CertVerifierWithTrustAnchors.
-    g_policy_cert_verifier_for_factory = NULL;
-
     // We must ensure that the network::CertVerifierWithTrustAnchors outlives
     // the PolicyCertService so shutdown the profile here. Additionally, we need
     // to run the message loop between freeing the PolicyCertService and
@@ -239,7 +206,6 @@
   TestingProfile* profile(int index) { return user_profiles_[index]; }
 
   content::TestBrowserThreadBundle threads_;
-  std::unique_ptr<network::CertVerifierWithTrustAnchors> cert_verifier_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
   FakeChromeUserManager* fake_user_manager_;  // Not owned
   user_manager::ScopedUserManager user_manager_enabler_;
@@ -412,11 +378,6 @@
       test_users_[0].GetUserEmail());
   LoginUser(0);
 
-  cert_verifier_.reset(
-      new network::CertVerifierWithTrustAnchors(base::Closure()));
-  cert_verifier_->InitializeOnIOThread(
-      base::MakeRefCounted<MockCertVerifyProc>());
-  g_policy_cert_verifier_for_factory = cert_verifier_.get();
   ASSERT_TRUE(
       policy::PolicyCertServiceFactory::GetInstance()->SetTestingFactoryAndUse(
           profile(0), base::BindRepeating(&TestPolicyCertServiceFactory)));
@@ -451,11 +412,6 @@
   // changed back to enabled.
   SetPrefBehavior(0, MultiProfileUserController::kBehaviorUnrestricted);
 
-  cert_verifier_.reset(
-      new network::CertVerifierWithTrustAnchors(base::Closure()));
-  cert_verifier_->InitializeOnIOThread(
-      base::MakeRefCounted<MockCertVerifyProc>());
-  g_policy_cert_verifier_for_factory = cert_verifier_.get();
   ASSERT_TRUE(
       policy::PolicyCertServiceFactory::GetInstance()->SetTestingFactoryAndUse(
           profile(0), base::BindRepeating(&TestPolicyCertServiceFactory)));
diff --git a/chrome/browser/chromeos/policy/policy_cert_service.cc b/chrome/browser/chromeos/policy/policy_cert_service.cc
index 08a1669..5330c81 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service.cc
+++ b/chrome/browser/chromeos/policy/policy_cert_service.cc
@@ -17,18 +17,11 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/cert/x509_certificate.h"
-#include "services/network/cert_verifier_with_trust_anchors.h"
 #include "services/network/nss_temp_certs_cache_chromeos.h"
-#include "services/network/public/cpp/features.h"
 
 namespace policy {
 
-PolicyCertService::~PolicyCertService() {
-  if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
-    DCHECK(cert_verifier_)
-        << "CreatePolicyCertVerifier() must be called after construction.";
-  }
-}
+PolicyCertService::~PolicyCertService() {}
 
 PolicyCertService::PolicyCertService(
     Profile* profile,
@@ -36,7 +29,6 @@
     UserNetworkConfigurationUpdater* net_conf_updater,
     user_manager::UserManager* user_manager)
     : profile_(profile),
-      cert_verifier_(NULL),
       user_id_(user_id),
       net_conf_updater_(net_conf_updater),
       user_manager_(user_manager),
@@ -45,35 +37,14 @@
   DCHECK(user_manager_);
 }
 
-PolicyCertService::PolicyCertService(
-    const std::string& user_id,
-    network::CertVerifierWithTrustAnchors* verifier,
-    user_manager::UserManager* user_manager)
-    : cert_verifier_(verifier),
-      user_id_(user_id),
+PolicyCertService::PolicyCertService(const std::string& user_id,
+                                     user_manager::UserManager* user_manager)
+    : user_id_(user_id),
       net_conf_updater_(NULL),
       user_manager_(user_manager),
       weak_ptr_factory_(this) {}
 
-std::unique_ptr<network::CertVerifierWithTrustAnchors>
-PolicyCertService::CreatePolicyCertVerifier() {
-  DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
-  base::Closure callback = base::Bind(
-      &PolicyCertServiceFactory::SetUsedPolicyCertificates, user_id_);
-  constexpr base::TaskTraits traits = {content::BrowserThread::UI};
-  auto cert_verifier = std::make_unique<network::CertVerifierWithTrustAnchors>(
-      base::Bind(base::IgnoreResult(&base::PostTaskWithTraits), FROM_HERE,
-                 traits, callback));
-  cert_verifier_ = cert_verifier.get();
-  // Certs are forwarded to |cert_verifier_|, thus register here after
-  // |cert_verifier_| is created.
-  StartObservingPolicyCertsInternal(true /* notify */);
-
-  return cert_verifier;
-}
-
 void PolicyCertService::StartObservingPolicyCerts() {
-  DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
   // Don't notify the network service since it will get the initial list of
   // trust anchors in NetworkContextParams::initial_trust_anchors.
   StartObservingPolicyCertsInternal(false /* notify */);
@@ -129,24 +100,12 @@
   if (!notify)
     return;
 
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
-    ProfileNetworkContextServiceFactory::GetForContext(profile_)
-        ->UpdateAdditionalCertificates(all_server_and_authority_certs_,
-                                       trust_anchors_);
-    return;
+  auto* profile_network_context =
+      ProfileNetworkContextServiceFactory::GetForContext(profile_);
+  if (profile_network_context) {  // null in unit tests.
+    profile_network_context->UpdateAdditionalCertificates(
+        all_server_and_authority_certs_, trust_anchors_);
   }
-
-  DCHECK(cert_verifier_);
-
-  // It's safe to use base::Unretained here, because it's guaranteed that
-  // |cert_verifier_| outlives this object (see description of
-  // CreatePolicyCertVerifier).
-  // Note: ProfileIOData, which owns the CertVerifier is deleted by a
-  // DeleteSoon on IO, i.e. after all pending tasks on IO are finished.
-  base::PostTaskWithTraits(
-      FROM_HERE, {content::BrowserThread::IO},
-      base::BindOnce(&network::CertVerifierWithTrustAnchors::SetTrustAnchors,
-                     base::Unretained(cert_verifier_), trust_anchors_));
 }
 
 bool PolicyCertService::UsedPolicyCertificates() const {
@@ -166,10 +125,8 @@
 // static
 std::unique_ptr<PolicyCertService> PolicyCertService::CreateForTesting(
     const std::string& user_id,
-    network::CertVerifierWithTrustAnchors* verifier,
     user_manager::UserManager* user_manager) {
-  return base::WrapUnique(
-      new PolicyCertService(user_id, verifier, user_manager));
+  return base::WrapUnique(new PolicyCertService(user_id, user_manager));
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/policy_cert_service.h b/chrome/browser/chromeos/policy/policy_cert_service.h
index 28e5eaa..14a20a0 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service.h
+++ b/chrome/browser/chromeos/policy/policy_cert_service.h
@@ -29,7 +29,6 @@
 }
 
 namespace network {
-class CertVerifierWithTrustAnchors;
 class NSSTempCertsCacheChromeOS;
 }
 
@@ -49,12 +48,6 @@
                     user_manager::UserManager* user_manager);
   ~PolicyCertService() override;
 
-  // Creates an associated PolicyCertVerifier. The returned object must only be
-  // used on the IO thread and must outlive this object.
-  // This can only be called if the network service is disabled.
-  std::unique_ptr<network::CertVerifierWithTrustAnchors>
-  CreatePolicyCertVerifier();
-
   // Start listening for trust anchor changes to push to the network service.
   // This only needs to be called with the network service.
   void StartObservingPolicyCerts();
@@ -81,12 +74,10 @@
 
   static std::unique_ptr<PolicyCertService> CreateForTesting(
       const std::string& user_id,
-      network::CertVerifierWithTrustAnchors* verifier,
       user_manager::UserManager* user_manager);
 
  private:
   PolicyCertService(const std::string& user_id,
-                    network::CertVerifierWithTrustAnchors* verifier,
                     user_manager::UserManager* user_manager);
 
   void StartObservingPolicyCertsInternal(bool notify);
@@ -96,7 +87,6 @@
       bool notify);
 
   Profile* profile_ = nullptr;
-  network::CertVerifierWithTrustAnchors* cert_verifier_;
   std::string user_id_;
   UserNetworkConfigurationUpdater* net_conf_updater_;
   user_manager::UserManager* user_manager_;
diff --git a/chrome/browser/chromeos/policy/policy_cert_service_factory.cc b/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
index 9c9c7fcf..b5ccb9c 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
+++ b/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
@@ -17,7 +17,6 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/user_manager/user_manager.h"
 #include "services/network/cert_verifier_with_trust_anchors.h"
-#include "services/network/public/cpp/features.h"
 
 namespace policy {
 
@@ -28,21 +27,8 @@
 }
 
 // static
-std::unique_ptr<network::CertVerifierWithTrustAnchors>
-PolicyCertServiceFactory::CreateForProfile(Profile* profile) {
-  DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
-  DCHECK(!GetInstance()->GetServiceForBrowserContext(profile, false));
-  PolicyCertService* service = static_cast<PolicyCertService*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-  if (!service)
-    return nullptr;
-  return service->CreatePolicyCertVerifier();
-}
-
-// static
 bool PolicyCertServiceFactory::CreateAndStartObservingForProfile(
     Profile* profile) {
-  DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
   // This can be called multiple times if the network process crashes.
   if (GetInstance()->GetServiceForBrowserContext(profile, false))
     return true;
diff --git a/chrome/browser/chromeos/policy/policy_cert_service_factory.h b/chrome/browser/chromeos/policy/policy_cert_service_factory.h
index 1e170ba..2138cef21 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service_factory.h
+++ b/chrome/browser/chromeos/policy/policy_cert_service_factory.h
@@ -20,10 +20,6 @@
 class PrefRegistrySimple;
 class Profile;
 
-namespace network {
-class CertVerifierWithTrustAnchors;
-}
-
 namespace policy {
 
 class PolicyCertService;
@@ -35,17 +31,6 @@
   // CreateForProfile.
   static PolicyCertService* GetForProfile(Profile* profile);
 
-  // Creates a new PolicyCertService and returns the associated
-  // PolicyCertVerifier. Returns nullptr if this service isn't allowed for
-  // |profile|, i.e. if NetworkConfigurationUpdater doesn't exist.
-  // This service is created separately for the original profile and the
-  // incognito profile.
-  // Note: NetworkConfigurationUpdater is currently only created for the primary
-  // user's profile.
-  // This should  only be called if the network service is disabled.
-  static std::unique_ptr<network::CertVerifierWithTrustAnchors>
-  CreateForProfile(Profile* profile);
-
   // Creates (if it's not already created) a PolicyCertService and gets it to
   // start listening for trust anchors for the profile. Returns false if this
   // service isn't allowed for |profile|, i.e. if NetworkConfigurationUpdater
diff --git a/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc b/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc
index eca3f756..0a64967 100644
--- a/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc
+++ b/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc
@@ -11,7 +11,8 @@
 #include "chrome/browser/chromeos/system/fake_input_device_settings.h"
 #include "chromeos/system/devicemode.h"
 #include "content/public/browser/browser_thread.h"
-#include "services/ws/public/cpp/input_devices/input_device_controller_client.h"
+#include "ui/ozone/public/input_controller.h"
+#include "ui/ozone/public/ozone_platform.h"
 
 namespace chromeos {
 namespace system {
@@ -19,9 +20,6 @@
 
 InputDeviceSettings* g_input_device_settings_impl_ozone_instance = nullptr;
 
-// Callback from SetInternalTouchpadEnabled().
-void OnSetInternalTouchpadEnabled(bool result) {}
-
 // InputDeviceSettings for Ozone.
 class InputDeviceSettingsImplOzone : public InputDeviceSettings {
  public:
@@ -50,8 +48,9 @@
   void SetInternalTouchpadEnabled(bool enabled) override;
   void SetTouchscreensEnabled(bool enabled) override;
 
-  // Cached InputDeviceControllerClient. It is owned by BrowserProcess.
-  ws::InputDeviceControllerClient* input_device_controller_client_;
+  ui::InputController* input_controller() {
+    return ui::OzonePlatform::GetInstance()->GetInputController();
+  }
 
   // Respective device setting objects.
   TouchpadSettings current_touchpad_settings_;
@@ -60,17 +59,12 @@
   DISALLOW_COPY_AND_ASSIGN(InputDeviceSettingsImplOzone);
 };
 
-InputDeviceSettingsImplOzone::InputDeviceSettingsImplOzone()
-    : input_device_controller_client_(g_browser_process->platform_part()
-                                          ->GetInputDeviceControllerClient()) {
-  // Make sure the input controller does exist.
-  DCHECK(input_device_controller_client_);
-}
+InputDeviceSettingsImplOzone::InputDeviceSettingsImplOzone() = default;
 
 void InputDeviceSettingsImplOzone::TouchpadExists(
     DeviceExistsCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  input_device_controller_client_->GetHasTouchpad(std::move(callback));
+  std::move(callback).Run(input_controller()->HasTouchpad());
 }
 
 void InputDeviceSettingsImplOzone::UpdateTouchpadSettings(
@@ -82,33 +76,33 @@
 void InputDeviceSettingsImplOzone::SetTouchpadSensitivity(int value) {
   DCHECK(value >= kMinPointerSensitivity && value <= kMaxPointerSensitivity);
   current_touchpad_settings_.SetSensitivity(value);
-  input_device_controller_client_->SetTouchpadSensitivity(value);
+  input_controller()->SetTouchpadSensitivity(value);
 }
 
 void InputDeviceSettingsImplOzone::SetNaturalScroll(bool enabled) {
   current_touchpad_settings_.SetNaturalScroll(enabled);
-  input_device_controller_client_->SetNaturalScroll(enabled);
+  input_controller()->SetNaturalScroll(enabled);
 }
 
 void InputDeviceSettingsImplOzone::SetTapToClick(bool enabled) {
   current_touchpad_settings_.SetTapToClick(enabled);
-  input_device_controller_client_->SetTapToClick(enabled);
+  input_controller()->SetTapToClick(enabled);
 }
 
 void InputDeviceSettingsImplOzone::SetThreeFingerClick(bool enabled) {
   // For Alex/ZGB.
   current_touchpad_settings_.SetThreeFingerClick(enabled);
-  input_device_controller_client_->SetThreeFingerClick(enabled);
+  input_controller()->SetThreeFingerClick(enabled);
 }
 
 void InputDeviceSettingsImplOzone::SetTapDragging(bool enabled) {
   current_touchpad_settings_.SetTapDragging(enabled);
-  input_device_controller_client_->SetTapDragging(enabled);
+  input_controller()->SetTapDragging(enabled);
 }
 
 void InputDeviceSettingsImplOzone::MouseExists(DeviceExistsCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  input_device_controller_client_->GetHasMouse(std::move(callback));
+  std::move(callback).Run(input_controller()->HasMouse());
 }
 
 void InputDeviceSettingsImplOzone::UpdateMouseSettings(
@@ -120,17 +114,17 @@
 void InputDeviceSettingsImplOzone::SetMouseSensitivity(int value) {
   DCHECK(value >= kMinPointerSensitivity && value <= kMaxPointerSensitivity);
   current_mouse_settings_.SetSensitivity(value);
-  input_device_controller_client_->SetMouseSensitivity(value);
+  input_controller()->SetMouseSensitivity(value);
 }
 
 void InputDeviceSettingsImplOzone::SetPrimaryButtonRight(bool right) {
   current_mouse_settings_.SetPrimaryButtonRight(right);
-  input_device_controller_client_->SetPrimaryButtonRight(right);
+  input_controller()->SetPrimaryButtonRight(right);
 }
 
 void InputDeviceSettingsImplOzone::SetMouseReverseScroll(bool enabled) {
   current_mouse_settings_.SetReverseScroll(enabled);
-  input_device_controller_client_->SetMouseReverseScroll(enabled);
+  input_controller()->SetMouseReverseScroll(enabled);
 }
 
 void InputDeviceSettingsImplOzone::ReapplyTouchpadSettings() {
@@ -147,12 +141,11 @@
 }
 
 void InputDeviceSettingsImplOzone::SetInternalTouchpadEnabled(bool enabled) {
-  input_device_controller_client_->SetInternalTouchpadEnabled(
-      enabled, base::BindOnce(&OnSetInternalTouchpadEnabled));
+  input_controller()->SetInternalTouchpadEnabled(enabled);
 }
 
 void InputDeviceSettingsImplOzone::SetTouchscreensEnabled(bool enabled) {
-  input_device_controller_client_->SetTouchscreensEnabled(enabled);
+  input_controller()->SetTouchscreensEnabled(enabled);
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/system_logs/touch_log_source.cc b/chrome/browser/chromeos/system_logs/touch_log_source.cc
index c89cfd5af..f951e49 100644
--- a/chrome/browser/chromeos/system_logs/touch_log_source.cc
+++ b/chrome/browser/chromeos/system_logs/touch_log_source.cc
@@ -17,11 +17,10 @@
 #include "base/logging.h"
 #include "base/process/launch.h"
 #include "base/task/post_task.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "content/public/browser/browser_thread.h"
-#include "services/ws/public/cpp/input_devices/input_device_controller_client.h"
 #include "ui/base/ui_base_features.h"
+#include "ui/ozone/public/input_controller.h"
+#include "ui/ozone/public/ozone_platform.h"
 
 using content::BrowserThread;
 
@@ -160,9 +159,9 @@
 
   // Collect touch event logs.
   const base::FilePath kBaseLogPath(kTouchEventLogDir);
-  ws::InputDeviceControllerClient* input_device_controller_client =
-      g_browser_process->platform_part()->GetInputDeviceControllerClient();
-  input_device_controller_client->GetTouchEventLog(
+  ui::InputController* input_controller =
+      ui::OzonePlatform::GetInstance()->GetInputController();
+  input_controller->GetTouchEventLog(
       kBaseLogPath, base::BindOnce(&OnEventLogCollected, std::move(response),
                                    std::move(callback)));
 }
@@ -197,9 +196,9 @@
   CollectTouchHudDebugLog(response.get());
 
   // Collect touch device status logs.
-  ws::InputDeviceControllerClient* input_device_controller_client =
-      g_browser_process->platform_part()->GetInputDeviceControllerClient();
-  input_device_controller_client->GetTouchDeviceStatus(base::BindOnce(
+  ui::InputController* input_controller =
+      ui::OzonePlatform::GetInstance()->GetInputController();
+  input_controller->GetTouchDeviceStatus(base::BindOnce(
       &OnStatusLogCollected, std::move(response), std::move(callback)));
 }
 
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc
index 801be3a..8c0aff6 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry.cc
@@ -129,71 +129,6 @@
   enabled_ = false;
 }
 
-// JobInterceptorFactory -------------------------------------------------------
-
-// Instances of JobInterceptorFactory are produced for ownership by the IO
-// thread where it handler URL requests. We should never hold
-// any pointers on this class, only produce them in response to
-// requests via |ProtocolHandlerRegistry::CreateJobInterceptorFactory|.
-ProtocolHandlerRegistry::JobInterceptorFactory::JobInterceptorFactory(
-    IOThreadDelegate* io_thread_delegate)
-    : io_thread_delegate_(io_thread_delegate) {
-  DCHECK(io_thread_delegate_.get());
-  DETACH_FROM_THREAD(thread_checker_);
-}
-
-ProtocolHandlerRegistry::JobInterceptorFactory::~JobInterceptorFactory() {
-}
-
-void ProtocolHandlerRegistry::JobInterceptorFactory::Chain(
-    std::unique_ptr<net::URLRequestJobFactory> job_factory) {
-  job_factory_ = std::move(job_factory);
-}
-
-net::URLRequestJob*
-ProtocolHandlerRegistry::JobInterceptorFactory::
-MaybeCreateJobWithProtocolHandler(
-    const std::string& scheme,
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate) const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  net::URLRequestJob* job = io_thread_delegate_->MaybeCreateJob(
-      request, network_delegate);
-  if (job)
-    return job;
-  return job_factory_->MaybeCreateJobWithProtocolHandler(
-      scheme, request, network_delegate);
-}
-
-net::URLRequestJob*
-ProtocolHandlerRegistry::JobInterceptorFactory::MaybeInterceptRedirect(
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate,
-    const GURL& location) const {
-  return job_factory_->MaybeInterceptRedirect(
-      request, network_delegate, location);
-}
-
-net::URLRequestJob*
-ProtocolHandlerRegistry::JobInterceptorFactory::MaybeInterceptResponse(
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate) const {
-  return job_factory_->MaybeInterceptResponse(request, network_delegate);
-}
-
-bool ProtocolHandlerRegistry::JobInterceptorFactory::IsHandledProtocol(
-    const std::string& scheme) const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  return io_thread_delegate_->IsHandledProtocol(scheme) ||
-      job_factory_->IsHandledProtocol(scheme);
-}
-
-bool ProtocolHandlerRegistry::JobInterceptorFactory::IsSafeRedirectTarget(
-    const GURL& location) const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  return job_factory_->IsSafeRedirectTarget(location);
-}
-
 // Delegate --------------------------------------------------------------------
 
 ProtocolHandlerRegistry::Delegate::~Delegate() {}
@@ -913,13 +848,3 @@
       &ProtocolHandlerRegistry::OnSetAsDefaultProtocolClientFinished,
       weak_ptr_factory_.GetWeakPtr(), protocol);
 }
-
-std::unique_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
-ProtocolHandlerRegistry::CreateJobInterceptorFactory() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // this is always created on the UI thread (in profile_io's
-  // InitializeOnUIThread. Any method calls must be done
-  // on the IO thread (this is checked).
-  return std::unique_ptr<JobInterceptorFactory>(
-      new JobInterceptorFactory(io_thread_delegate_.get()));
-}
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.h b/chrome/browser/custom_handlers/protocol_handler_registry.h
index 8c9dce7..cff3ad96 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry.h
+++ b/chrome/browser/custom_handlers/protocol_handler_registry.h
@@ -113,59 +113,10 @@
     DISALLOW_COPY_AND_ASSIGN(IOThreadDelegate);
   };
 
-  // JobInterceptorFactory intercepts URLRequestJob creation for URLRequests the
-  // ProtocolHandlerRegistry is registered to handle.  When no handler is
-  // registered, the URLRequest is passed along to the chained
-  // URLRequestJobFactory (set with |JobInterceptorFactory::Chain|).
-  // JobInterceptorFactory's are created via
-  // |ProtocolHandlerRegistry::CreateJobInterceptorFactory|.
-  class JobInterceptorFactory : public net::URLRequestJobFactory {
-   public:
-    // |io_thread_delegate| is used to perform actual job creation work.
-    explicit JobInterceptorFactory(IOThreadDelegate* io_thread_delegate);
-    ~JobInterceptorFactory() override;
-
-    // |job_factory| is set as the URLRequestJobFactory where requests are
-    // forwarded if JobInterceptorFactory decides to pass on them.
-    void Chain(std::unique_ptr<net::URLRequestJobFactory> job_factory);
-
-    // URLRequestJobFactory implementation.
-    net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
-        const std::string& scheme,
-        net::URLRequest* request,
-        net::NetworkDelegate* network_delegate) const override;
-
-    net::URLRequestJob* MaybeInterceptRedirect(
-        net::URLRequest* request,
-        net::NetworkDelegate* network_delegate,
-        const GURL& location) const override;
-
-    net::URLRequestJob* MaybeInterceptResponse(
-        net::URLRequest* request,
-        net::NetworkDelegate* network_delegate) const override;
-
-    bool IsHandledProtocol(const std::string& scheme) const override;
-    bool IsSafeRedirectTarget(const GURL& location) const override;
-
-   private:
-    // When JobInterceptorFactory decides to pass on particular requests,
-    // they're forwarded to the chained URLRequestJobFactory, |job_factory_|.
-    std::unique_ptr<URLRequestJobFactory> job_factory_;
-    // |io_thread_delegate_| performs the actual job creation decisions by
-    // mirroring the ProtocolHandlerRegistry on the IO thread.
-    scoped_refptr<IOThreadDelegate> io_thread_delegate_;
-
-    DISALLOW_COPY_AND_ASSIGN(JobInterceptorFactory);
-  };
-
   // Creates a new instance. Assumes ownership of |delegate|.
   ProtocolHandlerRegistry(content::BrowserContext* context, Delegate* delegate);
   ~ProtocolHandlerRegistry() override;
 
-  // Returns a net::URLRequestJobFactory suitable for use on the IO thread, but
-  // is initialized on the UI thread.
-  std::unique_ptr<JobInterceptorFactory> CreateJobInterceptorFactory();
-
   // Called when a site tries to register as a protocol handler. If the request
   // can be handled silently by the registry - either to ignore the request
   // or to update an existing handler - the request will succeed. If this
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
index 42db890..e467fb6 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
@@ -38,27 +38,6 @@
 
 namespace {
 
-void AssertInterceptedIO(
-    const GURL& url,
-    net::URLRequestJobFactory* interceptor) {
-  net::URLRequestContext context;
-  std::unique_ptr<net::URLRequest> request(context.CreateRequest(
-      url, net::DEFAULT_PRIORITY, nullptr, TRAFFIC_ANNOTATION_FOR_TESTS));
-  std::unique_ptr<net::URLRequestJob> job(
-      interceptor->MaybeCreateJobWithProtocolHandler(
-          url.scheme(), request.get(), context.network_delegate()));
-  ASSERT_TRUE(job.get());
-}
-
-void AssertIntercepted(
-    const GURL& url,
-    net::URLRequestJobFactory* interceptor) {
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(AssertInterceptedIO, url, base::Unretained(interceptor)));
-  base::RunLoop().RunUntilIdle();
-}
-
 // FakeURLRequestJobFactory returns NULL for all job creation requests and false
 // for all IsHandledProtocol() requests. FakeURLRequestJobFactory can be chained
 // to ProtocolHandlerRegistry::JobInterceptorFactory so the result of
@@ -94,26 +73,6 @@
   }
 };
 
-void AssertWillHandleIO(
-    const std::string& scheme,
-    bool expected,
-    ProtocolHandlerRegistry::JobInterceptorFactory* interceptor) {
-  interceptor->Chain(std::unique_ptr<net::URLRequestJobFactory>(
-      new FakeURLRequestJobFactory()));
-  ASSERT_EQ(expected, interceptor->IsHandledProtocol(scheme));
-  interceptor->Chain(std::unique_ptr<net::URLRequestJobFactory>());
-}
-
-void AssertWillHandle(
-    const std::string& scheme,
-    bool expected,
-    ProtocolHandlerRegistry::JobInterceptorFactory* interceptor) {
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
-                           base::BindOnce(AssertWillHandleIO, scheme, expected,
-                                          base::Unretained(interceptor)));
-  base::RunLoop().RunUntilIdle();
-}
-
 std::unique_ptr<base::DictionaryValue> GetProtocolHandlerValue(
     const std::string& protocol,
     const std::string& url) {
@@ -767,27 +726,6 @@
   ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("dont").size());
 }
 
-TEST_F(ProtocolHandlerRegistryTest, TestMaybeCreateTaskWorksFromIOThread) {
-  ProtocolHandler ph1 = CreateProtocolHandler("mailto", "test1");
-  registry()->OnAcceptRegisterProtocolHandler(ph1);
-  GURL url("mailto:someone@something.com");
-
-  std::unique_ptr<net::URLRequestJobFactory> interceptor(
-      registry()->CreateJobInterceptorFactory());
-  AssertIntercepted(url, interceptor.get());
-}
-
-TEST_F(ProtocolHandlerRegistryTest,
-       TestIsHandledProtocolWorksOnIOThread) {
-  std::string scheme("mailto");
-  ProtocolHandler ph1 = CreateProtocolHandler(scheme, "test1");
-  registry()->OnAcceptRegisterProtocolHandler(ph1);
-
-  std::unique_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> interceptor(
-      registry()->CreateJobInterceptorFactory());
-  AssertWillHandle(scheme, true, interceptor.get());
-}
-
 TEST_F(ProtocolHandlerRegistryTest, TestRemovingDefaultFallsBackToOldDefault) {
   ProtocolHandler ph1 = CreateProtocolHandler("mailto", "test1");
   ProtocolHandler ph2 = CreateProtocolHandler("mailto", "test2");
@@ -824,29 +762,6 @@
   ASSERT_EQ(ph1, handlers[1]);
 }
 
-TEST_F(ProtocolHandlerRegistryTest, TestClearDefaultGetsPropagatedToIO) {
-  std::string scheme("mailto");
-  ProtocolHandler ph1 = CreateProtocolHandler(scheme, "test1");
-  registry()->OnAcceptRegisterProtocolHandler(ph1);
-  registry()->ClearDefault(scheme);
-
-  std::unique_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> interceptor(
-      registry()->CreateJobInterceptorFactory());
-  AssertWillHandle(scheme, false, interceptor.get());
-}
-
-TEST_F(ProtocolHandlerRegistryTest, TestLoadEnabledGetsPropogatedToIO) {
-  std::string mailto("mailto");
-  ProtocolHandler ph1 = CreateProtocolHandler(mailto, "MailtoHandler");
-  registry()->OnAcceptRegisterProtocolHandler(ph1);
-
-  std::unique_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> interceptor(
-      registry()->CreateJobInterceptorFactory());
-  AssertWillHandle(mailto, true, interceptor.get());
-  registry()->Disable();
-  AssertWillHandle(mailto, false, interceptor.get());
-}
-
 TEST_F(ProtocolHandlerRegistryTest, TestReplaceHandler) {
   ProtocolHandler ph1 =
       CreateProtocolHandler("mailto", GURL("http://test.com/%s"));
diff --git a/chrome/browser/extensions/bookmark_app_helper_unittest.cc b/chrome/browser/extensions/bookmark_app_helper_unittest.cc
index 3b26e91a..654ddc2 100644
--- a/chrome/browser/extensions/bookmark_app_helper_unittest.cc
+++ b/chrome/browser/extensions/bookmark_app_helper_unittest.cc
@@ -190,6 +190,8 @@
 
 }  // namespace
 
+// Deprecated in favour of InstallManagerBookmarkAppTest.CreateBookmarkApp.
+// TODO(crbug.com/915043): Erase it.
 TEST_F(BookmarkAppHelperExtensionServiceTest, CreateBookmarkApp) {
   WebApplicationInfo web_app_info;
   web_app_info.app_url = GURL(kAppUrl);
@@ -223,6 +225,9 @@
           .is_null());
 }
 
+// Deprecated in favour of
+// InstallManagerBookmarkAppTest.CreateBookmarkAppDefaultApp.
+// TODO(crbug.com/915043): Erase it.
 TEST_F(BookmarkAppHelperExtensionServiceTest, CreateBookmarkAppDefaultApp) {
   WebApplicationInfo web_app_info;
   web_app_info.app_url = GURL(kAppUrl);
@@ -242,6 +247,9 @@
   EXPECT_FALSE(Manifest::IsPolicyLocation(helper.extension()->location()));
 }
 
+// Deprecated in favour of
+// InstallManagerBookmarkAppTest.CreateBookmarkAppPolicyInstalled.
+// TODO(crbug.com/915043): Erase it.
 TEST_F(BookmarkAppHelperExtensionServiceTest,
        CreateBookmarkAppPolicyInstalled) {
   WebApplicationInfo web_app_info;
@@ -273,6 +281,9 @@
       BookmarkAppHelperExtensionServiceInstallableSiteTest);
 };
 
+// Deprecated in favour of
+// InstallManagerBookmarkAppInstallableSiteTest.CreateBookmarkAppWithManifest.
+// TODO(crbug.com/915043): Erase it.
 TEST_P(BookmarkAppHelperExtensionServiceInstallableSiteTest,
        CreateBookmarkAppWithManifest) {
   WebApplicationInfo web_app_info;
@@ -314,6 +325,10 @@
   }
 }
 
+// Deprecated in favour of
+// InstallManagerBookmarkAppInstallableSiteTest
+// .CreateBookmarkAppWithManifestIcons.
+// TODO(crbug.com/915043): Erase it.
 TEST_P(BookmarkAppHelperExtensionServiceInstallableSiteTest,
        CreateBookmarkAppWithManifestIcons) {
   WebApplicationInfo web_app_info;
@@ -362,6 +377,10 @@
   }
 }
 
+// Deprecated in favour of
+// InstallManagerBookmarkAppInstallableSiteTest
+// .CreateBookmarkAppWithManifestNoScope.
+// TODO(crbug.com/915043): Erase it.
 TEST_P(BookmarkAppHelperExtensionServiceInstallableSiteTest,
        CreateBookmarkAppWithManifestNoScope) {
   WebApplicationInfo web_app_info;
@@ -395,6 +414,9 @@
                          ::testing::Values(ForInstallableSite::kNo,
                                            ForInstallableSite::kYes));
 
+// Deprecated in favour of
+// InstallManagerBookmarkAppTest.CreateBookmarkAppDefaultLauncherContainers.
+// TODO(crbug.com/915043): Erase it.
 TEST_F(BookmarkAppHelperExtensionServiceTest,
        CreateBookmarkAppDefaultLauncherContainers) {
   std::map<GURL, std::vector<SkBitmap>> icon_map;
@@ -455,6 +477,9 @@
   }
 }
 
+// Deprecated in favour of
+// InstallManagerBookmarkAppTest.CreateBookmarkAppForcedLauncherContainers.
+// TODO(crbug.com/915043): Erase it.
 TEST_F(BookmarkAppHelperExtensionServiceTest,
        CreateBookmarkAppForcedLauncherContainers) {
   WebApplicationInfo web_app_info;
@@ -498,6 +523,9 @@
   }
 }
 
+// Deprecated in favour of
+// InstallManagerBookmarkAppTest.CreateBookmarkAppWithoutManifest.
+// TODO(crbug.com/915043): Erase it.
 TEST_F(BookmarkAppHelperExtensionServiceTest,
        CreateBookmarkAppWithoutManifest) {
   WebApplicationInfo web_app_info;
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc
index 4178f4b..3040ea5 100644
--- a/chrome/browser/extensions/service_worker_apitest.cc
+++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -57,6 +57,7 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/browser/service_worker_task_queue.h"
+#include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/common/api/test.h"
 #include "extensions/common/value_builder.h"
 #include "extensions/common/verifier_formats.h"
@@ -1683,6 +1684,35 @@
   EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
 }
 
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, UninstallSelf) {
+  constexpr char kManifest[] =
+      R"({
+           "name": "Test Extension",
+           "manifest_version": 2,
+           "version": "0.1",
+           "background": {"service_worker": "script.js"}
+         })";
+
+  // This script uninstalls itself.
+  constexpr char kScript[] =
+      "chrome.management.uninstallSelf({showConfirmDialog: false});";
+
+  TestExtensionDir test_dir;
+
+  test_dir.WriteManifest(kManifest);
+  test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
+
+  // Consruct this before loading the extension, since the extension will
+  // immediately uninstall itself when it loads.
+  extensions::TestExtensionRegistryObserver observer(
+      extensions::ExtensionRegistry::Get(browser()->profile()));
+
+  base::FilePath path = test_dir.Pack();
+  scoped_refptr<const Extension> extension = LoadExtension(path);
+
+  EXPECT_EQ(extension, observer.WaitForExtensionUninstalled());
+}
+
 IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
                        PRE_EventsAfterRestart) {
   ExtensionTestMessageListener event_added_listener("ready", false);
diff --git a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc
index bae20ee6..0558944 100644
--- a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc
+++ b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc
@@ -81,7 +81,7 @@
 
   void GetAllNotifications(Notifications* notifications) override {
     DCHECK(notifications);
-
+    notifications->clear();
     for (const auto& pair : notifications_) {
       const auto& notif = pair.second;
       DCHECK(notif);
@@ -94,6 +94,22 @@
     }
   }
 
+  void DeleteNotifications(SchedulerClientType type) override {
+    auto it = notifications_.begin();
+    while (it != notifications_.end()) {
+      const auto& entry = *it->second;
+      ++it;
+      if (entry.type == type) {
+        store_->Delete(
+            entry.guid,
+            base::BindOnce(
+                &ScheduledNotificationManagerImpl::OnNotificationDeleted,
+                weak_ptr_factory_.GetWeakPtr()));
+        notifications_.erase(entry.guid);
+      }
+    }
+  }
+
   void OnStoreInitialized(InitCallback callback,
                           bool success,
                           CollectionStore<NotificationEntry>::Entries entries) {
diff --git a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.h b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.h
index 6ed3e8bc..3437053 100644
--- a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.h
+++ b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.h
@@ -59,6 +59,9 @@
   // by creation timestamp.
   virtual void GetAllNotifications(Notifications* notifications) = 0;
 
+  // Deletes all notifications of given SchedulerClientType.
+  virtual void DeleteNotifications(SchedulerClientType type) = 0;
+
   virtual ~ScheduledNotificationManager();
 
  protected:
diff --git a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc
index b5b1c132..0ba4d73 100644
--- a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc
+++ b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc
@@ -28,6 +28,10 @@
   return NotificationEntry(SchedulerClientType::kUnknown, base::GenerateGUID());
 }
 
+NotificationEntry CreateNotificationEntry(SchedulerClientType type) {
+  return NotificationEntry(type, base::GenerateGUID());
+}
+
 class MockDelegate : public ScheduledNotificationManager::Delegate {
  public:
   MockDelegate() = default;
@@ -225,5 +229,44 @@
   EXPECT_EQ(output2->create_time, entry2.create_time);
 }
 
+// Verify DeleteNotifications API, all notifications with given
+// SchedulerClientType should be deleted.
+TEST_F(ScheduledNotificationManagerTest, DeleteNotifications) {
+  // Type1: entry0
+  // Type2: entry1, entry2
+  // Type3: entry3
+  auto entry0 = CreateNotificationEntry(SchedulerClientType::kTest1);
+  auto entry1 = CreateNotificationEntry(SchedulerClientType::kTest2);
+  auto entry2 = CreateNotificationEntry(SchedulerClientType::kTest2);
+  auto entry3 = CreateNotificationEntry(SchedulerClientType::kTest3);
+
+  InitWithData(
+      std::vector<NotificationEntry>({entry0, entry1, entry2, entry3}));
+  ScheduledNotificationManager::Notifications notifications;
+  manager()->GetAllNotifications(&notifications);
+  EXPECT_EQ(notifications.size(), 3u);
+
+  EXPECT_CALL(*store(), Delete(_, _)).Times(2).RetiresOnSaturation();
+  manager()->DeleteNotifications(SchedulerClientType::kTest2);
+  manager()->GetAllNotifications(&notifications);
+  EXPECT_EQ(notifications.size(), 2u);
+
+  // Ensure deleting non-existing key will not crash, and store will not call
+  // Delete.
+  EXPECT_CALL(*store(), Delete(_, _)).Times(0).RetiresOnSaturation();
+  manager()->DeleteNotifications(SchedulerClientType::kTest2);
+  manager()->GetAllNotifications(&notifications);
+  EXPECT_EQ(notifications.size(), 2u);
+
+  EXPECT_CALL(*store(), Delete(_, _)).RetiresOnSaturation();
+  manager()->DeleteNotifications(SchedulerClientType::kTest1);
+  manager()->GetAllNotifications(&notifications);
+  EXPECT_EQ(notifications.size(), 1u);
+
+  EXPECT_CALL(*store(), Delete(_, _)).RetiresOnSaturation();
+  manager()->DeleteNotifications(SchedulerClientType::kTest3);
+  manager()->GetAllNotifications(&notifications);
+  EXPECT_EQ(notifications.size(), 0u);
+}
 }  // namespace
 }  // namespace notifications
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 7486d7f..d99a1174 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -199,6 +199,7 @@
 #include "content/public/test/download_test_observer.h"
 #include "content/public/test/mock_notification_observer.h"
 #include "content/public/test/network_service_test_helper.h"
+#include "content/public/test/no_renderer_crashes_assertion.h"
 #include "content/public/test/signed_exchange_browser_test_helper.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
@@ -2650,19 +2651,23 @@
   }
 
   // Test policy-installed extensions are reloaded when killed.
-  BackgroundContentsService::
-      SetRestartDelayForForceInstalledAppsAndExtensionsForTesting(0);
-  content::WindowedNotificationObserver extension_crashed_observer(
-      extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
-      content::NotificationService::AllSources());
-  extensions::TestExtensionRegistryObserver extension_loaded_observer(
-      extensions::ExtensionRegistry::Get(browser()->profile()), kGoodCrxId);
-  extensions::ExtensionHost* extension_host =
-      extensions::ProcessManager::Get(browser()->profile())
-          ->GetBackgroundHostForExtension(kGoodCrxId);
-  extension_host->render_process_host()->Shutdown(content::RESULT_CODE_KILLED);
-  extension_crashed_observer.Wait();
-  extension_loaded_observer.WaitForExtensionLoaded();
+  {
+    content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes;
+    BackgroundContentsService::
+        SetRestartDelayForForceInstalledAppsAndExtensionsForTesting(0);
+    content::WindowedNotificationObserver extension_crashed_observer(
+        extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
+        content::NotificationService::AllSources());
+    extensions::TestExtensionRegistryObserver extension_loaded_observer(
+        extensions::ExtensionRegistry::Get(browser()->profile()), kGoodCrxId);
+    extensions::ExtensionHost* extension_host =
+        extensions::ProcessManager::Get(browser()->profile())
+            ->GetBackgroundHostForExtension(kGoodCrxId);
+    extension_host->render_process_host()->Shutdown(
+        content::RESULT_CODE_KILLED);
+    extension_crashed_observer.Wait();
+    extension_loaded_observer.WaitForExtensionLoaded();
+  }
 }
 
 IN_PROC_BROWSER_TEST_F(PolicyTest,
diff --git a/chrome/browser/previews/previews_content_util.cc b/chrome/browser/previews/previews_content_util.cc
index ec184c7..b2f6363 100644
--- a/chrome/browser/previews/previews_content_util.cc
+++ b/chrome/browser/previews/previews_content_util.cc
@@ -104,6 +104,11 @@
         PreviewsLitePageNavigationThrottle::IneligibleReason::kCookiesBlocked);
   }
 
+  if (!decider->has_drp_headers()) {
+    ineligible_reasons.push_back(PreviewsLitePageNavigationThrottle::
+                                     IneligibleReason::kInvalidProxyHeaders);
+  }
+
   // Record UMA.
   for (PreviewsLitePageNavigationThrottle::IneligibleReason reason :
        ineligible_reasons) {
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc
index 209bec6..1a706ae 100644
--- a/chrome/browser/previews/previews_lite_page_browsertest.cc
+++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -1112,6 +1112,31 @@
 
 IN_PROC_BROWSER_TEST_P(
     PreviewsLitePageServerBrowserTest,
+    DISABLE_ON_WIN_MAC_CHROMESOS(LitePagePreviewsNoChromeProxyHeader)) {
+  ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess));
+  VerifyPreviewLoaded();
+
+  // Mimic a bad proxy header update.
+  net::HttpRequestHeaders empty;
+  PreviewsService* previews_service =
+      PreviewsServiceFactory::GetForProfile(browser()->profile());
+  PreviewsLitePageDecider* decider =
+      previews_service->previews_lite_page_decider();
+  decider->OnProxyRequestHeadersChanged(empty);
+
+  base::HistogramTester histogram_tester;
+  ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess));
+  VerifyPreviewNotLoaded();
+
+  histogram_tester.ExpectBucketCount(
+      "Previews.ServerLitePage.IneligibleReasons",
+      static_cast<int>(PreviewsLitePageNavigationThrottle::IneligibleReason::
+                           kInvalidProxyHeaders),
+      1);
+}
+
+IN_PROC_BROWSER_TEST_P(
+    PreviewsLitePageServerBrowserTest,
     DISABLE_ON_WIN_MAC_CHROMESOS(CoinFlipHoldbackTriggering)) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeatureWithParameters(
diff --git a/chrome/browser/previews/previews_lite_page_decider.cc b/chrome/browser/previews/previews_lite_page_decider.cc
index 036d3af..58012c5 100644
--- a/chrome/browser/previews/previews_lite_page_decider.cc
+++ b/chrome/browser/previews/previews_lite_page_decider.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "components/pref_registry/pref_registry_syncable.h"
@@ -138,7 +139,8 @@
       page_id_(base::RandUint64()),
       drp_settings_(nullptr),
       pref_service_(nullptr),
-      host_bypass_blacklist_(std::make_unique<base::DictionaryValue>()) {
+      host_bypass_blacklist_(std::make_unique<base::DictionaryValue>()),
+      drp_headers_valid_(false) {
   if (!browser_context)
     return;
 
@@ -244,6 +246,15 @@
 void PreviewsLitePageDecider::OnProxyRequestHeadersChanged(
     const net::HttpRequestHeaders& headers) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  std::string drp_header;
+  drp_headers_valid_ =
+      headers.GetHeader(data_reduction_proxy::chrome_proxy_header(),
+                        &drp_header) &&
+      (drp_header.find(",s=") != std::string::npos ||
+       drp_header.find(" s=") != std::string::npos ||
+       base::StartsWith(drp_header, "s=", base::CompareCase::SENSITIVE));
+
   // This is done so that successive page ids cannot be used to track users
   // across sessions. These sessions are contained in the chrome-proxy header.
   page_id_ = base::RandUint64();
diff --git a/chrome/browser/previews/previews_lite_page_decider.h b/chrome/browser/previews/previews_lite_page_decider.h
index df594e71..c9c0b18 100644
--- a/chrome/browser/previews/previews_lite_page_decider.h
+++ b/chrome/browser/previews/previews_lite_page_decider.h
@@ -97,12 +97,14 @@
                              base::TimeDelta duration) override;
   bool HostBlacklistedFromBypass(const std::string& host) override;
 
- private:
   // data_reduction_proxy::DataReductionProxySettingsObserver:
   void OnProxyRequestHeadersChanged(
       const net::HttpRequestHeaders& headers) override;
   void OnSettingsInitialized() override;
 
+  bool has_drp_headers() const { return drp_headers_valid_; }
+
+ private:
   // The time after which it is ok to send the server more preview requests.
   base::Optional<base::TimeTicks> retry_at_;
 
@@ -133,6 +135,10 @@
   // after the time value. This is stored persistently in prefs.
   std::unique_ptr<base::DictionaryValue> host_bypass_blacklist_;
 
+  // A bool that tracks if the last call to |OnProxyRequestHeadersChanged| had
+  // what looked like a valid chrome-proxy header.
+  bool drp_headers_valid_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(PreviewsLitePageDecider);
diff --git a/chrome/browser/previews/previews_lite_page_navigation_throttle.h b/chrome/browser/previews/previews_lite_page_navigation_throttle.h
index 593d5c43..1c5c5e62 100644
--- a/chrome/browser/previews/previews_lite_page_navigation_throttle.h
+++ b/chrome/browser/previews/previews_lite_page_navigation_throttle.h
@@ -63,7 +63,8 @@
     kECTUnknown_DEPRECATED = 8,
     kExceededMaxNavigationRestarts = 9,
     kPreviewsState_DEPRECATED = 10,
-    kMaxValue = kPreviewsState_DEPRECATED,
+    kInvalidProxyHeaders = 11,
+    kMaxValue = kInvalidProxyHeaders,
   };
 
   // The response type from the previews server. This enum must
diff --git a/chrome/browser/previews/previews_top_host_provider_impl.cc b/chrome/browser/previews/previews_top_host_provider_impl.cc
index c8f48f8..acdb84d 100644
--- a/chrome/browser/previews/previews_top_host_provider_impl.cc
+++ b/chrome/browser/previews/previews_top_host_provider_impl.cc
@@ -10,8 +10,11 @@
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
 #include "components/previews/content/previews_hints_util.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
 
 namespace {
 
@@ -48,6 +51,38 @@
   UpdateCurrentBlacklistState(HintsFetcherTopHostBlacklistState::kInitialized);
 }
 
+// static
+void PreviewsTopHostProviderImpl::MaybeUpdateTopHostBlacklist(
+    content::NavigationHandle* navigation_handle) {
+  if (!navigation_handle->GetURL().SchemeIsHTTPOrHTTPS())
+    return;
+
+  PrefService* pref_service =
+      Profile::FromBrowserContext(
+          navigation_handle->GetWebContents()->GetBrowserContext())
+          ->GetPrefs();
+
+  if (pref_service->GetInteger(kHintsFetcherTopHostBlacklistState) !=
+      static_cast<int>(HintsFetcherTopHostBlacklistState::kInitialized)) {
+    return;
+  }
+
+  DictionaryPrefUpdate blacklist_pref(pref_service,
+                                      kHintsFetcherTopHostBlacklist);
+  if (!blacklist_pref->FindKey(previews::HashHostForDictionary(
+          navigation_handle->GetURL().host()))) {
+    return;
+  }
+  blacklist_pref->RemovePath(
+      previews::HashHostForDictionary(navigation_handle->GetURL().host()));
+  if (blacklist_pref->empty()) {
+    blacklist_pref->Clear();
+    pref_service->SetInteger(
+        kHintsFetcherTopHostBlacklistState,
+        static_cast<int>(HintsFetcherTopHostBlacklistState::kEmpty));
+  }
+}
+
 HintsFetcherTopHostBlacklistState
 PreviewsTopHostProviderImpl::GetCurrentBlacklistState() const {
   return static_cast<HintsFetcherTopHostBlacklistState>(
diff --git a/chrome/browser/previews/previews_top_host_provider_impl.h b/chrome/browser/previews/previews_top_host_provider_impl.h
index d3cb3e5..8aac274 100644
--- a/chrome/browser/previews/previews_top_host_provider_impl.h
+++ b/chrome/browser/previews/previews_top_host_provider_impl.h
@@ -18,6 +18,7 @@
 
 namespace content {
 class BrowserContext;
+class NavigationHandle;
 }
 namespace previews {
 
@@ -28,6 +29,13 @@
   explicit PreviewsTopHostProviderImpl(content::BrowserContext* BrowserContext);
   ~PreviewsTopHostProviderImpl() override;
 
+  // Update the HintsFetcherTopHostBlacklist by attempting to remove the host
+  // for the current navigation from the blacklist. A host is removed if it is
+  // currently on the blacklist and the blacklist state is updated if the
+  // blacklist is empty after removing a host.
+  static void MaybeUpdateTopHostBlacklist(
+      content::NavigationHandle* navigation_handle);
+
   std::vector<std::string> GetTopHosts(size_t max_sites) override;
 
  private:
diff --git a/chrome/browser/previews/previews_top_host_provider_impl_unittest.cc b/chrome/browser/previews/previews_top_host_provider_impl_unittest.cc
index 463098f3a..e3cb5505 100644
--- a/chrome/browser/previews/previews_top_host_provider_impl_unittest.cc
+++ b/chrome/browser/previews/previews_top_host_provider_impl_unittest.cc
@@ -11,6 +11,7 @@
 #include "components/optimization_guide/optimization_guide_prefs.h"
 #include "components/prefs/pref_service.h"
 #include "components/previews/content/previews_hints_util.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace previews {
@@ -23,21 +24,31 @@
 
     top_host_provider_ =
         std::make_unique<PreviewsTopHostProviderImpl>(profile());
+    service_ = SiteEngagementService::Get(profile());
+    pref_service_ = profile()->GetPrefs();
   }
 
   void AddEngagedHosts(size_t num_hosts) {
-    SiteEngagementService* service = SiteEngagementService::Get(profile());
     for (size_t i = 1; i <= num_hosts; i++) {
-      GURL url = GURL(base::StringPrintf("https://domain%zu.com", i));
-      service->AddPointsForTesting(url, int(i));
+      AddEngagedHost(GURL(base::StringPrintf("https://domain%zu.com", i)),
+                     static_cast<int>(i));
     }
   }
 
-  void PopulateTopHostBlacklist(size_t num_hosts) {
-    PrefService* pref_service = profile()->GetPrefs();
+  void AddEngagedHost(GURL url, int num_points) {
+    service_->AddPointsForTesting(url, num_points);
+  }
 
+  bool IsHostBlacklisted(const std::string& host) {
+    const base::DictionaryValue* top_host_blacklist =
+        pref_service_->GetDictionary(
+            optimization_guide::prefs::kHintsFetcherTopHostBlacklist);
+    return top_host_blacklist->FindKey(previews::HashHostForDictionary(host));
+  }
+
+  void PopulateTopHostBlacklist(size_t num_hosts) {
     std::unique_ptr<base::DictionaryValue> top_host_filter =
-        pref_service
+        pref_service_
             ->GetDictionary(
                 optimization_guide::prefs::kHintsFetcherTopHostBlacklist)
             ->CreateDeepCopy();
@@ -46,15 +57,37 @@
       top_host_filter->SetBoolKey(
           HashHostForDictionary(base::StringPrintf("domain%zu.com", i)), true);
     }
-    pref_service->Set(optimization_guide::prefs::kHintsFetcherTopHostBlacklist,
-                      *top_host_filter);
+    pref_service_->Set(optimization_guide::prefs::kHintsFetcherTopHostBlacklist,
+                       *top_host_filter);
+  }
+
+  void AddHostToBlackList(const std::string& host) {
+    std::unique_ptr<base::DictionaryValue> top_host_filter =
+        pref_service_
+            ->GetDictionary(
+                optimization_guide::prefs::kHintsFetcherTopHostBlacklist)
+            ->CreateDeepCopy();
+    top_host_filter->SetBoolKey(previews::HashHostForDictionary(host), true);
+    pref_service_->Set(optimization_guide::prefs::kHintsFetcherTopHostBlacklist,
+                       *top_host_filter);
+  }
+
+  void SimulateUniqueNavigationsToTopHosts(size_t num_hosts) {
+    for (size_t i = 1; i <= num_hosts; i++) {
+      SimulateNavigation(GURL(base::StringPrintf("https://domain%zu.com", i)));
+    }
+  }
+
+  void SimulateNavigation(GURL url) {
+    std::unique_ptr<content::MockNavigationHandle> test_handle_ =
+        std::make_unique<content::MockNavigationHandle>(url, main_rfh());
+    PreviewsTopHostProviderImpl::MaybeUpdateTopHostBlacklist(
+        test_handle_.get());
   }
 
   void RemoveHostsFromBlacklist(size_t num_hosts_navigated) {
-    PrefService* pref_service = profile()->GetPrefs();
-
     std::unique_ptr<base::DictionaryValue> top_host_filter =
-        pref_service
+        pref_service_
             ->GetDictionary(
                 optimization_guide::prefs::kHintsFetcherTopHostBlacklist)
             ->CreateDeepCopy();
@@ -63,8 +96,8 @@
       top_host_filter->RemoveKey(
           HashHostForDictionary(base::StringPrintf("domain%zu.com", i)));
     }
-    pref_service->Set(optimization_guide::prefs::kHintsFetcherTopHostBlacklist,
-                      *top_host_filter);
+    pref_service_->Set(optimization_guide::prefs::kHintsFetcherTopHostBlacklist,
+                       *top_host_filter);
   }
 
   void SetTopHostBlacklistState(
@@ -77,10 +110,9 @@
 
   optimization_guide::prefs::HintsFetcherTopHostBlacklistState
   GetCurrentTopHostBlacklistState() {
-    PrefService* pref_service = profile()->GetPrefs();
     return static_cast<
         optimization_guide::prefs::HintsFetcherTopHostBlacklistState>(
-        pref_service->GetInteger(
+        pref_service_->GetInteger(
             optimization_guide::prefs::kHintsFetcherTopHostBlacklistState));
   }
 
@@ -92,6 +124,8 @@
 
  private:
   std::unique_ptr<PreviewsTopHostProviderImpl> top_host_provider_;
+  SiteEngagementService* service_;
+  PrefService* pref_service_;
 };
 
 TEST_F(PreviewsTopHostProviderImplTest, GetTopHostsMaxSites) {
@@ -195,4 +229,89 @@
       optimization_guide::prefs::HintsFetcherTopHostBlacklistState::kEmpty);
 }
 
+TEST_F(PreviewsTopHostProviderImplTest,
+       MaybeUpdateTopHostBlacklistNavigationsOnBlacklist) {
+  size_t engaged_hosts = 5;
+  size_t max_top_hosts = 5;
+  size_t num_hosts_blacklisted = 5;
+  size_t num_top_hosts = 3;
+  AddEngagedHosts(engaged_hosts);
+  // TODO(mcrouse): Remove once the blacklist is populated on initialization.
+  // The expected behavior will be that all hosts in the engagement service will
+  // be blacklisted on initialization.
+  PopulateTopHostBlacklist(num_hosts_blacklisted);
+
+  // Verify that all engaged hosts are blacklisted.
+  std::vector<std::string> hosts =
+      top_host_provider()->GetTopHosts(max_top_hosts);
+  EXPECT_EQ(hosts.size(), 0u);
+
+  // Navigate to some engaged hosts to trigger their removal from the top host
+  // blacklist.
+  SimulateUniqueNavigationsToTopHosts(num_top_hosts);
+
+  hosts = top_host_provider()->GetTopHosts(max_top_hosts);
+  EXPECT_EQ(hosts.size(), num_top_hosts);
+}
+
+TEST_F(PreviewsTopHostProviderImplTest,
+       MaybeUpdateTopHostBlacklistEmptyBlacklist) {
+  size_t engaged_hosts = 5;
+  size_t max_top_hosts = 5;
+  size_t num_hosts_blacklisted = 5;
+  size_t num_top_hosts = 5;
+  AddEngagedHosts(engaged_hosts);
+  // TODO(mcrouse): Remove once the blacklist is populated on initialization.
+  // The expected behavior will be that all hosts in the engagement service will
+  // be blacklisted on initialization.
+  PopulateTopHostBlacklist(num_hosts_blacklisted);
+
+  std::vector<std::string> hosts =
+      top_host_provider()->GetTopHosts(max_top_hosts);
+  EXPECT_EQ(hosts.size(), 0u);
+
+  SimulateUniqueNavigationsToTopHosts(num_top_hosts);
+
+  EXPECT_EQ(
+      GetCurrentTopHostBlacklistState(),
+      optimization_guide::prefs::HintsFetcherTopHostBlacklistState::kEmpty);
+
+  hosts = top_host_provider()->GetTopHosts(max_top_hosts);
+  EXPECT_EQ(hosts.size(), num_top_hosts);
+}
+
+TEST_F(PreviewsTopHostProviderImplTest,
+       HintsFetcherTopHostBlacklistNonHTTPOrHTTPSHost) {
+  size_t engaged_hosts = 5;
+  size_t max_top_hosts = 5;
+  size_t num_hosts_blacklisted = 5;
+  GURL http_url = GURL("http://anyscheme.com");
+  GURL file_url = GURL("file://anyscheme.com");
+  AddEngagedHosts(engaged_hosts);
+  AddEngagedHost(http_url, 5);
+  // TODO(mcrouse): Remove once the blacklist is populated on initialization.
+  // The expected behavior will be that all hosts in the engagement service will
+  // be blacklisted on initialization.
+  PopulateTopHostBlacklist(num_hosts_blacklisted);
+  AddHostToBlackList(http_url.host());
+
+  SetTopHostBlacklistState(optimization_guide::prefs::
+                               HintsFetcherTopHostBlacklistState::kInitialized);
+
+  // A Non HTTP/HTTPS navigation should not remove a host from the blacklist.
+  SimulateNavigation(file_url);
+  std::vector<std::string> hosts =
+      top_host_provider()->GetTopHosts(max_top_hosts);
+  EXPECT_EQ(hosts.size(), 0u);
+  // The host, anyscheme.com, should still be on the blacklist.
+  EXPECT_TRUE(IsHostBlacklisted(file_url.host()));
+
+  // TopHostProviderImpl prevents HTTP hosts from being returned.
+  SimulateNavigation(http_url);
+  hosts = top_host_provider()->GetTopHosts(max_top_hosts);
+  EXPECT_EQ(hosts.size(), 0u);
+
+  EXPECT_FALSE(IsHostBlacklisted(http_url.host()));
+}
+
 }  // namespace previews
diff --git a/chrome/browser/previews/previews_ui_tab_helper.cc b/chrome/browser/previews/previews_ui_tab_helper.cc
index cbb4d75..f28d555a 100644
--- a/chrome/browser/previews/previews_ui_tab_helper.cc
+++ b/chrome/browser/previews/previews_ui_tab_helper.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/previews/previews_content_util.h"
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
+#include "chrome/browser/previews/previews_top_host_provider_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
@@ -227,12 +228,10 @@
   is_stale_reload_ = is_reload;
 }
 
-void PreviewsUITabHelper::DidStartNavigation(
+void PreviewsUITabHelper::MaybeRecordPreviewReload(
     content::NavigationHandle* navigation_handle) {
   if (navigation_handle->GetReloadType() == content::ReloadType::NONE)
     return;
-  if (!navigation_handle->IsInMainFrame())
-    return;
   if (!previews_user_data_)
     return;
   if (!previews_user_data_->HasCommittedPreviewsType())
@@ -251,6 +250,17 @@
   }
 }
 
+void PreviewsUITabHelper::DidStartNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (!navigation_handle->IsInMainFrame())
+    return;
+
+  MaybeRecordPreviewReload(navigation_handle);
+
+  previews::PreviewsTopHostProviderImpl::MaybeUpdateTopHostBlacklist(
+      navigation_handle);
+}
+
 void PreviewsUITabHelper::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   // Delete Previews information later, so that other DidFinishNavigation
diff --git a/chrome/browser/previews/previews_ui_tab_helper.h b/chrome/browser/previews/previews_ui_tab_helper.h
index ca19333..e6c137a 100644
--- a/chrome/browser/previews/previews_ui_tab_helper.h
+++ b/chrome/browser/previews/previews_ui_tab_helper.h
@@ -5,10 +5,12 @@
 #ifndef CHROME_BROWSER_PREVIEWS_PREVIEWS_UI_TAB_HELPER_H_
 #define CHROME_BROWSER_PREVIEWS_PREVIEWS_UI_TAB_HELPER_H_
 
-#include <map>
-
 #include <stdint.h>
 
+#include <map>
+#include <memory>
+#include <utility>
+
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -129,6 +131,10 @@
   void DidStartNavigation(
       content::NavigationHandle* navigation_handle) override;
 
+  // Records the time of the navigation if the current navigation is a reload
+  // and a preview was shown.
+  void MaybeRecordPreviewReload(content::NavigationHandle* navigation_handle);
+
   // True if the UI for a preview has been shown for the page.
   bool displayed_preview_ui_ = false;
 
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index cf31bbd4..bad56f3 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -273,12 +273,6 @@
   protocol_handler_registry_io_thread_delegate_ =
       protocol_handler_registry->io_thread_delegate();
 
-  // The profile instance is only available here in the InitializeOnUIThread
-  // method, so we create the url job factory here, then save it for
-  // later delivery to the job factory in Init().
-  params->protocol_handler_interceptor =
-      protocol_handler_registry->CreateJobInterceptorFactory();
-
 #if defined(OS_CHROMEOS)
   // Enable client certificates for the Chrome OS sign-in frame, if this feature
   // is not disabled by a flag.
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 2fdb8e4..6951921 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -34,7 +34,6 @@
 #include "services/network/public/mojom/network_service.mojom.h"
 
 class HostContentSettingsMap;
-class ProtocolHandlerRegistry;
 
 namespace chromeos {
 class CertificateProvider;
@@ -213,17 +212,6 @@
     signin::AccountConsistencyMethod account_consistency =
         signin::AccountConsistencyMethod::kDisabled;
 
-    // This pointer exists only as a means of conveying a url job factory
-    // pointer from the protocol handler registry on the UI thread to the
-    // the URLRequestContext on the IO thread. The consumer MUST take
-    // ownership of the object by calling release() on this pointer.
-    std::unique_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
-        protocol_handler_interceptor;
-
-    // Holds the URLRequestInterceptor pointer that is created on the UI thread
-    // and then passed to the list of request_interceptors on the IO thread.
-    std::unique_ptr<net::URLRequestInterceptor> new_tab_page_interceptor;
-
 #if defined(OS_CHROMEOS)
     std::string username_hash;
     SystemKeySlotUseType system_key_slot_use_type = SystemKeySlotUseType::kNone;
diff --git a/chrome/browser/resources/chromeos/account_manager_welcome.html b/chrome/browser/resources/chromeos/account_manager_welcome.html
index 54e41f8..c39e14d 100644
--- a/chrome/browser/resources/chromeos/account_manager_welcome.html
+++ b/chrome/browser/resources/chromeos/account_manager_welcome.html
@@ -4,15 +4,14 @@
   <title>$i18n{welcomeTitle}</title>
   <meta charset="utf-8">
   <link rel="import" href="chrome://resources/html/polymer.html">
-  <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-  <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
+  <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
   <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 
   <link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
   <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
   <link rel="stylesheet" href="account_manager_shared.css">
   <custom-style>
-    <style is="custom-style" include="cr-shared-style paper-button-style">
+    <style is="custom-style" include="cr-shared-style">
     </style>
   </custom-style>
 
@@ -36,9 +35,9 @@
                   account_manager_welcome_2x.png 2x">
     </if>
     <div class="button-container">
-      <paper-button id="ok-button" class="action-button">
+      <cr-button id="ok-button" class="action-button">
         $i18n{okButton}
-      </paper-button>
+      </cr-button>
     </div>
   </div>
 </body>
diff --git a/chrome/browser/resources/chromeos/account_migration_welcome.html b/chrome/browser/resources/chromeos/account_migration_welcome.html
index 952623e..2bde61a 100644
--- a/chrome/browser/resources/chromeos/account_migration_welcome.html
+++ b/chrome/browser/resources/chromeos/account_migration_welcome.html
@@ -4,15 +4,14 @@
   <title>$i18n{welcomePageTitle}</title>
   <meta charset="utf-8">
   <link rel="import" href="chrome://resources/html/polymer.html">
-  <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-  <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
+  <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
   <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
   <link rel="import" href="account_migration_browser_proxy.html">
 
   <link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
   <link rel="stylesheet" href="account_manager_shared.css">
   <custom-style>
-    <style is="custom-style" include="cr-shared-style paper-button-style">
+    <style is="custom-style" include="cr-shared-style">
     </style>
   </custom-style>
 
@@ -36,12 +35,12 @@
                   account_manager_welcome_2x.png 2x">
     </if>
     <div class="button-container">
-      <paper-button id="cancel-button" class="cancel-button">
+      <cr-button id="cancel-button" class="cancel-button">
         $i18n{cancelButton}
-      </paper-button>
-      <paper-button id="migrate-button" class="action-button">
+      </cr-button>
+      <cr-button id="migrate-button" class="action-button">
         $i18n{migrateButton}
-      </paper-button>
+      </cr-button>
     </div>
   </div>
 </body>
diff --git a/chrome/browser/resources/chromeos/camera/src/js/models/filesystem.js b/chrome/browser/resources/chromeos/camera/src/js/models/filesystem.js
index ee5c97e7..6540ed4f 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/models/filesystem.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/models/filesystem.js
@@ -294,6 +294,9 @@
 cca.models.FileSystem.createThumbnail_ = function(isVideo, url) {
   const thumbnailWidth = 480;
   var element = document.createElement(isVideo ? 'video' : 'img');
+  if (isVideo) {
+    element.preload = 'auto';
+  }
   return new Promise((resolve, reject) => {
     element.addEventListener(isVideo ? 'canplay' : 'load', resolve);
     element.addEventListener('error', reject);
diff --git a/chrome/browser/resources/chromeos/emulator/audio_settings.html b/chrome/browser/resources/chromeos/emulator/audio_settings.html
index 871744a..96aab81 100644
--- a/chrome/browser/resources/chromeos/emulator/audio_settings.html
+++ b/chrome/browser/resources/chromeos/emulator/audio_settings.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
@@ -8,7 +9,6 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_radio_group/cr_radio_group.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="icons.html">
 <link rel="import" href="shared_styles.html">
 
@@ -54,9 +54,9 @@
         </form>
       </div>
       <div slot="button-container">
-        <paper-button class="action-button" on-click="insertEditedAudioNode">
+        <cr-button class="action-button" on-click="insertEditedAudioNode">
           Done
-        </paper-button>
+        </cr-button>
       </div>
     </cr-dialog>
 
@@ -99,9 +99,7 @@
         </tbody>
       </table>
       <div class="add-device-container">
-        <paper-button on-click="appendNewNode">
-          Add Node
-        </paper-button>
+        <cr-button on-click="appendNewNode">Add Node</cr-button>
       </div>
     </div>
   </template>
diff --git a/chrome/browser/resources/chromeos/emulator/battery_settings.html b/chrome/browser/resources/chromeos/emulator/battery_settings.html
index 2e08c751a..7067464 100644
--- a/chrome/browser/resources/chromeos/emulator/battery_settings.html
+++ b/chrome/browser/resources/chromeos/emulator/battery_settings.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
@@ -66,13 +67,14 @@
                 <cr-checkbox checked="{{item.connected}}"></cr-checkbox>
               </td>
               <td class="control-cell">
-                <paper-button on-tap="onSetAsSourceTap"
+                <cr-button on-click="onSetAsSourceClick"
+                    class$="[[cssClassForSetAsSource_(item,
+                        selectedPowerSourceId)]]"
                     hidden$="[[!isDualRole(item)]]"
-                    raised="[[!isSelectedSource(item, selectedPowerSourceId)]]"
                     disabled="[[!canBecomeSource(
                         item, selectedPowerSourceId, powerSourceOptions.*)]]">
                   Set as source
-                </paper-button>
+                </cr-button>
                 <div hidden$="[[isDualRole(item)]]">Source</div>
               </td>
               <td class="control-cell">
diff --git a/chrome/browser/resources/chromeos/emulator/battery_settings.js b/chrome/browser/resources/chromeos/emulator/battery_settings.js
index 65801e78..c913283 100644
--- a/chrome/browser/resources/chromeos/emulator/battery_settings.js
+++ b/chrome/browser/resources/chromeos/emulator/battery_settings.js
@@ -136,7 +136,11 @@
       chrome.send('updateBatteryPercent', [this.percent]);
   },
 
-  onSetAsSourceTap: function(e) {
+  /**
+   * @param {!{model: {item: {id: string}}}} e
+   * @private
+   */
+  onSetAsSourceClick_: function(e) {
     chrome.send('updatePowerSourceId', [e.model.item.id]);
   },
 
@@ -189,8 +193,13 @@
     return source.type == 'DualRoleUSB';
   },
 
-  isSelectedSource: function(source) {
-    return source.id == this.selectedPowerSourceId;
+  /**
+   * @param {!{id: string}} source
+   * @return {string}
+   * @private
+   */
+  cssClassForSetAsSource_: function(source) {
+    return source.id == this.selectedPowerSourceId ? '' : 'action-button';
   },
 
   canAmpsChange: function(type) {
diff --git a/chrome/browser/resources/chromeos/emulator/bluetooth_settings.html b/chrome/browser/resources/chromeos/emulator/bluetooth_settings.html
index 59142a23..00e1c009 100644
--- a/chrome/browser/resources/chromeos/emulator/bluetooth_settings.html
+++ b/chrome/browser/resources/chromeos/emulator/bluetooth_settings.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
@@ -8,7 +9,6 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_radio_group/cr_radio_group.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="icons.html">
 <link rel="import" href="shared_styles.html">
 
@@ -94,9 +94,9 @@
         </form>
       </div>
       <div slot="button-container">
-        <paper-button class="action-button" on-tap="onCloseTap_">
+        <cr-button class="action-button" on-click="onCloseClick_">
           Close
-        </paper-button>
+        </cr-button>
       </div>
     </cr-dialog>
 
@@ -167,9 +167,9 @@
         </tbody>
       </table>
       <div class="add-device-container">
-        <paper-button on-click="appendNewDevice">
+        <cr-button on-click="appendNewDevice">
           Add Device
-        </paper-button>
+        </cr-button>
       </div>
     </div>
   </template>
diff --git a/chrome/browser/resources/chromeos/emulator/bluetooth_settings.js b/chrome/browser/resources/chromeos/emulator/bluetooth_settings.js
index 4bcda58..1c36a83 100644
--- a/chrome/browser/resources/chromeos/emulator/bluetooth_settings.js
+++ b/chrome/browser/resources/chromeos/emulator/bluetooth_settings.js
@@ -475,7 +475,7 @@
   },
 
   /** @private */
-  onCloseTap_: function() {
+  onCloseClick_: function() {
     this.$.editDialog.close();
   },
 
diff --git a/chrome/browser/resources/chromeos/emulator/device_emulator_pages.html b/chrome/browser/resources/chromeos/emulator/device_emulator_pages.html
index 7727008..9b0123d 100644
--- a/chrome/browser/resources/chromeos/emulator/device_emulator_pages.html
+++ b/chrome/browser/resources/chromeos/emulator/device_emulator_pages.html
@@ -69,7 +69,7 @@
     <cr-toolbar page-name="Device Emulator"
         clear-label="clear"
         search-prompt="Search not working..."
-        on-cr-toolbar-menu-tap="onMenuButtonTap_"
+        on-cr-toolbar-menu-tap="onMenuButtonClick_"
         menu-label="Device Emulator"
         role="banner"
         show-menu>
diff --git a/chrome/browser/resources/chromeos/emulator/device_emulator_pages.js b/chrome/browser/resources/chromeos/emulator/device_emulator_pages.js
index 1411f5b..64fad29 100644
--- a/chrome/browser/resources/chromeos/emulator/device_emulator_pages.js
+++ b/chrome/browser/resources/chromeos/emulator/device_emulator_pages.js
@@ -28,7 +28,7 @@
   },
 
   /** @private */
-  onMenuButtonTap_: function() {
+  onMenuButtonClick_: function() {
     this.$.drawer.toggle();
   },
 
diff --git a/chrome/browser/resources/chromeos/emulator/shared_styles.html b/chrome/browser/resources/chromeos/emulator/shared_styles.html
index fcbec934..e49712f 100644
--- a/chrome/browser/resources/chromeos/emulator/shared_styles.html
+++ b/chrome/browser/resources/chromeos/emulator/shared_styles.html
@@ -107,7 +107,7 @@
         text-align: end;
       }
 
-      .add-device-container paper-button {
+      .add-device-container cr-button {
         color: rgb(82, 101, 162);
       }
     </style>
diff --git a/chrome/browser/resources/chromeos/zip_archiver/html/passphrase-dialog.html b/chrome/browser/resources/chromeos/zip_archiver/html/passphrase-dialog.html
index f697e84..93928ae4 100644
--- a/chrome/browser/resources/chromeos/zip_archiver/html/passphrase-dialog.html
+++ b/chrome/browser/resources/chromeos/zip_archiver/html/passphrase-dialog.html
@@ -1,14 +1,13 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
-<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 
 <dom-module id="passphrase-dialog">
   <template>
-    <style include="paper-button-style">
+    <style>
       cr-input,
-      paper-button {
+      cr-button {
         -webkit-app-region: no-drag;
       }
 
@@ -42,7 +41,7 @@
         text-overflow: ellipsis;
       }
 
-      paper-button + paper-button {
+      cr-button + cr-button {
         margin-inline-start: 8px;
       }
     </style>
@@ -53,15 +52,12 @@
               i18n-values="placeholder:ZIP_ARCHIVER_PASSPHRASE_INPUT_LABEL;aria-label:ZIP_ARCHIVER_PASSPHRASE_INPUT_LABEL">
     </cr-input>
     <div id="buttons">
-      <paper-button on-click="cancel"
-                    id="cancelButton"
-                    i18n-content="ZIP_ARCHIVER_PASSPHRASE_CANCEL">
-      </paper-button>
-      <paper-button class="action-button"
-                    on-click="accept"
-                    id="acceptButton"
-                    i18n-content="ZIP_ARCHIVER_PASSPHRASE_ACCEPT">
-      </paper-button>
+      <cr-button on-click="cancel" id="cancelButton"
+          i18n-content="ZIP_ARCHIVER_PASSPHRASE_CANCEL">
+      </cr-button>
+      <cr-button class="action-button" on-click="accept" id="acceptButton"
+          i18n-content="ZIP_ARCHIVER_PASSPHRASE_ACCEPT">
+      </cr-button>
     </div>
   </template>
 </dom-module>
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js
index 8104e15..be6258e 100644
--- a/chrome/browser/resources/local_ntp/customize.js
+++ b/chrome/browser/resources/local_ntp/customize.js
@@ -82,6 +82,7 @@
   BACKGROUNDS_IMAGE_MENU: 'backgrounds-image-menu',
   BACKGROUNDS_MENU: 'backgrounds-menu',
   BACKGROUNDS_UPLOAD: 'backgrounds-upload',
+  BACKGROUNDS_UPLOAD_WRAPPER: 'backgrounds-upload-wrapper',
   CANCEL: 'bg-sel-footer-cancel',
   COLORS_BUTTON: 'colors-button',
   COLORS_MENU: 'colors-menu',
@@ -457,13 +458,48 @@
   return 3;
 };
 
+/**
+ * @param {number} deltaX Change in the x direction.
+ * @param {number} deltaY Change in the y direction.
+ * @param {Element} current The current tile.
+ */
+customize.richerPicker_getNextTile = function(deltaX, deltaY, current) {
+  const menu = $(customize.IDS.CUSTOMIZATION_MENU);
+  const container = menu.classList.contains(customize.CLASSES.ON_IMAGE_MENU) ?
+      $(customize.IDS.BACKGROUNDS_IMAGE_MENU) :
+      $(customize.IDS.BACKGROUNDS_MENU);
+  const tiles = Array.from(
+      container.getElementsByClassName(customize.CLASSES.COLLECTION_TILE));
+  const curIndex = tiles.indexOf(current);
+  if (deltaX != 0) {
+    return tiles[curIndex + deltaX];
+  } else if (deltaY != 0) {
+    let nextIndex = tiles.indexOf(current);
+    const startingTop = current.getBoundingClientRect().top;
+    const startingLeft = current.getBoundingClientRect().left;
+
+    // Search until a tile in a different row and the same column is found.
+    while (tiles[nextIndex] &&
+           (tiles[nextIndex].getBoundingClientRect().top == startingTop ||
+            tiles[nextIndex].getBoundingClientRect().left != startingLeft)) {
+      nextIndex += deltaY;
+    }
+    return tiles[nextIndex];
+  }
+  return null;
+};
+
 /* Get the next tile when the arrow keys are used to navigate the grid.
  * Returns null if the tile doesn't exist.
  * @param {number} deltaX Change in the x direction.
  * @param {number} deltaY Change in the y direction.
- * @param {string} current Number of the current tile.
+ * @param {Element} currentElem The current tile.
  */
-customize.getNextTile = function(deltaX, deltaY, current) {
+customize.getNextTile = function(deltaX, deltaY, currentElem) {
+  if (configData.richerPicker) {
+    return customize.richerPicker_getNextTile(deltaX, deltaY, currentElem);
+  }
+  const current = currentElem.dataset.tileNum;
   let idPrefix = 'coll_tile_';
   if ($(customize.IDS.MENU)
           .classList.contains(customize.CLASSES.IMAGE_DIALOG)) {
@@ -576,6 +612,10 @@
     if (event.keyCode === customize.KEYCODES.ENTER) {
       event.preventDefault();
       event.stopPropagation();
+      if (event.currentTarget.onClickOverride) {
+        event.currentTarget.onClickOverride(event);
+        return;
+      }
       tileOnClickInteraction(event);
     } else if (
         event.keyCode === customize.KEYCODES.LEFT ||
@@ -590,17 +630,15 @@
       if (event.keyCode === customize.KEYCODES.LEFT) {
         target = customize.getNextTile(
             document.documentElement.classList.contains('rtl') ? 1 : -1, 0,
-            event.currentTarget.dataset.tileNum);
+            event.currentTarget);
       } else if (event.keyCode === customize.KEYCODES.UP) {
-        target =
-            customize.getNextTile(0, -1, event.currentTarget.dataset.tileNum);
+        target = customize.getNextTile(0, -1, event.currentTarget);
       } else if (event.keyCode === customize.KEYCODES.RIGHT) {
         target = customize.getNextTile(
             document.documentElement.classList.contains('rtl') ? -1 : 1, 0,
-            event.currentTarget.dataset.tileNum);
+            event.currentTarget);
       } else if (event.keyCode === customize.KEYCODES.DOWN) {
-        target =
-            customize.getNextTile(0, 1, event.currentTarget.dataset.tileNum);
+        target = customize.getNextTile(0, 1, event.currentTarget);
       }
       if (target) {
         target.focus();
@@ -623,6 +661,16 @@
     tileContainer.appendChild(tile);
   }
 
+  // Attach event listeners for upload and default tiles
+  $(customize.IDS.BACKGROUNDS_UPLOAD_WRAPPER).onkeydown =
+      tileOnKeyDownInteraction;
+  $(customize.IDS.BACKGROUNDS_DEFAULT_ICON).onkeydown =
+      tileOnKeyDownInteraction;
+  $(customize.IDS.BACKGROUNDS_UPLOAD_WRAPPER).onClickOverride =
+      $(customize.IDS.BACKGROUNDS_UPLOAD).onkeydown;
+  $(customize.IDS.BACKGROUNDS_DEFAULT_ICON).onClickOverride =
+      $(customize.IDS.BACKGROUNDS_DEFAULT).onkeydown;
+
   $(customize.IDS.TILES).focus();
 };
 
@@ -810,17 +858,15 @@
       if (event.keyCode == customize.KEYCODES.LEFT) {
         target = customize.getNextTile(
             document.documentElement.classList.contains('rtl') ? 1 : -1, 0,
-            event.currentTarget.dataset.tileNum);
+            event.currentTarget);
       } else if (event.keyCode == customize.KEYCODES.UP) {
-        target =
-            customize.getNextTile(0, -1, event.currentTarget.dataset.tileNum);
+        target = customize.getNextTile(0, -1, event.currentTarget);
       } else if (event.keyCode == customize.KEYCODES.RIGHT) {
         target = customize.getNextTile(
             document.documentElement.classList.contains('rtl') ? -1 : 1, 0,
-            event.currentTarget.dataset.tileNum);
+            event.currentTarget);
       } else if (event.keyCode == customize.KEYCODES.DOWN) {
-        target =
-            customize.getNextTile(0, 1, event.currentTarget.dataset.tileNum);
+        target = customize.getNextTile(0, 1, event.currentTarget);
       }
       if (target) {
         target.focus();
@@ -1382,6 +1428,12 @@
       backInteraction(event);
     }
   };
+  $(customize.IDS.MENU_BACK_CIRCLE).onkeyup = function(event) {
+    if (event.keyCode === customize.KEYCODES.ENTER ||
+        event.keyCode === customize.KEYCODES.SPACE) {
+      backInteraction(event);
+    }
+  };
   // Pressing Spacebar on the back arrow shouldn't scroll the dialog.
   $(customize.IDS.BACK_CIRCLE).onkeydown = function(event) {
     if (event.keyCode === customize.KEYCODES.SPACE) {
@@ -1441,6 +1493,24 @@
     }
   };
 
+  $(customize.IDS.BACKGROUNDS_MENU).onkeydown = function(event) {
+    if (event.keyCode === customize.KEYCODES.LEFT ||
+        event.keyCode === customize.KEYCODES.UP ||
+        event.keyCode === customize.KEYCODES.RIGHT ||
+        event.keyCode === customize.KEYCODES.DOWN) {
+      $(customize.IDS.BACKGROUNDS_UPLOAD_WRAPPER).focus();
+    }
+  };
+
+  $(customize.IDS.BACKGROUNDS_IMAGE_MENU).onkeydown = function(event) {
+    if (event.keyCode === customize.KEYCODES.LEFT ||
+        event.keyCode === customize.KEYCODES.UP ||
+        event.keyCode === customize.KEYCODES.RIGHT ||
+        event.keyCode === customize.KEYCODES.DOWN) {
+      $('img_tile_0').focus();
+    }
+  };
+
   $(customize.IDS.BACKGROUNDS_UPLOAD).onclick = uploadImageInteraction;
   $(customize.IDS.BACKGROUNDS_UPLOAD).onkeydown = function(event) {
     if (event.keyCode === customize.KEYCODES.ENTER ||
@@ -1449,7 +1519,7 @@
     }
   };
 
-  $(customize.IDS.BACKGROUNDS_DEFAULT).onclick = function() {
+  $(customize.IDS.BACKGROUNDS_DEFAULT).onclick = function(event) {
     const tile = $(customize.IDS.BACKGROUNDS_DEFAULT_ICON);
     tile.dataset.url = '';
     tile.dataset.attributionLine1 = '';
@@ -1457,6 +1527,12 @@
     tile.dataset.attributionActionUrl = '';
     customize.richerPicker_selectTile(tile);
   };
+  $(customize.IDS.BACKGROUNDS_DEFAULT).onkeydown = function(event) {
+    if (event.keyCode === customize.KEYCODES.ENTER ||
+        event.keyCode === customize.KEYCODES.SPACE) {
+      $(customize.IDS.BACKGROUNDS_DEFAULT).onclick(event);
+    }
+  };
 
   const richerPickerOpenBackgrounds = function() {
     customize.richerPicker_resetCustomizationMenu();
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 82b5da24..dbbd9eb 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -1030,11 +1030,16 @@
   width: 144px;
 }
 
+#backgrounds-menu .bg-sel-tile-bg.selected .bg-sel-tile:focus,
 #backgrounds-image-menu .bg-sel-tile-bg.selected .bg-sel-tile:focus,
 #colors-menu .bg-sel-tile-bg.selected .bg-sel-tile:focus {
   outline: none;
 }
 
+.using-mouse-nav .bg-sel-tile:focus {
+  outline: none;
+}
+
 #backgrounds-menu .bg-sel-tile,
 #backgrounds-image-menu .bg-sel-tile,
 #colors-menu .bg-sel-tile {
@@ -1142,6 +1147,14 @@
   transform: scaleX(-1);
 }
 
+#backgrounds-upload-wrapper {
+  display: inline-block;
+  left: 0;
+  opacity: 1;
+  position: relative;
+  top: 0;
+}
+
 #backgrounds-upload-icon {
   -webkit-mask-image: url(icons/upload.svg);
   -webkit-mask-repeat: no-repeat;
diff --git a/chrome/browser/resources/local_ntp/local_ntp.html b/chrome/browser/resources/local_ntp/local_ntp.html
index 3f67324..adb3f36 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.html
+++ b/chrome/browser/resources/local_ntp/local_ntp.html
@@ -172,7 +172,7 @@
   <dialog id="customization-menu" class="customize-dialog">
     <div id="menu-header">
       <div id="menu-back-wrapper">
-        <div id="menu-back-circle" tabindex="0">
+        <div id="menu-back-circle" tabindex="0" role="button">
           <div id="menu-back"></div>
         </div>
       </div>
@@ -201,22 +201,24 @@
       </div>
     </div>
     <div id="menu-contents">
-      <div id="backgrounds-menu" class="menu-panel">
+      <div id="backgrounds-menu" class="menu-panel" tabindex="0">
         <div id="backgrounds-upload" class="bg-sel-tile-bg">
-          <div id="backgrounds-upload-icon"></div>
-          <div id="backgrounds-upload-text">$i18n{uploadImage}</div>
+          <div id="backgrounds-upload-wrapper" class="bg-sel-tile" tabindex="-1">
+            <div id="backgrounds-upload-icon"></div>
+            <div id="backgrounds-upload-text">$i18n{uploadImage}</div>
+          </div>
         </div>
         <div id="backgrounds-default" class="bg-sel-tile-bg">
-          <div id="backgrounds-default-icon" class="bg-sel-tile">
+          <div id="backgrounds-default-icon" class="bg-sel-tile" tabindex="-1">
             <div class="mini-page">
               <div class="mini-header"></div>
               <div class="mini-shortcuts"></div>
             </div>
           </div>
           <div class="bg-sel-tile-title">$i18n{noBackground}</div>
-        </div>
+          </div>
       </div>
-      <div id="backgrounds-image-menu" class="menu-panel"></div>
+      <div id="backgrounds-image-menu" class="menu-panel" tabindex="0"></div>
       <div id="shortcuts-menu" class="menu-panel">
         <div id="sh-options">
           <div class="sh-option">
diff --git a/chrome/browser/resources/ntp4/images/2x/disclosure_triangle_mask.png b/chrome/browser/resources/ntp4/images/2x/disclosure_triangle_mask.png
deleted file mode 100644
index 72b4f2b..0000000
--- a/chrome/browser/resources/ntp4/images/2x/disclosure_triangle_mask.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/ntp4/images/disclosure_triangle_mask.png b/chrome/browser/resources/ntp4/images/disclosure_triangle_mask.png
deleted file mode 100644
index 7b70a3e..0000000
--- a/chrome/browser/resources/ntp4/images/disclosure_triangle_mask.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index afda4e4..b6d133f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -85,6 +85,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/no_renderer_crashes_assertion.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "crypto/sha2.h"
 #include "net/cookies/cookie_util.h"
@@ -1267,6 +1268,12 @@
   V4SafeBrowsingServiceMetadataTest() {}
 
  private:
+#if defined(ADDRESS_SANITIZER)
+  // TODO(lukasza): https://crbug.com/971820: Disallow renderer crashes once the
+  // bug is fixed.
+  content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(V4SafeBrowsingServiceMetadataTest);
 };
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 067e1db..376c5c6 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3080,7 +3080,6 @@
       "//components/payments/core",
       "//components/ui_devtools/views",
       "//device/vr/buildflags:buildflags",
-      "//services/ws/public/cpp/input_devices",
       "//ui/views:buildflags",
     ]
 
@@ -3173,6 +3172,7 @@
         "views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.cc",
         "views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h",
       ]
+      deps += [ "//ui/ozone" ]
     } else {
       sources += [
         "views/frame/opaque_browser_frame_view.cc",
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index f108f5b..4771a2d4 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
-#include "services/ws/public/cpp/input_devices/input_device_controller_client.h"
 #include "ui/aura/window.h"
 #include "url/gurl.h"
 
@@ -62,8 +61,3 @@
 ChromeShellDelegate::CreateScreenshotDelegate() {
   return std::make_unique<ChromeScreenshotGrabber>();
 }
-
-ws::InputDeviceControllerClient*
-ChromeShellDelegate::GetInputDeviceControllerClient() {
-  return g_browser_process->platform_part()->GetInputDeviceControllerClient();
-}
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index 6f0f743..75df60f 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -18,7 +18,6 @@
   std::unique_ptr<ash::ScreenshotDelegate> CreateScreenshotDelegate() override;
   ash::AccessibilityDelegate* CreateAccessibilityDelegate() override;
   void OpenKeyboardShortcutHelpPage() const override;
-  ws::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ChromeShellDelegate);
diff --git a/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.cc b/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.cc
index 616c0c54..3bf14a9 100644
--- a/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.cc
+++ b/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.cc
@@ -88,24 +88,16 @@
   keyboard_controller_->AddObserver(this);
 
   // Request the initial enabled state.
-  keyboard_controller_->IsKeyboardEnabled(
-      base::BindOnce(&ChromeKeyboardControllerClient::OnKeyboardEnabledChanged,
-                     weak_ptr_factory_.GetWeakPtr()));
+  OnKeyboardEnabledChanged(keyboard_controller_->IsKeyboardEnabled());
 
   // Request the initial set of enable flags.
-  keyboard_controller_->GetEnableFlags(base::BindOnce(
-      &ChromeKeyboardControllerClient::OnKeyboardEnableFlagsChanged,
-      weak_ptr_factory_.GetWeakPtr()));
+  OnKeyboardEnableFlagsChanged(keyboard_controller_->GetEnableFlags());
 
   // Request the initial visible state.
-  keyboard_controller_->IsKeyboardVisible(base::BindOnce(
-      &ChromeKeyboardControllerClient::OnKeyboardVisibilityChanged,
-      weak_ptr_factory_.GetWeakPtr()));
+  OnKeyboardVisibilityChanged(keyboard_controller_->IsKeyboardVisible());
 
   // Request the configuration.
-  keyboard_controller_->GetKeyboardConfig(
-      base::BindOnce(&ChromeKeyboardControllerClient::OnKeyboardConfigChanged,
-                     weak_ptr_factory_.GetWeakPtr()));
+  OnKeyboardConfigChanged(keyboard_controller_->GetKeyboardConfig());
 }
 
 ChromeKeyboardControllerClient::~ChromeKeyboardControllerClient() {
@@ -164,9 +156,8 @@
   keyboard_controller_->SetKeyboardConfig(config);
 }
 
-void ChromeKeyboardControllerClient::GetKeyboardEnabled(
-    base::OnceCallback<void(bool)> callback) {
-  keyboard_controller_->IsKeyboardEnabled(std::move(callback));
+bool ChromeKeyboardControllerClient::GetKeyboardEnabled() {
+  return keyboard_controller_->IsKeyboardEnabled();
 }
 
 void ChromeKeyboardControllerClient::SetEnableFlag(
@@ -264,9 +255,8 @@
 }
 
 void ChromeKeyboardControllerClient::OnKeyboardEnableFlagsChanged(
-    const std::vector<keyboard::KeyboardEnableFlag>& flags) {
-  keyboard_enable_flags_ =
-      std::set<keyboard::KeyboardEnableFlag>(flags.begin(), flags.end());
+    const std::set<keyboard::KeyboardEnableFlag>& flags) {
+  keyboard_enable_flags_ = flags;
 }
 
 void ChromeKeyboardControllerClient::OnKeyboardEnabledChanged(bool enabled) {
diff --git a/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h b/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h
index 49be1af..0f5200ea 100644
--- a/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h
+++ b/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h
@@ -11,6 +11,7 @@
 
 #include "ash/public/cpp/keyboard/keyboard_config.h"
 #include "ash/public/cpp/keyboard/keyboard_controller.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -92,9 +93,9 @@
   // Sets the new keyboard configuration and updates the cached config.
   void SetKeyboardConfig(const keyboard::KeyboardConfig& config);
 
-  // Invokes |callback| with the current enabled state. Call this after
-  // Set/ClearEnableFlag to get the updated enabled state.
-  void GetKeyboardEnabled(base::OnceCallback<void(bool)> callback);
+  // Returns the current enabled state. Call this after Set/ClearEnableFlag to
+  // get the updated enabled state.
+  bool GetKeyboardEnabled();
 
   // Sets/clears the privided keyboard enable state.
   void SetEnableFlag(const keyboard::KeyboardEnableFlag& flag);
@@ -143,7 +144,7 @@
 
   // ash::KeyboardControllerObserver:
   void OnKeyboardEnableFlagsChanged(
-      const std::vector<keyboard::KeyboardEnableFlag>& flags) override;
+      const std::set<keyboard::KeyboardEnableFlag>& flags) override;
   void OnKeyboardEnabledChanged(bool enabled) override;
   void OnKeyboardConfigChanged(const keyboard::KeyboardConfig& config) override;
   void OnKeyboardVisibilityChanged(bool visible) override;
diff --git a/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client_test_helper.cc b/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client_test_helper.cc
index 0d0a0130..eb48b68 100644
--- a/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client_test_helper.cc
+++ b/chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client_test_helper.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client_test_helper.h"
 
 #include <set>
+#include <utility>
+#include <vector>
 
 #include "ash/keyboard/ash_keyboard_controller.h"
 #include "ash/public/cpp/keyboard/keyboard_controller.h"
@@ -23,30 +25,26 @@
 
   // ash::KeyboardController:
   void KeyboardContentsLoaded(const gfx::Size& size) override {}
-  void GetKeyboardConfig(GetKeyboardConfigCallback callback) override {
-    std::move(callback).Run(keyboard_config_);
+  keyboard::KeyboardConfig GetKeyboardConfig() override {
+    return keyboard_config_;
   }
   void SetKeyboardConfig(
       const keyboard::KeyboardConfig& keyboard_config) override {
     keyboard_config_ = keyboard_config;
   }
-  void IsKeyboardEnabled(IsKeyboardEnabledCallback callback) override {
-    std::move(callback).Run(enabled_);
-  }
+  bool IsKeyboardEnabled() override { return enabled_; }
   void SetEnableFlag(keyboard::KeyboardEnableFlag flag) override {
     keyboard_enable_flags_.insert(flag);
   }
   void ClearEnableFlag(keyboard::KeyboardEnableFlag flag) override {
     keyboard_enable_flags_.erase(flag);
   }
-  void GetEnableFlags(GetEnableFlagsCallback callback) override {
-    std::move(callback).Run(std::vector<keyboard::KeyboardEnableFlag>());
+  const std::set<keyboard::KeyboardEnableFlag>& GetEnableFlags() override {
+    return keyboard_enable_flags_;
   }
   void ReloadKeyboardIfNeeded() override {}
   void RebuildKeyboardIfEnabled() override {}
-  void IsKeyboardVisible(IsKeyboardVisibleCallback callback) override {
-    std::move(callback).Run(visible_);
-  }
+  bool IsKeyboardVisible() override { return visible_; }
   void ShowKeyboard() override { visible_ = true; }
   void HideKeyboard(ash::HideReason reason) override { visible_ = false; }
   void SetContainerType(keyboard::ContainerType container_type,
diff --git a/chrome/browser/ui/ash/session_controller_client_impl_unittest.cc b/chrome/browser/ui/ash/session_controller_client_impl_unittest.cc
index 123708c..f4fccdd9 100644
--- a/chrome/browser/ui/ash/session_controller_client_impl_unittest.cc
+++ b/chrome/browser/ui/ash/session_controller_client_impl_unittest.cc
@@ -38,7 +38,6 @@
 #include "net/cert/x509_certificate.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
-#include "services/network/cert_verifier_with_trust_anchors.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using chromeos::FakeChromeUserManager;
@@ -49,16 +48,10 @@
 constexpr char kUser[] = "user@test.com";
 constexpr char kUserGaiaId[] = "0123456789";
 
-// Weak ptr to network::CertVerifierWithTrustAnchors - object is freed in test
-// destructor once we've ensured the profile has been shut down.
-network::CertVerifierWithTrustAnchors* g_policy_cert_verifier_for_factory =
-    nullptr;
-
 std::unique_ptr<KeyedService> CreateTestPolicyCertService(
     content::BrowserContext* context) {
   return policy::PolicyCertService::CreateForTesting(
-      kUser, g_policy_cert_verifier_for_factory,
-      user_manager::UserManager::Get());
+      kUser, user_manager::UserManager::Get());
 }
 
 // A user manager that does not set profiles as loaded and notifies observers
@@ -130,8 +123,6 @@
   void TearDown() override {
     user_manager_enabler_.reset();
     user_manager_ = nullptr;
-    // Clear our cached pointer to the network::CertVerifierWithTrustAnchors.
-    g_policy_cert_verifier_for_factory = nullptr;
     profile_manager_.reset();
 
     // We must ensure that the network::CertVerifierWithTrustAnchors outlives
@@ -191,7 +182,6 @@
 
   content::TestBrowserThreadBundle threads_;
   content::TestServiceManagerContext context_;
-  std::unique_ptr<network::CertVerifierWithTrustAnchors> cert_verifier_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
   session_manager::SessionManager session_manager_;
 
@@ -314,9 +304,6 @@
   user_manager()->LoginUser(account_id);
   EXPECT_EQ(ash::AddUserSessionPolicy::ALLOWED,
             SessionControllerClientImpl::GetAddUserSessionPolicy());
-  cert_verifier_.reset(
-      new network::CertVerifierWithTrustAnchors(base::Closure()));
-  g_policy_cert_verifier_for_factory = cert_verifier_.get();
   ASSERT_TRUE(
       policy::PolicyCertServiceFactory::GetInstance()->SetTestingFactoryAndUse(
           user_profile, base::BindRepeating(&CreateTestPolicyCertService)));
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index c9813f6..18db3e5 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -2044,6 +2044,10 @@
       }
     }
   }
+
+  // If an extension page was active, the toolbar may need to be updated to hide
+  // the extension name in the location icon.
+  UpdateToolbar(/*should_restore_state=*/false);
 }
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 55e9bf8..6a5dec3 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -1331,7 +1331,8 @@
 void CreateBookmarkAppFromCurrentWebContents(Browser* browser,
                                              bool force_shortcut_app) {
   base::RecordAction(UserMetricsAction("CreateHostedApp"));
-  web_app::CreateWebAppFromCurrentWebContents(browser, force_shortcut_app);
+  web_app::CreateWebAppFromCurrentWebContents(browser, force_shortcut_app,
+                                              base::DoNothing());
 }
 
 bool CanCreateBookmarkApp(const Browser* browser) {
diff --git a/chrome/browser/ui/cocoa/color_chooser_mac.h b/chrome/browser/ui/cocoa/color_chooser_mac.h
index 9dbcc9f..64da207 100644
--- a/chrome/browser/ui/cocoa/color_chooser_mac.h
+++ b/chrome/browser/ui/cocoa/color_chooser_mac.h
@@ -8,35 +8,13 @@
 #import <Cocoa/Cocoa.h>
 
 #import "base/mac/scoped_nsobject.h"
+#include "components/remote_cocoa/common/color_panel.mojom.h"
 #include "content/public/browser/color_chooser.h"
 #include "content/public/browser/web_contents.h"
+#include "mojo/public/cpp/bindings/binding.h"
 
-class ColorChooserMac;
-
-// A Listener class to act as a event target for NSColorPanel and send
-// the results to the C++ class, ColorChooserMac.
-@interface ColorPanelCocoa : NSObject {
- @protected
-  // We don't call DidChooseColor if the change wasn't caused by the user
-  // interacting with the panel.
-  BOOL nonUserChange_;
- @private
-  ColorChooserMac* chooser_;  // weak, owns this
-}
-
-- (id)initWithChooser:(ColorChooserMac*)chooser;
-
-- (void)windowWillClose:(NSNotification*)notification;
-
-// Called from NSColorPanel.
-- (void)didChooseColor:(NSColorPanel*)panel;
-
-// Sets color to the NSColorPanel as a non user change.
-- (void)setColor:(NSColor*)color;
-
-@end
-
-class ColorChooserMac : public content::ColorChooser {
+class ColorChooserMac : public content::ColorChooser,
+                        public remote_cocoa::mojom::ColorPanelHost {
  public:
   // Returns a ColorChooserMac instance owned by the ColorChooserMac class -
   // call End() when done to free it. Each call to Open() returns a new
@@ -45,28 +23,25 @@
   static ColorChooserMac* Open(content::WebContents* web_contents,
                                SkColor initial_color);
 
-  // Called from ColorPanelCocoa.
-  void DidChooseColorInColorPanel(SkColor color);
-  void DidCloseColorPanel();
-
-  // Set the color programmatically.
+  // content::ColorChooser.
   void SetSelectedColor(SkColor color) override;
-
-  // Call when done with the ColorChooserMac.
   void End() override;
 
  private:
+  // remote_cocoa::mojom::ColorPanelHost.
+  void DidChooseColorInColorPanel(SkColor color) override;
+  void DidCloseColorPanel() override;
+
   ColorChooserMac(content::WebContents* tab, SkColor initial_color);
 
   ~ColorChooserMac() override;
 
-  static ColorChooserMac* current_color_chooser_;
-
   // The web contents invoking the color chooser.  No ownership because it will
   // outlive this class.
   content::WebContents* web_contents_;
-  base::scoped_nsobject<ColorPanelCocoa> panel_;
 
+  remote_cocoa::mojom::ColorPanelPtr mojo_panel_ptr_;
+  mojo::Binding<remote_cocoa::mojom::ColorPanelHost> mojo_host_binding_;
   DISALLOW_COPY_AND_ASSIGN(ColorChooserMac);
 };
 
diff --git a/chrome/browser/ui/cocoa/color_chooser_mac.mm b/chrome/browser/ui/cocoa/color_chooser_mac.mm
index e7cdab7a2..fca16f9 100644
--- a/chrome/browser/ui/cocoa/color_chooser_mac.mm
+++ b/chrome/browser/ui/cocoa/color_chooser_mac.mm
@@ -6,150 +6,79 @@
 
 #include "base/logging.h"
 #include "chrome/browser/ui/color_chooser.h"
+#include "components/remote_cocoa/app_shim/color_panel_bridge.h"
+#include "components/remote_cocoa/browser/application_host.h"
+#include "components/remote_cocoa/browser/window.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "skia/ext/skia_utils_mac.h"
 
-ColorChooserMac* ColorChooserMac::current_color_chooser_ = NULL;
+namespace {
+// The currently active color chooser.
+ColorChooserMac* g_current_color_chooser = nullptr;
+}  // namespace
 
 // static
 ColorChooserMac* ColorChooserMac::Open(content::WebContents* web_contents,
                                        SkColor initial_color) {
-  if (current_color_chooser_)
-    current_color_chooser_->End();
-  DCHECK(!current_color_chooser_);
-  current_color_chooser_ =
-      new ColorChooserMac(web_contents, initial_color);
-  return current_color_chooser_;
+  if (g_current_color_chooser)
+    g_current_color_chooser->End();
+  DCHECK(!g_current_color_chooser);
+  // Note that WebContentsImpl::ColorChooser ultimately takes ownership (and
+  // deletes) the returned pointer.
+  g_current_color_chooser = new ColorChooserMac(web_contents, initial_color);
+  return g_current_color_chooser;
 }
 
 ColorChooserMac::ColorChooserMac(content::WebContents* web_contents,
                                  SkColor initial_color)
-    : web_contents_(web_contents) {
-  panel_.reset([[ColorPanelCocoa alloc] initWithChooser:this]);
-  [panel_ setColor:skia::SkColorToDeviceNSColor(initial_color)];
-  [[NSColorPanel sharedColorPanel] makeKeyAndOrderFront:nil];
+    : web_contents_(web_contents), mojo_host_binding_(this) {
+  remote_cocoa::mojom::ColorPanelHostPtr mojo_host_ptr;
+  mojo_host_binding_.Bind(mojo::MakeRequest(&mojo_host_ptr));
+  auto* application_host = remote_cocoa::ApplicationHost::GetForNativeView(
+      web_contents ? web_contents->GetNativeView() : gfx::NativeView());
+  if (application_host) {
+    application_host->GetApplication()->ShowColorPanel(
+        mojo::MakeRequest(&mojo_panel_ptr_), std::move(mojo_host_ptr));
+  } else {
+    mojo::MakeStrongBinding(std::make_unique<remote_cocoa::ColorPanelBridge>(
+                                std::move(mojo_host_ptr)),
+                            mojo::MakeRequest(&mojo_panel_ptr_));
+  }
+  mojo_panel_ptr_->Show(initial_color);
 }
 
 ColorChooserMac::~ColorChooserMac() {
   // Always call End() before destroying.
-  DCHECK(!panel_);
+  DCHECK_NE(g_current_color_chooser, this);
 }
 
 void ColorChooserMac::DidChooseColorInColorPanel(SkColor color) {
+  DCHECK_EQ(g_current_color_chooser, this);
   if (web_contents_)
     web_contents_->DidChooseColorInColorChooser(color);
 }
 
 void ColorChooserMac::DidCloseColorPanel() {
+  DCHECK_EQ(g_current_color_chooser, this);
   End();
 }
 
 void ColorChooserMac::End() {
-  if (panel_) {
-    panel_.reset();
-    DCHECK(current_color_chooser_ == this);
-    current_color_chooser_ = NULL;
+  if (g_current_color_chooser == this) {
+    g_current_color_chooser = nullptr;
     if (web_contents_)
       web_contents_->DidEndColorChooser();
   }
 }
 
 void ColorChooserMac::SetSelectedColor(SkColor color) {
-  [panel_ setColor:skia::SkColorToDeviceNSColor(color)];
-}
-
-@interface NSColorPanel (Private)
-// Private method returning the NSColorPanel's target.
-- (id)__target;
-@end
-
-@implementation ColorPanelCocoa
-
-- (id)initWithChooser:(ColorChooserMac*)chooser {
-  if ((self = [super init])) {
-    chooser_ = chooser;
-    NSColorPanel* panel = [NSColorPanel sharedColorPanel];
-    [panel setShowsAlpha:NO];
-    [panel setTarget:self];
-    [panel setAction:@selector(didChooseColor:)];
-
-    [[NSNotificationCenter defaultCenter]
-        addObserver:self
-           selector:@selector(windowWillClose:)
-               name:NSWindowWillCloseNotification
-             object:panel];
-  }
-  return self;
-}
-
-- (void)dealloc {
-  NSColorPanel* panel = [NSColorPanel sharedColorPanel];
-
-  // On macOS 10.13 the NSColorPanel delegate can apparently get reset to nil
-  // with the target left unchanged. Use the private __target method to see if
-  // the ColorPanelCocoa is still the target.
-  BOOL respondsToPrivateTargetMethod =
-      [panel respondsToSelector:@selector(__target)];
-  if (respondsToPrivateTargetMethod && [panel __target] == self) {
-    [panel setTarget:nil];
-    [panel setAction:nullptr];
-  }
-
-  [[NSNotificationCenter defaultCenter]
-      removeObserver:self
-                name:NSWindowWillCloseNotification
-              object:panel];
-
-  [super dealloc];
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
-  chooser_->DidCloseColorPanel();
-  nonUserChange_ = NO;
-}
-
-- (void)didChooseColor:(NSColorPanel*)panel {
-  if (nonUserChange_) {
-    nonUserChange_ = NO;
-    return;
-  }
-  nonUserChange_ = NO;
-  NSColor* color = [panel color];
-  if ([[color colorSpaceName] isEqualToString:NSNamedColorSpace]) {
-    color = [color colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
-    // Some colors in "Developer" palette in "Color Palettes" tab can't be
-    // converted to RGB. We just ignore such colors.
-    // TODO(tkent): We should notice the rejection to users.
-    if (!color)
-      return;
-  }
-  if ([color colorSpace] == [NSColorSpace genericRGBColorSpace]) {
-    // genericRGB -> deviceRGB conversion isn't ignorable.  We'd like to use RGB
-    // values shown in NSColorPanel UI.
-    CGFloat red, green, blue, alpha;
-    [color getRed:&red green:&green blue:&blue alpha:&alpha];
-    SkColor skColor = SkColorSetARGB(SkScalarRoundToInt(255.0 * alpha),
-                                     SkScalarRoundToInt(255.0 * red),
-                                     SkScalarRoundToInt(255.0 * green),
-                                     SkScalarRoundToInt(255.0 * blue));
-    chooser_->DidChooseColorInColorPanel(skColor);
-  } else {
-    chooser_->DidChooseColorInColorPanel(skia::NSDeviceColorToSkColor(
-        [[panel color] colorUsingColorSpaceName:NSDeviceRGBColorSpace]));
-  }
-}
-
-- (void)setColor:(NSColor*)color {
-  nonUserChange_ = YES;
-  [[NSColorPanel sharedColorPanel] setColor:color];
+  mojo_panel_ptr_->SetSelectedColor(color);
 }
 
 namespace chrome {
-
 content::ColorChooser* ShowColorChooser(content::WebContents* web_contents,
                                         SkColor initial_color) {
   return ColorChooserMac::Open(web_contents, initial_color);
 }
-
 }  // namepace chrome
-
-@end
diff --git a/chrome/browser/ui/cocoa/color_panel_cocoa_unittest.mm b/chrome/browser/ui/cocoa/color_panel_cocoa_unittest.mm
index 823365f..6169e16 100644
--- a/chrome/browser/ui/cocoa/color_panel_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/color_panel_cocoa_unittest.mm
@@ -4,6 +4,8 @@
 
 #import "chrome/browser/ui/cocoa/color_chooser_mac.h"
 
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
 #include "skia/ext/skia_utils_mac.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -26,6 +28,7 @@
     [[NSColorPanel sharedColorPanel] makeKeyAndOrderFront:nil];
     Init();
   }
+  base::test::ScopedTaskEnvironment task_environment_;
 };
 
 TEST_F(ColorPanelCocoaTest, ClearTargetOnEnd) {
@@ -36,6 +39,7 @@
     // Create a ColorPanelCocoa.
     ColorChooserMac* color_chooser_mac =
         ColorChooserMac::Open(nullptr, SK_ColorBLACK);
+    base::RunLoop().RunUntilIdle();
 
     // Confirm the NSColorPanel's configuration by the ColorChooserMac's
     // ColorPanelCocoa.
@@ -44,8 +48,6 @@
     // Release the ColorPanelCocoa.
     color_chooser_mac->End();
   }
-  // Confirm the ColorPanelCocoa is no longer the NSColorPanel's target
-  EXPECT_EQ([nscolor_panel __target], nil);
 }
 
 TEST_F(ColorPanelCocoaTest, SetColor) {
@@ -60,6 +62,7 @@
   SkColor initial_color = SK_ColorBLACK;
   ColorChooserMac* color_chooser_mac =
       ColorChooserMac::Open(nullptr, SK_ColorBLACK);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_NSEQ([nscolor_panel color],
               skia::SkColorToDeviceNSColor(initial_color));
@@ -67,6 +70,7 @@
   // Confirm that -[ColorPanelCocoa setColor:] sets the NSColorPanel's color.
   SkColor test_color = SK_ColorRED;
   color_chooser_mac->SetSelectedColor(test_color);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_NSEQ([nscolor_panel color], skia::SkColorToDeviceNSColor(test_color));
 
diff --git a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
index 6e54b33a..2357156 100644
--- a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
@@ -26,7 +26,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/strings/grit/ui_strings.h"
-#include "ui/views/cocoa/native_widget_mac_ns_window_host.h"
 
 using remote_cocoa::mojom::AlertDisposition;
 
@@ -144,13 +143,8 @@
   // remote_cocoa::ApplicationHost for that window to create the alert.
   // Otherwise create an AlertBridge in-process (but still communicate with it
   // over mojo).
-  auto* bridged_native_widget_host =
-      views::NativeWidgetMacNSWindowHost::GetFromNativeView(
-          dialog_->web_contents()->GetNativeView());
-  remote_cocoa::ApplicationHost* application_host =
-      bridged_native_widget_host
-          ? bridged_native_widget_host->application_host()
-          : nullptr;
+  auto* application_host = remote_cocoa::ApplicationHost::GetForNativeView(
+      dialog_->web_contents()->GetNativeView());
   if (application_host)
     application_host->GetApplication()->CreateAlert(std::move(bridge_request));
   else
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 f09ce779..e2a76c4 100644
--- a/chrome/browser/ui/page_action/page_action_icon_container.h
+++ b/chrome/browser/ui/page_action/page_action_icon_container.h
@@ -26,6 +26,8 @@
   // Signals a page action icon to update its visual state if it is present in
   // the browser window.
   virtual void UpdatePageActionIcon(PageActionIconType type) = 0;
+
+  virtual void ExecutePageActionIconForTesting(PageActionIconType type) = 0;
 };
 
 #endif  // CHROME_BROWSER_UI_PAGE_ACTION_PAGE_ACTION_ICON_CONTAINER_H_
diff --git a/chrome/browser/ui/views/DEPS b/chrome/browser/ui/views/DEPS
index fb12613..0301e1c3 100644
--- a/chrome/browser/ui/views/DEPS
+++ b/chrome/browser/ui/views/DEPS
@@ -1,7 +1,6 @@
 include_rules = [
  "+chrome/browser/ui/views",
  "+chrome/services/app_service/public",
- "+services/ws/public/cpp",
  "+third_party/libaddressinput",
 ]
 
diff --git a/chrome/browser/ui/views/extensions/extension_popup.cc b/chrome/browser/ui/views/extensions/extension_popup.cc
index a97884a..e4c2301 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.cc
+++ b/chrome/browser/ui/views/extensions/extension_popup.cc
@@ -33,7 +33,7 @@
     views::BubbleBorder::Arrow arrow,
     ShowAction show_action) {
   auto* popup =
-      new ExtensionPopup(host.release(), anchor_view, arrow, show_action);
+      new ExtensionPopup(std::move(host), anchor_view, arrow, show_action);
   views::BubbleDialogDelegateView::CreateBubble(popup);
 
 #if defined(USE_AURA)
@@ -168,14 +168,15 @@
     show_action_ = SHOW;
 }
 
-ExtensionPopup::ExtensionPopup(extensions::ExtensionViewHost* host,
-                               views::View* anchor_view,
-                               views::BubbleBorder::Arrow arrow,
-                               ShowAction show_action)
+ExtensionPopup::ExtensionPopup(
+    std::unique_ptr<extensions::ExtensionViewHost> host,
+    views::View* anchor_view,
+    views::BubbleBorder::Arrow arrow,
+    ShowAction show_action)
     : BubbleDialogDelegateView(anchor_view,
                                arrow,
                                views::BubbleBorder::SMALL_SHADOW),
-      host_(host),
+      host_(std::move(host)),
       show_action_(show_action) {
   set_margins(gfx::Insets());
   SetLayoutManager(std::make_unique<views::FillLayout>());
@@ -188,7 +189,7 @@
   // Listen for the containing view calling window.close();
   registrar_.Add(
       this, extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
-      content::Source<content::BrowserContext>(host->browser_context()));
+      content::Source<content::BrowserContext>(host_->browser_context()));
   content::DevToolsAgentHost::AddObserver(this);
   observer_.Add(GetExtensionView()->GetBrowser()->tab_strip_model());
 
diff --git a/chrome/browser/ui/views/extensions/extension_popup.h b/chrome/browser/ui/views/extensions/extension_popup.h
index 342f067..4a3ea77 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.h
+++ b/chrome/browser/ui/views/extensions/extension_popup.h
@@ -108,7 +108,7 @@
       content::DevToolsAgentHost* agent_host) override;
 
  private:
-  ExtensionPopup(extensions::ExtensionViewHost* host,
+  ExtensionPopup(std::unique_ptr<extensions::ExtensionViewHost> host,
                  views::View* anchor_view,
                  views::BubbleBorder::Arrow arrow,
                  ShowAction show_action);
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index ae49232..c90d55c 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1399,17 +1399,12 @@
   }
 
   LocationBarView* location_bar = GetLocationBarView();
-  PageActionIconView* icon_view =
-      (PageActionIconView*)location_bar->send_tab_to_self_icon_view();
   views::View* anchor_view = location_bar;
 
   send_tab_to_self::SendTabToSelfBubbleViewImpl* bubble =
       new send_tab_to_self::SendTabToSelfBubbleViewImpl(
           anchor_view, gfx::Point(), web_contents, controller);
 
-  if (icon_view) {
-    bubble->SetHighlightedButton(icon_view);
-  }
   views::BubbleDialogDelegateView::CreateBubble(bubble);
   bubble->Show(send_tab_to_self::SendTabToSelfBubbleViewImpl::USER_GESTURE);
 
diff --git a/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.cc b/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.cc
index a1072f3f..cf458b30 100644
--- a/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.cc
+++ b/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.cc
@@ -134,6 +134,13 @@
     icon->Update();
 }
 
+void OmniboxPageActionIconContainerView::ExecutePageActionIconForTesting(
+    PageActionIconType type) {
+  PageActionIconView* icon = GetPageActionIconView(type);
+  if (icon)
+    icon->ExecuteForTesting();
+}
+
 bool OmniboxPageActionIconContainerView::
     ActivateFirstInactiveBubbleForAccessibility() {
   for (PageActionIconView* icon : page_action_icons_) {
diff --git a/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h b/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h
index c588322..01496529 100644
--- a/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h
+++ b/chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h
@@ -69,6 +69,7 @@
 
   // PageActionIconContainer:
   void UpdatePageActionIcon(PageActionIconType type) override;
+  void ExecutePageActionIconForTesting(PageActionIconType type) override;
 
  private:
   // views::View:
diff --git a/chrome/browser/ui/views/page_action/pwa_install_view.cc b/chrome/browser/ui/views/page_action/pwa_install_view.cc
index bdaeae717..412fbcf1 100644
--- a/chrome/browser/ui/views/page_action/pwa_install_view.cc
+++ b/chrome/browser/ui/views/page_action/pwa_install_view.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/banners/app_banner_manager.h"
 #include "chrome/browser/installable/installable_metrics.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
+#include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/omnibox/browser/vector_icons.h"
@@ -54,9 +55,20 @@
 
 void PwaInstallView::OnExecuting(PageActionIconView::ExecuteSource source) {
   base::RecordAction(base::UserMetricsAction("PWAInstallIcon"));
-  web_app::CreateWebAppFromManifest(GetWebContents(),
-                                    WebappInstallSource::OMNIBOX_INSTALL_ICON,
-                                    base::DoNothing());
+  content::WebContents* web_contents = GetWebContents();
+  // TODO(https://crbug.com/956810): Make AppBannerManager listen for
+  // installations instead of having to notify it from every installation UI
+  // surface.
+  auto* manager = banners::AppBannerManager::FromWebContents(web_contents);
+  web_app::CreateWebAppFromManifest(
+      web_contents, WebappInstallSource::OMNIBOX_INSTALL_ICON,
+      base::BindOnce(
+          [](base::WeakPtr<banners::AppBannerManager> manager,
+             const web_app::AppId& app_id, web_app::InstallResultCode code) {
+            if (manager && code == web_app::InstallResultCode::kSuccess)
+              manager->OnInstall(false, blink::kWebDisplayModeStandalone);
+          },
+          manager ? manager->GetWeakPtr() : nullptr));
 }
 
 views::BubbleDialogDelegateView* PwaInstallView::GetBubble() const {
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.cc b/chrome/browser/ui/views/payments/editor_view_controller.cc
index bd56d9ff..0ff3199 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/editor_view_controller.cc
@@ -314,6 +314,17 @@
                      kFieldExtraViewHorizontalPadding - long_extra_view_width;
   columns_long->AddPaddingColumn(views::GridLayout::kFixedSize, long_padding);
 
+  // This column set is used for the error label in CreateInputField().
+  views::ColumnSet* columns_error = editor_layout->AddColumnSet(2);
+  columns_error->AddColumn(
+      views::GridLayout::LEADING, views::GridLayout::CENTER,
+      views::GridLayout::kFixedSize, views::GridLayout::FIXED, kLabelWidth, 0);
+  columns_error->AddPaddingColumn(views::GridLayout::kFixedSize,
+                                  kLabelInputFieldHorizontalPadding);
+  columns_error->AddColumn(views::GridLayout::LEADING,
+                           views::GridLayout::CENTER, 1.0,
+                           views::GridLayout::USE_PREF, 0, 0);
+
   views::View* first_field = nullptr;
   for (const auto& field : GetFieldDefinitions()) {
     bool valid = false;
@@ -331,11 +342,12 @@
   // Validate all fields and disable the primary (Done) button if necessary.
   primary_button()->SetEnabled(ValidateInputFields());
 
-  views::ColumnSet* required_field_columns = editor_layout->AddColumnSet(2);
+  views::ColumnSet* required_field_columns = editor_layout->AddColumnSet(3);
   required_field_columns->AddColumn(views::GridLayout::LEADING,
                                     views::GridLayout::CENTER, 1.0,
                                     views::GridLayout::USE_PREF, 0, 0);
-  editor_layout->StartRow(views::GridLayout::kFixedSize, 2);
+  editor_layout->StartRow(views::GridLayout::kFixedSize, 3);
+
   // Adds the "* indicates a required field" label in "hint" grey text.
   editor_layout->AddView(
       CreateHintLabel(
@@ -447,7 +459,7 @@
   if (extra_view)
     layout->AddView(extra_view.release());
 
-  layout->StartRow(views::GridLayout::kFixedSize, column_set);
+  layout->StartRow(views::GridLayout::kFixedSize, 2);
   layout->SkipColumns(1);
   std::unique_ptr<views::View> error_label_view =
       std::make_unique<views::View>();
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.cc
index 32c5b34..d0fd7a9 100644
--- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.cc
+++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.cc
@@ -90,13 +90,16 @@
 
 void SendTabToSelfBubbleViewImpl::Show(DisplayReason reason) {
   ShowForReason(reason);
-  // Keeps the send tab to self icon in omnibox while showing the bubble.
-  BrowserView::GetBrowserViewForBrowser(
-      chrome::FindBrowserWithWebContents(web_contents_))
-      ->toolbar_button_provider()
-      ->GetOmniboxPageActionIconContainerView()
-      ->GetPageActionIconView(PageActionIconType::kSendTabToSelf)
-      ->SetVisible(true);
+  // Keeps the send tab to self icon in omnibox and be highlighted while
+  // showing the bubble.
+  views::Button* highlight_button =
+      BrowserView::GetBrowserViewForBrowser(
+          chrome::FindBrowserWithWebContents(web_contents_))
+          ->toolbar_button_provider()
+          ->GetOmniboxPageActionIconContainerView()
+          ->GetPageActionIconView(PageActionIconType::kSendTabToSelf);
+  highlight_button->SetVisible(true);
+  SetHighlightedButton(highlight_button);
 }
 
 const std::vector<std::unique_ptr<SendTabToSelfBubbleDeviceButton>>&
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 3ad4e5f..a306da76 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -148,9 +148,9 @@
     run_loop_.QuitWhenIdle();
   }
 
-  void Wait() {
-    run_loop_.Run();
-  }
+  // The observer should be constructed prior to initiating the drag. To prevent
+  // misuse via constructing a temporary object, Wait is marked lvalue-only.
+  void Wait() & { run_loop_.Run(); }
 
  private:
   content::NotificationRegistrar registrar_;
@@ -583,6 +583,7 @@
                         base::OnceClosure task,
                         int tab = 0,
                         int drag_x_offset = 0) {
+    test::QuitDraggingObserver observer;
     // Move to the tab and drag it enough so that it detaches.
     const gfx::Point tab_0_center =
         GetCenterInScreenCoordinates(tab_strip->tab_at(tab));
@@ -590,7 +591,7 @@
     ASSERT_TRUE(DragInputToNotifyWhenDone(
         tab_0_center + gfx::Vector2d(drag_x_offset, GetDetachY(tab_strip)),
         std::move(task)));
-    test::QuitDraggingObserver().Wait();
+    observer.Wait();
   }
 
   Browser* browser() const { return InProcessBrowserTest::browser(); }
@@ -1244,7 +1245,6 @@
 
 }  // namespace
 
-// This is disabled until NativeViewHost::Detach really detaches.
 // Detaches a tab and while detached presses escape to revert the drag.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        PressEscapeWhileDetached) {
@@ -1608,6 +1608,7 @@
 void DragWindowAndVerifyOffset(DetachToBrowserTabDragControllerTest* test,
                                TabStrip* tab_strip,
                                int tab_index) {
+  test::QuitDraggingObserver observer;
   // Move to the tab and drag it enough so that it detaches.
   const gfx::Point tab_center =
       GetCenterInScreenCoordinates(tab_strip->tab_at(tab_index));
@@ -1640,7 +1641,7 @@
               ASSERT_TRUE(test->ReleaseInput());
             })));
       })));
-  test::QuitDraggingObserver().Wait();
+  observer.Wait();
 }
 
 }  // namespace
@@ -3032,6 +3033,7 @@
   // minimizing the window. See https://crbug.com/902897 for the details.
   ui::GestureConfiguration::GetInstance()->set_min_fling_velocity(1);
 
+  test::QuitDraggingObserver observer;
   TabStrip* tab_strip = GetTabStripForBrowser(browser());
   const gfx::Point tab_0_center =
       GetCenterInScreenCoordinates(tab_strip->tab_at(0));
@@ -3051,7 +3053,7 @@
               ASSERT_TRUE(ReleaseInput());
             })));
       })));
-  test::QuitDraggingObserver().Wait();
+  observer.Wait();
 
   ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
   ASSERT_FALSE(TabDragController::IsActive());
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 4be7369..38b857f 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -2146,7 +2146,10 @@
 void TabStrip::AnimateToIdealBounds() {
   // bounds_animator_ and animator_ should not run concurrently.
   // bounds_animator_ takes precedence, and can finish what animator_ started.
-  animator_->CompleteAnimationsWithoutDestroyingTabs();
+  if (animator_->IsAnimating()) {
+    LayoutToCurrentBounds();
+    animator_->CompleteAnimationsWithoutDestroyingTabs();
+  }
 
   for (int i = 0; i < tab_count(); ++i) {
     // If the tab is being dragged manually, skip it.
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 da46d67..3fcf042 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
@@ -106,6 +106,13 @@
     icon->Update();
 }
 
+void ToolbarPageActionIconContainerView::ExecutePageActionIconForTesting(
+    PageActionIconType type) {
+  PageActionIconView* icon = GetIconView(type);
+  if (icon)
+    icon->ExecuteForTesting();
+}
+
 SkColor ToolbarPageActionIconContainerView::GetPageActionInkDropColor() const {
   return GetToolbarInkDropBaseColor(this);
 }
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 0558126..d525bc7 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
@@ -39,6 +39,7 @@
 
   // PageActionIconContainer:
   void UpdatePageActionIcon(PageActionIconType icon_type) override;
+  void ExecutePageActionIconForTesting(PageActionIconType icon_type) override;
 
   // PageActionIconView::Delegate:
   SkColor GetPageActionInkDropColor() const override;
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
index 16d61236..2d69f63 100644
--- a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
+++ b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
@@ -80,8 +80,10 @@
   return provider->install_manager().CanInstallWebApp(web_contents);
 }
 
-void CreateWebAppFromCurrentWebContents(Browser* browser,
-                                        bool force_shortcut_app) {
+void CreateWebAppFromCurrentWebContents(
+    Browser* browser,
+    bool force_shortcut_app,
+    WebAppInstalledCallback installed_callback) {
   DCHECK(CanCreateWebApp(browser));
 
   content::WebContents* web_contents =
@@ -89,8 +91,6 @@
   auto* provider = WebAppProvider::GetForWebContents(web_contents);
   DCHECK(provider);
 
-  WebAppInstalledCallback installed_callback = base::DoNothing();
-
   WebappInstallSource install_source =
       InstallableMetrics::GetInstallSource(web_contents, InstallTrigger::MENU);
 
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_utils.h b/chrome/browser/ui/web_applications/web_app_dialog_utils.h
index 0c91f59..41159af 100644
--- a/chrome/browser/ui/web_applications/web_app_dialog_utils.h
+++ b/chrome/browser/ui/web_applications/web_app_dialog_utils.h
@@ -25,13 +25,15 @@
 // Returns true if a WebApp installation is allowed for the current page.
 bool CanCreateWebApp(const Browser* browser);
 
-// Initiates install of a WebApp for the current page.
-void CreateWebAppFromCurrentWebContents(Browser* browser,
-                                        bool force_shortcut_app);
-
 using WebAppInstalledCallback =
     base::OnceCallback<void(const AppId& app_id, InstallResultCode code)>;
 
+// Initiates install of a WebApp for the current page.
+void CreateWebAppFromCurrentWebContents(
+    Browser* browser,
+    bool force_shortcut_app,
+    WebAppInstalledCallback installed_callback);
+
 // Starts install of a WebApp for a given |web_contents|, initiated from
 // a promotional banner or omnibox install icon.
 // Returns false if WebApps are disabled for the profile behind |web_contents|.
diff --git a/chrome/browser/web_applications/components/web_app_shortcut.cc b/chrome/browser/web_applications/components/web_app_shortcut.cc
index 095752d..0116b96 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut.cc
@@ -31,10 +31,10 @@
 
 namespace web_app {
 
-ShortcutInfo::ShortcutInfo() {}
+ShortcutInfo::ShortcutInfo() = default;
 
 ShortcutInfo::~ShortcutInfo() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
 ShortcutLocations::ShortcutLocations()
diff --git a/chrome/browser/web_applications/components/web_app_shortcut.h b/chrome/browser/web_applications/components/web_app_shortcut.h
index 5e29fb6..afbce360 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut.h
+++ b/chrome/browser/web_applications/components/web_app_shortcut.h
@@ -7,6 +7,7 @@
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
+#include "base/sequence_checker.h"
 #include "base/strings/string16.h"
 #include "ui/gfx/image/image_family.h"
 #include "url/gurl.h"
@@ -39,10 +40,10 @@
   std::string version_for_display;
 
  private:
-  // ShortcutInfo must not be copied; generally it is passed around via
-  // unique_ptr. Since ImageFamily has a non-thread-safe reference count in
-  // its member and is bound to UI thread, destroy ShortcutInfo instance
-  // on UI thread.
+  // Since gfx::ImageFamily |favicon| has a non-thread-safe reference count in
+  // its member and is bound to current thread, always destroy ShortcutInfo
+  // instance on the same thread.
+  SEQUENCE_CHECKER(sequence_checker_);
   DISALLOW_COPY_AND_ASSIGN(ShortcutInfo);
 };
 
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm b/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm
index 2f9a548..7f57fc8 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm
+++ b/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm
@@ -415,8 +415,7 @@
   EXPECT_EQ(product_logo.Height(), [image size].height);
 }
 
-// Disabled, sometimes crashes on "Mac10.10 tests". https://crbug.com/741642
-TEST_F(WebAppShortcutCreatorTest, DISABLED_RevealAppShimInFinder) {
+TEST_F(WebAppShortcutCreatorTest, RevealAppShimInFinder) {
   WebAppShortcutCreatorMock shortcut_creator(app_data_dir_, info_.get());
   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
       .WillRepeatedly(Return(destination_dir_));
diff --git a/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc b/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc
index 7b306d30..8c813c05 100644
--- a/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc
+++ b/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc
@@ -8,21 +8,29 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/extensions/convert_web_app.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_service_test_base.h"
+#include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/installable/installable_metrics.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/web_applications/components/app_registrar.h"
+#include "chrome/browser/web_applications/bookmark_apps/test_web_app_provider.h"
 #include "chrome/browser/web_applications/components/install_manager.h"
+#include "chrome/browser/web_applications/components/install_options.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
+#include "chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h"
+#include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_util.h"
+#include "chrome/browser/web_applications/test/test_app_registrar.h"
+#include "chrome/browser/web_applications/test/test_data_retriever.h"
 #include "chrome/browser/web_applications/test/test_web_app_url_loader.h"
 #include "chrome/browser/web_applications/web_app_install_manager.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+#include "chrome/common/extensions/manifest_handlers/app_theme_color_info.h"
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/browser_context.h"
@@ -45,9 +53,12 @@
 const GURL kAppUrl("https://www.chromium.org/index.html");
 const GURL kAppScope("https://www.chromium.org/");
 const char kAppAlternativeScope[] = "http://www.chromium.org/new/";
+const char kAppDefaultScope[] = "http://www.chromium.org/";
 const char kAppTitle[] = "Test title";
 const char kAlternativeAppTitle[] = "Different test title";
 const char kAppDescription[] = "Test description";
+const char kAppIconURL1[] = "http://foo.com/1.png";
+const char kAppIconURL2[] = "http://foo.com/2.png";
 
 const int kIconSizeTiny = extension_misc::EXTENSION_ICON_BITTY;
 const int kIconSizeSmall = extension_misc::EXTENSION_ICON_SMALL;
@@ -69,6 +80,40 @@
   return icon_info;
 }
 
+void TestAcceptDialogCallback(
+    content::WebContents* initiator_web_contents,
+    std::unique_ptr<WebApplicationInfo> web_app_info,
+    web_app::ForInstallableSite for_installable_site,
+    web_app::InstallManager::WebAppInstallationAcceptanceCallback
+        acceptance_callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(acceptance_callback), true /*accept*/,
+                                std::move(web_app_info)));
+}
+
+// Use only real BookmarkAppInstallFinalizer::FinalizeInstall and mock any other
+// finalization steps as a no-operation.
+class BookmarkAppInstallFinalizerInstallOnly
+    : public BookmarkAppInstallFinalizer {
+ public:
+  using BookmarkAppInstallFinalizer::BookmarkAppInstallFinalizer;
+  ~BookmarkAppInstallFinalizerInstallOnly() override = default;
+
+  // InstallFinalizer:
+  void CreateOsShortcuts(const web_app::AppId& app_id,
+                         bool add_to_desktop,
+                         CreateOsShortcutsCallback callback) override {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(callback), true /*shortcuts_created*/
+                       ));
+  }
+  void PinAppToShelf(const web_app::AppId& app_id) override {}
+  void ReparentTab(const web_app::AppId& app_id,
+                   content::WebContents* web_contents) override {}
+  void RevealAppShim(const web_app::AppId& app_id) override {}
+};
+
 }  // namespace
 
 class InstallManagerBookmarkAppTest : public ExtensionServiceTestBase {
@@ -88,9 +133,36 @@
     web_contents_ =
         content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
 
+    DCHECK(profile()->AsTestingProfile());
+    auto* provider = static_cast<web_app::TestWebAppProvider*>(
+        web_app::WebAppProvider::Get(profile()));
+
+    auto registrar = std::make_unique<BookmarkAppRegistrar>(profile());
+    registrar_ = registrar.get();
+
+    auto install_finalizer =
+        std::make_unique<BookmarkAppInstallFinalizerInstallOnly>(profile());
+    install_finalizer_ = install_finalizer.get();
+
+    auto install_manager = std::make_unique<web_app::WebAppInstallManager>(
+        profile(), registrar.get(), install_finalizer.get());
+
+    install_manager->SetDataRetrieverFactoryForTesting(
+        base::BindLambdaForTesting([this]() {
+          // This factory requires a prepared DataRetriever. A test should
+          // create one with CreateDefaultDataToRetrieve, for example.
+          DCHECK(prepared_data_retriever_);
+          return std::unique_ptr<web_app::WebAppDataRetriever>(
+              std::move(prepared_data_retriever_));
+        }));
+
     auto test_url_loader = std::make_unique<web_app::TestWebAppUrlLoader>();
     test_url_loader_ = test_url_loader.get();
-    install_manager().SetUrlLoaderForTesting(std::move(test_url_loader));
+    install_manager->SetUrlLoaderForTesting(std::move(test_url_loader));
+
+    provider->SetRegistrar(std::move(registrar));
+    provider->SetInstallManager(std::move(install_manager));
+    provider->SetInstallFinalizer(std::move(install_finalizer));
   }
 
   void TearDown() override {
@@ -118,15 +190,404 @@
     return *test_url_loader_;
   }
 
+  web_app::TestDataRetriever* data_retriever() {
+    DCHECK(prepared_data_retriever_);
+    return prepared_data_retriever_.get();
+  }
+
+  void CreateEmptyDataRetriever() {
+    DCHECK(!prepared_data_retriever_);
+    prepared_data_retriever_ = std::make_unique<web_app::TestDataRetriever>();
+  }
+
+  void CreateDataRetrieverWithManifest(
+      std::unique_ptr<blink::Manifest> manifest,
+      bool is_installable) {
+    CreateEmptyDataRetriever();
+    data_retriever()->SetRendererWebApplicationInfo(
+        std::make_unique<WebApplicationInfo>());
+    data_retriever()->SetManifest(std::move(manifest), is_installable);
+  }
+
+  void CreateDataRetrieverWithRendererWebAppInfo(
+      std::unique_ptr<WebApplicationInfo> web_app_info,
+      bool is_installable) {
+    CreateEmptyDataRetriever();
+
+    data_retriever()->SetRendererWebApplicationInfo(std::move(web_app_info));
+
+    auto manifest = std::make_unique<blink::Manifest>();
+    data_retriever()->SetManifest(std::move(manifest), is_installable);
+
+    web_app::IconsMap icons_map;
+    icons_map[GURL(kAppUrl)].push_back(
+        CreateSquareBitmapWithColor(kIconSizeSmall, SK_ColorRED));
+    data_retriever()->SetIcons(std::move(icons_map));
+  }
+
+  void CreateDataRetrieverWithLaunchContainer(const GURL& app_url,
+                                              bool open_as_window,
+                                              bool is_installable) {
+    CreateEmptyDataRetriever();
+
+    auto web_app_info = std::make_unique<WebApplicationInfo>();
+    web_app_info->open_as_window = open_as_window;
+    data_retriever()->SetRendererWebApplicationInfo(std::move(web_app_info));
+
+    auto manifest = std::make_unique<blink::Manifest>();
+    manifest->start_url = app_url;
+    manifest->name =
+        base::NullableString16(base::UTF8ToUTF16(kAppTitle), false);
+    manifest->scope = GURL(kAppScope);
+    data_retriever()->SetManifest(std::move(manifest), is_installable);
+
+    data_retriever()->SetIcons(web_app::IconsMap{});
+  }
+
+  const Extension* InstallWebAppFromManifestWithFallback() {
+    base::RunLoop run_loop;
+    web_app::AppId app_id;
+
+    auto* provider = web_app::WebAppProviderBase::GetProviderBase(profile());
+
+    provider->install_manager().InstallWebAppFromManifestWithFallback(
+        web_contents(),
+        /*force_shortcut_app=*/false, WebappInstallSource::MENU_BROWSER_TAB,
+        base::BindOnce(TestAcceptDialogCallback),
+        base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
+                                       web_app::InstallResultCode code) {
+          EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+          app_id = installed_app_id;
+          run_loop.Quit();
+        }));
+
+    run_loop.Run();
+
+    const Extension* extension = service_->GetInstalledExtension(app_id);
+    DCHECK(extension);
+    return extension;
+  }
+
+  const Extension* InstallWebAppWithOptions(
+      const web_app::InstallOptions& install_options) {
+    base::RunLoop run_loop;
+    web_app::AppId app_id;
+
+    auto* provider = web_app::WebAppProviderBase::GetProviderBase(profile());
+
+    provider->install_manager().InstallWebAppWithOptions(
+        web_contents(), install_options,
+        base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
+                                       web_app::InstallResultCode code) {
+          EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+          app_id = installed_app_id;
+          run_loop.Quit();
+        }));
+
+    run_loop.Run();
+
+    const Extension* extension = service_->GetInstalledExtension(app_id);
+    DCHECK(extension);
+    return extension;
+  }
+
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<content::WebContents> web_contents_;
+
+  BookmarkAppRegistrar* registrar_ = nullptr;
+  BookmarkAppInstallFinalizerInstallOnly* install_finalizer_ = nullptr;
+
   web_app::TestWebAppUrlLoader* test_url_loader_ = nullptr;
+  std::unique_ptr<web_app::TestDataRetriever> prepared_data_retriever_;
 
   DISALLOW_COPY_AND_ASSIGN(InstallManagerBookmarkAppTest);
 };
 
+TEST_F(InstallManagerBookmarkAppTest, CreateBookmarkApp) {
+  auto web_app_info = std::make_unique<WebApplicationInfo>();
+  const GURL app_url(kAppUrl);
+  web_app_info->app_url = app_url;
+  web_app_info->title = base::UTF8ToUTF16(kAppTitle);
+  web_app_info->description = base::UTF8ToUTF16(kAppDescription);
+  CreateDataRetrieverWithRendererWebAppInfo(std::move(web_app_info),
+                                            /*is_installable=*/false);
+
+  const Extension* extension = InstallWebAppFromManifestWithFallback();
+
+  EXPECT_EQ(1u, registry()->enabled_extensions().size());
+  EXPECT_TRUE(extension->from_bookmark());
+  EXPECT_FALSE(extension->was_installed_by_default());
+  EXPECT_FALSE(Manifest::IsPolicyLocation(extension->location()));
+
+  EXPECT_EQ(kAppTitle, extension->name());
+  EXPECT_EQ(kAppDescription, extension->description());
+  EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension));
+  EXPECT_FALSE(IconsInfo::GetIconResource(extension, kIconSizeSmall,
+                                          ExtensionIconSet::MATCH_EXACTLY)
+                   .empty());
+  EXPECT_FALSE(
+      AppBannerSettingsHelper::GetSingleBannerEvent(
+          web_contents(), app_url, app_url.spec(),
+          AppBannerSettingsHelper::APP_BANNER_EVENT_DID_ADD_TO_HOMESCREEN)
+          .is_null());
+}
+
+TEST_F(InstallManagerBookmarkAppTest, CreateBookmarkAppDefaultApp) {
+  auto web_app_info = std::make_unique<WebApplicationInfo>();
+  const GURL app_url(kAppUrl);
+  web_app_info->app_url = app_url;
+  web_app_info->title = base::UTF8ToUTF16(kAppTitle);
+  web_app_info->description = base::UTF8ToUTF16(kAppDescription);
+  CreateDataRetrieverWithRendererWebAppInfo(std::move(web_app_info),
+                                            /*is_installable=*/false);
+
+  web_app::InstallOptions install_options;
+  install_options.install_source = web_app::InstallSource::kExternalDefault;
+
+  const Extension* extension = InstallWebAppWithOptions(install_options);
+
+  EXPECT_TRUE(extension->from_bookmark());
+  EXPECT_TRUE(extension->was_installed_by_default());
+  EXPECT_EQ(Manifest::EXTERNAL_PREF_DOWNLOAD, extension->location());
+  EXPECT_FALSE(Manifest::IsPolicyLocation(extension->location()));
+}
+
+TEST_F(InstallManagerBookmarkAppTest, CreateBookmarkAppPolicyInstalled) {
+  auto web_app_info = std::make_unique<WebApplicationInfo>();
+  const GURL app_url(kAppUrl);
+  web_app_info->app_url = app_url;
+  web_app_info->title = base::UTF8ToUTF16(kAppTitle);
+  web_app_info->description = base::UTF8ToUTF16(kAppDescription);
+  CreateDataRetrieverWithRendererWebAppInfo(std::move(web_app_info),
+                                            /*is_installable=*/false);
+
+  web_app::InstallOptions install_options;
+  install_options.install_source = web_app::InstallSource::kExternalPolicy;
+
+  const Extension* extension = InstallWebAppWithOptions(install_options);
+
+  EXPECT_TRUE(extension->from_bookmark());
+  EXPECT_FALSE(extension->was_installed_by_default());
+  EXPECT_TRUE(Manifest::IsPolicyLocation(extension->location()));
+}
+
+class InstallManagerBookmarkAppInstallableSiteTest
+    : public InstallManagerBookmarkAppTest,
+      public ::testing::WithParamInterface<web_app::ForInstallableSite> {
+ public:
+  InstallManagerBookmarkAppInstallableSiteTest() {}
+  ~InstallManagerBookmarkAppInstallableSiteTest() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InstallManagerBookmarkAppInstallableSiteTest);
+};
+
+TEST_P(InstallManagerBookmarkAppInstallableSiteTest,
+       CreateBookmarkAppWithManifest) {
+  const GURL app_url(kAppUrl);
+
+  auto manifest = std::make_unique<blink::Manifest>();
+  manifest->start_url = app_url;
+  manifest->name = base::NullableString16(base::UTF8ToUTF16(kAppTitle), false);
+  manifest->scope = GURL(kAppScope);
+  manifest->theme_color = SK_ColorBLUE;
+
+  const bool is_installable = GetParam() == web_app::ForInstallableSite::kYes;
+  CreateDataRetrieverWithManifest(std::move(manifest), is_installable);
+
+  const Extension* extension = InstallWebAppFromManifestWithFallback();
+
+  EXPECT_EQ(1u, registry()->enabled_extensions().size());
+  EXPECT_TRUE(extension->from_bookmark());
+  EXPECT_EQ(kAppTitle, extension->name());
+  EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension));
+  EXPECT_EQ(SK_ColorBLUE, AppThemeColorInfo::GetThemeColor(extension).value());
+  EXPECT_FALSE(
+      AppBannerSettingsHelper::GetSingleBannerEvent(
+          web_contents(), app_url, app_url.spec(),
+          AppBannerSettingsHelper::APP_BANNER_EVENT_DID_ADD_TO_HOMESCREEN)
+          .is_null());
+
+  if (GetParam() == web_app::ForInstallableSite::kYes) {
+    EXPECT_EQ(GURL(kAppScope), GetScopeURLFromBookmarkApp(extension));
+  } else {
+    EXPECT_EQ(GURL(), GetScopeURLFromBookmarkApp(extension));
+  }
+}
+
+TEST_P(InstallManagerBookmarkAppInstallableSiteTest,
+       CreateBookmarkAppWithManifestIcons) {
+  const GURL app_url(kAppUrl);
+
+  auto manifest = std::make_unique<blink::Manifest>();
+  manifest->start_url = app_url;
+  manifest->name = base::NullableString16(base::UTF8ToUTF16(kAppTitle), false);
+  manifest->scope = GURL(kAppScope);
+
+  blink::Manifest::ImageResource icon;
+  icon.src = GURL(kAppIconURL1);
+  icon.purpose = {blink::Manifest::ImageResource::Purpose::ANY};
+  manifest->icons.push_back(icon);
+  icon.src = GURL(kAppIconURL2);
+  manifest->icons.push_back(icon);
+
+  const bool is_installable = GetParam() == web_app::ForInstallableSite::kYes;
+
+  CreateDataRetrieverWithManifest(std::move(manifest), is_installable);
+
+  // In the legacy system Favicon URLs were ignored by WebAppIconDownloader
+  // because the site had a manifest with icons: Only 1 icon had to be
+  // downloaded since the other was provided by the InstallableManager. In the
+  // new extension-independent system we prefer to redownload all the icons: 2
+  // icons have to be downloaded.
+  data_retriever()->SetGetIconsDelegate(base::BindLambdaForTesting(
+      [&](content::WebContents* web_contents,
+          const std::vector<GURL>& icon_urls, bool skip_page_favicons) {
+        // Instructs the downloader to not query the page for favicons.
+        EXPECT_TRUE(skip_page_favicons);
+
+        const std::vector<GURL> expected_icon_urls{GURL(kAppIconURL1),
+                                                   GURL(kAppIconURL2)};
+        EXPECT_EQ(expected_icon_urls, icon_urls);
+
+        web_app::IconsMap icons_map;
+        icons_map[GURL(kAppIconURL1)].push_back(
+            CreateSquareBitmapWithColor(kIconSizeTiny, SK_ColorBLUE));
+        icons_map[GURL(kAppIconURL2)].push_back(
+            CreateSquareBitmapWithColor(kIconSizeSmall, SK_ColorRED));
+        return icons_map;
+      }));
+
+  const Extension* extension = InstallWebAppFromManifestWithFallback();
+
+  EXPECT_EQ(1u, registry()->enabled_extensions().size());
+  EXPECT_TRUE(extension->from_bookmark());
+  EXPECT_EQ(kAppTitle, extension->name());
+  EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension));
+
+  if (GetParam() == web_app::ForInstallableSite::kYes) {
+    EXPECT_EQ(GURL(kAppScope), GetScopeURLFromBookmarkApp(extension));
+  } else {
+    EXPECT_EQ(GURL(), GetScopeURLFromBookmarkApp(extension));
+  }
+}
+
+TEST_P(InstallManagerBookmarkAppInstallableSiteTest,
+       CreateBookmarkAppWithManifestNoScope) {
+  const GURL app_url(kAppUrl);
+
+  auto manifest = std::make_unique<blink::Manifest>();
+  manifest->start_url = app_url;
+  manifest->scope = GURL(kAppDefaultScope);
+  manifest->name = base::NullableString16(base::UTF8ToUTF16(kAppTitle), false);
+
+  const bool is_installable = GetParam() == web_app::ForInstallableSite::kYes;
+  CreateDataRetrieverWithManifest(std::move(manifest), is_installable);
+
+  const Extension* extension = InstallWebAppFromManifestWithFallback();
+
+  if (GetParam() == web_app::ForInstallableSite::kYes) {
+    EXPECT_EQ(GURL(kAppDefaultScope), GetScopeURLFromBookmarkApp(extension));
+  } else {
+    EXPECT_EQ(GURL(), GetScopeURLFromBookmarkApp(extension));
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         InstallManagerBookmarkAppInstallableSiteTest,
+                         ::testing::Values(web_app::ForInstallableSite::kNo,
+                                           web_app::ForInstallableSite::kYes));
+
+TEST_F(InstallManagerBookmarkAppTest,
+       CreateBookmarkAppDefaultLauncherContainers) {
+  {
+    CreateDataRetrieverWithLaunchContainer(
+        GURL(kAppUrl), /*open_as_window=*/true, /*is_installable=*/true);
+
+    const Extension* extension = InstallWebAppFromManifestWithFallback();
+
+    EXPECT_EQ(LAUNCH_CONTAINER_WINDOW,
+              GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
+
+    // Mark the app as not locally installed and check that it now opens in a
+    // tab.
+    SetBookmarkAppIsLocallyInstalled(profile(), extension, false);
+    EXPECT_EQ(LAUNCH_CONTAINER_TAB,
+              GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
+
+    // Mark the app as locally installed and check that it now opens in a
+    // window.
+    SetBookmarkAppIsLocallyInstalled(profile(), extension, true);
+    EXPECT_EQ(LAUNCH_CONTAINER_WINDOW,
+              GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
+  }
+  {
+    CreateDataRetrieverWithLaunchContainer(GURL("https://www.example.org/"),
+                                           /*open_as_window=*/false,
+                                           /*is_installable=*/false);
+
+    const Extension* extension = InstallWebAppFromManifestWithFallback();
+
+    EXPECT_EQ(LAUNCH_CONTAINER_TAB,
+              GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
+  }
+}
+
+TEST_F(InstallManagerBookmarkAppTest,
+       CreateBookmarkAppForcedLauncherContainers) {
+  {
+    CreateDataRetrieverWithLaunchContainer(GURL("https://www.example.org/"),
+                                           /*open_as_window=*/true,
+                                           /*is_installable=*/true);
+
+    web_app::InstallOptions install_options;
+    install_options.launch_container = web_app::LaunchContainer::kTab;
+
+    const Extension* extension = InstallWebAppWithOptions(install_options);
+
+    EXPECT_EQ(LAUNCH_CONTAINER_TAB,
+              GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
+  }
+  {
+    CreateDataRetrieverWithLaunchContainer(
+        GURL(kAppUrl), /*open_as_window=*/false, /*is_installable=*/false);
+
+    web_app::InstallOptions install_options;
+    install_options.launch_container = web_app::LaunchContainer::kWindow;
+
+    const Extension* extension = InstallWebAppWithOptions(install_options);
+
+    EXPECT_EQ(LAUNCH_CONTAINER_WINDOW,
+              GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
+  }
+}
+
+TEST_F(InstallManagerBookmarkAppTest, CreateBookmarkAppWithoutManifest) {
+  auto web_app_info = std::make_unique<WebApplicationInfo>();
+  const GURL app_url(kAppUrl);
+  web_app_info->app_url = app_url;
+  web_app_info->title = base::UTF8ToUTF16(kAppTitle);
+  web_app_info->description = base::UTF8ToUTF16(kAppDescription);
+
+  CreateEmptyDataRetriever();
+  data_retriever()->SetRendererWebApplicationInfo(std::move(web_app_info));
+  auto manifest = std::make_unique<blink::Manifest>();
+  data_retriever()->SetManifest(std::move(manifest), /*is_installable=*/false);
+  data_retriever()->SetIcons(web_app::IconsMap{});
+
+  const Extension* extension = InstallWebAppFromManifestWithFallback();
+
+  EXPECT_EQ(kAppTitle, extension->name());
+  EXPECT_EQ(kAppDescription, extension->description());
+  EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension));
+  EXPECT_EQ(GURL(), GetScopeURLFromBookmarkApp(extension));
+  EXPECT_FALSE(AppThemeColorInfo::GetThemeColor(extension));
+}
+
 TEST_F(InstallManagerBookmarkAppTest, CreateWebAppFromInfo) {
+  CreateEmptyDataRetriever();
+
   auto web_app_info = std::make_unique<WebApplicationInfo>();
   web_app_info->app_url = kAppUrl;
   web_app_info->title = base::UTF8ToUTF16(kAppTitle);
@@ -153,7 +614,7 @@
   run_loop.Run();
 
   const Extension* extension = service_->GetInstalledExtension(app_id);
-  EXPECT_TRUE(extension);
+  ASSERT_TRUE(extension);
 
   EXPECT_EQ(1u, registry()->enabled_extensions().size());
   EXPECT_TRUE(extension->from_bookmark());
@@ -179,6 +640,8 @@
 }
 
 TEST_F(InstallManagerBookmarkAppTest, InstallOrUpdateWebAppFromSync) {
+  CreateEmptyDataRetriever();
+
   EXPECT_EQ(0u, registry()->enabled_extensions().size());
 
   auto web_app_info = std::make_unique<WebApplicationInfo>();
@@ -246,6 +709,7 @@
   // On ChromeOS, it always behaves as if app is installed.
   EXPECT_TRUE(provider->registrar().IsInstalled(app_id));
 
+  CreateEmptyDataRetriever();
   {
     base::RunLoop run_loop;
 
@@ -281,6 +745,4 @@
   }
 }
 
-// TODO(loyso): Convert more tests from bookmark_app_helper_unittest.cc
-
 }  // namespace extensions
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index fb7da23..919853e 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -226,6 +226,7 @@
 
     // PageActionIconContainer:
     void UpdatePageActionIcon(PageActionIconType type) override {}
+    void ExecutePageActionIconForTesting(PageActionIconType type) override {}
 
    private:
     DISALLOW_COPY_AND_ASSIGN(TestOmniboxPageActionIconContainer);
diff --git a/chrome/test/data/local_ntp/local_ntp_browsertest.html b/chrome/test/data/local_ntp/local_ntp_browsertest.html
index 3517f42..3c4ea02 100644
--- a/chrome/test/data/local_ntp/local_ntp_browsertest.html
+++ b/chrome/test/data/local_ntp/local_ntp_browsertest.html
@@ -158,7 +158,7 @@
     <dialog id="customization-menu" class="customize-dialog">
       <div id="menu-header">
         <div id="menu-back-wrapper">
-          <div id="menu-back-circle" tabindex="0">
+          <div id="menu-back-circle" tabindex="0" role="button">
             <div id="menu-back"></div>
           </div>
         </div>
@@ -187,13 +187,15 @@
         </div>
       </div>
       <div id="menu-contents">
-        <div id="backgrounds-menu" class="menu-panel">
+        <div id="backgrounds-menu" class="menu-panel" tabindex="0">
           <div id="backgrounds-upload" class="bg-sel-tile-bg">
-            <div id="backgrounds-upload-icon"></div>
-            <div id="backgrounds-upload-text">$i18n{uploadImage}</div>
+            <div id="backgrounds-upload-wrapper" class="bg-sel-tile" tabindex="-1">
+              <div id="backgrounds-upload-icon"></div>
+              <div id="backgrounds-upload-text">$i18n{uploadImage}</div>
+            </div>
           </div>
           <div id="backgrounds-default" class="bg-sel-tile-bg">
-            <div id="backgrounds-default-icon" class="bg-sel-tile">
+            <div id="backgrounds-default-icon" class="bg-sel-tile" tabindex="-1">
               <div class="mini-page">
                 <div class="mini-header"></div>
                 <div class="mini-shortcuts"></div>
@@ -202,7 +204,7 @@
             <div class="bg-sel-tile-title">$i18n{noBackground}</div>
           </div>
         </div>
-        <div id="backgrounds-image-menu" class="menu-panel"></div>
+        <div id="backgrounds-image-menu" class="menu-panel" tabindex="-1"></div>
         <div id="shortcuts-menu" class="menu-panel">
           <div id="sh-options">
             <div class="sh-option">
diff --git a/chromecast/media/audio/cast_audio_output_stream_unittest.cc b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
index 31a9f05..9960ad1 100644
--- a/chromecast/media/audio/cast_audio_output_stream_unittest.cc
+++ b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
@@ -369,6 +369,7 @@
   RunThreadsUntilIdle();
 
   stream->Close();
+  RunThreadsUntilIdle();
 }
 
 TEST_F(CastAudioOutputStreamTest, CloseCancelsOpen) {
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index 4630256..016432ca 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -20,7 +20,7 @@
 
 // Enables or disables Crostini Backup.
 const base::Feature kCrostiniBackup{"CrostiniBackup",
-                                    base::FEATURE_DISABLED_BY_DEFAULT};
+                                    base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables or disables Crostini GPU support.
 const base::Feature kCrostiniGpuSupport{"CrostiniGpuSupport",
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc
index 037682b9..bdafd0b0 100644
--- a/components/arc/ime/arc_ime_service.cc
+++ b/components/arc/ime/arc_ime_service.cc
@@ -93,6 +93,13 @@
     return window->GetHost()->GetInputMethod();
   }
 
+  bool IsImeBlocked(aura::Window* window) const override {
+    // WMHelper is not created in tests.
+    if (!exo::WMHelper::HasInstance())
+      return false;
+    return exo::WMHelper::GetInstance()->IsImeBlocked(window);
+  }
+
  private:
   ArcImeService* const ime_service_;
 
@@ -215,15 +222,39 @@
   // This shouldn't be reached on production, since the window lost the focus
   // and called OnWindowFocused() before destroying.
   // But we handle this case for testing.
-  DCHECK_EQ(window, focused_arc_window_);
-  OnWindowFocused(nullptr, focused_arc_window_);
+  if (window == focused_arc_window_)
+    OnWindowFocused(nullptr, focused_arc_window_);
 }
 
 void ArcImeService::OnWindowRemovingFromRootWindow(aura::Window* window,
                                                    aura::Window* new_root) {
-  DCHECK_EQ(window, focused_arc_window_);
   // IMEs are associated with root windows, hence we may need to detach/attach.
-  ReattachInputMethod(focused_arc_window_, new_root);
+  if (window == focused_arc_window_)
+    ReattachInputMethod(focused_arc_window_, new_root);
+}
+
+void ArcImeService::OnWindowPropertyChanged(aura::Window* window,
+                                            const void* key,
+                                            intptr_t old) {
+  if (window == focused_arc_window_)
+    return;
+
+  bool ime_blocked = arc_window_delegate_->IsImeBlocked(focused_arc_window_);
+  if (last_ime_blocked_ == ime_blocked)
+    return;
+  last_ime_blocked_ = ime_blocked;
+
+  // IME blocking has changed.
+  ui::InputMethod* const input_method = GetInputMethod();
+  if (input_method) {
+    if (has_composition_text_) {
+      // If it has composition text, clear both ARC's current composition text
+      // and Chrome IME's one.
+      ClearCompositionText();
+      input_method->CancelComposition(this);
+    }
+    input_method->OnTextInputTypeChanged(this);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -238,6 +269,10 @@
   const bool attach = arc_window_delegate_->IsInArcAppWindow(gained_focus);
 
   if (detach) {
+    // The focused window and the toplevel window are different in production,
+    // but in tests they can be the same, so avoid adding the observer twice.
+    if (focused_arc_window_ != focused_arc_window_->GetToplevelWindow())
+      focused_arc_window_->GetToplevelWindow()->RemoveObserver(this);
     focused_arc_window_->RemoveObserver(this);
     focused_arc_window_ = nullptr;
   }
@@ -245,6 +280,10 @@
     DCHECK_EQ(nullptr, focused_arc_window_);
     focused_arc_window_ = gained_focus;
     focused_arc_window_->AddObserver(this);
+    // The focused window and the toplevel window are different in production,
+    // but in tests they can be the same, so avoid adding the observer twice.
+    if (focused_arc_window_ != focused_arc_window_->GetToplevelWindow())
+      focused_arc_window_->GetToplevelWindow()->AddObserver(this);
   }
 
   ReattachInputMethod(detach ? lost_focus : nullptr, focused_arc_window_);
@@ -330,9 +369,9 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// Overridden from keyboard::KeyboardControllerObserver
+// Overridden from ash::KeyboardControllerObserver
 void ArcImeService::OnKeyboardAppearanceChanged(
-    const keyboard::KeyboardStateDescriptor& state) {
+    const ash::KeyboardStateDescriptor& state) {
   gfx::Rect new_bounds = state.occluded_bounds_in_screen;
   // Multiply by the scale factor. To convert from DIP to physical pixels.
   // The default scale factor is always used in Android side regardless of
@@ -378,6 +417,10 @@
 }
 
 void ArcImeService::InsertChar(const ui::KeyEvent& event) {
+  // When IME is blocked for the window, let Exo handle the event.
+  if (arc_window_delegate_->IsImeBlocked(focused_arc_window_))
+    return;
+
   // According to the document in text_input_client.h, InsertChar() is called
   // even when the text input type is NONE. We ignore such events, since for
   // ARC we are only interested in the event as a method of text input.
@@ -419,6 +462,8 @@
 }
 
 ui::TextInputType ArcImeService::GetTextInputType() const {
+  if (arc_window_delegate_->IsImeBlocked(focused_arc_window_))
+    return ui::TEXT_INPUT_TYPE_NONE;
   return ime_type_;
 }
 
diff --git a/components/arc/ime/arc_ime_service.h b/components/arc/ime/arc_ime_service.h
index 53eb8b5..2b3276e 100644
--- a/components/arc/ime/arc_ime_service.h
+++ b/components/arc/ime/arc_ime_service.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "base/macros.h"
 #include "base/optional.h"
 #include "components/arc/ime/arc_ime_bridge.h"
@@ -42,7 +42,7 @@
                       public aura::EnvObserver,
                       public aura::WindowObserver,
                       public aura::client::FocusChangeObserver,
-                      public keyboard::KeyboardControllerObserver,
+                      public ash::KeyboardControllerObserver,
                       public ui::TextInputClient {
  public:
   // Returns singleton instance for the given BrowserContext,
@@ -64,6 +64,7 @@
     virtual void UnregisterFocusObserver() = 0;
     virtual ui::InputMethod* GetInputMethodForWindow(
         aura::Window* window) const = 0;
+    virtual bool IsImeBlocked(aura::Window* window) const = 0;
   };
 
   // Injects the custom IPC bridge object for testing purpose only.
@@ -80,6 +81,9 @@
   void OnWindowDestroying(aura::Window* window) override;
   void OnWindowRemovingFromRootWindow(aura::Window* window,
                                       aura::Window* new_root) override;
+  void OnWindowPropertyChanged(aura::Window* window,
+                               const void* key,
+                               intptr_t old) override;
 
   // Overridden from aura::client::FocusChangeObserver:
   void OnWindowFocused(aura::Window* gained_focus,
@@ -101,9 +105,9 @@
       bool is_screen_coordinates) override;
   void RequestHideIme() override;
 
-  // Overridden from keyboard::KeyboardControllerObserver.
+  // Overridden from ash::KeyboardControllerObserver.
   void OnKeyboardAppearanceChanged(
-      const keyboard::KeyboardStateDescriptor& state) override;
+      const ash::KeyboardStateDescriptor& state) override;
 
   // Overridden from ui::TextInputClient:
   void SetCompositionText(const ui::CompositionText& composition) override;
@@ -178,6 +182,10 @@
   base::string16 text_in_range_;
   gfx::Range selection_range_;
 
+  // Return value of IsImeBlocked() last time OnWindowPropertyChanged() is
+  // called. It might not be the latest blocking state.
+  bool last_ime_blocked_ = false;
+
   aura::Window* focused_arc_window_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(ArcImeService);
diff --git a/components/arc/ime/arc_ime_service_unittest.cc b/components/arc/ime/arc_ime_service_unittest.cc
index b29a822..3a878ac 100644
--- a/components/arc/ime/arc_ime_service_unittest.cc
+++ b/components/arc/ime/arc_ime_service_unittest.cc
@@ -141,6 +141,10 @@
     return window ? test_input_method_ : nullptr;
   }
 
+  bool IsImeBlocked(aura::Window* window) const override {
+    return ime_blocked_;
+  }
+
   std::unique_ptr<aura::Window> CreateFakeArcWindow() {
     const int id = next_id_++;
     arc_window_id_.insert(id);
@@ -154,11 +158,14 @@
         &dummy_delegate_, id, gfx::Rect(), nullptr));
   }
 
+  void set_ime_blocked(bool ime_blocked) { ime_blocked_ = ime_blocked; }
+
  private:
   aura::test::TestWindowDelegate dummy_delegate_;
   int next_id_;
   std::set<int> arc_window_id_;
   ui::InputMethod* test_input_method_;
+  bool ime_blocked_ = false;
 };
 
 }  // namespace
@@ -272,6 +279,11 @@
                                     mojom::TEXT_INPUT_FLAG_NONE);
   instance_->InsertChar(ui::KeyEvent('a', ui::VKEY_A, ui::DomCode::NONE, 0));
   EXPECT_EQ(1, fake_arc_ime_bridge_->count_send_insert_text());
+
+  // When IME is blocked, the event is not forwarded.
+  fake_window_delegate_->set_ime_blocked(true);
+  instance_->InsertChar(ui::KeyEvent('a', ui::VKEY_A, ui::DomCode::NONE, 0));
+  EXPECT_EQ(1, fake_arc_ime_bridge_->count_send_insert_text());
 }
 
 TEST_F(ArcImeServiceTest, WindowFocusTracking) {
@@ -358,8 +370,8 @@
   EXPECT_FALSE(fake_arc_ime_bridge_->last_keyboard_availability());
 
   const gfx::Rect keyboard_bounds(0, 480, 1200, 320);
-  keyboard::KeyboardStateDescriptor desc{true, keyboard_bounds, keyboard_bounds,
-                                         keyboard_bounds};
+  ash::KeyboardStateDescriptor desc{true, keyboard_bounds, keyboard_bounds,
+                                    keyboard_bounds};
   instance_->OnKeyboardAppearanceChanged(desc);
   EXPECT_EQ(keyboard_bounds, fake_arc_ime_bridge_->last_keyboard_bounds());
   EXPECT_TRUE(fake_arc_ime_bridge_->last_keyboard_availability());
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 7f37047..5860082 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -401,6 +401,17 @@
                                           always_on_top);
 }
 
+void ClientControlledShellSurface::SetImeBlocked(bool ime_blocked) {
+  TRACE_EVENT1("exo", "ClientControlledShellSurface::SetImeBlocked",
+               "ime_blocked", ime_blocked);
+
+  if (!widget_)
+    CreateShellSurfaceWidget(ui::SHOW_STATE_NORMAL);
+
+  WMHelper::GetInstance()->SetImeBlocked(widget_->GetNativeWindow(),
+                                         ime_blocked);
+}
+
 void ClientControlledShellSurface::SetOrientation(Orientation orientation) {
   TRACE_EVENT1("exo", "ClientControlledShellSurface::SetOrientation",
                "orientation",
diff --git a/components/exo/client_controlled_shell_surface.h b/components/exo/client_controlled_shell_surface.h
index e60ce6f..c30fa22 100644
--- a/components/exo/client_controlled_shell_surface.h
+++ b/components/exo/client_controlled_shell_surface.h
@@ -130,6 +130,9 @@
   // Sets the surface to be on top of all other windows.
   void SetAlwaysOnTop(bool always_on_top);
 
+  // Sets the IME to be blocked so that all events are forwarded by Exo.
+  void SetImeBlocked(bool ime_blocked);
+
   // Controls the visibility of the system UI when this surface is active.
   void SetSystemUiVisibility(bool autohide);
 
diff --git a/components/exo/keyboard.cc b/components/exo/keyboard.cc
index 35528cb..8676a34 100644
--- a/components/exo/keyboard.cc
+++ b/components/exo/keyboard.cc
@@ -58,6 +58,10 @@
 }
 
 bool ConsumedByIme(Surface* focus, const ui::KeyEvent* event) {
+  // When IME is blocked, Exo can handle any key events.
+  if (WMHelper::GetInstance()->IsImeBlocked(focus->window()))
+    return false;
+
   // Check if IME consumed the event, to avoid it to be doubly processed.
   // First let us see whether IME is active and is in text input mode.
   views::Widget* widget =
@@ -341,7 +345,7 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// keyboard::KeyboardControllerObserver overrides:
+// ash::KeyboardControllerObserver overrides:
 
 void Keyboard::OnKeyboardEnabledChanged(bool enabled) {
   if (device_configuration_delegate_) {
diff --git a/components/exo/keyboard.h b/components/exo/keyboard.h
index 12b089b..c371a97 100644
--- a/components/exo/keyboard.h
+++ b/components/exo/keyboard.h
@@ -7,7 +7,7 @@
 
 #include <vector>
 
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
@@ -34,7 +34,7 @@
 class Keyboard : public ui::EventHandler,
                  public SurfaceObserver,
                  public SeatObserver,
-                 public keyboard::KeyboardControllerObserver {
+                 public ash::KeyboardControllerObserver {
  public:
   Keyboard(KeyboardDelegate* delegate, Seat* seat);
   ~Keyboard() override;
@@ -65,7 +65,7 @@
   void OnSurfaceFocusing(Surface* gaining_focus) override;
   void OnSurfaceFocused(Surface* gained_focus) override;
 
-  // Overridden from keyboard::KeyboardControllerObserver
+  // Overridden from ash::KeyboardControllerObserver
   void OnKeyboardEnabledChanged(bool is_enabled) override;
 
  private:
diff --git a/components/exo/test/exo_test_base_views.cc b/components/exo/test/exo_test_base_views.cc
index b2843cac..368a2ae5 100644
--- a/components/exo/test/exo_test_base_views.cc
+++ b/components/exo/test/exo_test_base_views.cc
@@ -64,6 +64,8 @@
   void RemovePostTargetHandler(ui::EventHandler* handler) override {}
   bool IsTabletModeWindowManagerEnabled() const override { return false; }
   double GetDefaultDeviceScaleFactor() const override { return 1.0; }
+  void SetImeBlocked(aura::Window* window, bool ime_blocked) override {}
+  bool IsImeBlocked(aura::Window* window) const override { return false; }
 
   LifetimeManager* GetLifetimeManager() override { return &lifetime_manager_; }
   aura::client::CaptureClient* GetCaptureClient() override { return nullptr; }
diff --git a/components/exo/text_input.cc b/components/exo/text_input.cc
index 55a08df..1124aa1 100644
--- a/components/exo/text_input.cc
+++ b/components/exo/text_input.cc
@@ -319,7 +319,7 @@
   return false;
 }
 
-void TextInput::OnKeyboardVisibilityStateChanged(bool is_visible) {
+void TextInput::OnKeyboardVisibilityChanged(bool is_visible) {
   delegate_->OnVirtualKeyboardVisibilityChanged(is_visible);
 }
 
diff --git a/components/exo/text_input.h b/components/exo/text_input.h
index c71e477..da70882 100644
--- a/components/exo/text_input.h
+++ b/components/exo/text_input.h
@@ -5,7 +5,7 @@
 #ifndef COMPONENTS_EXO_TEXT_INPUT_H_
 #define COMPONENTS_EXO_TEXT_INPUT_H_
 
-#include "ash/keyboard/ui/keyboard_controller_observer.h"
+#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "base/optional.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/base/ime/text_input_flags.h"
@@ -29,7 +29,7 @@
 
 // This class bridges the ChromeOS input method and a text-input context.
 class TextInput : public ui::TextInputClient,
-                  public keyboard::KeyboardControllerObserver {
+                  public ash::KeyboardControllerObserver {
  public:
   class Delegate {
    public:
@@ -139,8 +139,8 @@
       const gfx::Range& range,
       const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
 
-  // keyboard::KeyboardControllerObserver:
-  void OnKeyboardVisibilityStateChanged(bool is_visible) override;
+  // ash::KeyboardControllerObserver:
+  void OnKeyboardVisibilityChanged(bool is_visible) override;
 
  private:
   void AttachInputMethod();
diff --git a/components/exo/text_input_unittest.cc b/components/exo/text_input_unittest.cc
index ca0d5bf..f46e0ac 100644
--- a/components/exo/text_input_unittest.cc
+++ b/components/exo/text_input_unittest.cc
@@ -165,7 +165,7 @@
 
   EXPECT_CALL(observer, OnShowVirtualKeyboardIfEnabled)
       .WillOnce(testing::Invoke(
-          [this]() { text_input()->OnKeyboardVisibilityStateChanged(true); }));
+          [this]() { text_input()->OnKeyboardVisibilityChanged(true); }));
   EXPECT_CALL(*delegate(), OnVirtualKeyboardVisibilityChanged(true)).Times(1);
   text_input()->ShowVirtualKeyboardIfEnabled();
 
@@ -182,7 +182,7 @@
   EXPECT_CALL(observer, OnTextInputStateChanged(text_input())).Times(1);
   EXPECT_CALL(observer, OnShowVirtualKeyboardIfEnabled)
       .WillOnce(testing::Invoke(
-          [this]() { text_input()->OnKeyboardVisibilityStateChanged(true); }));
+          [this]() { text_input()->OnKeyboardVisibilityChanged(true); }));
   EXPECT_CALL(*delegate(), Activated).Times(1);
   EXPECT_CALL(*delegate(), OnVirtualKeyboardVisibilityChanged(true)).Times(1);
   text_input()->Activate(surface());
diff --git a/components/exo/wayland/zcr_remote_shell.cc b/components/exo/wayland/zcr_remote_shell.cc
index b0ef96f..82155b5 100644
--- a/components/exo/wayland/zcr_remote_shell.cc
+++ b/components/exo/wayland/zcr_remote_shell.cc
@@ -525,6 +525,14 @@
       gfx::Rect(x, y, width, height));
 }
 
+void remote_surface_block_ime(wl_client* client, wl_resource* resource) {
+  GetUserDataAs<ClientControlledShellSurface>(resource)->SetImeBlocked(true);
+}
+
+void remote_surface_unblock_ime(wl_client* client, wl_resource* resource) {
+  GetUserDataAs<ClientControlledShellSurface>(resource)->SetImeBlocked(false);
+}
+
 const struct zcr_remote_surface_v1_interface remote_surface_implementation = {
     remote_surface_destroy,
     remote_surface_set_app_id,
@@ -568,7 +576,9 @@
     remote_surface_set_orientation_lock,
     remote_surface_pip,
     remote_surface_set_bounds,
-    remote_surface_set_aspect_ratio};
+    remote_surface_set_aspect_ratio,
+    remote_surface_block_ime,
+    remote_surface_unblock_ime};
 
 ////////////////////////////////////////////////////////////////////////////////
 // notification_surface_interface:
diff --git a/components/exo/wm_helper.h b/components/exo/wm_helper.h
index 2629279..ab96ad2 100644
--- a/components/exo/wm_helper.h
+++ b/components/exo/wm_helper.h
@@ -119,6 +119,8 @@
   virtual void RemovePostTargetHandler(ui::EventHandler* handler) = 0;
   virtual bool IsTabletModeWindowManagerEnabled() const = 0;
   virtual double GetDefaultDeviceScaleFactor() const = 0;
+  virtual void SetImeBlocked(aura::Window* window, bool ime_blocked) = 0;
+  virtual bool IsImeBlocked(aura::Window* window) const = 0;
 
   virtual LifetimeManager* GetLifetimeManager() = 0;
   virtual aura::client::CaptureClient* GetCaptureClient() = 0;
diff --git a/components/exo/wm_helper_chromeos.cc b/components/exo/wm_helper_chromeos.cc
index 269d1f1..c79e89a 100644
--- a/components/exo/wm_helper_chromeos.cc
+++ b/components/exo/wm_helper_chromeos.cc
@@ -25,6 +25,9 @@
   return ash::Shell::Get()->GetPrimaryRootWindow();
 }
 
+// A property key to store whether IME should be blocked for the surface.
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kImeBlockedKey, false)
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -212,6 +215,15 @@
   return display_info.display_modes()[0].device_scale_factor();
 }
 
+void WMHelperChromeOS::SetImeBlocked(aura::Window* window, bool ime_blocked) {
+  DCHECK_EQ(window, window->GetToplevelWindow());
+  window->SetProperty(kImeBlockedKey, ime_blocked);
+}
+
+bool WMHelperChromeOS::IsImeBlocked(aura::Window* window) const {
+  return window && window->GetToplevelWindow()->GetProperty(kImeBlockedKey);
+}
+
 WMHelper::LifetimeManager* WMHelperChromeOS::GetLifetimeManager() {
   return &lifetime_manager_;
 }
diff --git a/components/exo/wm_helper_chromeos.h b/components/exo/wm_helper_chromeos.h
index 856d49f..45338cb 100644
--- a/components/exo/wm_helper_chromeos.h
+++ b/components/exo/wm_helper_chromeos.h
@@ -90,6 +90,8 @@
   void RemovePostTargetHandler(ui::EventHandler* handler) override;
   bool IsTabletModeWindowManagerEnabled() const override;
   double GetDefaultDeviceScaleFactor() const override;
+  void SetImeBlocked(aura::Window* window, bool ime_blocked) override;
+  bool IsImeBlocked(aura::Window* window) const override;
 
   LifetimeManager* GetLifetimeManager() override;
   aura::client::CaptureClient* GetCaptureClient() override;
diff --git a/components/feed/core/feed_logging_metrics.cc b/components/feed/core/feed_logging_metrics.cc
index f42e042..dd745c9 100644
--- a/components/feed/core/feed_logging_metrics.cc
+++ b/components/feed/core/feed_logging_metrics.cc
@@ -38,6 +38,11 @@
       base::StringPrintf("%s.%s", histogram_base.c_str(), "TaskTime"),     \
       task_time);
 
+#define AGE_CUSTOM_UMA_HISTOGRAM_TIMES(histogram_name, time)  \
+  UMA_HISTOGRAM_CUSTOM_TIMES(histogram_name, time,            \
+                             base::TimeDelta::FromSeconds(1), \
+                             base::TimeDelta::FromDays(7), 100);
+
 // The constant integers(bucket sizes) and strings(UMA names) in this file need
 // matching with Zine's in the file
 // components/ntp_snippets/content_suggestions_metrics.cc. The purpose to have
@@ -110,8 +115,21 @@
   kMaxValue = KUploadAllActionsForURL
 };
 
+// Values correspond to
+// third_party/feed/src/main/proto/search/now/ui/action/feed_action.proto.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class ElementType {
+  KUnknownElementType = 0,
+  KCardLargeImage = 1,
+  KCardSmallImage = 2,
+  KInterestHeader = 3,
+  KTooltip = 4,
+  kMaxValue = KTooltip
+};
+
 // Each suffix here should correspond to an entry under histogram suffix
-// ContentSuggestionCategory in histograms.xml.
+// FeedSpinnerType in histograms.xml.
 std::string GetSpinnerTypeSuffix(SpinnerType spinner_type) {
   switch (spinner_type) {
     case SpinnerType::KInitialLoad:
@@ -133,6 +151,26 @@
 }
 
 // Each suffix here should correspond to an entry under histogram suffix
+// FeedElementType in histograms.xml.
+std::string GetElementTypeSuffix(ElementType element_type) {
+  switch (element_type) {
+    case ElementType::KUnknownElementType:
+      return "UnknownElementType";
+    case ElementType::KCardLargeImage:
+      return "CardLargeImage";
+    case ElementType::KCardSmallImage:
+      return "CardSmallImage";
+    case ElementType::KInterestHeader:
+      return "InterestHeader";
+    case ElementType::KTooltip:
+      return "Tooltip";
+  }
+
+  NOTREACHED();
+  return std::string();
+}
+
+// Each suffix here should correspond to an entry under histogram suffix
 // FeedTaskType in histograms.xml.
 void ReportTaskTime(TaskType task_type, int delay_time_ms, int task_time_ms) {
   switch (task_type) {
@@ -398,7 +436,7 @@
 }
 
 void RecordSpinnerTimeUMA(const char* base_name,
-                          base::TimeDelta time,
+                          const base::TimeDelta& time,
                           int spinner_type) {
   SpinnerType type = static_cast<SpinnerType>(spinner_type);
   std::string suffix = GetSpinnerTypeSuffix(type);
@@ -408,6 +446,32 @@
   base::UmaHistogramTimes(base_name, time);
 }
 
+void RecordElementPositionUMA(const char* base_name,
+                              int position,
+                              int element_type) {
+  ElementType type = static_cast<ElementType>(element_type);
+  std::string suffix = GetElementTypeSuffix(type);
+  std::string histogram_name(
+      base::StringPrintf("%s.%s", base_name, suffix.c_str()));
+  base::UmaHistogramExactLinear(histogram_name, position, kMaxSuggestionsTotal);
+  base::UmaHistogramExactLinear(base_name, position, kMaxSuggestionsTotal);
+}
+
+void RecordElementTimeUMA(const char* base_name,
+                          const base::TimeDelta& time,
+                          int element_type) {
+  ElementType type = static_cast<ElementType>(element_type);
+  std::string suffix = GetElementTypeSuffix(type);
+  std::string histogram_name(
+      base::StringPrintf("%s.%s", base_name, suffix.c_str()));
+  base::UmaHistogramCustomTimes(histogram_name, time,
+                                base::TimeDelta::FromSeconds(1),
+                                base::TimeDelta::FromDays(7), 100);
+  base::UmaHistogramCustomTimes(base_name, time,
+                                base::TimeDelta::FromSeconds(1),
+                                base::TimeDelta::FromDays(7), 100);
+}
+
 }  // namespace
 
 FeedLoggingMetrics::FeedLoggingMetrics(
@@ -438,20 +502,17 @@
                              kMaxSuggestionsTotal);
 
   base::TimeDelta age = clock_->Now() - publish_date;
-  UMA_HISTOGRAM_CUSTOM_TIMES("NewTabPage.ContentSuggestions.ShownAge.Articles",
-                             age, base::TimeDelta::FromSeconds(1),
-                             base::TimeDelta::FromDays(7), 100);
+  AGE_CUSTOM_UMA_HISTOGRAM_TIMES(
+      "NewTabPage.ContentSuggestions.ShownAge.Articles", age);
 
   UMA_HISTOGRAM_EXACT_LINEAR(
       "NewTabPage.ContentSuggestions.ShownScoreNormalized.Articles",
       ToUMAScore(score), 11);
 
   // Records the time since the fetch time of the displayed snippet.
-  UMA_HISTOGRAM_CUSTOM_TIMES(
-      "NewTabPage.ContentSuggestions.TimeSinceSuggestionFetched",
-      clock_->Now() - fetch_date, base::TimeDelta::FromSeconds(1),
-      base::TimeDelta::FromDays(7),
-      /*bucket_count=*/100);
+  base::TimeDelta fetch_age = clock_->Now() - fetch_date;
+  AGE_CUSTOM_UMA_HISTOGRAM_TIMES(
+      "NewTabPage.ContentSuggestions.TimeSinceSuggestionFetched", fetch_age);
 
   // When the first of the articles suggestions is shown, then we count this as
   // a single usage of content suggestions.
@@ -467,9 +528,8 @@
                              kMaxSuggestionsTotal);
 
   base::TimeDelta age = clock_->Now() - publish_date;
-  UMA_HISTOGRAM_CUSTOM_TIMES("NewTabPage.ContentSuggestions.OpenedAge.Articles",
-                             age, base::TimeDelta::FromSeconds(1),
-                             base::TimeDelta::FromDays(7), 100);
+  AGE_CUSTOM_UMA_HISTOGRAM_TIMES(
+      "NewTabPage.ContentSuggestions.OpenedAge.Articles", age);
 
   UMA_HISTOGRAM_EXACT_LINEAR(
       "NewTabPage.ContentSuggestions.OpenedScoreNormalized.Articles",
@@ -501,9 +561,8 @@
                              position, kMaxSuggestionsTotal);
 
   base::TimeDelta age = clock_->Now() - publish_date;
-  UMA_HISTOGRAM_CUSTOM_TIMES(
-      "NewTabPage.ContentSuggestions.MenuOpenedAge.Articles", age,
-      base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(7), 100);
+  AGE_CUSTOM_UMA_HISTOGRAM_TIMES(
+      "NewTabPage.ContentSuggestions.MenuOpenedAge.Articles", age);
 
   UMA_HISTOGRAM_EXACT_LINEAR(
       "NewTabPage.ContentSuggestions.MenuOpenedScoreNormalized.Articles",
@@ -598,6 +657,29 @@
   }
 }
 
+void FeedLoggingMetrics::OnVisualElementClicked(int element_type,
+                                                int position,
+                                                base::Time fetch_date) {
+  RecordElementPositionUMA("ContentSuggestions.Feed.VisualElement.Clicked",
+                           position, element_type);
+
+  RecordElementTimeUMA(
+      "ContentSuggestions.Feed.VisualElement.Clicked."
+      "TimeSinceElementFetched",
+      clock_->Now() - fetch_date, element_type);
+}
+
+void FeedLoggingMetrics::OnVisualElementViewed(int element_type,
+                                               int position,
+                                               base::Time fetch_date) {
+  RecordElementPositionUMA("ContentSuggestions.Feed.VisualElement.Viewed",
+                           position, element_type);
+
+  RecordElementTimeUMA(
+      "ContentSuggestions.Feed.VisualElement.Viewed.TimeSinceElementFetched",
+      clock_->Now() - fetch_date, element_type);
+}
+
 void FeedLoggingMetrics::OnInternalError(int internal_error) {
   // TODO(https://crbug.com/935602): The max value here is fragile, figure out
   // some way to test the @IntDef size.
diff --git a/components/feed/core/feed_logging_metrics.h b/components/feed/core/feed_logging_metrics.h
index c203e08..d73a39d 100644
--- a/components/feed/core/feed_logging_metrics.h
+++ b/components/feed/core/feed_logging_metrics.h
@@ -89,6 +89,14 @@
 
   void OnPietFrameRenderingEvent(std::vector<int> piet_error_codes);
 
+  void OnVisualElementClicked(int element_type,
+                              int position,
+                              base::Time fetch_date);
+
+  void OnVisualElementViewed(int element_type,
+                             int position,
+                             base::Time fetch_date);
+
   void OnInternalError(int internal_error);
 
   void OnTokenCompleted(bool was_synthetic, int content_count, int token_count);
diff --git a/components/nacl/broker/nacl_broker_manifest.cc b/components/nacl/broker/nacl_broker_manifest.cc
index 0cec707..9cdf5447 100644
--- a/components/nacl/broker/nacl_broker_manifest.cc
+++ b/components/nacl/broker/nacl_broker_manifest.cc
@@ -27,7 +27,6 @@
                                 "content.mojom.ChildControl",
                                 "content.mojom.ChildHistogramFetcherFactory",
                                 "content.mojom.ResourceUsageReporter",
-                                "tracing.mojom.BackgroundTracingAgent",
                             })
 
           .Build()};
diff --git a/components/nacl/loader/nacl_loader_manifest.cc b/components/nacl/loader/nacl_loader_manifest.cc
index a3ca0395..2f250a2 100644
--- a/components/nacl/loader/nacl_loader_manifest.cc
+++ b/components/nacl/loader/nacl_loader_manifest.cc
@@ -26,7 +26,6 @@
                                 "content.mojom.ChildControl",
                                 "content.mojom.ChildHistogramFetcherFactory",
                                 "content.mojom.ResourceUsageReporter",
-                                "tracing.mojom.BackgroundTracingAgent",
                             })
           .Build()};
   return *manifest;
diff --git a/components/previews/content/hint_cache_store.cc b/components/previews/content/hint_cache_store.cc
index 4ef0a37..74d1f08 100644
--- a/components/previews/content/hint_cache_store.cc
+++ b/components/previews/content/hint_cache_store.cc
@@ -812,6 +812,21 @@
     return;
   }
 
+  if (entry->has_expiry_time_secs() &&
+      entry->expiry_time_secs() <=
+          base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds()) {
+    // An expired hint should be loaded rarely if the user is regularly fetching
+    // and storing fresh hints. Expired fetched hints are removed each time
+    // fresh hints are fetched and placed into the store. In the future, the
+    // expired hints could be asynchronously removed if necessary.
+    // An empty hint is returned instead of the expired one.
+    UMA_HISTOGRAM_BOOLEAN(
+        "Previews.HintCacheStore.OnLoadHint.FetchedHintExpired", true);
+    std::unique_ptr<optimization_guide::proto::Hint> loaded_hint(nullptr);
+    std::move(callback).Run(entry_key, std::move(loaded_hint));
+    return;
+  }
+
   // Release the Hint into a Hint unique_ptr. This eliminates the need for any
   // copies of the entry's hint.
   std::unique_ptr<optimization_guide::proto::Hint> loaded_hint(
diff --git a/components/previews/content/hint_cache_store_unittest.cc b/components/previews/content/hint_cache_store_unittest.cc
index 5c26000..cce4eca 100644
--- a/components/previews/content/hint_cache_store_unittest.cc
+++ b/components/previews/content/hint_cache_store_unittest.cc
@@ -1557,4 +1557,67 @@
   EXPECT_TRUE(hint_loaded_counts_pref()->empty());
 }
 
+TEST_F(HintCacheStoreTest, FetchedHintsLoadExpiredHint) {
+  base::HistogramTester histogram_tester;
+  MetadataSchemaState schema_state = MetadataSchemaState::kValid;
+  size_t initial_hint_count = 10;
+  base::Time update_time = base::Time().Now();
+  SeedInitialData(schema_state, initial_hint_count);
+  CreateDatabase();
+  InitializeStore(schema_state);
+
+  base::Version version("2.0.0");
+  std::unique_ptr<HintUpdateData> update_data =
+      hint_store()->MaybeCreateUpdateDataForComponentHints(
+          base::Version(kUpdateComponentVersion));
+  ASSERT_TRUE(update_data);
+
+  optimization_guide::proto::Hint hint1;
+  hint1.set_key("domain1.org");
+  hint1.set_key_representation(optimization_guide::proto::HOST_SUFFIX);
+  update_data->MoveHintIntoUpdateData(std::move(hint1));
+  optimization_guide::proto::Hint hint2;
+  hint2.set_key("host.domain2.org");
+  hint2.set_key_representation(optimization_guide::proto::HOST_SUFFIX);
+  update_data->MoveHintIntoUpdateData(std::move(hint2));
+
+  UpdateComponentHints(std::move(update_data));
+
+  // Add fetched hints to the store that expired.
+  update_data = hint_store()->CreateUpdateDataForFetchedHints(
+      update_time, update_time - base::TimeDelta().FromDays(10));
+
+  optimization_guide::proto::Hint fetched_hint1;
+  fetched_hint1.set_key("domain2.org");
+  fetched_hint1.set_key_representation(optimization_guide::proto::HOST_SUFFIX);
+  update_data->MoveHintIntoUpdateData(std::move(fetched_hint1));
+  optimization_guide::proto::Hint fetched_hint2;
+  fetched_hint2.set_key("domain3.org");
+  fetched_hint2.set_key_representation(optimization_guide::proto::HOST_SUFFIX);
+  update_data->MoveHintIntoUpdateData(std::move(fetched_hint2));
+
+  UpdateFetchedHints(std::move(update_data));
+
+  // Hint for host.domain2.org should be a fetched hint ("3_" prefix)
+  // as fetched hints take priority.
+  std::string host_suffix = "host.domain2.org";
+  HintCacheStore::EntryKey hint_entry_key;
+  if (!hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) {
+    FAIL() << "Hint entry not found for host suffix: " << host_suffix;
+  }
+  EXPECT_EQ(hint_entry_key, "3_domain2.org");
+  hint_store()->LoadHint(hint_entry_key,
+                         base::BindOnce(&HintCacheStoreTest::OnHintLoaded,
+                                        base::Unretained(this)));
+
+  // OnLoadHint callback
+  db()->GetCallback(true);
+
+  // |hint_entry_key| will be a fetched hint but the entry will be empty.
+  EXPECT_EQ(last_loaded_hint_entry_key(), hint_entry_key);
+  EXPECT_FALSE(last_loaded_hint());
+  histogram_tester.ExpectBucketCount(
+      "Previews.HintCacheStore.OnLoadHint.FetchedHintExpired", true, 1);
+}
+
 }  // namespace previews
diff --git a/components/remote_cocoa/DEPS b/components/remote_cocoa/DEPS
index 646c0f5..755476f 100644
--- a/components/remote_cocoa/DEPS
+++ b/components/remote_cocoa/DEPS
@@ -3,6 +3,7 @@
   "+components/crash/core/common/crash_key.h",
   "+components/viz/common",
   "+mojo/public/cpp/bindings",
+  "+skia/ext",
   "+ui/accelerated_widget_mac",
   "+ui/base",
   "+ui/compositor",
diff --git a/components/remote_cocoa/app_shim/BUILD.gn b/components/remote_cocoa/app_shim/BUILD.gn
index 912d967..e795b80 100644
--- a/components/remote_cocoa/app_shim/BUILD.gn
+++ b/components/remote_cocoa/app_shim/BUILD.gn
@@ -26,6 +26,8 @@
     "bridged_content_view_touch_bar.mm",
     "browser_native_widget_window_mac.h",
     "browser_native_widget_window_mac.mm",
+    "color_panel_bridge.h",
+    "color_panel_bridge.mm",
     "drag_drop_client.h",
     "mouse_capture.h",
     "mouse_capture.mm",
diff --git a/components/remote_cocoa/app_shim/application_bridge.h b/components/remote_cocoa/app_shim/application_bridge.h
index 8c5c703..f19c3a17 100644
--- a/components/remote_cocoa/app_shim/application_bridge.h
+++ b/components/remote_cocoa/app_shim/application_bridge.h
@@ -41,6 +41,8 @@
 
   // mojom::Application:
   void CreateAlert(mojom::AlertBridgeRequest bridge_request) override;
+  void ShowColorPanel(mojom::ColorPanelRequest request,
+                      mojom::ColorPanelHostPtr host) override;
   void CreateNativeWidgetNSWindow(
       uint64_t bridge_id,
       mojom::NativeWidgetNSWindowAssociatedRequest bridge_request,
diff --git a/components/remote_cocoa/app_shim/application_bridge.mm b/components/remote_cocoa/app_shim/application_bridge.mm
index b810fd9..628196e 100644
--- a/components/remote_cocoa/app_shim/application_bridge.mm
+++ b/components/remote_cocoa/app_shim/application_bridge.mm
@@ -7,8 +7,10 @@
 #include "base/bind.h"
 #include "base/no_destructor.h"
 #include "components/remote_cocoa/app_shim/alert.h"
+#include "components/remote_cocoa/app_shim/color_panel_bridge.h"
 #include "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
 #include "components/remote_cocoa/app_shim/native_widget_ns_window_host_helper.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/cocoa/remote_accessibility_api.h"
 
@@ -119,6 +121,12 @@
   ignore_result(new AlertBridge(std::move(bridge_request)));
 }
 
+void ApplicationBridge::ShowColorPanel(mojom::ColorPanelRequest request,
+                                       mojom::ColorPanelHostPtr host) {
+  mojo::MakeStrongBinding(std::make_unique<ColorPanelBridge>(std::move(host)),
+                          std::move(request));
+}
+
 void ApplicationBridge::CreateNativeWidgetNSWindow(
     uint64_t bridge_id,
     mojom::NativeWidgetNSWindowAssociatedRequest bridge_request,
diff --git a/components/remote_cocoa/app_shim/color_panel_bridge.h b/components/remote_cocoa/app_shim/color_panel_bridge.h
new file mode 100644
index 0000000..0c767b4a
--- /dev/null
+++ b/components/remote_cocoa/app_shim/color_panel_bridge.h
@@ -0,0 +1,32 @@
+// 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_REMOTE_COCOA_APP_SHIM_COLOR_PANEL_BRIDGE_H_
+#define COMPONENTS_REMOTE_COCOA_APP_SHIM_COLOR_PANEL_BRIDGE_H_
+
+#include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h"
+#include "components/remote_cocoa/common/color_panel.mojom.h"
+
+namespace remote_cocoa {
+
+// A bridge between the mojo ColorPanel interface and the Objective C
+// ColorPanelListener.
+class REMOTE_COCOA_APP_SHIM_EXPORT ColorPanelBridge
+    : public remote_cocoa::mojom::ColorPanel {
+ public:
+  ColorPanelBridge(mojom::ColorPanelHostPtr host);
+  ~ColorPanelBridge() override;
+  mojom::ColorPanelHost* host() { return host_.get(); }
+
+  // mojom::ColorPanel.
+  void Show(uint32_t initial_color) override;
+  void SetSelectedColor(uint32_t color) override;
+
+ private:
+  mojom::ColorPanelHostPtr host_;
+};
+
+}  // namespace remote_cocoa
+
+#endif  // COMPONENTS_REMOTE_COCOA_APP_SHIM_COLOR_PANEL_BRIDGE_H_
diff --git a/components/remote_cocoa/app_shim/color_panel_bridge.mm b/components/remote_cocoa/app_shim/color_panel_bridge.mm
new file mode 100644
index 0000000..12eaee1
--- /dev/null
+++ b/components/remote_cocoa/app_shim/color_panel_bridge.mm
@@ -0,0 +1,140 @@
+// 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/remote_cocoa/app_shim/color_panel_bridge.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "skia/ext/skia_utils_mac.h"
+
+namespace {
+// The currently active bridge, to which the ColorPanelListener will forward
+// its observations.
+remote_cocoa::ColorPanelBridge* g_current_panel_bridge = nullptr;
+}  // namespace
+
+// A singleton listener class to act as a event target for NSColorPanel and
+// send the results to the C++ class, ColorPanelBridge.
+@interface ColorPanelListener : NSObject {
+ @protected
+  // We don't call DidChooseColor if the change wasn't caused by the user
+  // interacting with the panel.
+  BOOL nonUserChange_;
+}
+// Called from NSNotificationCenter.
+- (void)windowWillClose:(NSNotification*)notification;
+
+// Called from NSColorPanel.
+- (void)didChooseColor:(NSColorPanel*)panel;
+
+// The singleton instance.
++ (ColorPanelListener*)instance;
+
+// Show the NSColorPanel.
+- (void)showColorPanel;
+
+// Sets color to the NSColorPanel as a non user change.
+- (void)setColor:(NSColor*)color;
+@end
+
+@implementation ColorPanelListener
+- (id)init {
+  if ((self = [super init])) {
+    NSColorPanel* panel = [NSColorPanel sharedColorPanel];
+    [[NSNotificationCenter defaultCenter]
+        addObserver:self
+           selector:@selector(windowWillClose:)
+               name:NSWindowWillCloseNotification
+             object:panel];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  // This object is never freed.
+  NOTREACHED();
+  [super dealloc];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+  if (g_current_panel_bridge)
+    g_current_panel_bridge->host()->DidCloseColorPanel();
+  nonUserChange_ = NO;
+}
+
+- (void)didChooseColor:(NSColorPanel*)panel {
+  if (nonUserChange_) {
+    nonUserChange_ = NO;
+    return;
+  }
+  nonUserChange_ = NO;
+  NSColor* color = [panel color];
+  if ([[color colorSpaceName] isEqualToString:NSNamedColorSpace]) {
+    color = [color colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
+    // Some colors in "Developer" palette in "Color Palettes" tab can't be
+    // converted to RGB. We just ignore such colors.
+    // TODO(tkent): We should notice the rejection to users.
+    if (!color)
+      return;
+  }
+  SkColor skColor = 0;
+  if ([color colorSpace] == [NSColorSpace genericRGBColorSpace]) {
+    // genericRGB -> deviceRGB conversion isn't ignorable.  We'd like to use RGB
+    // values shown in NSColorPanel UI.
+    CGFloat red, green, blue, alpha;
+    [color getRed:&red green:&green blue:&blue alpha:&alpha];
+    skColor = SkColorSetARGB(
+        SkScalarRoundToInt(255.0 * alpha), SkScalarRoundToInt(255.0 * red),
+        SkScalarRoundToInt(255.0 * green), SkScalarRoundToInt(255.0 * blue));
+  } else {
+    skColor = skia::NSDeviceColorToSkColor(
+        [[panel color] colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
+  }
+  if (g_current_panel_bridge)
+    g_current_panel_bridge->host()->DidChooseColorInColorPanel(skColor);
+}
+
++ (ColorPanelListener*)instance {
+  static ColorPanelListener* listener = [[ColorPanelListener alloc] init];
+  return listener;
+}
+
+- (void)showColorPanel {
+  NSColorPanel* panel = [NSColorPanel sharedColorPanel];
+  [panel setShowsAlpha:NO];
+  [panel setTarget:self];
+  [panel setAction:@selector(didChooseColor:)];
+  [panel makeKeyAndOrderFront:nil];
+}
+
+- (void)setColor:(NSColor*)color {
+  nonUserChange_ = YES;
+  [[NSColorPanel sharedColorPanel] setColor:color];
+}
+@end
+
+namespace remote_cocoa {
+
+ColorPanelBridge::ColorPanelBridge(mojom::ColorPanelHostPtr host)
+    : host_(std::move(host)) {
+  g_current_panel_bridge = this;
+}
+
+ColorPanelBridge::~ColorPanelBridge() {
+  if (g_current_panel_bridge == this)
+    g_current_panel_bridge = nullptr;
+}
+
+void ColorPanelBridge::Show(uint32_t initial_color) {
+  ColorPanelListener* listener = [ColorPanelListener instance];
+  [listener setColor:skia::SkColorToDeviceNSColor(initial_color)];
+  [listener showColorPanel];
+}
+
+void ColorPanelBridge::SetSelectedColor(uint32_t color) {
+  ColorPanelListener* listener = [ColorPanelListener instance];
+  [listener setColor:skia::SkColorToDeviceNSColor(color)];
+}
+
+}  // namespace remote_cocoa
diff --git a/components/remote_cocoa/browser/application_host.h b/components/remote_cocoa/browser/application_host.h
index 233aa35e4..c83371c9 100644
--- a/components/remote_cocoa/browser/application_host.h
+++ b/components/remote_cocoa/browser/application_host.h
@@ -9,6 +9,7 @@
 #include "base/observer_list_types.h"
 #include "components/remote_cocoa/browser/remote_cocoa_browser_export.h"
 #include "components/remote_cocoa/common/application.mojom.h"
+#include "ui/gfx/native_widget_types.h"
 
 namespace remote_cocoa {
 
@@ -33,6 +34,8 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(const Observer* observer);
 
+  static ApplicationHost* GetForNativeView(gfx::NativeView view);
+
  private:
   mojom::ApplicationAssociatedPtr application_ptr_;
   base::ObserverList<Observer> observers_;
diff --git a/components/remote_cocoa/browser/application_host.mm b/components/remote_cocoa/browser/application_host.mm
index ae14569..1d77bac 100644
--- a/components/remote_cocoa/browser/application_host.mm
+++ b/components/remote_cocoa/browser/application_host.mm
@@ -4,6 +4,9 @@
 
 #include "components/remote_cocoa/browser/application_host.h"
 
+#import <Cocoa/Cocoa.h>
+
+#include "components/remote_cocoa/browser/window.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 
 namespace remote_cocoa {
@@ -29,4 +32,10 @@
   observers_.RemoveObserver(observer);
 }
 
+// static
+ApplicationHost* ApplicationHost::GetForNativeView(gfx::NativeView view) {
+  gfx::NativeWindow window([view.GetNativeNSView() window]);
+  return GetWindowApplicationHost(window);
+}
+
 }  // namespace remote_cocoa
diff --git a/components/remote_cocoa/common/BUILD.gn b/components/remote_cocoa/common/BUILD.gn
index a8da71b..ae88645 100644
--- a/components/remote_cocoa/common/BUILD.gn
+++ b/components/remote_cocoa/common/BUILD.gn
@@ -10,6 +10,7 @@
   sources = [
     "alert.mojom",
     "application.mojom",
+    "color_panel.mojom",
     "native_widget_ns_window.mojom",
     "native_widget_ns_window_host.mojom",
     "select_file_dialog.mojom",
diff --git a/components/remote_cocoa/common/application.mojom b/components/remote_cocoa/common/application.mojom
index 9f41b8f..786e5f92 100644
--- a/components/remote_cocoa/common/application.mojom
+++ b/components/remote_cocoa/common/application.mojom
@@ -5,6 +5,7 @@
 module remote_cocoa.mojom;
 
 import "components/remote_cocoa/common/alert.mojom";
+import "components/remote_cocoa/common/color_panel.mojom";
 import "components/remote_cocoa/common/native_widget_ns_window.mojom";
 import "components/remote_cocoa/common/native_widget_ns_window_host.mojom";
 import "components/remote_cocoa/common/text_input_host.mojom";
@@ -27,6 +28,9 @@
   // Create a bridge for an NSAlert. The resulting object owns its own lifetime.
   CreateAlert(AlertBridge& alert_bridge_request);
 
+  // Show the NSColorPanel in this application.
+  ShowColorPanel(ColorPanel& request, ColorPanelHost host);
+
   // Create a window for a native widget. The resulting object will be owned by
   // the connection for |host|. Closing that connection will result in deleting
   // the bridge.
diff --git a/components/remote_cocoa/common/color_panel.mojom b/components/remote_cocoa/common/color_panel.mojom
new file mode 100644
index 0000000..b1519b9
--- /dev/null
+++ b/components/remote_cocoa/common/color_panel.mojom
@@ -0,0 +1,23 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module remote_cocoa.mojom;
+
+// Interface to the NSColorPanel.
+interface ColorPanel {
+  // Show the panel with initial color |initial_sk_color|.
+  Show(uint32 initial_sk_color);
+
+  // Programmatically set the selected color to |sk_color|.
+  SetSelectedColor(uint32 sk_color);
+};
+
+// NSColorPanel's interface to the browser.
+interface ColorPanelHost {
+  // Specify that the user color selection has changed.
+  DidChooseColorInColorPanel(uint32 sk_color);
+
+  // Sepecify that the user has closed the panel.
+  DidCloseColorPanel();
+};
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_http_popup.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_http_popup.Pixel_XL-25.png.sha1
index d27a97a..f959db7b 100644
--- a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_http_popup.Pixel_XL-25.png.sha1
+++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_http_popup.Pixel_XL-25.png.sha1
@@ -1 +1 @@
-d227fb8426ac42742dc2edb1947be83db684617a
\ No newline at end of file
+05bdbeb07592d88f819fde004996d6dd1f9ae4c5
\ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_http_popup.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_http_popup.Pixel_XL-26.png.sha1
index 5f6b506..f20eda82 100644
--- a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_http_popup.Pixel_XL-26.png.sha1
+++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_http_popup.Pixel_XL-26.png.sha1
@@ -1 +1 @@
-15c8f8f4a2cafd01d203390758d38e8b2460e093
\ No newline at end of file
+5beb3cf51a29d5999ef0f08a74769354c30d4e48
\ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_bad_cert_popup.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_bad_cert_popup.Pixel_XL-25.png.sha1
index 6f889f2d..489567fe 100644
--- a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_bad_cert_popup.Pixel_XL-25.png.sha1
+++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_bad_cert_popup.Pixel_XL-25.png.sha1
@@ -1 +1 @@
-1cb9e7b549ee40a26d20bc8b9e28f5a7a9248440
\ No newline at end of file
+bab5f5c368b80d75db2f8150d17352e87d120f4e
\ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_bad_cert_popup.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_bad_cert_popup.Pixel_XL-26.png.sha1
index 1657c26..da749cc 100644
--- a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_bad_cert_popup.Pixel_XL-26.png.sha1
+++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_bad_cert_popup.Pixel_XL-26.png.sha1
@@ -1 +1 @@
-b02278e520c41cdd3ccf52d66c13d8eb1a90ca56
\ No newline at end of file
+ed37b6fd37d9d95fcac3421a41092a9d4b22610c
\ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_popup.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_popup.Pixel_XL-25.png.sha1
index 9220787..a286705 100644
--- a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_popup.Pixel_XL-25.png.sha1
+++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_popup.Pixel_XL-25.png.sha1
@@ -1 +1 @@
-cb341266df169a673ea23f202a2ef4051b08994d
\ No newline at end of file
+e41e7e2b2e4165de37c047b02cb5b82e7586ee38
\ No newline at end of file
diff --git a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_popup.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_popup.Pixel_XL-26.png.sha1
index e070c14d..4599113 100644
--- a/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_popup.Pixel_XL-26.png.sha1
+++ b/components/test/data/vr_browser_ui/render_tests/VrBrowserNativeUiTest.security_token_https_popup.Pixel_XL-26.png.sha1
@@ -1 +1 @@
-f8946d5df09e9bb9c7344427f21965deeba9451a
\ No newline at end of file
+306a8db476ec0e3bf17eae89bd2a99876f9a8225
\ No newline at end of file
diff --git a/components/tracing/BUILD.gn b/components/tracing/BUILD.gn
index 470d686..f0c2452 100644
--- a/components/tracing/BUILD.gn
+++ b/components/tracing/BUILD.gn
@@ -8,6 +8,8 @@
   sources = [
     "child/background_tracing_agent_impl.cc",
     "child/background_tracing_agent_impl.h",
+    "child/background_tracing_agent_provider_impl.cc",
+    "child/background_tracing_agent_provider_impl.h",
     "common/graphics_memory_dump_provider_android.cc",
     "common/graphics_memory_dump_provider_android.h",
     "tracing_export.h",
diff --git a/components/tracing/child/background_tracing_agent_impl.cc b/components/tracing/child/background_tracing_agent_impl.cc
index 3bffae0..25e0d239 100644
--- a/components/tracing/child/background_tracing_agent_impl.cc
+++ b/components/tracing/child/background_tracing_agent_impl.cc
@@ -8,15 +8,10 @@
 
 #include "base/metrics/statistics_recorder.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
-using base::trace_event::MemoryDumpManager;
-using base::trace_event::TraceLog;
-
 namespace tracing {
-
 namespace {
 
 constexpr base::TimeDelta kMinTimeBetweenHistogramChanges =
@@ -24,31 +19,14 @@
 
 }  // namespace
 
-// static
-void BackgroundTracingAgentImpl::Create(
-    mojo::PendingReceiver<mojom::BackgroundTracingAgent> receiver) {
-  mojo::MakeSelfOwnedReceiver(std::make_unique<BackgroundTracingAgentImpl>(),
-                              std::move(receiver));
-}
-
-void BackgroundTracingAgentImpl::CreateFromRequest(
-    mojo::InterfaceRequest<mojom::BackgroundTracingAgent> request) {
-  Create(std::move(request));
-}
-
-BackgroundTracingAgentImpl::BackgroundTracingAgentImpl() = default;
-
-BackgroundTracingAgentImpl::~BackgroundTracingAgentImpl() = default;
-
-void BackgroundTracingAgentImpl::Initialize(
-    uint64_t tracing_process_id,
-    mojo::PendingRemote<mojom::BackgroundTracingAgentClient> client) {
-  MemoryDumpManager::GetInstance()->set_tracing_process_id(tracing_process_id);
-
-  client_.Bind(std::move(client));
+BackgroundTracingAgentImpl::BackgroundTracingAgentImpl(
+    mojo::PendingRemote<mojom::BackgroundTracingAgentClient> client)
+    : client_(std::move(client)) {
   client_->OnInitialized();
 }
 
+BackgroundTracingAgentImpl::~BackgroundTracingAgentImpl() = default;
+
 void BackgroundTracingAgentImpl::SetUMACallback(
     const std::string& histogram_name,
     int32_t histogram_lower_value,
diff --git a/components/tracing/child/background_tracing_agent_impl.h b/components/tracing/child/background_tracing_agent_impl.h
index 500e378..dca6f4d 100644
--- a/components/tracing/child/background_tracing_agent_impl.h
+++ b/components/tracing/child/background_tracing_agent_impl.h
@@ -25,20 +25,11 @@
 class TRACING_EXPORT BackgroundTracingAgentImpl
     : public mojom::BackgroundTracingAgent {
  public:
-  static void Create(
-      mojo::PendingReceiver<mojom::BackgroundTracingAgent> receiver);
-
-  // For backwards compat.
-  static void CreateFromRequest(
-      mojo::InterfaceRequest<mojom::BackgroundTracingAgent> request);
-
-  BackgroundTracingAgentImpl();
+  explicit BackgroundTracingAgentImpl(
+      mojo::PendingRemote<mojom::BackgroundTracingAgentClient> client);
   ~BackgroundTracingAgentImpl() override;
 
   // mojom::BackgroundTracingAgent methods:
-  void Initialize(uint64_t tracing_process_id,
-                  mojo::PendingRemote<mojom::BackgroundTracingAgentClient>
-                      pending_client) override;
   void SetUMACallback(const std::string& histogram_name,
                       int32_t histogram_lower_value,
                       int32_t histogram_upper_value,
diff --git a/components/tracing/child/background_tracing_agent_impl_unittest.cc b/components/tracing/child/background_tracing_agent_impl_unittest.cc
index 743e789..a32cb57 100644
--- a/components/tracing/child/background_tracing_agent_impl_unittest.cc
+++ b/components/tracing/child/background_tracing_agent_impl_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "base/test/scoped_task_environment.h"
+#include "components/tracing/child/background_tracing_agent_provider_impl.h"
 #include "mojo/public/cpp/bindings/unique_receiver_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -47,8 +48,9 @@
 class BackgroundTracingAgentImplTest : public testing::Test {
  public:
   BackgroundTracingAgentImplTest() {
-    agent_set_.Add(std::make_unique<tracing::BackgroundTracingAgentImpl>(),
-                   agent_.BindNewPipeAndPassReceiver());
+    provider_set_.Add(
+        std::make_unique<tracing::BackgroundTracingAgentProviderImpl>(),
+        provider_.BindNewPipeAndPassReceiver());
 
     auto recorder = std::make_unique<BackgroundTracingAgentClientRecorder>();
     recorder_ = recorder.get();
@@ -57,7 +59,8 @@
     client_set_.Add(std::move(recorder),
                     client.InitWithNewPipeAndPassReceiver());
 
-    agent_->Initialize(0, std::move(client));
+    provider_->Create(0, std::move(client),
+                      agent_.BindNewPipeAndPassReceiver());
   }
 
   tracing::mojom::BackgroundTracingAgent* agent() { return agent_.get(); }
@@ -66,8 +69,10 @@
 
  private:
   base::test::ScopedTaskEnvironment task_environment_;
+  mojo::Remote<tracing::mojom::BackgroundTracingAgentProvider> provider_;
   mojo::Remote<tracing::mojom::BackgroundTracingAgent> agent_;
-  mojo::UniqueReceiverSet<tracing::mojom::BackgroundTracingAgent> agent_set_;
+  mojo::UniqueReceiverSet<tracing::mojom::BackgroundTracingAgentProvider>
+      provider_set_;
   mojo::UniqueReceiverSet<tracing::mojom::BackgroundTracingAgentClient>
       client_set_;
   BackgroundTracingAgentClientRecorder* recorder_ = nullptr;
diff --git a/components/tracing/child/background_tracing_agent_provider_impl.cc b/components/tracing/child/background_tracing_agent_provider_impl.cc
new file mode 100644
index 0000000..5f1f4115
--- /dev/null
+++ b/components/tracing/child/background_tracing_agent_provider_impl.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 "components/tracing/child/background_tracing_agent_provider_impl.h"
+
+#include <memory>
+
+#include "base/metrics/statistics_recorder.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/trace_event.h"
+#include "components/tracing/child/background_tracing_agent_impl.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+
+namespace tracing {
+
+BackgroundTracingAgentProviderImpl::BackgroundTracingAgentProviderImpl() =
+    default;
+
+BackgroundTracingAgentProviderImpl::~BackgroundTracingAgentProviderImpl() =
+    default;
+
+void BackgroundTracingAgentProviderImpl::AddBinding(
+    mojo::PendingReceiver<mojom::BackgroundTracingAgentProvider> provider) {
+  self_receiver_set_.Add(this, std::move(provider));
+}
+
+void BackgroundTracingAgentProviderImpl::Create(
+    uint64_t tracing_process_id,
+    mojo::PendingRemote<mojom::BackgroundTracingAgentClient> client,
+    mojo::PendingReceiver<mojom::BackgroundTracingAgent> agent) {
+  base::trace_event::MemoryDumpManager::GetInstance()->set_tracing_process_id(
+      tracing_process_id);
+
+  agent_receiver_set_.Add(
+      std::make_unique<BackgroundTracingAgentImpl>(std::move(client)),
+      std::move(agent));
+}
+
+}  // namespace tracing
diff --git a/components/tracing/child/background_tracing_agent_provider_impl.h b/components/tracing/child/background_tracing_agent_provider_impl.h
new file mode 100644
index 0000000..4ac0e44
--- /dev/null
+++ b/components/tracing/child/background_tracing_agent_provider_impl.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 COMPONENTS_TRACING_CHILD_BACKGROUND_TRACING_AGENT_PROVIDER_IMPL_H_
+#define COMPONENTS_TRACING_CHILD_BACKGROUND_TRACING_AGENT_PROVIDER_IMPL_H_
+
+#include "base/macros.h"
+#include "components/tracing/common/background_tracing_agent.mojom.h"
+#include "components/tracing/tracing_export.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/unique_receiver_set.h"
+
+namespace tracing {
+
+class TRACING_EXPORT BackgroundTracingAgentProviderImpl
+    : public mojom::BackgroundTracingAgentProvider {
+ public:
+  BackgroundTracingAgentProviderImpl();
+  ~BackgroundTracingAgentProviderImpl() override;
+
+  void AddBinding(
+      mojo::PendingReceiver<mojom::BackgroundTracingAgentProvider> provider);
+
+  // mojom::BackgroundTracingAgentProvider methods:
+  void Create(
+      uint64_t tracing_process_id,
+      mojo::PendingRemote<mojom::BackgroundTracingAgentClient> client,
+      mojo::PendingReceiver<mojom::BackgroundTracingAgent> agent) override;
+
+ private:
+  mojo::ReceiverSet<mojom::BackgroundTracingAgentProvider> self_receiver_set_;
+  mojo::UniqueReceiverSet<mojom::BackgroundTracingAgent> agent_receiver_set_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundTracingAgentProviderImpl);
+};
+
+}  // namespace tracing
+
+#endif  // COMPONENTS_TRACING_CHILD_BACKGROUND_TRACING_AGENT_PROVIDER_IMPL_H_
diff --git a/components/tracing/common/background_tracing_agent.mojom b/components/tracing/common/background_tracing_agent.mojom
index 9f502c8..6260b65 100644
--- a/components/tracing/common/background_tracing_agent.mojom
+++ b/components/tracing/common/background_tracing_agent.mojom
@@ -15,10 +15,6 @@
 // specific metrics being hit and control when to start/stop tracing in
 // response. How metrics are communicated b/w processes is not covered here.
 interface BackgroundTracingAgent {
-  // Call this method first. Results in an OnInitialized callback.
-  Initialize(uint64 tracing_process_id,
-             pending_remote<BackgroundTracingAgentClient> client);
-
   // Call this method to begin reporting metrics corresponding to the named
   // histogram. Lower and upper bound values constrain what data is reported.
   // This results in OnTriggerBackgroundTrace callbacks (multiple if |repeat|
@@ -33,3 +29,11 @@
   // histogram.
   ClearUMACallback(string histogram_name);
 };
+
+// This interface is used to construct a BackgroundTracingAgent.
+interface BackgroundTracingAgentProvider {
+  // Results in an OnInitialized callback to |client|.
+  Create(uint64 tracing_process_id,
+         pending_remote<BackgroundTracingAgentClient> client,
+         pending_receiver<BackgroundTracingAgent> agent);
+};
diff --git a/components/viz/common/gpu/vulkan_in_process_context_provider.cc b/components/viz/common/gpu/vulkan_in_process_context_provider.cc
index 3e59e9d..1e685b26 100644
--- a/components/viz/common/gpu/vulkan_in_process_context_provider.cc
+++ b/components/viz/common/gpu/vulkan_in_process_context_provider.cc
@@ -87,8 +87,8 @@
                      instance_extensions.size(), instance_extensions.data(),
                      device_extensions.size(), device_extensions.data());
   backend_context.fVkExtensions = &gr_extensions;
-
-  backend_context.fDeviceFeatures = &device_queue_->enabled_device_features();
+  backend_context.fDeviceFeatures2 =
+      &device_queue_->enabled_device_features_2();
   backend_context.fGetProc = get_proc;
 
   gr_context_ = GrContext::MakeVulkan(backend_context);
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index 481c063..f62d97f 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -336,7 +336,10 @@
     // Tracing adds too much overhead to the profiling service.
     if (service_manager::SandboxTypeFromCommandLine(*cmd_line) !=
         service_manager::SANDBOX_TYPE_PROFILING) {
-      BackgroundTracingManagerImpl::ActivateForProcess(this);
+      BackgroundTracingManagerImpl::ActivateForProcess(
+          data_.id,
+          static_cast<ChildProcessHostImpl*>(child_process_host_.get())
+              ->child_control());
     }
   }
 
diff --git a/content/browser/compositor/DEPS b/content/browser/compositor/DEPS
index 9140430..e032424 100644
--- a/content/browser/compositor/DEPS
+++ b/content/browser/compositor/DEPS
@@ -2,7 +2,6 @@
  "+components/viz/common",
  "+components/viz/host",
  "+components/viz/service",
- "+services/ws/public/cpp",
  "+ui/platform_window",
 ]
 
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 50522f01..aa0d62ca 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -1336,7 +1336,7 @@
             cookie->GetDomain(""), cookie->GetPath(""),
             cookie->GetSecure(false), cookie->GetHttpOnly(false),
             cookie->GetSameSite(""), cookie->GetExpires(-1));
-    if (!cookie) {
+    if (!net_cookie) {
       callback->sendFailure(Response::InvalidParams("Invalid cookie fields"));
       return;
     }
diff --git a/content/browser/renderer_host/DEPS b/content/browser/renderer_host/DEPS
index 83f75617..76bb5ac6 100644
--- a/content/browser/renderer_host/DEPS
+++ b/content/browser/renderer_host/DEPS
@@ -3,7 +3,6 @@
   "+components/viz/common",
   "+components/viz/host",
   "+components/viz/service",
-  "+services/ws/public",
   "+third_party/blink/public/platform/web_gesture_curve.h",
   "+third_party/zlib",
   "+ui/events/gestures/blink/web_gesture_curve_impl.h",
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index b0fffeb..574ba1a 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1743,7 +1743,8 @@
 
     // In single process mode, browser-side tracing and memory will cover the
     // whole process including renderers.
-    BackgroundTracingManagerImpl::ActivateForProcess(this);
+    BackgroundTracingManagerImpl::ActivateForProcess(
+        GetID(), child_control_interface_.get());
 
     fast_shutdown_started_ = false;
   }
diff --git a/content/browser/tracing/background_tracing_agent_client_impl.cc b/content/browser/tracing/background_tracing_agent_client_impl.cc
index 422043a..3822ff3 100644
--- a/content/browser/tracing/background_tracing_agent_client_impl.cc
+++ b/content/browser/tracing/background_tracing_agent_client_impl.cc
@@ -16,23 +16,24 @@
 // static
 void BackgroundTracingAgentClientImpl::Create(
     int child_process_id,
-    mojo::PendingRemote<tracing::mojom::BackgroundTracingAgent> pending_agent) {
-  uint64_t tracing_process_id =
-      ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
-          child_process_id);
-
+    mojo::PendingRemote<tracing::mojom::BackgroundTracingAgentProvider>
+        pending_provider) {
   mojo::PendingRemote<tracing::mojom::BackgroundTracingAgentClient> client;
-  auto receiver = client.InitWithNewPipeAndPassReceiver();
+  auto client_receiver = client.InitWithNewPipeAndPassReceiver();
 
-  mojo::Remote<tracing::mojom::BackgroundTracingAgent> agent(
-      std::move(pending_agent));
-  agent->Initialize(tracing_process_id, std::move(client));
+  mojo::Remote<tracing::mojom::BackgroundTracingAgent> agent;
+
+  mojo::Remote<tracing::mojom::BackgroundTracingAgentProvider> provider(
+      std::move(pending_provider));
+  provider->Create(ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
+                       child_process_id),
+                   std::move(client), agent.BindNewPipeAndPassReceiver());
 
   // Lifetime bound to the agent, which means it is bound to the lifetime of
   // the child process. Will be cleaned up when the process exits.
   mojo::MakeSelfOwnedReceiver(
       base::WrapUnique(new BackgroundTracingAgentClientImpl(std::move(agent))),
-      std::move(receiver));
+      std::move(client_receiver));
 }
 
 BackgroundTracingAgentClientImpl::~BackgroundTracingAgentClientImpl() {
diff --git a/content/browser/tracing/background_tracing_agent_client_impl.h b/content/browser/tracing/background_tracing_agent_client_impl.h
index d7ce9ec..97de4ba 100644
--- a/content/browser/tracing/background_tracing_agent_client_impl.h
+++ b/content/browser/tracing/background_tracing_agent_client_impl.h
@@ -17,9 +17,10 @@
 class BackgroundTracingAgentClientImpl
     : public tracing::mojom::BackgroundTracingAgentClient {
  public:
-  static void Create(int child_process_id,
-                     mojo::PendingRemote<tracing::mojom::BackgroundTracingAgent>
-                         pending_agent);
+  static void Create(
+      int child_process_id,
+      mojo::PendingRemote<tracing::mojom::BackgroundTracingAgentProvider>
+          pending_provider);
 
   ~BackgroundTracingAgentClientImpl() override;
 
diff --git a/content/browser/tracing/background_tracing_manager_impl.cc b/content/browser/tracing/background_tracing_manager_impl.cc
index 1dc755c..0a964ce 100644
--- a/content/browser/tracing/background_tracing_manager_impl.cc
+++ b/content/browser/tracing/background_tracing_manager_impl.cc
@@ -25,6 +25,7 @@
 #include "content/browser/tracing/background_tracing_agent_client_impl.h"
 #include "content/browser/tracing/background_tracing_rule.h"
 #include "content/browser/tracing/tracing_controller_impl.h"
+#include "content/common/child_control.mojom.h"
 #include "content/public/browser/browser_child_process_host.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -63,31 +64,22 @@
 
 // static
 void BackgroundTracingManagerImpl::ActivateForProcess(
-    BrowserChildProcessHost* host) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    int child_process_id,
+    mojom::ChildControl* child_control) {
+  mojo::PendingRemote<tracing::mojom::BackgroundTracingAgentProvider>
+      pending_provider;
+  child_control->GetBackgroundTracingAgentProvider(
+      pending_provider.InitWithNewPipeAndPassReceiver());
 
-  tracing::mojom::BackgroundTracingAgentPtr agent;
-  content::BindInterface(host->GetHost(), &agent);
-
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(
-          [](int child_process_id,
-             tracing::mojom::BackgroundTracingAgentPtrInfo info) {
-            BackgroundTracingAgentClientImpl::Create(child_process_id,
-                                                     std::move(info));
-          },
-          host->GetData().id, agent.PassInterface()));
-}
-
-// static
-void BackgroundTracingManagerImpl::ActivateForProcess(RenderProcessHost* host) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  tracing::mojom::BackgroundTracingAgentPtr agent;
-  content::BindInterface(host, &agent);
-  BackgroundTracingAgentClientImpl::Create(host->GetID(),
-                                           agent.PassInterface());
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::UI},
+        base::BindOnce(&BackgroundTracingAgentClientImpl::Create,
+                       child_process_id, std::move(pending_provider)));
+    return;
+  }
+  BackgroundTracingAgentClientImpl::Create(child_process_id,
+                                           std::move(pending_provider));
 }
 
 BackgroundTracingManagerImpl::BackgroundTracingManagerImpl()
diff --git a/content/browser/tracing/background_tracing_manager_impl.h b/content/browser/tracing/background_tracing_manager_impl.h
index f620a91..982aa09 100644
--- a/content/browser/tracing/background_tracing_manager_impl.h
+++ b/content/browser/tracing/background_tracing_manager_impl.h
@@ -27,11 +27,12 @@
 }  // namespace tracing
 
 namespace content {
+namespace mojom {
+class ChildControl;
+}  // namespace mojom
 
 class BackgroundTracingRule;
 class BackgroundTracingActiveScenario;
-class BrowserChildProcessHost;
-class RenderProcessHost;
 class TracingDelegate;
 
 class BackgroundTracingManagerImpl : public BackgroundTracingManager {
@@ -85,8 +86,8 @@
 
   CONTENT_EXPORT static BackgroundTracingManagerImpl* GetInstance();
 
-  static void ActivateForProcess(BrowserChildProcessHost* host);
-  static void ActivateForProcess(RenderProcessHost* host);
+  static void ActivateForProcess(int child_process_id,
+                                 mojom::ChildControl* child_control);
 
   bool SetActiveScenario(std::unique_ptr<BackgroundTracingConfig>,
                          ReceiveCallback,
diff --git a/content/browser/worker_host/shared_worker_service_impl_unittest.cc b/content/browser/worker_host/shared_worker_service_impl_unittest.cc
index 84513ca4..39b5705 100644
--- a/content/browser/worker_host/shared_worker_service_impl_unittest.cc
+++ b/content/browser/worker_host/shared_worker_service_impl_unittest.cc
@@ -5,11 +5,12 @@
 #include "content/browser/worker_host/shared_worker_service_impl.h"
 
 #include <memory>
-#include <queue>
 #include <set>
 #include <string>
 
 #include "base/bind.h"
+#include "base/containers/flat_map.h"
+#include "base/containers/queue.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "content/browser/site_instance_impl.h"
@@ -38,6 +39,43 @@
 
 namespace content {
 
+namespace {
+
+void ConnectToSharedWorker(blink::mojom::SharedWorkerConnectorPtr connector,
+                           const GURL& url,
+                           const std::string& name,
+                           MockSharedWorkerClient* client,
+                           MessagePortChannel* local_port) {
+  blink::mojom::SharedWorkerInfoPtr info(blink::mojom::SharedWorkerInfo::New(
+      url, name, std::string(),
+      blink::mojom::ContentSecurityPolicyType::kReport,
+      blink::mojom::IPAddressSpace::kPublic));
+
+  mojo::MessagePipe message_pipe;
+  *local_port = MessagePortChannel(std::move(message_pipe.handle0));
+
+  blink::mojom::SharedWorkerClientPtr client_proxy;
+  client->Bind(mojo::MakeRequest(&client_proxy));
+
+  connector->Connect(std::move(info), std::move(client_proxy),
+                     blink::mojom::SharedWorkerCreationContextType::kSecure,
+                     std::move(message_pipe.handle1), nullptr);
+}
+
+// Helper to delete the given WebContents and shut down its process. This is
+// useful because if FastShutdownIfPossible() is called without deleting the
+// WebContents first, shutdown does not actually start.
+void KillProcess(std::unique_ptr<WebContents> web_contents) {
+  RenderFrameHost* frame_host = web_contents->GetMainFrame();
+  RenderProcessHost* process_host = frame_host->GetProcess();
+  web_contents.reset();
+  process_host->FastShutdownIfPossible(/*page_count=*/0,
+                                       /*skip_unload_handlers=*/true);
+  ASSERT_TRUE(process_host->FastShutdownStarted());
+}
+
+}  // namespace
+
 class SharedWorkerServiceImplTest : public RenderViewHostImplTestHarness {
  public:
   blink::mojom::SharedWorkerConnectorPtr MakeSharedWorkerConnector(
@@ -49,26 +87,51 @@
     return connector;
   }
 
-  static blink::mojom::SharedWorkerFactoryRequest WaitForFactoryRequest() {
-    if (s_factory_request_received_.empty()) {
+  // Waits until a SharedWorkerFactoryRequest from the given process is
+  // received. kInvalidUniqueID means any process.
+  blink::mojom::SharedWorkerFactoryRequest WaitForFactoryRequest(
+      int process_id) {
+    if (CheckNotReceivedFactoryRequest(process_id)) {
       base::RunLoop run_loop;
-      s_factory_request_callback_ = run_loop.QuitClosure();
+      factory_request_callback_ = run_loop.QuitClosure();
+      factory_request_callback_process_id_ = process_id;
       run_loop.Run();
     }
-    auto rv = std::move(s_factory_request_received_.front());
-    s_factory_request_received_.pop();
+    auto iter = (process_id == ChildProcessHost::kInvalidUniqueID)
+                    ? received_factory_requests_.begin()
+                    : received_factory_requests_.find(process_id);
+    DCHECK(iter != received_factory_requests_.end());
+    auto& queue = iter->second;
+    DCHECK(!queue.empty());
+    auto rv = std::move(queue.front());
+    queue.pop();
+    if (queue.empty())
+      received_factory_requests_.erase(iter);
     return rv;
   }
 
-  static bool CheckNotReceivedFactoryRequest() {
-    return s_factory_request_received_.empty();
+  bool CheckNotReceivedFactoryRequest(int process_id) {
+    if (process_id == ChildProcessHost::kInvalidUniqueID)
+      return received_factory_requests_.empty();
+    return !base::Contains(received_factory_requests_, process_id);
   }
 
-  static void BindSharedWorkerFactory(mojo::ScopedMessagePipeHandle handle) {
-    if (s_factory_request_callback_)
-      std::move(s_factory_request_callback_).Run();
-    s_factory_request_received_.push(
-        blink::mojom::SharedWorkerFactoryRequest(std::move(handle)));
+  // Receives a SharedWorkerFactoryRequest.
+  void BindSharedWorkerFactory(int process_id,
+                               mojo::ScopedMessagePipeHandle handle) {
+    if (factory_request_callback_ &&
+        (factory_request_callback_process_id_ == process_id ||
+         factory_request_callback_process_id_ ==
+             ChildProcessHost::kInvalidUniqueID)) {
+      factory_request_callback_process_id_ = ChildProcessHost::kInvalidUniqueID;
+      std::move(factory_request_callback_).Run();
+    }
+
+    if (!base::Contains(received_factory_requests_, process_id)) {
+      received_factory_requests_.emplace(
+          process_id, base::queue<blink::mojom::SharedWorkerFactoryRequest>());
+    }
+    received_factory_requests_[process_id].emplace(std::move(handle));
   }
 
   std::unique_ptr<TestWebContents> CreateWebContents(const GURL& url) {
@@ -113,9 +176,17 @@
   }
 
   std::unique_ptr<TestBrowserContext> browser_context_;
-  static std::queue<blink::mojom::SharedWorkerFactoryRequest>
-      s_factory_request_received_;
-  static base::OnceClosure s_factory_request_callback_;
+
+  // Holds received SharedWorkerFactoryRequests for each process.
+  base::flat_map<int /* process_id */,
+                 base::queue<blink::mojom::SharedWorkerFactoryRequest>>
+      received_factory_requests_;
+
+  // The callback is called when a SharedWorkerFactoryRequest for the specified
+  // process is received. kInvalidUniqueID means any process.
+  base::OnceClosure factory_request_callback_;
+  int factory_request_callback_process_id_ = ChildProcessHost::kInvalidUniqueID;
+
   std::unique_ptr<MockRenderProcessHostFactory> render_process_host_factory_;
   std::unique_ptr<NotImplementedNetworkURLLoaderFactory> url_loader_factory_;
 
@@ -127,46 +198,16 @@
   DISALLOW_COPY_AND_ASSIGN(SharedWorkerServiceImplTest);
 };
 
-// static
-std::queue<blink::mojom::SharedWorkerFactoryRequest>
-    SharedWorkerServiceImplTest::s_factory_request_received_;
-
-// static
-base::OnceClosure SharedWorkerServiceImplTest::s_factory_request_callback_;
-
-namespace {
-
-void ConnectToSharedWorker(blink::mojom::SharedWorkerConnectorPtr connector,
-                           const GURL& url,
-                           const std::string& name,
-                           MockSharedWorkerClient* client,
-                           MessagePortChannel* local_port) {
-  blink::mojom::SharedWorkerInfoPtr info(blink::mojom::SharedWorkerInfo::New(
-      url, name, std::string(),
-      blink::mojom::ContentSecurityPolicyType::kReport,
-      blink::mojom::IPAddressSpace::kPublic));
-
-  mojo::MessagePipe message_pipe;
-  *local_port = MessagePortChannel(std::move(message_pipe.handle0));
-
-  blink::mojom::SharedWorkerClientPtr client_proxy;
-  client->Bind(mojo::MakeRequest(&client_proxy));
-
-  connector->Connect(std::move(info), std::move(client_proxy),
-                     blink::mojom::SharedWorkerCreationContextType::kSecure,
-                     std::move(message_pipe.handle1), nullptr);
-}
-
-}  // namespace
-
 TEST_F(SharedWorkerServiceImplTest, BasicTest) {
   std::unique_ptr<TestWebContents> web_contents =
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host = web_contents->GetMainFrame();
   MockRenderProcessHost* renderer_host = render_frame_host->GetProcess();
+  const int process_id = renderer_host->GetID();
   renderer_host->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -178,7 +219,7 @@
                         kUrl, "name", &client, &local_port);
 
   blink::mojom::SharedWorkerFactoryRequest factory_request =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id);
   MockSharedWorkerFactory factory(std::move(factory_request));
   base::RunLoop().RunUntilIdle();
 
@@ -239,9 +280,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
   MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
+  const int process_id0 = renderer_host0->GetID();
   renderer_host0->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id0));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -255,7 +298,7 @@
   base::RunLoop().RunUntilIdle();
 
   blink::mojom::SharedWorkerFactoryRequest factory_request =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id0);
   MockSharedWorkerFactory factory(std::move(factory_request));
   base::RunLoop().RunUntilIdle();
 
@@ -309,9 +352,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
   MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
+  const int process_id1 = renderer_host1->GetID();
   renderer_host1->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id1));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -324,7 +369,7 @@
   base::RunLoop().RunUntilIdle();
 
   // Should not have tried to create a new shared worker.
-  EXPECT_TRUE(CheckNotReceivedFactoryRequest());
+  EXPECT_TRUE(CheckNotReceivedFactoryRequest(process_id1));
 
   int connection_request_id1;
   MessagePortChannel port1;
@@ -372,9 +417,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
   MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
+  const int process_id0 = renderer_host0->GetID();
   renderer_host0->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id0));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -383,9 +430,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
   MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
+  const int process_id1 = renderer_host1->GetID();
   renderer_host1->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id1));
 
   // First client, creates worker.
 
@@ -397,7 +446,7 @@
   base::RunLoop().RunUntilIdle();
 
   blink::mojom::SharedWorkerFactoryRequest factory_request =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id0);
   MockSharedWorkerFactory factory(std::move(factory_request));
   base::RunLoop().RunUntilIdle();
 
@@ -421,7 +470,7 @@
                         kUrl, kName, &client1, &local_port1);
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_TRUE(CheckNotReceivedFactoryRequest());
+  EXPECT_TRUE(CheckNotReceivedFactoryRequest(process_id1));
 
   EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
   EXPECT_TRUE(client1.CheckReceivedOnCreated());
@@ -445,9 +494,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
   MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
+  const int process_id0 = renderer_host0->GetID();
   renderer_host0->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id0));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -456,9 +507,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
   MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
+  const int process_id1 = renderer_host1->GetID();
   renderer_host1->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id1));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -472,7 +525,7 @@
   base::RunLoop().RunUntilIdle();
 
   blink::mojom::SharedWorkerFactoryRequest factory_request0 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id0);
   MockSharedWorkerFactory factory0(std::move(factory_request0));
   base::RunLoop().RunUntilIdle();
 
@@ -497,7 +550,7 @@
   base::RunLoop().RunUntilIdle();
 
   blink::mojom::SharedWorkerFactoryRequest factory_request1 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id1);
   MockSharedWorkerFactory factory1(std::move(factory_request1));
   base::RunLoop().RunUntilIdle();
 
@@ -532,9 +585,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
   MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
+  const int process_id0 = renderer_host0->GetID();
   renderer_host0->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id0));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -543,9 +598,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
   MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
+  const int process_id1 = renderer_host1->GetID();
   renderer_host1->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id1));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -559,7 +616,7 @@
   base::RunLoop().RunUntilIdle();
 
   blink::mojom::SharedWorkerFactoryRequest factory_request0 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id0);
   MockSharedWorkerFactory factory0(std::move(factory_request0));
   base::RunLoop().RunUntilIdle();
 
@@ -584,7 +641,7 @@
   base::RunLoop().RunUntilIdle();
 
   blink::mojom::SharedWorkerFactoryRequest factory_request1 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id1);
   MockSharedWorkerFactory factory1(std::move(factory_request1));
   base::RunLoop().RunUntilIdle();
 
@@ -618,9 +675,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
   MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
+  const int process_id0 = renderer_host0->GetID();
   renderer_host0->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id0));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -629,9 +688,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
   MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
+  const int process_id1 = renderer_host1->GetID();
   renderer_host1->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id1));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -651,10 +712,11 @@
 
   base::RunLoop().RunUntilIdle();
 
-  // Check that the worker was created.
+  // Check that the worker was created. The request could come from either
+  // process.
 
   blink::mojom::SharedWorkerFactoryRequest factory_request =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(ChildProcessHost::kInvalidUniqueID);
   MockSharedWorkerFactory factory(std::move(factory_request));
 
   base::RunLoop().RunUntilIdle();
@@ -685,9 +747,7 @@
   EXPECT_TRUE(worker.CheckReceivedTerminate());
 }
 
-// TODO(https://crbug.com/968971): Flaky fails on all bots.
-TEST_F(SharedWorkerServiceImplTest,
-       DISABLED_CreateWorkerTest_PendingCase_URLMismatch) {
+TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase_URLMismatch) {
   const GURL kUrl0("http://example.com/w0.js");
   const GURL kUrl1("http://example.com/w1.js");
   const char kName[] = "name";
@@ -699,7 +759,8 @@
   MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
   renderer_host0->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), renderer_host0->GetID()));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -710,7 +771,8 @@
   MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
   renderer_host1->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), renderer_host1->GetID()));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -733,11 +795,11 @@
   // Check that both workers were created.
 
   blink::mojom::SharedWorkerFactoryRequest factory_request0 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(renderer_host0->GetID());
   MockSharedWorkerFactory factory0(std::move(factory_request0));
 
   blink::mojom::SharedWorkerFactoryRequest factory_request1 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(renderer_host1->GetID());
   MockSharedWorkerFactory factory1(std::move(factory_request1));
 
   base::RunLoop().RunUntilIdle();
@@ -778,9 +840,7 @@
   EXPECT_TRUE(worker1.CheckReceivedTerminate());
 }
 
-// TODO(https://crbug.com/968971): Flaky fails on all bots.
-TEST_F(SharedWorkerServiceImplTest,
-       DISABLED_CreateWorkerTest_PendingCase_NameMismatch) {
+TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase_NameMismatch) {
   const GURL kUrl("http://example.com/w.js");
   const char kName0[] = "name0";
   const char kName1[] = "name1";
@@ -790,9 +850,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
   MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
+  const int process_id0 = renderer_host0->GetID();
   renderer_host0->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id0));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -801,9 +863,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
   MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
+  const int process_id1 = renderer_host1->GetID();
   renderer_host1->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id1));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -826,11 +890,11 @@
   // Check that both workers were created.
 
   blink::mojom::SharedWorkerFactoryRequest factory_request0 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id0);
   MockSharedWorkerFactory factory0(std::move(factory_request0));
 
   blink::mojom::SharedWorkerFactoryRequest factory_request1 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id1);
   MockSharedWorkerFactory factory1(std::move(factory_request1));
 
   base::RunLoop().RunUntilIdle();
@@ -881,9 +945,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
   MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
+  const int process_id0 = renderer_host0->GetID();
   renderer_host0->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id0));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -891,9 +957,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
   MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
+  const int process_id1 = renderer_host1->GetID();
   renderer_host1->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id1));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -901,9 +969,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host2 = web_contents2->GetMainFrame();
   MockRenderProcessHost* renderer_host2 = render_frame_host2->GetProcess();
+  const int process_id2 = renderer_host2->GetID();
   renderer_host2->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id2));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host2->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -918,7 +988,7 @@
   // Starts a worker.
 
   blink::mojom::SharedWorkerFactoryRequest factory_request0 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id0);
   MockSharedWorkerFactory factory0(std::move(factory_request0));
 
   base::RunLoop().RunUntilIdle();
@@ -936,9 +1006,7 @@
   EXPECT_TRUE(client0.CheckReceivedOnCreated());
 
   // Kill this process, which should make worker0 unavailable.
-  web_contents0.reset();
-  renderer_host0->FastShutdownIfPossible(0, true);
-  ASSERT_TRUE(renderer_host0->FastShutdownStarted());
+  KillProcess(std::move(web_contents0));
 
   // Start a new client, attemping to connect to the same worker.
   MockSharedWorkerClient client1;
@@ -952,7 +1020,7 @@
   // The previous worker is unavailable, so a new worker is created.
 
   blink::mojom::SharedWorkerFactoryRequest factory_request1 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id1);
   MockSharedWorkerFactory factory1(std::move(factory_request1));
 
   base::RunLoop().RunUntilIdle();
@@ -979,7 +1047,7 @@
 
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_TRUE(CheckNotReceivedFactoryRequest());
+  EXPECT_TRUE(CheckNotReceivedFactoryRequest(process_id2));
 
   EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
   EXPECT_TRUE(client2.CheckReceivedOnCreated());
@@ -995,9 +1063,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
   MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
+  const int process_id0 = renderer_host0->GetID();
   renderer_host0->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id0));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -1005,9 +1075,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
   MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
+  const int process_id1 = renderer_host1->GetID();
   renderer_host1->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id1));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -1015,9 +1087,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host2 = web_contents2->GetMainFrame();
   MockRenderProcessHost* renderer_host2 = render_frame_host2->GetProcess();
+  const int process_id2 = renderer_host2->GetID();
   renderer_host2->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id2));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host2->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -1027,10 +1101,14 @@
                             renderer_host0, render_frame_host0->GetRoutingID()),
                         kUrl, kName, &client0, &local_port0);
 
-  // Kill this process, which should make worker0 unavailable.
-  renderer_host0->FastShutdownIfPossible(0, true);
+  blink::mojom::SharedWorkerFactoryRequest factory_request0 =
+      WaitForFactoryRequest(process_id0);
+  MockSharedWorkerFactory factory0(std::move(factory_request0));
 
-  // Start a new client, attemping to connect to the same worker.
+  // Kill this process, which should make worker0 unavailable.
+  KillProcess(std::move(web_contents0));
+
+  // Start a new client, attempting to connect to the same worker.
   MockSharedWorkerClient client1;
   MessagePortChannel local_port1;
   ConnectToSharedWorker(MakeSharedWorkerConnector(
@@ -1042,10 +1120,11 @@
   // The previous worker is unavailable, so a new worker is created.
 
   blink::mojom::SharedWorkerFactoryRequest factory_request1 =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(process_id1);
   MockSharedWorkerFactory factory1(std::move(factory_request1));
 
-  EXPECT_TRUE(CheckNotReceivedFactoryRequest());
+  EXPECT_TRUE(
+      CheckNotReceivedFactoryRequest(ChildProcessHost::kInvalidUniqueID));
 
   base::RunLoop().RunUntilIdle();
 
@@ -1070,7 +1149,8 @@
 
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_TRUE(CheckNotReceivedFactoryRequest());
+  EXPECT_TRUE(
+      CheckNotReceivedFactoryRequest(ChildProcessHost::kInvalidUniqueID));
 
   EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
   EXPECT_TRUE(client2.CheckReceivedOnCreated());
@@ -1085,10 +1165,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
   MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
+  const int process_id0 = renderer_host0->GetID();
   renderer_host0->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::BindRepeating(
-          &SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id0));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -1097,10 +1178,11 @@
       CreateWebContents(GURL("http://example.com/"));
   TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
   MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
+  const int process_id1 = renderer_host1->GetID();
   renderer_host1->OverrideBinderForTesting(
       blink::mojom::SharedWorkerFactory::Name_,
-      base::BindRepeating(
-          &SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+      base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
+                          base::Unretained(this), process_id1));
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
@@ -1119,9 +1201,9 @@
                         kURL, kName, &client1, &local_port1);
   base::RunLoop().RunUntilIdle();
 
-  // Expect a factory request.
+  // Expect a factory request. It can come from either process.
   blink::mojom::SharedWorkerFactoryRequest factory_request =
-      WaitForFactoryRequest();
+      WaitForFactoryRequest(ChildProcessHost::kInvalidUniqueID);
   MockSharedWorkerFactory factory(std::move(factory_request));
   base::RunLoop().RunUntilIdle();
 
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index 2c058a2..cab79ad 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -38,6 +38,7 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "components/tracing/child/background_tracing_agent_impl.h"
+#include "components/tracing/child/background_tracing_agent_provider_impl.h"
 #include "content/child/child_histogram_fetcher_impl.h"
 #include "content/child/child_process.h"
 #include "content/child/thread_safe_sender.h"
@@ -446,9 +447,6 @@
   registry->AddInterface(base::Bind(&ChildThreadImpl::OnChildControlRequest,
                                     base::Unretained(this)),
                          base::ThreadTaskRunnerHandle::Get());
-  registry->AddInterface(
-      base::Bind(&tracing::BackgroundTracingAgentImpl::CreateFromRequest),
-      base::ThreadTaskRunnerHandle::Get());
   GetServiceManagerConnection()->AddConnectionFilter(
       std::make_unique<SimpleConnectionFilter>(std::move(registry)));
 
@@ -704,6 +702,16 @@
 }
 #endif  //  IPC_MESSAGE_LOG_ENABLED
 
+void ChildThreadImpl::GetBackgroundTracingAgentProvider(
+    mojo::PendingReceiver<tracing::mojom::BackgroundTracingAgentProvider>
+        receiver) {
+  if (!background_tracing_agent_provider_) {
+    background_tracing_agent_provider_ =
+        std::make_unique<tracing::BackgroundTracingAgentProviderImpl>();
+  }
+  background_tracing_agent_provider_->AddBinding(std::move(receiver));
+}
+
 void ChildThreadImpl::RunService(
     const std::string& service_name,
     mojo::PendingReceiver<service_manager::mojom::Service> receiver) {
diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h
index 3245d77..cf8c92e4 100644
--- a/content/child/child_thread_impl.h
+++ b/content/child/child_thread_impl.h
@@ -49,6 +49,10 @@
 }  // namespace core
 }  // namespace mojo
 
+namespace tracing {
+class BackgroundTracingAgentProviderImpl;
+}  // namespace tracing
+
 namespace content {
 class InProcessChildThreadParams;
 class ThreadSafeSender;
@@ -145,6 +149,9 @@
 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
   void SetIPCLoggingEnabled(bool enable) override;
 #endif
+  void GetBackgroundTracingAgentProvider(
+      mojo::PendingReceiver<tracing::mojom::BackgroundTracingAgentProvider>
+          receiver) override;
   void RunService(
       const std::string& service_name,
       mojo::PendingReceiver<service_manager::mojom::Service> receiver) override;
@@ -236,6 +243,9 @@
 
   std::unique_ptr<base::PowerMonitor> power_monitor_;
 
+  std::unique_ptr<tracing::BackgroundTracingAgentProviderImpl>
+      background_tracing_agent_provider_;
+
   scoped_refptr<base::SingleThreadTaskRunner> browser_process_io_runner_;
 
   std::unique_ptr<variations::ChildProcessFieldTrialSyncer> field_trial_syncer_;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 3387bbf..25d40e6 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -503,6 +503,7 @@
 
   public_deps = [
     "//components/services/leveldb/public/interfaces",
+    "//components/tracing/common:interfaces",
     "//content/public/common:interfaces",
     "//content/public/common:resource_type_bindings",
     "//ipc:mojom_constants",
diff --git a/content/common/child_control.mojom b/content/common/child_control.mojom
index c840289ab..1bac2fd6 100644
--- a/content/common/child_control.mojom
+++ b/content/common/child_control.mojom
@@ -4,6 +4,7 @@
 
 module content.mojom;
 
+import "components/tracing/common/background_tracing_agent.mojom";
 import "services/service_manager/public/mojom/service.mojom";
 
 interface ChildControl {
@@ -14,6 +15,10 @@
   [EnableIf=ipc_logging]
   SetIPCLoggingEnabled(bool on);
 
+  // Used to configure triggering for background tracing of child processes.
+  GetBackgroundTracingAgentProvider(
+      pending_receiver<tracing.mojom.BackgroundTracingAgentProvider> receiver);
+
   // Tells the child process to run an instance of a service named
   // |service_name|, binding it to |receiver|. This is used by the browser to
   // support launching of packaged services within Utility or GPU processes.
diff --git a/content/common/child_process_host_impl.h b/content/common/child_process_host_impl.h
index 7ed3a4ce..e299a9e 100644
--- a/content/common/child_process_host_impl.h
+++ b/content/common/child_process_host_impl.h
@@ -75,6 +75,7 @@
       mojo::PendingReceiver<service_manager::mojom::Service> receiver) override;
 
   base::Process& peer_process() { return peer_process_; }
+  mojom::ChildControl* child_control() { return child_control_.get(); }
 
  private:
   friend class ChildProcessHost;
diff --git a/content/public/app/content_gpu_manifest.cc b/content/public/app/content_gpu_manifest.cc
index 586eaedc..06b9be3 100644
--- a/content/public/app/content_gpu_manifest.cc
+++ b/content/public/app/content_gpu_manifest.cc
@@ -23,7 +23,6 @@
                                 "content.mojom.ChildHistogramFetcherFactory",
                                 "content.mojom.ResourceUsageReporter",
                                 "IPC.mojom.ChannelBootstrap",
-                                "tracing.mojom.BackgroundTracingAgent",
                                 "ui.ozone.mojom.DeviceCursor",
                                 "ui.ozone.mojom.DrmDevice",
                                 "ui.ozone.mojom.WaylandBufferManagerGpu",
diff --git a/content/public/app/content_plugin_manifest.cc b/content/public/app/content_plugin_manifest.cc
index c3dd3fb..6d17755 100644
--- a/content/public/app/content_plugin_manifest.cc
+++ b/content/public/app/content_plugin_manifest.cc
@@ -23,7 +23,6 @@
                                 "content.mojom.ChildHistogramFetcherFactory",
                                 "content.mojom.ResourceUsageReporter",
                                 "IPC.mojom.ChannelBootstrap",
-                                "tracing.mojom.BackgroundTracingAgent",
                             })
           .RequireCapability("device", "device:power_monitor")
           .RequireCapability(mojom::kSystemServiceName, "dwrite_font_proxy")
diff --git a/content/public/app/content_renderer_manifest.cc b/content/public/app/content_renderer_manifest.cc
index e6e52645..27ffa5c 100644
--- a/content/public/app/content_renderer_manifest.cc
+++ b/content/public/app/content_renderer_manifest.cc
@@ -34,7 +34,6 @@
                   "content.mojom.RenderWidgetWindowTreeClientFactory",
                   "content.mojom.ResourceUsageReporter",
                   "IPC.mojom.ChannelBootstrap",
-                  "tracing.mojom.BackgroundTracingAgent",
                   "visitedlink.mojom.VisitedLinkNotificationSink",
                   "web_cache.mojom.WebCache",
               })
diff --git a/content/public/app/content_utility_manifest.cc b/content/public/app/content_utility_manifest.cc
index 575a2a37..e3eafb7 100644
--- a/content/public/app/content_utility_manifest.cc
+++ b/content/public/app/content_utility_manifest.cc
@@ -24,7 +24,6 @@
                                 "content.mojom.ChildHistogramFetcherFactory",
                                 "content.mojom.ResourceUsageReporter",
                                 "IPC.mojom.ChannelBootstrap",
-                                "tracing.mojom.BackgroundTracingAgent",
                                 "printing.mojom.PdfToEmfConverterFactory",
                                 "printing.mojom.PdfToPwgRasterConverter",
                             })
diff --git a/content/public/browser/DEPS b/content/public/browser/DEPS
index c77149d..08ef71e 100644
--- a/content/public/browser/DEPS
+++ b/content/public/browser/DEPS
@@ -11,7 +11,6 @@
   "+services/service_manager/sandbox",
   "+services/video_capture/public/mojom",
   "+services/viz/public/interfaces",
-  "+services/ws/public/mojom",
 ]
 
 specific_include_rules = {
diff --git a/content/public/common/cursor_info.cc b/content/public/common/cursor_info.cc
index e4e1aff..f3e50e1 100644
--- a/content/public/common/cursor_info.cc
+++ b/content/public/common/cursor_info.cc
@@ -19,9 +19,7 @@
 bool CursorInfo::operator==(const CursorInfo& other) const {
   return type == other.type && hotspot == other.hotspot &&
          image_scale_factor == other.image_scale_factor &&
-         (custom_image.getGenerationID() ==
-              other.custom_image.getGenerationID() ||
-          gfx::BitmapsAreEqual(custom_image, other.custom_image));
+         gfx::BitmapsAreEqual(custom_image, other.custom_image);
 }
 
 blink::WebCursorInfo CursorInfo::GetWebCursorInfo() const {
diff --git a/content/shell/browser/DEPS b/content/shell/browser/DEPS
index 0e08b66..2d807b6 100644
--- a/content/shell/browser/DEPS
+++ b/content/shell/browser/DEPS
@@ -6,7 +6,6 @@
   "+services/network/public",
   "+services/service_manager/public/cpp",
   "+services/service_manager/sandbox",
-  "+services/ws/public",
   "+ui/ozone/public",
 ]
 
diff --git a/docs/security/android-ipc.md b/docs/security/android-ipc.md
new file mode 100644
index 0000000..b9131e6d
--- /dev/null
+++ b/docs/security/android-ipc.md
@@ -0,0 +1,139 @@
+# Android IPC Security Considerations
+
+Generally Chrome communicates between its processes using the
+[Mojo](../../mojo/README.md) [inter-process communication (IPC)
+mechanism](mojo.md). For most features, this is the preferred IPC mechanism to
+use. However, as an Android application, there are certain interactions with
+other applications and the Android OS that necessitate using different IPC
+mechanisms to communicate. This document covers security concerns related to
+those Android-specific IPC mechanisms.
+
+The Chrome browser process is typically the only process type that will interact
+with these different IPC mechanisms.
+
+## Intents
+
+[Intents](https://developer.android.com/guide/components/intents-filters) are
+the most common type of inter-process communication mechanism on Android. They
+are most commonly used to start Activities and they internally carry data
+associated with that Activity (e.g. using the `ACTION_SEND` Intent to share a
+piece of content and including either text or image data in the Intent body).
+
+### Inbound Intents
+
+Because any application can dispatch Intents with Chrome as the receiver, when
+receiving an inbound Intent, you should never fully trust the data contained
+within. Data sent from other applications could be malicious or malformed, and
+so you must validate or sanitze the data before passing it to other trusted
+components of the browser process. Intents are handled in Java though, so
+following the [Rule of 2](rule-of-2.md) is generally easy. (Though take note
+that certain Android classes are just Java wrappers around native code, which
+would not be considered safe by that rule.)
+
+It is **fundamentally impossible** to determine the sender of an Intent, so the
+security model of your feature cannot depend on authenticating the sender. Do
+not trust `Intent.EXTRA_REFERRER`. See also the discussion below about
+[capability tokens](#capability-tokens).
+
+One way to authorize Intents is to use the system's
+[`android:permission`](https://developer.android.com/guide/topics/permissions/overview#permission_enforcement)
+attribute on a component's (e.g. Activity, Service, etc.) manifest declaration.
+You can [define a custom permission](https://developer.android.com/guide/topics/permissions/defining) and
+set the `android:protectionLevel` of the permission to `"signature"` or
+`"signatureOrSystem"` to restrict access to just components signed by the same
+certificate (or trusted system components).
+
+## Outbound Intents {#outbound-intents}
+
+There are [two types of Intents](https://developer.android.com/guide/components/intents-filters?hl=en#Types):
+implicit and explicit. With implicit Intents, the receiving application is not
+specified by the sender and the system uses a resolution process to find the
+most suitable component to handle it. An implicit Intent can sometimes result in
+a chooser being shown to the user when multiple applications could handle it.
+Explicit Intents specify either the package name or a fully qualified
+`ComponentName`, so the recipient is known at the time it is dispatched.
+Implicit Intents can result in an unexpected (and maybe malicious) application
+receiving user data. If it is possible to know the target application when
+sending an Intent, always prefer using an explicit Intent.
+
+## PendingIntents
+
+A [PendingIntent](https://developer.android.com/reference/android/app/PendingIntent)
+is created by one application and vended to another. The object allows the
+receiving application to start the component (i.e. Activity, Service, Broadcast)
+_as if the creating application started it_. Similar to a [setuid binary](https://en.wikipedia.org/wiki/Setuid),
+you must use this with care, as it can even be used to start non-exported
+components of the creating application.
+
+It is possible to retrieve information about the creator package of the
+PendingIntent using the [`getCreatorPackage()`](https://developer.android.com/reference/android/app/PendingIntent.html#getCreatorPackage())
+method. This is the identity under which the Intent, which the PendingIntent
+represents, will be started. Note that you cannot retrieve specific information
+about the Intent (e.g. its target and extras). And as discussed above with
+Intents, it is not possible to determine the application that called
+`PendingIntent.send()`.
+
+## Binder
+
+[Binder](https://developer.android.com/reference/android/os/Binder) is the low
+level IPC mechanism on Android, and it is what Intents and other Framework-level
+primitives are built upon.
+
+### Bound Services
+
+To communicate between components using Binder, you declare a `<service>` in
+your manifest and connect to it using [`Context.bindService()`](https://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent,%2520android.content.ServiceConnection,%2520int)).
+This is referred to a as a [bound service](https://developer.android.com/guide/components/bound-services).
+
+One of the powerful properties of a bound service is that you can determine the
+identity of your communicating peer. This can only be done during a Binder
+transaction (e.g. in an [AIDL](https://developer.android.com/guide/components/aidl)
+method implementation or a [`Handler.Callback`](https://developer.android.com/reference/android/os/Handler.Callback.html))
+that is **not** marked [`FLAG_ONEWAY`](https://developer.android.com/reference/android/os/IBinder).
+During the transaction use [`Binder.getCallingUid()`](https://developer.android.com/reference/android/os/Binder.html#getCallingUid())
+to retrieve the package's UID.
+
+In Android, every installed application is given a unique user ID (UID). This
+can be used as a key to query the [PackageManager](https://developer.android.com/reference/android/content/pm/PackageManager),
+to retrieve the [PackageInfo](https://developer.android.com/reference/android/content/pm/PackageInfo)
+for the application. With the PackageInfo, information about the applications
+code signing certificates can be retrieved and cryptographically authenticated.
+This is a strong authentication check and it is the **only** reliable mechanism
+by which you can authenticate your peer.
+
+In Chrome, the helper functions
+[`ExternalAuthUtils.isCallerValid()`](https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java?l=157&rcl=fa790f69ce80bf2e192d710ea08b8343cad93fbb)
+and `isCallerValidForPackage()` can perform these checks for you.
+
+## Capability Tokens {#capability-tokens}
+
+We define a **capability token** to be an unforgeable object that the holder may
+present to another application as authentication to access a specific
+capability. Binder objects are backed by the kernel (i.e. are unforgeable), are
+transferable, and are comparable using `isEqual()`, so Binders can be used as
+capability tokens.
+
+One security factor to bear in mind is that because capability tokens are
+transferable, they do not strongly authenticate a caller's identity. One
+application may deliberately or accidentally transfer a capability token to
+another application, or a token could be exfiltrated via an application logic
+vulnerability. Therefore, only use capability tokens for access control, not
+identity authentication.
+
+While noting the above factor, capability tokens can be useful for
+authenticating Intents. If two applications have established a Binder
+connection, they can use the channel to exchange a capability token. One
+application constructs a generic Binder (using the
+[`Binder(String)`](https://developer.android.com/reference/android/os/Binder.html#Binder(java.lang.String))
+constructor) and sends the object over that `ServiceConnection` to the other
+application, while retaining a reference to it.
+
+The generic Binder object can then be transmitted as an Intent extra when
+sending Intents between the two applications. By comparing the object with
+`Binder.isEqual()`, you can validate the capability token. Be sure to use an
+[explicit Intent](#outbound-intents) when sending such an Intent.
+
+This same approach can also be done with using a PendingIntent to a non-exported
+component as a capability token. Internally PendingIntents use a Binder token
+approach, so the only significant difference is the additional capability
+conferred by the PendingIntent to start a component.
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index e76fde47..cd99f5b 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -280,7 +280,7 @@
   },
   "management": [{
     "dependencies": ["permission:management"],
-    "contexts": ["blessed_extension"],
+    "contexts": ["blessed_extension", "extension_service_worker"],
     "default_parent": true
   }, {
     "channel": "stable",
diff --git a/extensions/renderer/worker_thread_dispatcher.cc b/extensions/renderer/worker_thread_dispatcher.cc
index 47b79e0f..6b94e6ff 100644
--- a/extensions/renderer/worker_thread_dispatcher.cc
+++ b/extensions/renderer/worker_thread_dispatcher.cc
@@ -100,6 +100,10 @@
     if (worker_thread_id == kMainThreadId)
       return false;
     base::TaskRunner* runner = GetTaskRunnerFor(worker_thread_id);
+    // The TaskRunner may have been destroyed, for example, if the extension
+    // was unloaded, so check before trying to post a task.
+    if (runner == nullptr)
+      return false;
     bool task_posted = runner->PostTask(
         FROM_HERE, base::BindOnce(&WorkerThreadDispatcher::ForwardIPC,
                                   worker_thread_id, message));
@@ -130,7 +134,8 @@
 base::TaskRunner* WorkerThreadDispatcher::GetTaskRunnerFor(
     int worker_thread_id) {
   base::AutoLock lock(task_runner_map_lock_);
-  return task_runner_map_[worker_thread_id];
+  auto it = task_runner_map_.find(worker_thread_id);
+  return it == task_runner_map_.end() ? nullptr : it->second;
 }
 
 bool WorkerThreadDispatcher::Send(IPC::Message* message) {
diff --git a/fuchsia/engine/BUILD.gn b/fuchsia/engine/BUILD.gn
index 0a4486f..a175283 100644
--- a/fuchsia/engine/BUILD.gn
+++ b/fuchsia/engine/BUILD.gn
@@ -168,12 +168,6 @@
     "lib/libswiftshader_libEGL.so",
     "lib/libswiftshader_libGLESv2.so",
   ]
-  if (!is_debug) {
-    excluded_files += [
-      "lib/libVkLayer_core_validation.so",
-      "lib/libVkLayer_parameter_validation.so",
-    ]
-  }
 }
 
 fuchsia_package_runner("web_engine_runner") {
diff --git a/fuchsia/runners/cast/not_implemented_api_bindings.js b/fuchsia/runners/cast/not_implemented_api_bindings.js
index c6150dc..1c1f5ef 100644
--- a/fuchsia/runners/cast/not_implemented_api_bindings.js
+++ b/fuchsia/runners/cast/not_implemented_api_bindings.js
@@ -59,183 +59,203 @@
   };
 
 
-  cast.__platform__.canDisplayType =
-      cast.__platform__._notImplemented('canDisplayType', true);
+  if (!cast.__platform__.canDisplayType) {
+    cast.__platform__.canDisplayType =
+        cast.__platform__._notImplemented('canDisplayType', true);
+  }
 
-  cast.__platform__.setAssistantMessageHandler =
-      cast.__platform__._notImplemented('setAssistantMessageHandler');
+  if (!cast.__platform__.setAssistantMessageHandler) {
+    cast.__platform__.setAssistantMessageHandler =
+        cast.__platform__._notImplemented('setAssistantMessageHandler');
+  }
 
-  cast.__platform__.sendAssistantRequest =
-      cast.__platform__._notImplemented('sendAssistantRequest');
+  if (!cast.__platform__.sendAssistantRequest) {
+    cast.__platform__.sendAssistantRequest =
+        cast.__platform__._notImplemented('sendAssistantRequest');
+  }
 
-  cast.__platform__.setWindowRequestHandler =
-      cast.__platform__._notImplemented('setWindowRequestHandler');
+  if (!cast.__platform__.setWindowRequestHandler) {
+    cast.__platform__.setWindowRequestHandler =
+        cast.__platform__._notImplemented('setWindowRequestHandler');
+  }
 
-  cast.__platform__.takeScreenshot =
-      cast.__platform__._notImplemented('takeScreenshot');
+  if (!cast.__platform__.takeScreenshot) {
+    cast.__platform__.takeScreenshot =
+        cast.__platform__._notImplemented('takeScreenshot');
+  }
 
 
-  cast.__platform__.crypto = {};
+  if (!cast.__platform__.crypto) {
+    cast.__platform__.crypto = {};
 
-  cast.__platform__.crypto.encrypt =
-      cast.__platform__._notImplemented(
-          'crypto.encrypt',
-          new ArrayBuffer(0),
-          cast.__platform__.ReturnType.PROMISE_RESOLVED);
+    cast.__platform__.crypto.encrypt =
+        cast.__platform__._notImplemented(
+            'crypto.encrypt',
+            new ArrayBuffer(0),
+            cast.__platform__.ReturnType.PROMISE_RESOLVED);
 
-  cast.__platform__.crypto.decrypt =
-      cast.__platform__._notImplemented(
-          'crypto.decrypt',
-          new ArrayBuffer(0),
-          cast.__platform__.ReturnType.PROMISE_RESOLVED);
+    cast.__platform__.crypto.decrypt =
+        cast.__platform__._notImplemented(
+            'crypto.decrypt',
+            new ArrayBuffer(0),
+            cast.__platform__.ReturnType.PROMISE_RESOLVED);
 
-  cast.__platform__.crypto.sign =
-      cast.__platform__._notImplemented(
-          'crypto.sign',
-          new ArrayBuffer(0),
-          cast.__platform__.ReturnType.PROMISE_RESOLVED);
+    cast.__platform__.crypto.sign =
+        cast.__platform__._notImplemented(
+            'crypto.sign',
+            new ArrayBuffer(0),
+            cast.__platform__.ReturnType.PROMISE_RESOLVED);
 
-  cast.__platform__.crypto.unwrapKey =
-      cast.__platform__._notImplemented(
-          'crypto.unwrapKey',
-          undefined,
-          cast.__platform__.ReturnType.PROMISE_REJECTED);
+    cast.__platform__.crypto.unwrapKey =
+        cast.__platform__._notImplemented(
+            'crypto.unwrapKey',
+            undefined,
+            cast.__platform__.ReturnType.PROMISE_REJECTED);
 
-  cast.__platform__.crypto.verify =
-      cast.__platform__._notImplemented(
-          'crypto.verify',
-          true,
-          cast.__platform__.ReturnType.PROMISE_RESOLVED);
+    cast.__platform__.crypto.verify =
+        cast.__platform__._notImplemented(
+            'crypto.verify',
+            true,
+            cast.__platform__.ReturnType.PROMISE_RESOLVED);
 
-  cast.__platform__.crypto.wrapKey =
-      cast.__platform__._notImplemented(
-          'crypto.wrapKey',
-          undefined,
-          cast.__platform__.ReturnType.PROMISE_REJECTED);
+    cast.__platform__.crypto.wrapKey =
+        cast.__platform__._notImplemented(
+            'crypto.wrapKey',
+            undefined,
+            cast.__platform__.ReturnType.PROMISE_REJECTED);
+  }
 
 
-  cast.__platform__.cryptokeys = {};
+  if (!cast.__platform__.cryptokeys) {
+    cast.__platform__.cryptokeys = {};
 
-  cast.__platform__.cryptokeys.getKeyByName =
-      cast.__platform__._notImplemented(
-          'cryptokeys.getKeyByName',
-          '',
-          cast.__platform__.ReturnType.PROMISE_REJECTED);
+    cast.__platform__.cryptokeys.getKeyByName =
+        cast.__platform__._notImplemented(
+            'cryptokeys.getKeyByName',
+            '',
+            cast.__platform__.ReturnType.PROMISE_REJECTED);
+  }
 
 
-  cast.__platform__.display = {};
+  if (!cast.__platform__.display) {
+    cast.__platform__.display = {};
 
-  cast.__platform__.display.updateOutputMode =
-      cast.__platform__._notImplemented(
-          'display.updateOutputMode',
-          Promise.resolve(),
-          cast.__platform__.ReturnType.PROMISE_RESOLVED);
+    cast.__platform__.display.updateOutputMode =
+        cast.__platform__._notImplemented(
+            'display.updateOutputMode',
+            Promise.resolve(),
+            cast.__platform__.ReturnType.PROMISE_RESOLVED);
 
-  cast.__platform__.display.getHdcpVersion =
-      cast.__platform__._notImplemented(
-          'display.getHdcpVersion',
-          '0',
-          cast.__platform__.ReturnType.PROMISE_RESOLVED);
+    cast.__platform__.display.getHdcpVersion =
+        cast.__platform__._notImplemented(
+            'display.getHdcpVersion',
+            '0',
+            cast.__platform__.ReturnType.PROMISE_RESOLVED);
+  }
 
 
-  cast.__platform__.metrics = {};
+  if (!cast.__platform__.metrics) {
+    cast.__platform__.metrics = {};
 
-  cast.__platform__.metrics.logBoolToUma =
-      cast.__platform__._notImplemented(
-          'metrics.logBoolToUma');
+    cast.__platform__.metrics.logBoolToUma =
+        cast.__platform__._notImplemented(
+            'metrics.logBoolToUma');
 
-  cast.__platform__.metrics.logIntToUma =
-      cast.__platform__._notImplemented(
-          'metrics.logIntToUma');
+    cast.__platform__.metrics.logIntToUma =
+        cast.__platform__._notImplemented(
+            'metrics.logIntToUma');
 
-  cast.__platform__.metrics.logEventToUma =
-      cast.__platform__._notImplemented(
-          'metrics.logEventToUma');
+    cast.__platform__.metrics.logEventToUma =
+        cast.__platform__._notImplemented(
+            'metrics.logEventToUma');
 
-  cast.__platform__.metrics.logHistogramValueToUma =
-      cast.__platform__._notImplemented(
-          'metrics.logHistogramValueToUma');
+    cast.__platform__.metrics.logHistogramValueToUma =
+        cast.__platform__._notImplemented(
+            'metrics.logHistogramValueToUma');
 
-  cast.__platform__.metrics.setMplVersion =
-      cast.__platform__._notImplemented('metrics.setMplVersion');
+    cast.__platform__.metrics.setMplVersion =
+        cast.__platform__._notImplemented('metrics.setMplVersion');
+  }
 
 
+  if (!cast.__platform__.accessibility) {
+    cast.__platform__.accessibility = {};
+
+    cast.__platform__.accessibility.getAccessibilitySettings =
+        cast.__platform__._notImplemented(
+            'accessibility.getAccessibilitySettings',
+            {isColorInversionEnabled: false, isScreenReaderEnabled: false},
+            cast.__platform__.ReturnType.PROMISE_RESOLVED);
+
+    cast.__platform__.accessibility.setColorInversion =
+        cast.__platform__._notImplemented(
+            'accessibility.setColorInversion');
+
+    cast.__platform__.accessibility.setMagnificationGesture =
+        cast.__platform__._notImplemented(
+            'accessibility.setMagnificationGesture');
+  }
 
 
-  cast.__platform__.accessibility = {};
+  if (!cast.__platform__.windowManager) {
+    cast.__platform__.windowManager = {};
 
-  cast.__platform__.accessibility.getAccessibilitySettings =
-      cast.__platform__._notImplemented(
-          'accessibility.getAccessibilitySettings',
-          {isColorInversionEnabled: false, isScreenReaderEnabled: false},
-          cast.__platform__.ReturnType.PROMISE_RESOLVED);
+    cast.__platform__.windowManager.onBackGesture =
+        cast.__platform__._notImplemented('windowManager.onBackGesture',
+            undefined,
+            cast.__platform__.ReturnType.CALLBACK);
 
-  cast.__platform__.accessibility.setColorInversion =
-      cast.__platform__._notImplemented(
-          'accessibility.setColorInversion');
+    cast.__platform__.windowManager.onBackGestureProgress =
+        cast.__platform__._notImplemented('windowManager.onBackGestureProgress',
+            [0],
+            cast.__platform__.ReturnType.CALLBACK);
 
-  cast.__platform__.accessibility.setMagnificationGesture =
-      cast.__platform__._notImplemented(
-          'accessibility.setMagnificationGesture');
+    cast.__platform__.windowManager.onBackGestureCancel =
+        cast.__platform__._notImplemented('windowManager.onBackGestureCancel',
+            undefined,
+            cast.__platform__.ReturnType.CALLBACK);
 
+    cast.__platform__.windowManager.onTopDragGestureDone =
+        cast.__platform__._notImplemented('windowManager.onTopDragGestureDone',
+            undefined,
+            cast.__platform__.ReturnType.CALLBACK);
 
-  cast.__platform__.windowManager = {};
+    cast.__platform__.windowManager.onTopDragGestureProgress =
+        cast.__platform__._notImplemented(
+            'windowManager.onTopDragGestureProgress',
+            [0],
+            cast.__platform__.ReturnType.CALLBACK);
 
-  cast.__platform__.windowManager.onBackGesture =
-      cast.__platform__._notImplemented('windowManager.onBackGesture',
-          undefined,
-          cast.__platform__.ReturnType.CALLBACK);
+    cast.__platform__.windowManager.onTapGesture =
+        cast.__platform__._notImplemented('windowManager.onTapGesture',
+            undefined,
+            cast.__platform__.ReturnType.CALLBACK);
 
-  cast.__platform__.windowManager.onBackGestureProgress =
-      cast.__platform__._notImplemented('windowManager.onBackGestureProgress',
-          [0],
-          cast.__platform__.ReturnType.CALLBACK);
+    cast.__platform__.windowManager.onTapDownGesture =
+        cast.__platform__._notImplemented('windowManager.onTapDownGesture',
+            undefined,
+            cast.__platform__.ReturnType.CALLBACK);
 
-  cast.__platform__.windowManager.onBackGestureCancel =
-      cast.__platform__._notImplemented('windowManager.onBackGestureCancel',
-          undefined,
-          cast.__platform__.ReturnType.CALLBACK);
+    cast.__platform__.windowManager.canTopDrag =
+        cast.__platform__._notImplemented('windowManager.canTopDrag', false);
 
-  cast.__platform__.windowManager.onTopDragGestureDone =
-      cast.__platform__._notImplemented('windowManager.onTopDragGestureDone',
-          undefined,
-          cast.__platform__.ReturnType.CALLBACK);
+    cast.__platform__.windowManager.canGoBack =
+        cast.__platform__._notImplemented('windowManager.canGoBack', false);
 
-  cast.__platform__.windowManager.onTopDragGestureProgress =
-      cast.__platform__._notImplemented(
-          'windowManager.onTopDragGestureProgress',
-          [0],
-          cast.__platform__.ReturnType.CALLBACK);
+    cast.__platform__.windowManager.onRightDragGestureDone =
+        cast.__platform__._notImplemented(
+            'windowManager.onRightDragGestureDone',
+            undefined,
+            cast.__platform__.ReturnType.CALLBACK);
 
-  cast.__platform__.windowManager.onTapGesture =
-      cast.__platform__._notImplemented('windowManager.onTapGesture',
-          undefined,
-          cast.__platform__.ReturnType.CALLBACK);
+    cast.__platform__.windowManager.onRightDragGestureProgress =
+        cast.__platform__._notImplemented(
+            'windowManager.onRightDragGestureProgress',
+            [0, 0],
+            cast.__platform__.ReturnType.CALLBACK);
 
-  cast.__platform__.windowManager.onTapDownGesture =
-      cast.__platform__._notImplemented('windowManager.onTapDownGesture',
-          undefined,
-          cast.__platform__.ReturnType.CALLBACK);
-
-  cast.__platform__.windowManager.canTopDrag =
-      cast.__platform__._notImplemented('windowManager.canTopDrag', false);
-
-  cast.__platform__.windowManager.canGoBack =
-      cast.__platform__._notImplemented('windowManager.canGoBack', false);
-
-  cast.__platform__.windowManager.onRightDragGestureDone =
-      cast.__platform__._notImplemented('windowManager.onRightDragGestureDone',
-          undefined,
-          cast.__platform__.ReturnType.CALLBACK);
-
-  cast.__platform__.windowManager.onRightDragGestureProgress =
-      cast.__platform__._notImplemented(
-          'windowManager.onRightDragGestureProgress',
-          [0, 0],
-          cast.__platform__.ReturnType.CALLBACK);
-
-  cast.__platform__.windowManager.canRightDrag =
-      cast.__platform__._notImplemented(
-          'windowManager.canRightDrag', false);
-
+    cast.__platform__.windowManager.canRightDrag =
+        cast.__platform__._notImplemented(
+            'windowManager.canRightDrag', false);
+  }
 }
diff --git a/gpu/command_buffer/service/gr_cache_controller.cc b/gpu/command_buffer/service/gr_cache_controller.cc
index 8e26fe334..84bbf65 100644
--- a/gpu/command_buffer/service/gr_cache_controller.cc
+++ b/gpu/command_buffer/service/gr_cache_controller.cc
@@ -7,6 +7,7 @@
 #include <chrono>
 
 #include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "ui/gl/gl_context.h"
 
@@ -31,6 +32,9 @@
   if (!purge_gr_cache_cb_.IsCancelled())
     return;
 
+  // Record memory usage periodically.
+  RecordGrContextMemory();
+
   constexpr int kOldResourceCleanupDelaySeconds = 5;
   // Here we ask GrContext to free any resources that haven't been used in
   // a long while even if it is under budget. Below we set a call back to
@@ -68,5 +72,13 @@
   context_state_->gr_context()->freeGpuResources();
 }
 
+void GrCacheController::RecordGrContextMemory() const {
+  int resource_count = 0;
+  size_t resource_bytes = 0;
+  context_state_->gr_context()->getResourceCacheUsage(&resource_count,
+                                                      &resource_bytes);
+  UMA_HISTOGRAM_MEMORY_KB("GPU.GrContextMemoryKb", resource_bytes / 1000);
+}
+
 }  // namespace raster
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gr_cache_controller.h b/gpu/command_buffer/service/gr_cache_controller.h
index d207a923..8e578d7 100644
--- a/gpu/command_buffer/service/gr_cache_controller.h
+++ b/gpu/command_buffer/service/gr_cache_controller.h
@@ -30,6 +30,7 @@
 
  private:
   void PurgeGrCache(uint64_t idle_id);
+  void RecordGrContextMemory() const;
 
   // The |current_idle_id_| is used to avoid continuously posting tasks to clear
   // the GrContext. Each time the context is used this id is incremented and
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index 80ef980..591a064 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -3276,14 +3276,6 @@
       ]
     },
     {
-      "id": 305,
-      "description": "Disable MESA_framebuffer_flip_y until passing WebGL 2.0 Conformance tests",
-      "cr_bugs": [964010],
-      "disabled_extensions": [
-        "GL_MESA_framebuffer_flip_y"
-      ]
-    },
-    {
       "id": 306,
       "description": "Program binaries don't contain transform feedback varyings on Mali GPUs",
       "cr_bugs": [961950],
diff --git a/gpu/vulkan/android/vulkan_implementation_android.cc b/gpu/vulkan/android/vulkan_implementation_android.cc
index e3b427e..7ac90d7 100644
--- a/gpu/vulkan/android/vulkan_implementation_android.cc
+++ b/gpu/vulkan/android/vulkan_implementation_android.cc
@@ -143,7 +143,8 @@
           VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
           VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
           VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
-          VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME};
+          VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
+          VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME};
 }
 
 VkFence VulkanImplementationAndroid::CreateVkFenceForGpuFence(
diff --git a/gpu/vulkan/generate_bindings.py b/gpu/vulkan/generate_bindings.py
index 8706466..89f31fdd 100755
--- a/gpu/vulkan/generate_bindings.py
+++ b/gpu/vulkan/generate_bindings.py
@@ -92,6 +92,10 @@
 { 'name': 'vkGetAndroidHardwareBufferPropertiesANDROID' },
 ]
 
+VULKAN_PHYSICAL_DEVICE_FUNCTIONS_ANDROID = [
+{ 'name': 'vkGetPhysicalDeviceFeatures2' },
+]
+
 VULKAN_DEVICE_FUNCTIONS_LINUX_OR_ANDROID = [
 { 'name': 'vkGetSemaphoreFdKHR' },
 { 'name': 'vkImportSemaphoreFdKHR' },
@@ -164,6 +168,7 @@
 def GenerateHeaderFile(file, unassociated_functions, instance_functions,
                        physical_device_functions, device_functions,
                        device_functions_android,
+                       physical_device_functions_android,
                        device_functions_linux_or_android,
                        device_functions_linux, device_functions_fuchsia,
                        queue_functions, command_buffer_functions,
@@ -264,13 +269,20 @@
 
   file.write("""\
 
-  // Android only device functions.
 #if defined(OS_ANDROID)
+  // Android only device functions.
 """)
 
   WriteFunctionDeclarations(file, device_functions_android)
 
   file.write("""\
+
+  // Android only physical device functions.
+""")
+
+  WriteFunctionDeclarations(file, physical_device_functions_android)
+
+  file.write("""\
 #endif
 """)
 
@@ -371,6 +383,16 @@
   ])
   file.write("#endif\n")
 
+  file.write("""\
+
+#if defined(OS_ANDROID)
+""")
+
+  WriteMacros(file, physical_device_functions_android)
+
+  file.write("""\
+#endif
+""")
 
   file.write("""\
 
@@ -485,6 +507,7 @@
 def GenerateSourceFile(file, unassociated_functions, instance_functions,
                        physical_device_functions, device_functions,
                        device_functions_android,
+                       physical_device_functions_android,
                        device_functions_linux_or_android,
                        device_functions_linux, device_functions_fuchsia,
                        queue_functions, command_buffer_functions,
@@ -550,6 +573,17 @@
   WriteInstanceFunctionPointerInitialization(file, physical_device_functions)
 
   file.write("""\
+#if defined(OS_ANDROID)
+""")
+
+  WriteInstanceFunctionPointerInitialization(file,
+                                             physical_device_functions_android)
+
+  file.write("""\
+#endif
+""")
+
+  file.write("""\
 
   return true;
 }
@@ -679,6 +713,7 @@
                      VULKAN_INSTANCE_FUNCTIONS,
                      VULKAN_PHYSICAL_DEVICE_FUNCTIONS, VULKAN_DEVICE_FUNCTIONS,
                      VULKAN_DEVICE_FUNCTIONS_ANDROID,
+                     VULKAN_PHYSICAL_DEVICE_FUNCTIONS_ANDROID,
                      VULKAN_DEVICE_FUNCTIONS_LINUX_OR_ANDROID,
                      VULKAN_DEVICE_FUNCTIONS_LINUX,
                      VULKAN_DEVICE_FUNCTIONS_FUCHSIA,
@@ -694,6 +729,7 @@
                      VULKAN_INSTANCE_FUNCTIONS,
                      VULKAN_PHYSICAL_DEVICE_FUNCTIONS, VULKAN_DEVICE_FUNCTIONS,
                      VULKAN_DEVICE_FUNCTIONS_ANDROID,
+                     VULKAN_PHYSICAL_DEVICE_FUNCTIONS_ANDROID,
                      VULKAN_DEVICE_FUNCTIONS_LINUX_OR_ANDROID,
                      VULKAN_DEVICE_FUNCTIONS_LINUX,
                      VULKAN_DEVICE_FUNCTIONS_FUCHSIA,
diff --git a/gpu/vulkan/vulkan_device_queue.cc b/gpu/vulkan/vulkan_device_queue.cc
index c6f08fd..441940cb 100644
--- a/gpu/vulkan/vulkan_device_queue.cc
+++ b/gpu/vulkan/vulkan_device_queue.cc
@@ -134,15 +134,40 @@
                             std::begin(required_extensions),
                             std::end(required_extensions));
 
+#if defined(OS_ANDROID)
+  // Query if VkPhysicalDeviceSamplerYcbcrConversionFeatures is supported by
+  // the implementation. This extension must be supported for android.
+  // Note that vulkan is only turned on in chrome for android P+ and android P+
+  // requires vulkan apiVersion 1.1.
+  sampler_ycbcr_conversion_features_.sType =
+      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
+  sampler_ycbcr_conversion_features_.pNext = nullptr;
+
+  // Add VkPhysicalDeviceSamplerYcbcrConversionFeatures struct to pNext chain
+  // of VkPhysicalDeviceFeatures2.
+  enabled_device_features_2_.pNext = &sampler_ycbcr_conversion_features_;
+  vkGetPhysicalDeviceFeatures2(vk_physical_device_,
+                               &enabled_device_features_2_);
+  if (!sampler_ycbcr_conversion_features_.samplerYcbcrConversion) {
+    LOG(ERROR) << "samplerYcbcrConversion is not supported";
+    return false;
+  }
+
+  // Disable all physical device features by default.
+  memset(&enabled_device_features_2_.features, 0,
+         sizeof(enabled_device_features_2_.features));
+#endif
+
   VkDeviceCreateInfo device_create_info = {};
   device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+  device_create_info.pNext = enabled_device_features_2_.pNext;
   device_create_info.queueCreateInfoCount = 1;
   device_create_info.pQueueCreateInfos = &queue_create_info;
   device_create_info.enabledLayerCount = enabled_layer_names.size();
   device_create_info.ppEnabledLayerNames = enabled_layer_names.data();
   device_create_info.enabledExtensionCount = enabled_extensions.size();
   device_create_info.ppEnabledExtensionNames = enabled_extensions.data();
-  device_create_info.pEnabledFeatures = &enabled_device_features_;
+  device_create_info.pEnabledFeatures = &enabled_device_features_2_.features;
 
   result = vkCreateDevice(vk_physical_device_, &device_create_info, nullptr,
                           &owned_vk_device_);
diff --git a/gpu/vulkan/vulkan_device_queue.h b/gpu/vulkan/vulkan_device_queue.h
index f026fd2..df3a0b0 100644
--- a/gpu/vulkan/vulkan_device_queue.h
+++ b/gpu/vulkan/vulkan_device_queue.h
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "build/build_config.h"
 #include "gpu/vulkan/vulkan_export.h"
 #include "ui/gfx/extension_set.h"
 
@@ -80,8 +81,8 @@
 
   VulkanFenceHelper* GetFenceHelper() const { return cleanup_helper_.get(); }
 
-  const VkPhysicalDeviceFeatures& enabled_device_features() const {
-    return enabled_device_features_;
+  const VkPhysicalDeviceFeatures2& enabled_device_features_2() const {
+    return enabled_device_features_2_;
   }
 
  private:
@@ -94,7 +95,12 @@
   uint32_t vk_queue_index_ = 0;
   const VkInstance vk_instance_;
   std::unique_ptr<VulkanFenceHelper> cleanup_helper_;
-  VkPhysicalDeviceFeatures enabled_device_features_ = {};
+  VkPhysicalDeviceFeatures2 enabled_device_features_2_ = {};
+
+#if defined(OS_ANDROID)
+  VkPhysicalDeviceSamplerYcbcrConversionFeatures
+      sampler_ycbcr_conversion_features_ = {};
+#endif
 
   DISALLOW_COPY_AND_ASSIGN(VulkanDeviceQueue);
 };
diff --git a/gpu/vulkan/vulkan_function_pointers.cc b/gpu/vulkan/vulkan_function_pointers.cc
index ddd920e8..6fc83aa 100644
--- a/gpu/vulkan/vulkan_function_pointers.cc
+++ b/gpu/vulkan/vulkan_function_pointers.cc
@@ -157,6 +157,18 @@
     return false;
   }
 
+#if defined(OS_ANDROID)
+  vkGetPhysicalDeviceFeatures2Fn =
+      reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
+          vkGetInstanceProcAddrFn(vk_instance, "vkGetPhysicalDeviceFeatures2"));
+  if (!vkGetPhysicalDeviceFeatures2Fn) {
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
+                  << "vkGetPhysicalDeviceFeatures2";
+    return false;
+  }
+
+#endif
+
   return true;
 }
 
diff --git a/gpu/vulkan/vulkan_function_pointers.h b/gpu/vulkan/vulkan_function_pointers.h
index 5bcb24d..0d9f8f6 100644
--- a/gpu/vulkan/vulkan_function_pointers.h
+++ b/gpu/vulkan/vulkan_function_pointers.h
@@ -139,10 +139,13 @@
   PFN_vkUpdateDescriptorSets vkUpdateDescriptorSetsFn = nullptr;
   PFN_vkWaitForFences vkWaitForFencesFn = nullptr;
 
-  // Android only device functions.
 #if defined(OS_ANDROID)
+  // Android only device functions.
   PFN_vkGetAndroidHardwareBufferPropertiesANDROID
       vkGetAndroidHardwareBufferPropertiesANDROIDFn = nullptr;
+
+  // Android only physical device functions.
+  PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2Fn = nullptr;
 #endif
 
   // Device functions shared between Linux and Android.
@@ -243,6 +246,11 @@
       ->vkGetPhysicalDeviceXlibPresentationSupportKHRFn
 #endif
 
+#if defined(OS_ANDROID)
+#define vkGetPhysicalDeviceFeatures2 \
+  gpu::GetVulkanFunctionPointers()->vkGetPhysicalDeviceFeatures2Fn
+#endif
+
 // Device functions
 #define vkAllocateCommandBuffers \
   gpu::GetVulkanFunctionPointers()->vkAllocateCommandBuffersFn
diff --git a/headless/lib/headless_browser_browsertest.cc b/headless/lib/headless_browser_browsertest.cc
index 49c74d7..7c7b9db 100644
--- a/headless/lib/headless_browser_browsertest.cc
+++ b/headless/lib/headless_browser_browsertest.cc
@@ -21,6 +21,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test.h"
+#include "content/public/test/no_renderer_crashes_assertion.h"
 #include "headless/lib/browser/headless_browser_context_impl.h"
 #include "headless/lib/browser/headless_web_contents_impl.h"
 #include "headless/lib/headless_macros.h"
@@ -470,6 +471,8 @@
 #define MAYBE_GenerateMinidump DISABLED_GenerateMinidump
 #endif  // defined(HEADLESS_USE_BREAKPAD) || defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(CrashReporterTest, MAYBE_GenerateMinidump) {
+  content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes;
+
   // Navigates a tab to chrome://crash and checks that a minidump is generated.
   // Note that we only test renderer crashes here -- browser crashes need to be
   // tested with a separate harness.
diff --git a/headless/lib/headless_devtools_client_browsertest.cc b/headless/lib/headless_devtools_client_browsertest.cc
index 7519a75e..58f4c449 100644
--- a/headless/lib/headless_devtools_client_browsertest.cc
+++ b/headless/lib/headless_devtools_client_browsertest.cc
@@ -18,6 +18,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test.h"
+#include "content/public/test/no_renderer_crashes_assertion.h"
 #include "headless/lib/browser/headless_web_contents_impl.h"
 #include "headless/public/devtools/domains/browser.h"
 #include "headless/public/devtools/domains/dom.h"
@@ -473,6 +474,9 @@
     EXPECT_EQ(base::TERMINATION_STATUS_ABNORMAL_TERMINATION, status);
 #endif
   }
+
+ private:
+  content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes_;
 };
 
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessCrashObserverTest);
diff --git a/infra/config/cr-buildbucket-dev.cfg b/infra/config/cr-buildbucket-dev.cfg
index 2da7dfc..b8918a0 100644
--- a/infra/config/cr-buildbucket-dev.cfg
+++ b/infra/config/cr-buildbucket-dev.cfg
@@ -94,6 +94,7 @@
       category: "Chromium"
       execution_timeout_secs: 10800  # 3h
       service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com"
+      swarming_tags: "vpython:native-python-wrapper"
       build_numbers: YES
       recipe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index 3e4c64a..a02ac3d2 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -961,6 +961,7 @@
     builders {
       name: "Android FYI 32 dEQP Vk Release (Pixel 2)"
       mixins: "android-gpu-fyi-ci"
+      mixins: "builderless"
       mixins: "goma-rbe-prod"
     }
 
@@ -973,6 +974,7 @@
     builders {
       name: "Android FYI 32 Vk Release (Pixel 2)"
       mixins: "android-gpu-fyi-ci"
+      mixins: "builderless"
       mixins: "goma-rbe-prod"
     }
 
@@ -985,6 +987,7 @@
     builders {
       name: "Android FYI 64 dEQP Vk Release (Pixel 2)"
       mixins: "android-gpu-fyi-ci"
+      mixins: "builderless"
       mixins: "goma-rbe-prod"
     }
 
@@ -997,6 +1000,7 @@
     builders {
       name: "Android FYI 64 Vk Release (Pixel 2)"
       mixins: "android-gpu-fyi-ci"
+      mixins: "builderless"
       mixins: "goma-rbe-prod"
     }
 
@@ -1051,6 +1055,7 @@
     builders {
       name: "Android FYI Release (Pixel 2)"
       mixins: "android-gpu-fyi-ci"
+      mixins: "builderless"
       mixins: "goma-rbe-prod"
     }
 
@@ -2733,13 +2738,6 @@
       mixins: "fyi-ci"
     }
     builders {
-      name: "Chromium Mac 10.13"
-      dimensions: "os:Mac-10.13"
-      dimensions: "cores:4"
-      mixins: "fyi-ci"
-      mixins: "goma-rbe-prod"
-    }
-    builders {
       name: "linux-archive-dbg"
       dimensions: "os:Ubuntu-14.04"
       # Bump to 32 if needed.
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index 1dd0538..d11beada 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -2079,10 +2079,6 @@
     short_name: "jmb"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Chromium Mac 10.13"
-    category: "default"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Mac deterministic"
     category: "deterministic"
   }
@@ -2801,11 +2797,6 @@
     short_name: "bld"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Chromium Mac 10.13"
-    category: "week2c|mac"
-    short_name: "10.13"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Mac ASAN Release"
     category: "week2c|mac|asan"
   }
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index e4b96d2..f763f7a 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -116,7 +116,6 @@
   triggers: "Chromium Linux Goma RBE ToT"
   triggers: "Chromium Linux Goma RBE ToT (ATS)"
   triggers: "Chromium Linux Goma Staging"
-  triggers: "Chromium Mac 10.13"
   triggers: "Chromium Mac Goma RBE Prod"
   triggers: "Chromium Mac Goma RBE Staging"
   triggers: "Chromium Mac Goma RBE Staging (clobber)"
@@ -378,7 +377,6 @@
   triggers: "win-archive-dbg"
   triggers: "win-jumbo-rel"
   triggers: "win-archive-rel"
-  triggers: "win-celab-builder-rel"
   triggers: "win-pixel-builder-rel"
   triggers: "win32-arm64-rel"
   triggers: "win32-archive-dbg"
@@ -3352,16 +3350,6 @@
 }
 
 job {
-  id: "Chromium Mac 10.13"
-  acl_sets: "default"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "Chromium Mac 10.13"
-  }
-}
-
-job {
   id: "ChromiumOS ASAN Release"
   acl_sets: "default"
   buildbucket: {
diff --git a/ios/chrome/browser/ui/settings/language/language_settings_egtest.mm b/ios/chrome/browser/ui/settings/language/language_settings_egtest.mm
index a8db591..391fdcc2 100644
--- a/ios/chrome/browser/ui/settings/language/language_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/language/language_settings_egtest.mm
@@ -44,31 +44,27 @@
 // Labels used to identify language entries.
 NSString* const kLanguageEntryThreeLabelsTemplate = @"%@, %@, %@";
 NSString* const kLanguageEntryTwoLabelsTemplate = @"%@, %@";
-NSString* const kEnglishLabel = @"English (United States)";
+NSString* const kEnglishLabel = @"English";
 NSString* const kTurkishLabel = @"Turkish";
 NSString* const kTurkishNativeLabel = @"Türkçe";
+NSString* const kAragoneseLabel = @"Aragonese";
 NSString* const kNeverTranslateLabel = @"Never Translate";
 NSString* const kOfferToTranslateLabel = @"Offer to Translate";
 
 // Matcher for the Language Settings's main page table view.
 id<GREYMatcher> LanguageSettingsTableView() {
-  return grey_allOf(
-      grey_accessibilityID(kLanguageSettingsTableViewAccessibilityIdentifier),
-      grey_sufficientlyVisible(), nil);
+  return grey_accessibilityID(
+      kLanguageSettingsTableViewAccessibilityIdentifier);
 }
 
 // Matcher for the Language Settings's Add Language page table view.
 id<GREYMatcher> AddLanguageTableView() {
-  return grey_allOf(
-      grey_accessibilityID(kAddLanguageTableViewAccessibilityIdentifier),
-      grey_sufficientlyVisible(), nil);
+  return grey_accessibilityID(kAddLanguageTableViewAccessibilityIdentifier);
 }
 
 // Matcher for the Language Settings's Language Details page table view.
 id<GREYMatcher> LanguageDetailsTableView() {
-  return grey_allOf(
-      grey_accessibilityID(kLanguageDetailsTableViewAccessibilityIdentifier),
-      grey_sufficientlyVisible(), nil);
+  return grey_accessibilityID(kLanguageDetailsTableViewAccessibilityIdentifier);
 }
 
 // Matcher for the Language Settings's general Settings menu entry.
@@ -85,15 +81,6 @@
                     grey_sufficientlyVisible(), nil);
 }
 
-// Matcher for the nav bar's back button to the Language Settings's main page.
-id<GREYMatcher> NavigationBarLanguageSettingsButton() {
-  return grey_allOf(
-      ButtonWithAccessibilityLabelId(IDS_IOS_LANGUAGE_SETTINGS_TITLE),
-      grey_kindOfClass([UIButton class]),
-      grey_ancestor(grey_kindOfClass([UINavigationBar class])),
-      grey_sufficientlyVisible(), nil);
-}
-
 // Matcher for the search bar.
 id<GREYMatcher> SearchBar() {
   return grey_allOf(
@@ -144,6 +131,22 @@
              : grey_not(grey_accessibilityTrait(UIAccessibilityTraitSelected));
 }
 
+// Matcher for the delete button for a language entry in the Language Settings's
+// main page.
+id<GREYMatcher> LanguageEntryDeleteButton() {
+  return grey_allOf(grey_accessibilityLabel(@"Delete"),
+                    grey_sufficientlyVisible(), nil);
+}
+
+// Matcher for the nav bar's edit button.
+id<GREYMatcher> NavigationBarEditButton() {
+  return grey_allOf(
+      ButtonWithAccessibilityLabelId(IDS_IOS_NAVIGATION_BAR_EDIT_BUTTON),
+      grey_kindOfClass([UIButton class]),
+      grey_ancestor(grey_kindOfClass([UINavigationBar class])),
+      grey_sufficientlyVisible(), nil);
+}
+
 }  // namespace
 
 @interface LanguageSettingsTestCase : ChromeTestCase
@@ -169,19 +172,32 @@
   // Make sure Translate is enabled.
   SetBooleanUserPref(browserState, prefs::kOfferTranslateEnabled, YES);
 
-  // Make sure "en-US" is the only accept language.
+  // Make sure "en" is the only accept language.
   std::vector<std::string> languages;
   translatePrefs_->GetLanguageList(&languages);
   for (const auto& language : languages) {
     translatePrefs_->RemoveFromLanguageList(language);
   }
-  translatePrefs_->AddToLanguageList("en-US", /*force_blocked=*/false);
+  translatePrefs_->AddToLanguageList("en", /*force_blocked=*/false);
 }
 
 - (void)tearDown {
-  // Go back to the general Settings menu and close it.
+  // Keep navigating back while a Language Settings subpage is displaying.
+  NSError* error = nil;
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
-      performAction:grey_tap()];
+      assertWithMatcher:grey_notNil()
+                  error:&error];
+  while (!error) {
+    [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+        performAction:grey_tap()];
+
+    error = nil;
+    [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+        assertWithMatcher:grey_notNil()
+                    error:&error];
+  }
+
+  // Close the general Settings menu.
   [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
       performAction:grey_tap()];
 
@@ -208,7 +224,7 @@
   VerifyAccessibilityForCurrentScreen();
 
   // Navigate back.
-  [[EarlGrey selectElementWithMatcher:NavigationBarLanguageSettingsButton()]
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
       performAction:grey_tap()];
 
   // Test accessibility on the Language Details page.
@@ -220,10 +236,6 @@
   [[EarlGrey selectElementWithMatcher:LanguageDetailsTableView()]
       assertWithMatcher:grey_notNil()];
   VerifyAccessibilityForCurrentScreen();
-
-  // Navigate back.
-  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
-      performAction:grey_tap()];
 }
 
 // Tests that the Translate Switch enables/disables Translate and the UI gets
@@ -346,7 +358,7 @@
 
   // Verify the prefs are up-to-date.
   ios::ChromeBrowserState* browserState = GetOriginalBrowserState();
-  GREYAssertEqual("en-US,tr",
+  GREYAssertEqual("en,tr",
                   browserState->GetPrefs()->GetString(kAcceptLanguages),
                   @"Unexpected value for kAcceptLanguages pref");
 }
@@ -373,10 +385,11 @@
 
   // Verify both options are enabled and "Never Translate" is selected.
   [[EarlGrey selectElementWithMatcher:NeverTranslateButton()]
-      assertWithMatcher:grey_allOf(grey_enabled(), ElementIsSelected(YES),
-                                   nil)];
+      assertWithMatcher:grey_allOf(grey_userInteractionEnabled(),
+                                   ElementIsSelected(YES), nil)];
   [[EarlGrey selectElementWithMatcher:OfferToTranslateButton()]
-      assertWithMatcher:grey_allOf(grey_enabled(), ElementIsSelected(NO), nil)];
+      assertWithMatcher:grey_allOf(grey_userInteractionEnabled(),
+                                   ElementIsSelected(NO), nil)];
 
   // Tap the "Offer to Translate" button.
   [[EarlGrey selectElementWithMatcher:OfferToTranslateButton()]
@@ -403,10 +416,11 @@
 
   // Verify both options are enabled and "Offer to Translate" is selected.
   [[EarlGrey selectElementWithMatcher:NeverTranslateButton()]
-      assertWithMatcher:grey_allOf(grey_enabled(), ElementIsSelected(NO), nil)];
+      assertWithMatcher:grey_allOf(grey_userInteractionEnabled(),
+                                   ElementIsSelected(NO), nil)];
   [[EarlGrey selectElementWithMatcher:OfferToTranslateButton()]
-      assertWithMatcher:grey_allOf(grey_enabled(), ElementIsSelected(YES),
-                                   nil)];
+      assertWithMatcher:grey_allOf(grey_userInteractionEnabled(),
+                                   ElementIsSelected(YES), nil)];
 
   // Tap the "Never Translate" button.
   [[EarlGrey selectElementWithMatcher:NeverTranslateButton()]
@@ -416,7 +430,7 @@
   [[EarlGrey selectElementWithMatcher:LanguageSettingsTableView()]
       assertWithMatcher:grey_notNil()];
 
-  // Verify "Turkish" is blocked.
+  // Verify "Turkish" is Translate-blocked.
   languageEntryLabel = [NSString
       stringWithFormat:kLanguageEntryThreeLabelsTemplate, kTurkishLabel,
                        kTurkishNativeLabel, kNeverTranslateLabel];
@@ -428,4 +442,172 @@
                  @"Turkish is expected to be Translate-blocked");
 }
 
+// Tests that the target language cannot be unblocked.
+- (void)testUnblockTargetLanguage {
+  [ChromeEarlGreyUI openSettingsMenu];
+
+  // Add "Turkish" to the list of accept languages.
+  translatePrefs_->AddToLanguageList("tr", /*force_blocked=*/false);
+  // Verify the prefs are up-to-date.
+  GREYAssertTrue(translatePrefs_->IsBlockedLanguage("tr"),
+                 @"Turkish is expected to be Translate-blocked");
+
+  // Make "Turkish" the target language.
+  translatePrefs_->SetRecentTargetLanguage("tr");
+
+  // Go to the Language Settings page.
+  [ChromeEarlGreyUI tapSettingsMenuButton:LanguageSettingsButton()];
+
+  // Go to the "Turkish" Language Details page.
+  NSString* languageEntryLabel = [NSString
+      stringWithFormat:kLanguageEntryThreeLabelsTemplate, kTurkishLabel,
+                       kTurkishNativeLabel, kNeverTranslateLabel];
+  [[EarlGrey selectElementWithMatcher:LanguageEntry(languageEntryLabel)]
+      performAction:grey_tap()];
+
+  // Verify the "Never Translate" option is enabled and selected while
+  // "Offer to Translate" is disabled and unselected.
+  [[EarlGrey selectElementWithMatcher:NeverTranslateButton()]
+      assertWithMatcher:grey_allOf(grey_userInteractionEnabled(),
+                                   ElementIsSelected(YES), nil)];
+  [[EarlGrey selectElementWithMatcher:OfferToTranslateButton()]
+      assertWithMatcher:grey_allOf(grey_not(grey_userInteractionEnabled()),
+                                   ElementIsSelected(NO), nil)];
+}
+
+// Tests that the last Translate-blocked language cannot be unblocked.
+- (void)testUnblockLastBlockedLanguage {
+  [ChromeEarlGreyUI openSettingsMenu];
+
+  // Make sure "Turkish" is the target language and not "en".
+  translatePrefs_->SetRecentTargetLanguage("tr");
+
+  // Go to the Language Settings page.
+  [ChromeEarlGreyUI tapSettingsMenuButton:LanguageSettingsButton()];
+
+  // Go to the "Turkish" Language Details page.
+  NSString* languageEntryLabel = [NSString
+      stringWithFormat:kLanguageEntryThreeLabelsTemplate, kEnglishLabel,
+                       kEnglishLabel, kNeverTranslateLabel];
+  [[EarlGrey selectElementWithMatcher:LanguageEntry(languageEntryLabel)]
+      performAction:grey_tap()];
+
+  // Verify the "Never Translate" option is enabled and selected while
+  // "Offer to Translate" is disabled and unselected.
+  [[EarlGrey selectElementWithMatcher:NeverTranslateButton()]
+      assertWithMatcher:grey_allOf(grey_userInteractionEnabled(),
+                                   ElementIsSelected(YES), nil)];
+  [[EarlGrey selectElementWithMatcher:OfferToTranslateButton()]
+      assertWithMatcher:grey_allOf(grey_not(grey_userInteractionEnabled()),
+                                   ElementIsSelected(NO), nil)];
+}
+
+// Tests that an unsupported language cannot be unblocked.
+- (void)testUnblockUnsupportedLanguage {
+  [ChromeEarlGreyUI openSettingsMenu];
+
+  // Add "Aragonese" to the list of accept languages.
+  translatePrefs_->AddToLanguageList("an", /*force_blocked=*/false);
+  // Verify the prefs are up-to-date.
+  GREYAssertTrue(translatePrefs_->IsBlockedLanguage("an"),
+                 @"Aragonese is expected to be Translate-blocked");
+
+  // Go to the Language Settings page.
+  [ChromeEarlGreyUI tapSettingsMenuButton:LanguageSettingsButton()];
+
+  // Go to the "Aragonese" Language Details page.
+  NSString* languageEntryLabel = [NSString
+      stringWithFormat:kLanguageEntryThreeLabelsTemplate, kAragoneseLabel,
+                       kAragoneseLabel, kNeverTranslateLabel];
+  [[EarlGrey selectElementWithMatcher:LanguageEntry(languageEntryLabel)]
+      performAction:grey_tap()];
+
+  // Verify the "Never Translate" option is enabled and selected while
+  // "Offer to Translate" is disabled and unselected.
+  [[EarlGrey selectElementWithMatcher:NeverTranslateButton()]
+      assertWithMatcher:grey_allOf(grey_userInteractionEnabled(),
+                                   ElementIsSelected(YES), nil)];
+  [[EarlGrey selectElementWithMatcher:OfferToTranslateButton()]
+      assertWithMatcher:grey_allOf(grey_not(grey_userInteractionEnabled()),
+                                   ElementIsSelected(NO), nil)];
+}
+
+// Tests that the Add Language button as well as the Translate switch are
+// disabled in edit mode.
+- (void)testEditMode {
+  [ChromeEarlGreyUI openSettingsMenu];
+
+  // Go to the Language Settings page.
+  [ChromeEarlGreyUI tapSettingsMenuButton:LanguageSettingsButton()];
+
+  // Switch on edit mode.
+  [[EarlGrey selectElementWithMatcher:NavigationBarEditButton()]
+      performAction:grey_tap()];
+
+  // Verify that the Add Language button is disabled.
+  [[EarlGrey selectElementWithMatcher:AddLanguageButton()]
+      assertWithMatcher:grey_not(grey_userInteractionEnabled())];
+
+  // Verify that the Translate switch is on and disabled.
+  [[EarlGrey
+      selectElementWithMatcher:SettingsSwitchCell(
+                                   kTranslateSwitchAccessibilityIdentifier, YES,
+                                   NO)] assertWithMatcher:grey_notNil()];
+}
+
+// Tests that languages, except the last one, can be deleted from the list of
+// accept languages.
+- (void)testDeleteLanguage {
+  [ChromeEarlGreyUI openSettingsMenu];
+
+  // Add "Turkish" to the list of accept languages.
+  translatePrefs_->AddToLanguageList("tr", /*force_blocked=*/false);
+  // Verify the prefs are up-to-date.
+  GREYAssertTrue(translatePrefs_->IsBlockedLanguage("tr"),
+                 @"Turkish is expected to be Translate-blocked");
+
+  // Go to the Language Settings page.
+  [ChromeEarlGreyUI tapSettingsMenuButton:LanguageSettingsButton()];
+
+  // Swipe left on the "English" language entry.
+  NSString* englishLanguageEntryLabel = [NSString
+      stringWithFormat:kLanguageEntryThreeLabelsTemplate, kEnglishLabel,
+                       kEnglishLabel, kNeverTranslateLabel];
+  id swipeAction = grey_swipeFastInDirection(kGREYDirectionLeft);
+  [[EarlGrey selectElementWithMatcher:LanguageEntry(englishLanguageEntryLabel)]
+      performAction:swipeAction];
+
+  // Verify that a delete button is visible.
+  [[EarlGrey selectElementWithMatcher:LanguageEntryDeleteButton()]
+      assertWithMatcher:grey_notNil()];
+
+  // Swipe left on the "Turkish" language entry.
+  NSString* turkishLanguageEntryLabel = [NSString
+      stringWithFormat:kLanguageEntryThreeLabelsTemplate, kTurkishLabel,
+                       kTurkishNativeLabel, kNeverTranslateLabel];
+  [[EarlGrey selectElementWithMatcher:LanguageEntry(turkishLanguageEntryLabel)]
+      performAction:swipeAction];
+
+  // Verify that a delete button is visible and tap it.
+  [[EarlGrey selectElementWithMatcher:LanguageEntryDeleteButton()]
+      performAction:grey_tap()];
+
+  // Verify that the "Turkish" language entry does not exist anymore.
+  [[EarlGrey selectElementWithMatcher:LanguageEntry(turkishLanguageEntryLabel)]
+      assertWithMatcher:grey_nil()];
+
+  // Verify the prefs are up-to-date.
+  ios::ChromeBrowserState* browserState = GetOriginalBrowserState();
+  GREYAssertEqual("en", browserState->GetPrefs()->GetString(kAcceptLanguages),
+                  @"Unexpected value for kAcceptLanguages pref");
+
+  // Swipe left on the "English" language entry.
+  [[EarlGrey selectElementWithMatcher:LanguageEntry(englishLanguageEntryLabel)]
+      performAction:swipeAction];
+
+  // Verify that a delete button is not visible.
+  [[EarlGrey selectElementWithMatcher:LanguageEntryDeleteButton()]
+      assertWithMatcher:grey_nil()];
+}
+
 @end
diff --git a/media/gpu/vaapi/OWNERS b/media/gpu/vaapi/OWNERS
index 02abd7f..7671f222 100644
--- a/media/gpu/vaapi/OWNERS
+++ b/media/gpu/vaapi/OWNERS
@@ -4,3 +4,6 @@
 
 # (M)JPEG related stuff
 per-file *jpeg*=andrescj@chromium.org
+
+# General VA-API decoding related stuff
+per-file *image_decoder*=andrescj@chromium.org
diff --git a/media/gpu/vaapi/vaapi_image_decoder.cc b/media/gpu/vaapi/vaapi_image_decoder.cc
index c94aaf0..5bafbd6 100644
--- a/media/gpu/vaapi/vaapi_image_decoder.cc
+++ b/media/gpu/vaapi/vaapi_image_decoder.cc
@@ -6,13 +6,37 @@
 
 #include <va/va.h>
 
+#include "base/logging.h"
 #include "media/gpu/vaapi/vaapi_wrapper.h"
 
 namespace media {
 
+namespace {
+
+VAProfile ConvertToVAProfile(VaapiImageDecoder::Type type) {
+  switch (type) {
+    case VaapiImageDecoder::Type::kJpeg:
+      return VAProfileJPEGBaseline;
+    case VaapiImageDecoder::Type::kWebP:
+      return VAProfileVP8Version0_3;
+    default:
+      NOTREACHED() << "Undefined Type value";
+      return VAProfileNone;
+  }
+}
+
+}  // namespace
+
 VaapiImageDecoder::VaapiImageDecoder()
     : va_surface_id_(VA_INVALID_SURFACE), va_rt_format_(kInvalidVaRtFormat) {}
 
 VaapiImageDecoder::~VaapiImageDecoder() = default;
 
+bool VaapiImageDecoder::Initialize(const base::RepeatingClosure& error_uma_cb) {
+  const VAProfile va_profile = ConvertToVAProfile(GetType());
+  vaapi_wrapper_ =
+      VaapiWrapper::Create(VaapiWrapper::kDecode, va_profile, error_uma_cb);
+  return !!vaapi_wrapper_;
+}
+
 }  // namespace media
diff --git a/media/gpu/vaapi/vaapi_image_decoder.h b/media/gpu/vaapi/vaapi_image_decoder.h
index 39a3072..68eaf26 100644
--- a/media/gpu/vaapi/vaapi_image_decoder.h
+++ b/media/gpu/vaapi/vaapi_image_decoder.h
@@ -50,11 +50,17 @@
 // more implementing classes are added (e.g. VaapiWebPDecoder).
 class VaapiImageDecoder {
  public:
+  // Type of image decoder.
+  enum class Type {
+    kJpeg,
+    kWebP,
+  };
+
   virtual ~VaapiImageDecoder();
 
-  // Initializes |vaapi_wrapper_| in kDecode mode with the appropriate VAAPI
-  // profile and |error_uma_cb| for error reporting.
-  virtual bool Initialize(const base::RepeatingClosure& error_uma_cb) = 0;
+  // Uses GetType() to initialize |vaapi_wrapper_| in kDecode mode with the
+  // appropriate VAAPI profile and |error_uma_cb| for error reporting.
+  bool Initialize(const base::RepeatingClosure& error_uma_cb);
 
   // Decodes a picture. It will fill VA-API parameters and call the
   // corresponding VA-API methods according to the image in |encoded_image|.
@@ -66,6 +72,9 @@
       base::span<const uint8_t> encoded_image,
       VaapiImageDecodeStatus* status) = 0;
 
+  // Returns the type of the current decoder.
+  virtual Type GetType() const = 0;
+
  protected:
   VaapiImageDecoder();
 
diff --git a/media/gpu/vaapi/vaapi_jpeg_decoder.cc b/media/gpu/vaapi/vaapi_jpeg_decoder.cc
index f7af7fd..53b26a8 100644
--- a/media/gpu/vaapi/vaapi_jpeg_decoder.cc
+++ b/media/gpu/vaapi/vaapi_jpeg_decoder.cc
@@ -217,16 +217,6 @@
   }
 }
 
-bool VaapiJpegDecoder::Initialize(const base::RepeatingClosure& error_uma_cb) {
-  vaapi_wrapper_ = VaapiWrapper::Create(VaapiWrapper::kDecode,
-                                        VAProfileJPEGBaseline, error_uma_cb);
-  if (!vaapi_wrapper_) {
-    VLOGF(1) << "Failed initializing VAAPI";
-    return false;
-  }
-  return true;
-}
-
 scoped_refptr<VASurface> VaapiJpegDecoder::Decode(
     base::span<const uint8_t> encoded_image,
     VaapiImageDecodeStatus* status) {
@@ -342,6 +332,10 @@
                                          base::DoNothing() /* release_cb */);
 }
 
+VaapiImageDecoder::Type VaapiJpegDecoder::GetType() const {
+  return VaapiImageDecoder::Type::kJpeg;
+}
+
 std::unique_ptr<ScopedVAImage> VaapiJpegDecoder::GetImage(
     uint32_t preferred_image_fourcc,
     VaapiImageDecodeStatus* status) {
diff --git a/media/gpu/vaapi/vaapi_jpeg_decoder.h b/media/gpu/vaapi/vaapi_jpeg_decoder.h
index e4e27a7..270a748 100644
--- a/media/gpu/vaapi/vaapi_jpeg_decoder.h
+++ b/media/gpu/vaapi/vaapi_jpeg_decoder.h
@@ -30,9 +30,9 @@
   ~VaapiJpegDecoder() override;
 
   // VaapiImageDecoder implementation.
-  bool Initialize(const base::RepeatingClosure& error_uma_cb) override;
   scoped_refptr<VASurface> Decode(base::span<const uint8_t> encoded_image,
                                   VaapiImageDecodeStatus* status) override;
+  Type GetType() const override;
 
   // Get the decoded data from the last Decode() call as a ScopedVAImage. The
   // VAImage's format will be either |preferred_image_fourcc| if the conversion
diff --git a/mojo/core/channel_mac.cc b/mojo/core/channel_mac.cc
index 1737269..8820afe 100644
--- a/mojo/core/channel_mac.cc
+++ b/mojo/core/channel_mac.cc
@@ -353,8 +353,8 @@
         sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t) +
         (message->num_handles() * sizeof(mach_msg_port_descriptor_t));
     const size_t expected_message_size =
-        round_msg(mach_header_size + sizeof(uint64_t) +
-                  message->data_num_bytes() + sizeof(mach_msg_audit_trailer_t));
+        round_msg(mach_header_size + message->data_num_bytes() +
+                  sizeof(mach_msg_audit_trailer_t));
     const bool transfer_message_ool =
         expected_message_size >= send_buffer_.size();
 
diff --git a/mojo/core/channel_unittest.cc b/mojo/core/channel_unittest.cc
index e561db2..14db631 100644
--- a/mojo/core/channel_unittest.cc
+++ b/mojo/core/channel_unittest.cc
@@ -11,9 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/optional.h"
 #include "base/process/process_handle.h"
-#include "base/process/process_metrics.h"
 #include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
 #include "mojo/core/platform_handle_utils.h"
@@ -510,68 +508,6 @@
   EXPECT_EQ(0u, delegate_b.error_count_);
 }
 
-class SingleMessageWaiterDelegate : public Channel::Delegate {
- public:
-  SingleMessageWaiterDelegate() {}
-
-  void OnChannelMessage(const void* payload,
-                        size_t payload_size,
-                        std::vector<PlatformHandle> handles) override {
-    message_received_ = true;
-    run_loop_->Quit();
-  }
-
-  void OnChannelError(Channel::Error error) override {
-    channel_error_ = true;
-    run_loop_->Quit();
-  }
-
-  void Reset(base::RunLoop* loop) {
-    run_loop_ = loop;
-    message_received_ = false;
-    channel_error_ = false;
-  }
-
-  bool message_received() { return message_received_; }
-  bool channel_error() { return channel_error_; }
-
- private:
-  bool message_received_ = false;
-  bool channel_error_ = false;
-  base::RunLoop* run_loop_;
-  DISALLOW_COPY_AND_ASSIGN(SingleMessageWaiterDelegate);
-};
-
-TEST(ChannelTest, MessageSizeTest) {
-  base::MessageLoop message_loop(base::MessageLoop::TYPE_IO);
-  PlatformChannel platform_channel;
-
-  SingleMessageWaiterDelegate receiver_delegate;
-  scoped_refptr<Channel> receiver = Channel::Create(
-      &receiver_delegate,
-      ConnectionParams(platform_channel.TakeLocalEndpoint()),
-      Channel::HandlePolicy::kAcceptHandles, message_loop.task_runner());
-  receiver->Start();
-
-  MockChannelDelegate sender_delegate;
-  scoped_refptr<Channel> sender = Channel::Create(
-      &sender_delegate, ConnectionParams(platform_channel.TakeRemoteEndpoint()),
-      Channel::HandlePolicy::kAcceptHandles, message_loop.task_runner());
-  sender->Start();
-
-  for (uint32_t i = 0; i < base::GetPageSize() * 4; ++i) {
-    SCOPED_TRACE(base::StringPrintf("message size %d", i));
-    sender->Write(std::make_unique<Channel::Message>(i, 0));
-
-    base::RunLoop loop;
-    receiver_delegate.Reset(&loop);
-    loop.Run();
-
-    EXPECT_TRUE(receiver_delegate.message_received());
-    EXPECT_FALSE(receiver_delegate.channel_error());
-  }
-}
-
 }  // namespace
 }  // namespace core
 }  // namespace mojo
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index 451cc99..dd27bf5 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -51,7 +51,6 @@
   "//ui/base/ime/mojo/typemaps.gni",
   "//ui/base/mojo/typemaps.gni",
   "//ui/display/mojo/typemaps.gni",
-  "//ui/events/devices/mojo/typemaps.gni",
   "//ui/events/mojo/typemaps.gni",
   "//ui/gfx/typemaps.gni",
   "//ui/latency/mojo/typemaps.gni",
diff --git a/services/BUILD.gn b/services/BUILD.gn
index 3cb6a04..524fbbcd 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -51,10 +51,6 @@
     ]
   }
 
-  if (use_aura) {
-    deps += [ "//services/ws/input_devices:tests" ]
-  }
-
   if (is_android) {
     deps += [
       "//services/data_decoder/public/cpp/android:safe_json_java",
diff --git a/services/content/public/cpp/DEPS b/services/content/public/cpp/DEPS
index 5b70cd5..b541399 100644
--- a/services/content/public/cpp/DEPS
+++ b/services/content/public/cpp/DEPS
@@ -1,8 +1,5 @@
 include_rules = [
   "+net/http/http_response_headers.h",
-
-  "+services/ws/public",
-
   "+ui/accessibility",
   "+ui/aura",
   "+ui/views",
diff --git a/services/tracing/perfetto/json_trace_exporter.cc b/services/tracing/perfetto/json_trace_exporter.cc
index 0b9d58e..f3504332 100644
--- a/services/tracing/perfetto/json_trace_exporter.cc
+++ b/services/tracing/perfetto/json_trace_exporter.cc
@@ -216,7 +216,7 @@
   // Delegate to the subclasses to parse the packets. It will create
   // ScopedJSONTraceEventAppenders to write the contained events along with
   // other trace fields.
-  ProcessPackets(packets);
+  ProcessPackets(packets, has_more);
 
   if (!has_more) {
     if (label_filter_.empty()) {
diff --git a/services/tracing/perfetto/json_trace_exporter.h b/services/tracing/perfetto/json_trace_exporter.h
index 596d778d..f14ca24 100644
--- a/services/tracing/perfetto/json_trace_exporter.h
+++ b/services/tracing/perfetto/json_trace_exporter.h
@@ -221,8 +221,8 @@
   // Subclasses implement this to add data from |packets| to the JSON output.
   // For example they can add traceEvents through AddTraceEvent(), or add
   // metadata through AddChromeMetadata().
-  virtual void ProcessPackets(
-      const std::vector<perfetto::TracePacket>& packets) = 0;
+  virtual void ProcessPackets(const std::vector<perfetto::TracePacket>& packets,
+                              bool has_more) = 0;
 
   // If true then all trace events should be skipped. AddTraceEvent should not
   // be called.
diff --git a/services/tracing/perfetto/json_trace_exporter_unittest.cc b/services/tracing/perfetto/json_trace_exporter_unittest.cc
index 107033c..eabd334 100644
--- a/services/tracing/perfetto/json_trace_exporter_unittest.cc
+++ b/services/tracing/perfetto/json_trace_exporter_unittest.cc
@@ -104,8 +104,8 @@
   std::vector<perfetto::protos::TraceStats> stats;
 
  protected:
-  void ProcessPackets(
-      const std::vector<perfetto::TracePacket>& packets) override {
+  void ProcessPackets(const std::vector<perfetto::TracePacket>& packets,
+                      bool has_more) override {
     ++process_packets_calls_;
     DCHECK(packets.size() == infos_.size())
         << " different sizes of packets versus expected behaviour test set up "
diff --git a/services/tracing/perfetto/track_event_json_exporter.cc b/services/tracing/perfetto/track_event_json_exporter.cc
index 2dfb388..5c6be7d 100644
--- a/services/tracing/perfetto/track_event_json_exporter.cc
+++ b/services/tracing/perfetto/track_event_json_exporter.cc
@@ -5,6 +5,7 @@
 #include "services/tracing/perfetto/track_event_json_exporter.h"
 
 #include <cinttypes>
+#include <memory>
 
 #include "base/json/string_escape.h"
 #include "base/strings/string_util.h"
@@ -69,12 +70,15 @@
     : JSONTraceExporter(std::move(argument_filter_predicate),
                         std::move(metadata_filter_predicate),
                         std::move(callback)),
-      current_state_(0) {}
+      current_state_(std::make_unique<ProducerWriterState>(0)) {}
 
-TrackEventJSONExporter::~TrackEventJSONExporter() {}
+TrackEventJSONExporter::~TrackEventJSONExporter() {
+  DCHECK(!current_state_ || !current_state_->last_seen_thread_descriptor);
+}
 
 void TrackEventJSONExporter::ProcessPackets(
-    const std::vector<perfetto::TracePacket>& packets) {
+    const std::vector<perfetto::TracePacket>& packets,
+    bool has_more) {
   for (auto& encoded_packet : packets) {
     // These are perfetto::TracePackets, but ChromeTracePacket is a mirror that
     // reduces binary bloat and only has the fields we are interested in. So
@@ -86,7 +90,7 @@
     // If this is a different packet_sequence_id we have to reset all our state
     // and wait for the first state_clear before emitting anything.
     if (packet.trusted_packet_sequence_id() !=
-        current_state_.trusted_packet_sequence_id) {
+        current_state_->trusted_packet_sequence_id) {
       StartNewState(packet.trusted_packet_sequence_id(),
                     packet.incremental_state_cleared());
     } else if (packet.incremental_state_cleared()) {
@@ -95,10 +99,10 @@
       // If we've lost packets we can no longer trust any timestamp data and
       // other state which might have been dropped. We will keep skipping events
       // until we start a new sequence.
-      LOG_IF(ERROR, current_state_.incomplete)
+      LOG_IF(ERROR, current_state_->incomplete)
           << "Previous packet was dropped. Skipping TraceEvents until reset or "
           << "new sequence.";
-      current_state_.incomplete = true;
+      current_state_->incomplete = true;
     }
 
     // Now we process the data from the packet. First by getting the interned
@@ -123,37 +127,42 @@
       // and has no equivalent in the old trace format. We thus ignore it.
     }
   }
+  if (!has_more) {
+    EmitThreadDescriptorIfNeeded();
+  }
 }
 
 TrackEventJSONExporter::ProducerWriterState::ProducerWriterState(
     uint32_t sequence_id)
-    : ProducerWriterState(sequence_id, false, false, true) {}
+    : ProducerWriterState(sequence_id, false, nullptr, true) {}
 
 TrackEventJSONExporter::ProducerWriterState::ProducerWriterState(
     uint32_t sequence_id,
     bool emitted_process,
-    bool emitted_thread,
+    std::unique_ptr<ThreadDescriptor> last_seen_thread_descriptor,
     bool incomplete)
     : trusted_packet_sequence_id(sequence_id),
       emitted_process_metadata(emitted_process),
-      emitted_thread_metadata(emitted_thread),
+      last_seen_thread_descriptor(std::move(last_seen_thread_descriptor)),
       incomplete(incomplete) {}
 
 TrackEventJSONExporter::ProducerWriterState::~ProducerWriterState() {}
 
 void TrackEventJSONExporter::StartNewState(uint32_t trusted_packet_sequence_id,
                                            bool state_cleared) {
-  current_state_ = ProducerWriterState{
+  EmitThreadDescriptorIfNeeded();
+  current_state_ = std::make_unique<ProducerWriterState>(
       trusted_packet_sequence_id, /* emitted_process = */ false,
-      /* emitted_thread = */ false, /* incomplete = */ !state_cleared};
+      /* last_seen_thread_descriptor = */ nullptr,
+      /* incomplete = */ !state_cleared);
 }
 
 void TrackEventJSONExporter::ResetIncrementalState() {
-  current_state_ =
-      ProducerWriterState{current_state_.trusted_packet_sequence_id,
-                          current_state_.emitted_process_metadata,
-                          current_state_.emitted_thread_metadata,
-                          /* incomplete = */ false};
+  current_state_ = std::make_unique<ProducerWriterState>(
+      current_state_->trusted_packet_sequence_id,
+      current_state_->emitted_process_metadata,
+      std::move(current_state_->last_seen_thread_descriptor),
+      /* incomplete = */ false);
 }
 
 int64_t TrackEventJSONExporter::ComputeTimeUs(const TrackEvent& event) {
@@ -161,9 +170,9 @@
     case TrackEvent::kTimestampAbsoluteUs:
       return event.timestamp_absolute_us();
     case TrackEvent::kTimestampDeltaUs:
-      DCHECK(current_state_.time_us != -1);
-      current_state_.time_us += event.timestamp_delta_us();
-      return current_state_.time_us;
+      DCHECK(current_state_->time_us != -1);
+      current_state_->time_us += event.timestamp_delta_us();
+      return current_state_->time_us;
     case TrackEvent::TIMESTAMP_NOT_SET:
       DLOG(FATAL) << "Event has no timestamp this shouldn't be possible";
       return -1;
@@ -176,9 +185,9 @@
     case TrackEvent::kThreadTimeAbsoluteUs:
       return event.thread_time_absolute_us();
     case TrackEvent::kThreadTimeDeltaUs:
-      DCHECK(current_state_.thread_time_us != -1);
-      current_state_.thread_time_us += event.thread_time_delta_us();
-      return current_state_.thread_time_us;
+      DCHECK(current_state_->thread_time_us != -1);
+      current_state_->thread_time_us += event.thread_time_delta_us();
+      return current_state_->thread_time_us;
     case TrackEvent::THREAD_TIME_NOT_SET:
       return base::nullopt;
   }
@@ -189,7 +198,7 @@
   DCHECK(packet.has_interned_data());
 
   // InternedData is only emitted on sequences with incremental state.
-  if (current_state_.incomplete) {
+  if (current_state_->incomplete) {
     return;
   }
 
@@ -197,24 +206,24 @@
   // Even if the interned data was reset we should not change the values in the
   // interned data.
   for (const auto& event_cat : data.event_categories()) {
-    auto iter = current_state_.interned_event_categories_.insert(
+    auto iter = current_state_->interned_event_categories_.insert(
         std::make_pair(event_cat.iid(), event_cat.name()));
     DCHECK(iter.second || iter.first->second == event_cat.name());
   }
   for (const auto& event_name : data.legacy_event_names()) {
-    auto iter = current_state_.interned_legacy_event_names_.insert(
+    auto iter = current_state_->interned_legacy_event_names_.insert(
         std::make_pair(event_name.iid(), event_name.name()));
     DCHECK(iter.second || iter.first->second == event_name.name());
   }
   for (const auto& debug_name : data.debug_annotation_names()) {
-    auto iter = current_state_.interned_debug_annotation_names_.insert(
+    auto iter = current_state_->interned_debug_annotation_names_.insert(
         std::make_pair(debug_name.iid(), debug_name.name()));
     DCHECK(iter.second || iter.first->second == debug_name.name());
   }
   for (const auto& src_loc : data.source_locations()) {
-    auto iter = current_state_.interned_source_locations_.insert(std::make_pair(
-        src_loc.iid(),
-        std::make_pair(src_loc.file_name(), src_loc.function_name())));
+    auto iter = current_state_->interned_source_locations_.insert(
+        std::make_pair(src_loc.iid(), std::make_pair(src_loc.file_name(),
+                                                     src_loc.function_name())));
     DCHECK(iter.second ||
            (iter.first->second.first == src_loc.file_name() &&
             iter.first->second.second == src_loc.function_name()));
@@ -226,10 +235,10 @@
   DCHECK(packet.has_process_descriptor());
   const auto& process = packet.process_descriptor();
   // Save the current state we need for future packets.
-  current_state_.pid = process.pid();
+  current_state_->pid = process.pid();
 
   // ProcessDescriptor is only emitted on sequences with incremental state.
-  if (current_state_.incomplete) {
+  if (current_state_->incomplete) {
     return;
   }
 
@@ -240,10 +249,10 @@
   }
 
   // Prevent duplicates by only emitting the metadata once.
-  if (current_state_.emitted_process_metadata) {
+  if (current_state_->emitted_process_metadata) {
     return;
   }
-  current_state_.emitted_process_metadata = true;
+  current_state_->emitted_process_metadata = true;
 
   if (!process.cmdline().empty()) {
     NOTIMPLEMENTED();
@@ -252,7 +261,7 @@
   if (process.has_legacy_sort_index()) {
     auto event_builder =
         AddTraceEvent("process_sort_index", "__metadata", 'M', 0,
-                      current_state_.pid, current_state_.pid);
+                      current_state_->pid, current_state_->pid);
     auto args_builder = event_builder.BuildArgs();
     auto* add_arg = args_builder->MaybeAddArg("sort_index");
     if (add_arg) {
@@ -261,8 +270,9 @@
   }
 
   const auto emit_process_name = [this](const char* name) {
-    auto event_builder = AddTraceEvent("process_name", "__metadata", 'M', 0,
-                                       current_state_.pid, current_state_.pid);
+    auto event_builder =
+        AddTraceEvent("process_name", "__metadata", 'M', 0, current_state_->pid,
+                      current_state_->pid);
     auto args_builder = event_builder.BuildArgs();
     auto* add_arg = args_builder->MaybeAddArg("name");
     if (add_arg) {
@@ -305,33 +315,36 @@
   DCHECK(packet.has_thread_descriptor());
 
   // ThreadDescriptor is only emitted on sequences with incremental state.
-  if (current_state_.incomplete) {
+  if (current_state_->incomplete) {
     return;
   }
 
   const auto& thread = packet.thread_descriptor();
   // Save the current state we need for future packets.
-  current_state_.pid = thread.pid();
-  current_state_.tid = thread.tid();
-  current_state_.time_us = thread.reference_timestamp_us();
-  current_state_.thread_time_us = thread.reference_thread_time_us();
+  current_state_->pid = thread.pid();
+  current_state_->tid = thread.tid();
+  current_state_->time_us = thread.reference_timestamp_us();
+  current_state_->thread_time_us = thread.reference_thread_time_us();
 
   // If we aren't outputting traceEvents then we don't need to look at the
   // metadata that might need to be emitted.
   if (!ShouldOutputTraceEvents()) {
     return;
   }
+  current_state_->last_seen_thread_descriptor =
+      std::make_unique<ThreadDescriptor>();
+  *current_state_->last_seen_thread_descriptor = thread;
+}
 
-  // Prevent duplicates by only emitting the metadata once.
-  if (current_state_.emitted_thread_metadata) {
+void TrackEventJSONExporter::EmitThreadDescriptorIfNeeded() {
+  if (!current_state_->last_seen_thread_descriptor) {
     return;
   }
-  current_state_.emitted_thread_metadata = true;
-
+  const auto& thread = *current_state_->last_seen_thread_descriptor;
   if (thread.has_legacy_sort_index()) {
     auto event_builder =
         AddTraceEvent("thread_sort_index", "__metadata", 'M', 0,
-                      current_state_.pid, current_state_.tid);
+                      current_state_->pid, current_state_->tid);
     auto args_builder = event_builder.BuildArgs();
     auto* add_arg = args_builder->MaybeAddArg("sort_index");
     if (add_arg) {
@@ -340,8 +353,9 @@
   }
 
   const auto emit_thread_name = [this](const char* name) {
-    auto event_builder = AddTraceEvent("thread_name", "__metadata", 'M', 0,
-                                       current_state_.pid, current_state_.tid);
+    auto event_builder =
+        AddTraceEvent("thread_name", "__metadata", 'M', 0, current_state_->pid,
+                      current_state_->tid);
     auto args_builder = event_builder.BuildArgs();
     auto* add_arg = args_builder->MaybeAddArg("name");
     if (add_arg) {
@@ -356,6 +370,7 @@
       emit_thread_name(name);
     }
   }
+  current_state_->last_seen_thread_descriptor.reset();
 }
 
 void TrackEventJSONExporter::HandleChromeEvents(
@@ -382,7 +397,7 @@
   DCHECK(packet.has_track_event());
 
   // TrackEvents need incremental state.
-  if (current_state_.incomplete) {
+  if (current_state_->incomplete) {
     return;
   }
 
@@ -403,7 +418,7 @@
   all_categories.reserve(track.category_iids().size());
   for (const auto& cat_iid : track.category_iids()) {
     const std::string& name =
-        GetInternedName(cat_iid, current_state_.interned_event_categories_);
+        GetInternedName(cat_iid, current_state_->interned_event_categories_);
     all_categories.push_back(name);
   }
   const std::string joined_categories = base::JoinString(all_categories, ",");
@@ -440,7 +455,7 @@
     ArgumentBuilder* args_builder) {
   const std::string& name =
       GetInternedName(debug_annotation.name_iid(),
-                      current_state_.interned_debug_annotation_names_);
+                      current_state_->interned_debug_annotation_names_);
 
   auto* maybe_arg = args_builder->MaybeAddArg(name);
   if (!maybe_arg) {
@@ -453,8 +468,8 @@
     const perfetto::protos::TaskExecution& task,
     ArgumentBuilder* args_builder) {
   auto iter =
-      current_state_.interned_source_locations_.find(task.posted_from_iid());
-  DCHECK(iter != current_state_.interned_source_locations_.end());
+      current_state_->interned_source_locations_.find(task.posted_from_iid());
+  DCHECK(iter != current_state_->interned_source_locations_.end());
 
   // If source locations were turned off, only the file is provided. JSON
   // expects the event to then have only an "src" attribute.
@@ -486,12 +501,12 @@
 
   // Determine which pid and tid to use.
   int32_t pid =
-      event.pid_override() == 0 ? current_state_.pid : event.pid_override();
+      event.pid_override() == 0 ? current_state_->pid : event.pid_override();
   int32_t tid =
-      event.tid_override() == 0 ? current_state_.tid : event.tid_override();
+      event.tid_override() == 0 ? current_state_->tid : event.tid_override();
 
   const std::string& name = GetInternedName(
-      event.name_iid(), current_state_.interned_legacy_event_names_);
+      event.name_iid(), current_state_->interned_legacy_event_names_);
 
   // Build the actual json output, if we are missing the interned name we just
   // use the interned ID.
diff --git a/services/tracing/perfetto/track_event_json_exporter.h b/services/tracing/perfetto/track_event_json_exporter.h
index a98c976..09afd5c 100644
--- a/services/tracing/perfetto/track_event_json_exporter.h
+++ b/services/tracing/perfetto/track_event_json_exporter.h
@@ -5,10 +5,13 @@
 #ifndef SERVICES_TRACING_PERFETTO_TRACK_EVENT_JSON_EXPORTER_H_
 #define SERVICES_TRACING_PERFETTO_TRACK_EVENT_JSON_EXPORTER_H_
 
+#include <memory>
 #include <string>
 #include <unordered_map>
 
+#include "base/macros.h"
 #include "services/tracing/perfetto/json_trace_exporter.h"
+#include "third_party/perfetto/protos/perfetto/trace/chrome/chrome_trace_packet.pb.h"
 
 namespace perfetto {
 namespace protos {
@@ -31,15 +34,16 @@
   ~TrackEventJSONExporter() override;
 
  protected:
-  void ProcessPackets(
-      const std::vector<perfetto::TracePacket>& packets) override;
+  void ProcessPackets(const std::vector<perfetto::TracePacket>& packets,
+                      bool has_more) override;
 
  private:
   struct ProducerWriterState {
     ProducerWriterState(uint32_t sequence_id);
     ProducerWriterState(uint32_t sequence_id,
                         bool emitted_process,
-                        bool emitted_thread,
+                        std::unique_ptr<perfetto::protos::ThreadDescriptor>
+                            last_seen_thread_descriptor,
                         bool incomplete);
     ~ProducerWriterState();
 
@@ -56,7 +60,8 @@
     // containing this data are periodically emitted and so would occur
     // frequently if not suppressed.
     bool emitted_process_metadata = false;
-    bool emitted_thread_metadata = false;
+    std::unique_ptr<perfetto::protos::ThreadDescriptor>
+        last_seen_thread_descriptor;
 
     // Until we see a TracePacket that will initialize our state we will skip
     // all data besides stateful information. Once we've been reset on the same
@@ -69,6 +74,8 @@
         interned_source_locations_;
     std::unordered_map<uint32_t, std::string> interned_legacy_event_names_;
     std::unordered_map<uint32_t, std::string> interned_debug_annotation_names_;
+
+    DISALLOW_COPY_AND_ASSIGN(ProducerWriterState);
   };
 
   // Packet sequences are given in order so when we encounter a new one we need
@@ -93,6 +100,7 @@
       const perfetto::protos::ChromeTracePacket& packet);
   void HandleThreadDescriptor(
       const perfetto::protos::ChromeTracePacket& packet);
+  void EmitThreadDescriptorIfNeeded();
   void HandleChromeEvents(const perfetto::protos::ChromeTracePacket& packet);
   void HandleTrackEvent(const perfetto::protos::ChromeTracePacket& packet);
 
@@ -111,7 +119,10 @@
       int64_t timestamp_us);
 
   // Tracks all the interned state in the current sequence.
-  ProducerWriterState current_state_;
+  std::unique_ptr<ProducerWriterState> current_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(TrackEventJSONExporter);
 };
+
 }  // namespace tracing
 #endif  // SERVICES_TRACING_PERFETTO_TRACK_EVENT_JSON_EXPORTER_H_
diff --git a/services/tracing/perfetto/track_event_json_exporter_unittest.cc b/services/tracing/perfetto/track_event_json_exporter_unittest.cc
index 4be9cc2..8865624 100644
--- a/services/tracing/perfetto/track_event_json_exporter_unittest.cc
+++ b/services/tracing/perfetto/track_event_json_exporter_unittest.cc
@@ -564,9 +564,14 @@
 TEST_F(TrackEventJsonExporterTest, MultipleThreadDescriptors) {
   std::vector<perfetto::protos::TracePacket> trace_packet_protos;
   trace_analyzer::TraceEventVector events;
+  // Thread can have no name in the first packet.
+  AddThreadDescriptorPacket(/* sort_index = */ base::nullopt,
+                            ThreadDescriptor::CHROME_THREAD_UNSPECIFIED,
+                            base::nullopt, kReferenceTimeUs,
+                            kReferenceThreadTimeUs, &trace_packet_protos);
   AddThreadDescriptorPacket(
       /* sort_index = */ 2, ThreadDescriptor::CHROME_THREAD_UNSPECIFIED,
-      kThreadName, kReferenceTimeUs, kReferenceThreadTimeUs,
+      "different_thread_name", kReferenceTimeUs, kReferenceThreadTimeUs,
       &trace_packet_protos);
   // This packet will be ignored because we've already emitted the sort_index of
   // 2 and thread_name kThreadName so we suppress this metadata because it
@@ -574,14 +579,9 @@
   ASSERT_NE("different_thread_name", kThreadName);
   AddThreadDescriptorPacket(
       /* sort_index = */ 3, ThreadDescriptor::CHROME_THREAD_UNSPECIFIED,
-      "different_thread_name", kReferenceTimeUs, kReferenceThreadTimeUs,
+      kThreadName, kReferenceTimeUs, kReferenceThreadTimeUs,
       &trace_packet_protos);
   trace_packet_protos.back().set_incremental_state_cleared(true);
-  // Empty packet doesn't change anything.
-  AddThreadDescriptorPacket(/* sort_index = */ base::nullopt,
-                            ThreadDescriptor::CHROME_THREAD_UNSPECIFIED,
-                            base::nullopt, kReferenceTimeUs,
-                            kReferenceThreadTimeUs, &trace_packet_protos);
   FinalizePackets(trace_packet_protos);
   ASSERT_EQ(2u, trace_analyzer()->FindEvents(
                     Query(Query::EVENT_CATEGORY) == Query::String("__metadata"),
@@ -591,7 +591,7 @@
     if (event->name == "thread_name") {
       EXPECT_EQ(kThreadName, event->GetKnownArgAsString("name"));
     } else if (event->name == "thread_sort_index") {
-      EXPECT_EQ(2, event->GetKnownArgAsInt("sort_index"));
+      EXPECT_EQ(3, event->GetKnownArgAsInt("sort_index"));
     } else {
       ADD_FAILURE() << "Unexpected event name: " << event->name;
     }
@@ -609,7 +609,7 @@
   for (size_t i = 0; i < 2; ++i) {
     const auto* event = events[i];
     if (event->name == "thread_name") {
-      EXPECT_EQ(kThreadName, event->GetKnownArgAsString("name"));
+      EXPECT_EQ("different_thread_name", event->GetKnownArgAsString("name"));
     } else if (event->name == "thread_sort_index") {
       EXPECT_EQ(2, event->GetKnownArgAsInt("sort_index"));
     } else {
@@ -619,7 +619,7 @@
   for (size_t i = 2; i < events.size(); ++i) {
     const auto* event = events[i];
     if (event->name == "thread_name") {
-      EXPECT_EQ("different_thread_name", event->GetKnownArgAsString("name"));
+      EXPECT_EQ(kThreadName, event->GetKnownArgAsString("name"));
     } else if (event->name == "thread_sort_index") {
       EXPECT_EQ(3, event->GetKnownArgAsInt("sort_index"));
     } else {
diff --git a/services/ws/input_devices/BUILD.gn b/services/ws/input_devices/BUILD.gn
deleted file mode 100644
index 9eda1de..0000000
--- a/services/ws/input_devices/BUILD.gn
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//testing/test.gni")
-
-source_set("input_devices") {
-  sources = [
-    "input_device_server.cc",
-    "input_device_server.h",
-  ]
-
-  deps = [
-    "//base",
-    "//services/service_manager/public/cpp",
-    "//ui/events/devices",
-  ]
-
-  public_deps = [
-    "//services/ws/public/mojom/input_devices",
-  ]
-}
-
-source_set("tests") {
-  testonly = true
-
-  sources = [
-    "input_device_unittests.cc",
-  ]
-
-  deps = [
-    ":input_devices",
-    "//base",
-    "//base/test:test_support",
-    "//services/service_manager/public/cpp",
-    "//services/ws/public/cpp/input_devices",
-    "//services/ws/public/mojom/input_devices",
-    "//testing/gtest",
-    "//ui/events/devices",
-  ]
-}
diff --git a/services/ws/input_devices/OWNERS b/services/ws/input_devices/OWNERS
deleted file mode 100644
index 65aaa31..0000000
--- a/services/ws/input_devices/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-kylechar@chromium.org
diff --git a/services/ws/input_devices/input_device_server.cc b/services/ws/input_devices/input_device_server.cc
deleted file mode 100644
index 072be9d..0000000
--- a/services/ws/input_devices/input_device_server.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/ws/input_devices/input_device_server.h"
-
-#include <utility>
-#include <vector>
-
-#include "ui/events/devices/device_data_manager.h"
-#include "ui/events/devices/input_device.h"
-#include "ui/events/devices/touchscreen_device.h"
-
-namespace ws {
-
-InputDeviceServer::InputDeviceServer() = default;
-
-InputDeviceServer::~InputDeviceServer() {
-  if (manager_ && ui::DeviceDataManager::HasInstance()) {
-    manager_->RemoveObserver(this);
-    manager_ = nullptr;
-  }
-}
-
-void InputDeviceServer::RegisterAsObserver() {
-  if (!manager_ && ui::DeviceDataManager::HasInstance()) {
-    manager_ = ui::DeviceDataManager::GetInstance();
-    manager_->AddObserver(this);
-  }
-}
-
-bool InputDeviceServer::IsRegisteredAsObserver() const {
-  return manager_ != nullptr;
-}
-
-void InputDeviceServer::AddBinding(mojom::InputDeviceServerRequest request) {
-  DCHECK(IsRegisteredAsObserver());
-  bindings_.AddBinding(this, std::move(request));
-}
-
-void InputDeviceServer::AddObserver(
-    mojom::InputDeviceObserverMojoPtr observer) {
-  // We only want to send this message once, so we need to check to make sure
-  // device lists are actually complete before sending it to a new observer.
-  if (manager_->AreDeviceListsComplete())
-    SendDeviceListsComplete(observer.get());
-  observers_.AddPtr(std::move(observer));
-}
-
-void InputDeviceServer::OnInputDeviceConfigurationChanged(
-    uint8_t input_device_types) {
-  if (input_device_types & ui::InputDeviceEventObserver::kKeyboard)
-    OnKeyboardDeviceConfigurationChanged();
-  if (input_device_types & ui::InputDeviceEventObserver::kMouse)
-    OnMouseDeviceConfigurationChanged();
-  if (input_device_types & ui::InputDeviceEventObserver::kTouchpad)
-    OnTouchpadDeviceConfigurationChanged();
-  if (input_device_types & ui::InputDeviceEventObserver::kTouchscreen)
-    OnTouchscreenDeviceConfigurationChanged();
-  if (input_device_types & ui::InputDeviceEventObserver::kUncategorized)
-    OnUncategorizedDeviceConfigurationChanged();
-}
-
-void InputDeviceServer::OnKeyboardDeviceConfigurationChanged() {
-  if (!manager_->AreDeviceListsComplete())
-    return;
-
-  auto& devices = manager_->GetKeyboardDevices();
-  observers_.ForAllPtrs([&devices](mojom::InputDeviceObserverMojo* observer) {
-    observer->OnKeyboardDeviceConfigurationChanged(devices);
-  });
-}
-
-void InputDeviceServer::OnMouseDeviceConfigurationChanged() {
-  if (!manager_->AreDeviceListsComplete())
-    return;
-
-  auto& devices = manager_->GetMouseDevices();
-  observers_.ForAllPtrs([&devices](mojom::InputDeviceObserverMojo* observer) {
-    observer->OnMouseDeviceConfigurationChanged(devices);
-  });
-}
-
-void InputDeviceServer::OnTouchpadDeviceConfigurationChanged() {
-  if (!manager_->AreDeviceListsComplete())
-    return;
-
-  auto& devices = manager_->GetTouchpadDevices();
-  observers_.ForAllPtrs([&devices](mojom::InputDeviceObserverMojo* observer) {
-    observer->OnTouchpadDeviceConfigurationChanged(devices);
-  });
-}
-
-void InputDeviceServer::OnDeviceListsComplete() {
-  observers_.ForAllPtrs([this](mojom::InputDeviceObserverMojo* observer) {
-    SendDeviceListsComplete(observer);
-  });
-}
-
-void InputDeviceServer::OnStylusStateChanged(ui::StylusState state) {
-  observers_.ForAllPtrs([state](mojom::InputDeviceObserverMojo* observer) {
-    observer->OnStylusStateChanged(state);
-  });
-}
-
-void InputDeviceServer::OnTouchDeviceAssociationChanged() {
-  OnTouchscreenDeviceConfigurationChanged();
-}
-
-void InputDeviceServer::SendDeviceListsComplete(
-    mojom::InputDeviceObserverMojo* observer) {
-  DCHECK(manager_->AreDeviceListsComplete());
-
-  observer->OnDeviceListsComplete(
-      manager_->GetKeyboardDevices(), manager_->GetTouchscreenDevices(),
-      manager_->GetMouseDevices(), manager_->GetTouchpadDevices(),
-      manager_->GetUncategorizedDevices(),
-      manager_->AreTouchscreenTargetDisplaysValid());
-}
-
-void InputDeviceServer::OnTouchscreenDeviceConfigurationChanged() {
-  if (!manager_->AreDeviceListsComplete())
-    return;
-
-  auto& devices = manager_->GetTouchscreenDevices();
-  const bool are_touchscreen_target_displays_valid =
-      manager_->AreTouchscreenTargetDisplaysValid();
-  observers_.ForAllPtrs([&devices, are_touchscreen_target_displays_valid](
-                            mojom::InputDeviceObserverMojo* observer) {
-    observer->OnTouchscreenDeviceConfigurationChanged(
-        devices, are_touchscreen_target_displays_valid);
-  });
-}
-
-void InputDeviceServer::OnUncategorizedDeviceConfigurationChanged() {
-  if (!manager_->AreDeviceListsComplete())
-    return;
-
-  auto& devices = manager_->GetUncategorizedDevices();
-  observers_.ForAllPtrs([&devices](mojom::InputDeviceObserverMojo* observer) {
-    observer->OnUncategorizedDeviceConfigurationChanged(devices);
-  });
-}
-
-}  // namespace ws
diff --git a/services/ws/input_devices/input_device_server.h b/services/ws/input_devices/input_device_server.h
deleted file mode 100644
index 5830d727..0000000
--- a/services/ws/input_devices/input_device_server.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_WS_INPUT_DEVICES_INPUT_DEVICE_SERVER_H_
-#define SERVICES_WS_INPUT_DEVICES_INPUT_DEVICE_SERVER_H_
-
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/ws/public/mojom/input_devices/input_device_server.mojom.h"
-#include "ui/events/devices/input_device_event_observer.h"
-
-namespace ui {
-class DeviceDataManager;
-}
-
-namespace ws {
-
-// Listens to DeviceDataManager for updates on input-devices and forwards those
-// updates to any registered InputDeviceObserverMojo in other processes via
-// Mojo IPC. This runs in the mus-ws process.
-class InputDeviceServer : public mojom::InputDeviceServer,
-                          public ui::InputDeviceEventObserver {
- public:
-  InputDeviceServer();
-  ~InputDeviceServer() override;
-
-  // Registers this instance as a local observer with DeviceDataManager.
-  void RegisterAsObserver();
-  bool IsRegisteredAsObserver() const;
-
-  // Binds an interface request to this instance. RegisterAsObserver() must be
-  // successfully called before this, to get local input-device event updates.
-  void AddBinding(mojom::InputDeviceServerRequest request);
-
-  // mojom::InputDeviceServer:
-  void AddObserver(mojom::InputDeviceObserverMojoPtr observer) override;
-
-  // ui::InputDeviceEventObserver:
-  void OnInputDeviceConfigurationChanged(uint8_t input_device_types) override;
-  void OnDeviceListsComplete() override;
-  void OnStylusStateChanged(ui::StylusState state) override;
-  void OnTouchDeviceAssociationChanged() override;
-
- private:
-  // Sends the current state of all input-devices to an observer.
-  void SendDeviceListsComplete(mojom::InputDeviceObserverMojo* observer);
-
-  void OnKeyboardDeviceConfigurationChanged();
-  void OnTouchscreenDeviceConfigurationChanged();
-  void OnMouseDeviceConfigurationChanged();
-  void OnTouchpadDeviceConfigurationChanged();
-  void OnUncategorizedDeviceConfigurationChanged();
-
-  mojo::BindingSet<mojom::InputDeviceServer> bindings_;
-  mojo::InterfacePtrSet<mojom::InputDeviceObserverMojo> observers_;
-
-  // DeviceDataManager instance we are registered as an observer with.
-  ui::DeviceDataManager* manager_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(InputDeviceServer);
-};
-
-}  // namespace ws
-
-#endif  // SERVICES_WS_INPUT_DEVICES_INPUT_DEVICE_SERVER_H_
diff --git a/services/ws/input_devices/input_device_unittests.cc b/services/ws/input_devices/input_device_unittests.cc
deleted file mode 100644
index 6de4839..0000000
--- a/services/ws/input_devices/input_device_unittests.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/test/scoped_task_environment.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "services/ws/input_devices/input_device_server.h"
-#include "services/ws/public/cpp/input_devices/input_device_client.h"
-#include "services/ws/public/mojom/input_devices/input_device_server.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/devices/device_data_manager.h"
-#include "ui/events/devices/device_hotplug_event_observer.h"
-
-namespace ws {
-
-namespace {
-
-// Helper to place items into a std::vector<T> to provide as input.
-template <class T>
-std::vector<T> AsVector(std::initializer_list<T> input) {
-  return std::vector<T>(input);
-}
-
-// Test client that doesn't register itself as the InputDeviceManager.
-class TestInputDeviceClient : public InputDeviceClient {
- public:
-  TestInputDeviceClient() : InputDeviceClient(false) {}
-  ~TestInputDeviceClient() override {}
-
-  using InputDeviceClient::GetIntefacePtr;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestInputDeviceClient);
-};
-
-class InputDeviceTest : public testing::Test {
- public:
-  InputDeviceTest() {}
-  ~InputDeviceTest() override {}
-
-  void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
-
-  void AddClientAsObserver(TestInputDeviceClient* client) {
-    server_.AddObserver(client->GetIntefacePtr());
-  }
-
-  ui::DeviceHotplugEventObserver* GetHotplugObserver() {
-    return ui::DeviceDataManager::GetInstance();
-  }
-
-  // testing::Test:
-  void SetUp() override {
-    ui::DeviceDataManager::CreateInstance();
-    server_.RegisterAsObserver();
-  }
-
-  void TearDown() override { ui::DeviceDataManager::DeleteInstance(); }
-
- private:
-  base::test::ScopedTaskEnvironment scoped_task_environment_{
-      base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
-  InputDeviceServer server_;
-
-  DISALLOW_COPY_AND_ASSIGN(InputDeviceTest);
-};
-
-}  // namespace
-
-TEST_F(InputDeviceTest, DeviceListsComplete) {
-  TestInputDeviceClient client;
-  AddClientAsObserver(&client);
-
-  RunUntilIdle();
-  EXPECT_FALSE(client.AreDeviceListsComplete());
-
-  GetHotplugObserver()->OnDeviceListsComplete();
-
-  // Observer should get notification for device lists complete now.
-  RunUntilIdle();
-  EXPECT_TRUE(client.AreDeviceListsComplete());
-}
-
-TEST_F(InputDeviceTest, DeviceListsCompleteTwoClients) {
-  TestInputDeviceClient client1;
-  AddClientAsObserver(&client1);
-
-  TestInputDeviceClient client2;
-  AddClientAsObserver(&client2);
-
-  RunUntilIdle();
-  EXPECT_FALSE(client1.AreDeviceListsComplete());
-  EXPECT_FALSE(client2.AreDeviceListsComplete());
-
-  GetHotplugObserver()->OnDeviceListsComplete();
-
-  // Both observers should get notifications for device lists complete now.
-  RunUntilIdle();
-  EXPECT_TRUE(client1.AreDeviceListsComplete());
-  EXPECT_TRUE(client2.AreDeviceListsComplete());
-}
-
-TEST_F(InputDeviceTest, AddDevices) {
-  const ui::TouchscreenDevice touchscreen(
-      100, ui::INPUT_DEVICE_INTERNAL, "Touchscreen", gfx::Size(2600, 1700), 3);
-
-  TestInputDeviceClient client;
-  AddClientAsObserver(&client);
-
-  // Add keyboard and mark device lists complete.
-  GetHotplugObserver()->OnTouchscreenDevicesUpdated(AsVector({touchscreen}));
-  GetHotplugObserver()->OnDeviceListsComplete();
-
-  RunUntilIdle();
-  EXPECT_TRUE(client.AreDeviceListsComplete());
-  EXPECT_EQ(1u, client.GetTouchscreenDevices().size());
-  EXPECT_EQ(0u, client.GetKeyboardDevices().size());
-  EXPECT_EQ(0u, client.GetMouseDevices().size());
-  EXPECT_EQ(0u, client.GetTouchpadDevices().size());
-}
-
-TEST_F(InputDeviceTest, AddDeviceAfterComplete) {
-  const ui::InputDevice keyboard1(100, ui::INPUT_DEVICE_INTERNAL, "Keyboard1");
-  const ui::InputDevice keyboard2(200, ui::INPUT_DEVICE_USB, "Keyboard2");
-  const ui::InputDevice mouse(300, ui::INPUT_DEVICE_USB, "Mouse");
-
-  TestInputDeviceClient client;
-  AddClientAsObserver(&client);
-
-  // Add mouse and mark device lists complete.
-  GetHotplugObserver()->OnKeyboardDevicesUpdated(AsVector({keyboard1}));
-  GetHotplugObserver()->OnDeviceListsComplete();
-
-  RunUntilIdle();
-  EXPECT_TRUE(client.AreDeviceListsComplete());
-  EXPECT_EQ(1lu, client.GetKeyboardDevices().size());
-
-  // Add a second keyboard and a mouse.
-  GetHotplugObserver()->OnMouseDevicesUpdated(AsVector({mouse}));
-  GetHotplugObserver()->OnKeyboardDevicesUpdated(
-      AsVector({keyboard1, keyboard2}));
-
-  RunUntilIdle();
-  EXPECT_EQ(0u, client.GetTouchscreenDevices().size());
-  EXPECT_EQ(2u, client.GetKeyboardDevices().size());
-  EXPECT_EQ(1u, client.GetMouseDevices().size());
-  EXPECT_EQ(0u, client.GetTouchpadDevices().size());
-}
-
-TEST_F(InputDeviceTest, AddThenRemoveDevice) {
-  const ui::InputDevice mouse(100, ui::INPUT_DEVICE_INTERNAL, "Mouse");
-
-  TestInputDeviceClient client;
-  AddClientAsObserver(&client);
-
-  // Add mouse and mark device lists complete.
-  GetHotplugObserver()->OnMouseDevicesUpdated(AsVector({mouse}));
-  GetHotplugObserver()->OnDeviceListsComplete();
-
-  RunUntilIdle();
-  EXPECT_TRUE(client.AreDeviceListsComplete());
-  EXPECT_EQ(1u, client.GetMouseDevices().size());
-
-  // Remove mouse device.
-  GetHotplugObserver()->OnMouseDevicesUpdated(AsVector<ui::InputDevice>({}));
-
-  RunUntilIdle();
-  EXPECT_EQ(0u, client.GetMouseDevices().size());
-}
-
-TEST_F(InputDeviceTest, CheckClientDeviceFields) {
-  const ui::InputDevice touchpad(100, ui::INPUT_DEVICE_INTERNAL, "Touchpad");
-
-  TestInputDeviceClient client;
-  AddClientAsObserver(&client);
-
-  // Add touchpad and mark device lists complete.
-  GetHotplugObserver()->OnTouchpadDevicesUpdated(AsVector({touchpad}));
-  GetHotplugObserver()->OnDeviceListsComplete();
-
-  RunUntilIdle();
-  EXPECT_TRUE(client.AreDeviceListsComplete());
-  EXPECT_EQ(1u, client.GetTouchpadDevices().size());
-
-  // Check the touchpad fields match.
-  const ui::InputDevice& output = client.GetTouchpadDevices()[0];
-  EXPECT_EQ(touchpad.id, output.id);
-  EXPECT_EQ(touchpad.type, output.type);
-  EXPECT_EQ(touchpad.name, output.name);
-}
-
-}  // namespace ws
diff --git a/services/ws/public/cpp/input_devices/BUILD.gn b/services/ws/public/cpp/input_devices/BUILD.gn
deleted file mode 100644
index 6cc6e00..0000000
--- a/services/ws/public/cpp/input_devices/BUILD.gn
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("input_devices") {
-  sources = [
-    "input_device_client.cc",
-    "input_device_client.h",
-  ]
-
-  deps = [
-    "//base",
-    "//services/service_manager/public/cpp",
-    "//ui/events/devices",
-  ]
-
-  public_deps = [
-    "//services/ws/public/mojom/input_devices",
-  ]
-
-  if (is_chromeos) {
-    sources += [
-      "input_device_controller_client.cc",
-      "input_device_controller_client.h",
-    ]
-    public_deps += [
-      "//services/ws/public/mojom:constants",
-      "//ui/ozone",
-    ]
-  }
-}
-
-if (is_chromeos) {
-  source_set("input_device_controller") {
-    sources = [
-      "input_device_controller.cc",
-      "input_device_controller.h",
-    ]
-
-    deps = [
-      "//base",
-      "//services/service_manager/public/cpp",
-      "//ui/events:dom_keycode_converter",
-      "//ui/ozone",
-    ]
-
-    public_deps = [
-      "//services/ws/public/mojom/input_devices",
-    ]
-
-    # This target is really an implementation detail of the ui service, which
-    # is hosted in ash. Until Ash is switched out of process chrome needs to
-    # depend upon it too.
-    visibility = [
-      "//ash:ash",
-      "//chrome/browser",
-      "//services/ws:lib",
-    ]
-  }
-}
diff --git a/services/ws/public/cpp/input_devices/OWNERS b/services/ws/public/cpp/input_devices/OWNERS
deleted file mode 100644
index 65aaa31..0000000
--- a/services/ws/public/cpp/input_devices/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-kylechar@chromium.org
diff --git a/services/ws/public/cpp/input_devices/input_device_client.cc b/services/ws/public/cpp/input_devices/input_device_client.cc
deleted file mode 100644
index a58e7ae4..0000000
--- a/services/ws/public/cpp/input_devices/input_device_client.cc
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/ws/public/cpp/input_devices/input_device_client.h"
-
-#include "base/logging.h"
-
-namespace ws {
-
-InputDeviceClient::InputDeviceClient() : InputDeviceClient(true) {}
-
-InputDeviceClient::~InputDeviceClient() {
-  if (is_input_device_manager_)
-    InputDeviceManager::ClearInstance();
-}
-
-void InputDeviceClient::Connect(mojom::InputDeviceServerPtr server) {
-  DCHECK(server.is_bound());
-  server->AddObserver(GetIntefacePtr());
-}
-
-const std::vector<ui::InputDevice>& InputDeviceClient::GetKeyboardDevices()
-    const {
-  return keyboard_devices_;
-}
-
-const std::vector<ui::TouchscreenDevice>&
-InputDeviceClient::GetTouchscreenDevices() const {
-  return touchscreen_devices_;
-}
-
-const std::vector<ui::InputDevice>& InputDeviceClient::GetMouseDevices() const {
-  return mouse_devices_;
-}
-
-const std::vector<ui::InputDevice>& InputDeviceClient::GetTouchpadDevices()
-    const {
-  return touchpad_devices_;
-}
-
-const std::vector<ui::InputDevice>& InputDeviceClient::GetUncategorizedDevices()
-    const {
-  return uncategorized_devices_;
-}
-
-bool InputDeviceClient::AreDeviceListsComplete() const {
-  return device_lists_complete_;
-}
-
-bool InputDeviceClient::AreTouchscreensEnabled() const {
-  // TODO(kylechar): This obviously isn't right. We either need to pass this
-  // state around or modify the interface.
-  return true;
-}
-
-bool InputDeviceClient::AreTouchscreenTargetDisplaysValid() const {
-  return are_touchscreen_target_displays_valid_;
-}
-
-void InputDeviceClient::AddObserver(ui::InputDeviceEventObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void InputDeviceClient::RemoveObserver(ui::InputDeviceEventObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-InputDeviceClient::InputDeviceClient(bool is_input_device_manager)
-    : binding_(this), is_input_device_manager_(is_input_device_manager) {
-  if (is_input_device_manager_)
-    InputDeviceManager::SetInstance(this);
-}
-
-mojom::InputDeviceObserverMojoPtr InputDeviceClient::GetIntefacePtr() {
-  mojom::InputDeviceObserverMojoPtr ptr;
-  binding_.Bind(mojo::MakeRequest(&ptr));
-  return ptr;
-}
-
-void InputDeviceClient::OnKeyboardDeviceConfigurationChanged(
-    const std::vector<ui::InputDevice>& devices) {
-  keyboard_devices_ = devices;
-  NotifyObserversKeyboardDeviceConfigurationChanged();
-}
-
-void InputDeviceClient::OnUncategorizedDeviceConfigurationChanged(
-    const std::vector<ui::InputDevice>& devices) {
-  uncategorized_devices_ = devices;
-  NotifyObserversUncategorizedDeviceConfigurationChanged();
-}
-
-void InputDeviceClient::OnTouchscreenDeviceConfigurationChanged(
-    const std::vector<ui::TouchscreenDevice>& devices,
-    bool touchscreen_target_display_ids_changed) {
-  if (touchscreen_target_display_ids_changed)
-    DCHECK_EQ(touchscreen_devices_.size(), devices.size());
-
-  touchscreen_devices_ = devices;
-  if (touchscreen_target_display_ids_changed) {
-    are_touchscreen_target_displays_valid_ = true;
-    for (auto& observer : observers_)
-      observer.OnTouchDeviceAssociationChanged();
-  } else {
-    are_touchscreen_target_displays_valid_ = false;
-    NotifyObserversTouchscreenDeviceConfigurationChanged();
-  }
-}
-
-void InputDeviceClient::OnMouseDeviceConfigurationChanged(
-    const std::vector<ui::InputDevice>& devices) {
-  mouse_devices_ = devices;
-  for (auto& observer : observers_) {
-    observer.OnInputDeviceConfigurationChanged(
-        ui::InputDeviceEventObserver::kMouse);
-  }
-}
-
-void InputDeviceClient::OnTouchpadDeviceConfigurationChanged(
-    const std::vector<ui::InputDevice>& devices) {
-  touchpad_devices_ = devices;
-  NotifyObserversTouchpadDeviceConfigurationChanged();
-}
-
-void InputDeviceClient::OnDeviceListsComplete(
-    const std::vector<ui::InputDevice>& keyboard_devices,
-    const std::vector<ui::TouchscreenDevice>& touchscreen_devices,
-    const std::vector<ui::InputDevice>& mouse_devices,
-    const std::vector<ui::InputDevice>& touchpad_devices,
-    const std::vector<ui::InputDevice>& uncategorized_devices,
-    bool are_touchscreen_target_displays_valid) {
-  are_touchscreen_target_displays_valid_ =
-      are_touchscreen_target_displays_valid;
-  // Update the cached device lists if the received list isn't empty.
-  if (!keyboard_devices.empty())
-    OnKeyboardDeviceConfigurationChanged(keyboard_devices);
-  if (!touchscreen_devices.empty()) {
-    touchscreen_devices_ = touchscreen_devices;
-    are_touchscreen_target_displays_valid_ =
-        are_touchscreen_target_displays_valid;
-    NotifyObserversTouchscreenDeviceConfigurationChanged();
-  }
-  if (!mouse_devices.empty())
-    OnMouseDeviceConfigurationChanged(mouse_devices);
-  if (!touchpad_devices.empty())
-    OnTouchpadDeviceConfigurationChanged(touchpad_devices);
-
-  if (!uncategorized_devices.empty())
-    OnUncategorizedDeviceConfigurationChanged(uncategorized_devices);
-
-  if (!device_lists_complete_) {
-    device_lists_complete_ = true;
-    NotifyObserversDeviceListsComplete();
-  }
-}
-
-void InputDeviceClient::OnStylusStateChanged(ui::StylusState state) {
-  for (auto& observer : observers_)
-    observer.OnStylusStateChanged(state);
-}
-
-void InputDeviceClient::NotifyObserversDeviceListsComplete() {
-  for (auto& observer : observers_)
-    observer.OnDeviceListsComplete();
-}
-
-void InputDeviceClient::NotifyObserversKeyboardDeviceConfigurationChanged() {
-  for (auto& observer : observers_) {
-    observer.OnInputDeviceConfigurationChanged(
-        ui::InputDeviceEventObserver::kKeyboard);
-  }
-}
-
-void InputDeviceClient::NotifyObserversTouchscreenDeviceConfigurationChanged() {
-  for (auto& observer : observers_) {
-    observer.OnInputDeviceConfigurationChanged(
-        ui::InputDeviceEventObserver::kTouchscreen);
-  }
-}
-
-void InputDeviceClient::NotifyObserversTouchpadDeviceConfigurationChanged() {
-  for (auto& observer : observers_) {
-    observer.OnInputDeviceConfigurationChanged(
-        ui::InputDeviceEventObserver::kTouchpad);
-  }
-}
-
-void InputDeviceClient::
-    NotifyObserversUncategorizedDeviceConfigurationChanged() {
-  for (auto& observer : observers_) {
-    observer.OnInputDeviceConfigurationChanged(
-        ui::InputDeviceEventObserver::kUncategorized);
-  }
-}
-
-}  // namespace ws
diff --git a/services/ws/public/cpp/input_devices/input_device_client.h b/services/ws/public/cpp/input_devices/input_device_client.h
deleted file mode 100644
index a8864ab..0000000
--- a/services/ws/public/cpp/input_devices/input_device_client.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_WS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CLIENT_H_
-#define SERVICES_WS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CLIENT_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/ws/public/mojom/input_devices/input_device_server.mojom.h"
-#include "ui/events/devices/input_device.h"
-#include "ui/events/devices/input_device_event_observer.h"
-#include "ui/events/devices/input_device_manager.h"
-#include "ui/events/devices/touchscreen_device.h"
-
-namespace ws {
-
-// Allows in-process client code to register as a InputDeviceEventObserver and
-// get information about input-devices. InputDeviceClient itself acts as an
-// InputDeviceObserverMojo and registers to get updates from InputDeviceServer.
-// Essentially, InputDeviceClient forwards input-device events and caches
-// input-device state.
-class InputDeviceClient : public mojom::InputDeviceObserverMojo,
-                          public ui::InputDeviceManager {
- public:
-  InputDeviceClient();
-  ~InputDeviceClient() override;
-
-  // Connects to mojo:ui as an observer on InputDeviceServer to receive input
-  // device updates.
-  void Connect(mojom::InputDeviceServerPtr server);
-
-  // ui::InputDeviceManager:
-  const std::vector<ui::InputDevice>& GetKeyboardDevices() const override;
-  const std::vector<ui::TouchscreenDevice>& GetTouchscreenDevices()
-      const override;
-  const std::vector<ui::InputDevice>& GetMouseDevices() const override;
-  const std::vector<ui::InputDevice>& GetTouchpadDevices() const override;
-  const std::vector<ui::InputDevice>& GetUncategorizedDevices() const override;
-  bool AreDeviceListsComplete() const override;
-  bool AreTouchscreensEnabled() const override;
-  bool AreTouchscreenTargetDisplaysValid() const override;
-  void AddObserver(ui::InputDeviceEventObserver* observer) override;
-  void RemoveObserver(ui::InputDeviceEventObserver* observer) override;
-
- protected:
-  // Default constructor registers as InputDeviceManager. Can be subclassed in
-  // tests to avoid this.
-  explicit InputDeviceClient(bool is_input_device_manager);
-  mojom::InputDeviceObserverMojoPtr GetIntefacePtr();
-
-  // mojom::InputDeviceObserverMojo:
-  void OnKeyboardDeviceConfigurationChanged(
-      const std::vector<ui::InputDevice>& devices) override;
-  void OnTouchscreenDeviceConfigurationChanged(
-      const std::vector<ui::TouchscreenDevice>& devices,
-      bool touchscreen_target_display_ids_changed) override;
-  void OnMouseDeviceConfigurationChanged(
-      const std::vector<ui::InputDevice>& devices) override;
-  void OnTouchpadDeviceConfigurationChanged(
-      const std::vector<ui::InputDevice>& devices) override;
-  void OnUncategorizedDeviceConfigurationChanged(
-      const std::vector<ui::InputDevice>& devices) override;
-  void OnDeviceListsComplete(
-      const std::vector<ui::InputDevice>& keyboard_devices,
-      const std::vector<ui::TouchscreenDevice>& touchscreen_devices,
-      const std::vector<ui::InputDevice>& mouse_devices,
-      const std::vector<ui::InputDevice>& touchpad_devices,
-      const std::vector<ui::InputDevice>& uncategorized_devices,
-      bool are_touchscreen_target_displays_valid) override;
-  void OnStylusStateChanged(ui::StylusState state) override;
-
- private:
-  friend class InputDeviceClientTestApi;
-
-  void NotifyObserversDeviceListsComplete();
-  void NotifyObserversKeyboardDeviceConfigurationChanged();
-  void NotifyObserversTouchscreenDeviceConfigurationChanged();
-  void NotifyObserversTouchpadDeviceConfigurationChanged();
-  void NotifyObserversUncategorizedDeviceConfigurationChanged();
-
-  mojo::Binding<mojom::InputDeviceObserverMojo> binding_;
-
-  bool is_input_device_manager_;
-
-  // Holds the list of input devices and signal that we have received the lists
-  // after initialization.
-  std::vector<ui::InputDevice> keyboard_devices_;
-  std::vector<ui::TouchscreenDevice> touchscreen_devices_;
-  std::vector<ui::InputDevice> mouse_devices_;
-  std::vector<ui::InputDevice> touchpad_devices_;
-  std::vector<ui::InputDevice> uncategorized_devices_;
-  bool device_lists_complete_ = false;
-  bool are_touchscreen_target_displays_valid_ = false;
-
-  // List of in-process observers.
-  base::ObserverList<ui::InputDeviceEventObserver>::Unchecked observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(InputDeviceClient);
-};
-
-}  // namespace ws
-
-#endif  // SERVICES_WS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CLIENT_H_
diff --git a/services/ws/public/cpp/input_devices/input_device_controller.cc b/services/ws/public/cpp/input_devices/input_device_controller.cc
deleted file mode 100644
index 3202a57..0000000
--- a/services/ws/public/cpp/input_devices/input_device_controller.cc
+++ /dev/null
@@ -1,174 +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 "services/ws/public/cpp/input_devices/input_device_controller.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "ui/events/devices/input_device.h"
-#include "ui/events/devices/touchscreen_device.h"
-#include "ui/events/keycodes/dom/dom_code.h"
-#include "ui/events/keycodes/dom/keycode_converter.h"
-#include "ui/ozone/public/input_controller.h"
-#include "ui/ozone/public/ozone_platform.h"
-
-namespace ws {
-
-InputDeviceController::InputDeviceController() = default;
-
-InputDeviceController::~InputDeviceController() = default;
-
-void InputDeviceController::AddInterface(
-    service_manager::BinderRegistry* registry,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
-  // base::Unretained() is safe here as this class is tied to the life of
-  // Service, so that no requests should come in after this class is deleted.
-  registry->AddInterface<mojom::InputDeviceController>(
-      base::Bind(&InputDeviceController::BindInputDeviceControllerRequest,
-                 base::Unretained(this)),
-      task_runner);
-}
-
-void InputDeviceController::AddKeyboardDeviceObserver(
-    mojom::KeyboardDeviceObserverPtr observer) {
-  NotifyObserver(observer.get());
-  observers_.AddPtr(std::move(observer));
-}
-
-void InputDeviceController::GetHasTouchpad(GetHasTouchpadCallback callback) {
-  std::move(callback).Run(GetInputController()->HasTouchpad());
-}
-
-void InputDeviceController::GetHasMouse(GetHasMouseCallback callback) {
-  std::move(callback).Run(GetInputController()->HasMouse());
-}
-
-void InputDeviceController::SetCapsLockEnabled(bool enabled) {
-  GetInputController()->SetCapsLockEnabled(enabled);
-  NotifyObservers();
-}
-
-void InputDeviceController::SetNumLockEnabled(bool enabled) {
-  GetInputController()->SetNumLockEnabled(enabled);
-}
-
-void InputDeviceController::SetAutoRepeatEnabled(bool enabled) {
-  GetInputController()->SetAutoRepeatEnabled(enabled);
-  NotifyObservers();
-}
-
-void InputDeviceController::SetAutoRepeatRate(
-    base::TimeDelta auto_repeat_delay,
-    base::TimeDelta auto_repeat_interval) {
-  GetInputController()->SetAutoRepeatRate(auto_repeat_delay,
-                                          auto_repeat_interval);
-}
-
-void InputDeviceController::SetKeyboardLayoutByName(const std::string& name) {
-  GetInputController()->SetCurrentLayoutByName(name);
-}
-
-void InputDeviceController::SetTouchpadSensitivity(int32_t value) {
-  GetInputController()->SetTouchpadSensitivity(value);
-}
-
-void InputDeviceController::SetTapToClick(bool enabled) {
-  GetInputController()->SetTapToClick(enabled);
-}
-
-void InputDeviceController::SetThreeFingerClick(bool enabled) {
-  GetInputController()->SetThreeFingerClick(enabled);
-}
-
-void InputDeviceController::SetTapDragging(bool enabled) {
-  GetInputController()->SetTapDragging(enabled);
-}
-
-void InputDeviceController::SetNaturalScroll(bool enabled) {
-  GetInputController()->SetNaturalScroll(enabled);
-}
-
-void InputDeviceController::SetMouseSensitivity(int32_t value) {
-  GetInputController()->SetMouseSensitivity(value);
-}
-
-void InputDeviceController::SetPrimaryButtonRight(bool right) {
-  GetInputController()->SetPrimaryButtonRight(right);
-}
-
-void InputDeviceController::SetMouseReverseScroll(bool enabled) {
-  GetInputController()->SetMouseReverseScroll(enabled);
-}
-
-void InputDeviceController::GetTouchDeviceStatus(
-    GetTouchDeviceStatusCallback callback) {
-  GetInputController()->GetTouchDeviceStatus(std::move(callback));
-}
-
-void InputDeviceController::GetTouchEventLog(
-    const base::FilePath& out_dir,
-    GetTouchEventLogCallback callback) {
-  GetInputController()->GetTouchEventLog(out_dir, std::move(callback));
-}
-
-void InputDeviceController::SetTapToClickPaused(bool state) {
-  GetInputController()->SetTapToClickPaused(state);
-}
-
-void InputDeviceController::SetInternalTouchpadEnabled(
-    bool enabled,
-    SetInternalTouchpadEnabledCallback callback) {
-  ui::InputController* input_controller = GetInputController();
-  const bool value_changed =
-      input_controller->HasTouchpad() &&
-      (input_controller->IsInternalTouchpadEnabled() != enabled);
-  if (value_changed)
-    input_controller->SetInternalTouchpadEnabled(enabled);
-  std::move(callback).Run(value_changed);
-}
-
-void InputDeviceController::SetTouchscreensEnabled(bool enabled) {
-  GetInputController()->SetTouchscreensEnabled(enabled);
-}
-
-void InputDeviceController::SetInternalKeyboardFilter(
-    bool enable_filter,
-    const std::vector<uint32_t>& allowed_keys) {
-  std::vector<ui::DomCode> dom_codes;
-  for (uint32_t key : allowed_keys) {
-    // NOTE: DomCodes and UsbKeycodes are the same thing.
-    const ui::DomCode dom_code = ui::KeycodeConverter::UsbKeycodeToDomCode(key);
-    if (dom_code != ui::DomCode::NONE)
-      dom_codes.push_back(dom_code);
-  }
-  GetInputController()->SetInternalKeyboardFilter(enable_filter,
-                                                  std::move(dom_codes));
-}
-
-ui::InputController* InputDeviceController::GetInputController() {
-  return ui::OzonePlatform::GetInstance()->GetInputController();
-}
-
-void InputDeviceController::NotifyObservers() {
-  observers_.ForAllPtrs([this](mojom::KeyboardDeviceObserver* observer) {
-    NotifyObserver(observer);
-  });
-}
-
-void InputDeviceController::NotifyObserver(
-    mojom::KeyboardDeviceObserver* observer) {
-  mojom::KeyboardDeviceStatePtr state = mojom::KeyboardDeviceState::New();
-  ui::InputController* input_controller = GetInputController();
-  state->is_caps_lock_enabled = input_controller->IsCapsLockEnabled();
-  state->is_auto_repeat_enabled = input_controller->IsAutoRepeatEnabled();
-  observer->OnKeyboardStateChanged(std::move(state));
-}
-
-void InputDeviceController::BindInputDeviceControllerRequest(
-    mojom::InputDeviceControllerRequest request) {
-  bindings_.AddBinding(this, std::move(request));
-}
-
-}  // namespace ws
diff --git a/services/ws/public/cpp/input_devices/input_device_controller.h b/services/ws/public/cpp/input_devices/input_device_controller.h
deleted file mode 100644
index 26e6619..0000000
--- a/services/ws/public/cpp/input_devices/input_device_controller.h
+++ /dev/null
@@ -1,83 +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 SERVICES_WS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CONTROLLER_H_
-#define SERVICES_WS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CONTROLLER_H_
-
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/ws/public/mojom/input_devices/input_device_controller.mojom.h"
-
-namespace ui {
-class InputController;
-}  // namespace ui
-
-namespace ws {
-
-// Implementation of mojom::InputDeviceController that forwards to
-// ui::InputController.
-class InputDeviceController : public mojom::InputDeviceController {
- public:
-  InputDeviceController();
-  ~InputDeviceController() override;
-
-  // Registers the interface provided by this class with |registry|.
-  void AddInterface(
-      service_manager::BinderRegistry* registry,
-      const scoped_refptr<base::SequencedTaskRunner>& task_runner = nullptr);
-
-  // mojom::InputDeviceController::
-  void AddKeyboardDeviceObserver(
-      mojom::KeyboardDeviceObserverPtr observer) override;
-  void GetHasTouchpad(GetHasTouchpadCallback callback) override;
-  void GetHasMouse(GetHasMouseCallback callback) override;
-  void SetCapsLockEnabled(bool enabled) override;
-  void SetNumLockEnabled(bool enabled) override;
-  void SetAutoRepeatEnabled(bool enabled) override;
-  void SetAutoRepeatRate(base::TimeDelta auto_repeat_delay,
-                         base::TimeDelta auto_repeat_interval) override;
-  void SetKeyboardLayoutByName(const std::string& name) override;
-  void SetTouchpadSensitivity(int32_t value) override;
-  void SetTapToClick(bool enabled) override;
-  void SetThreeFingerClick(bool enabled) override;
-  void SetTapDragging(bool enabled) override;
-  void SetNaturalScroll(bool enabled) override;
-  void SetMouseSensitivity(int32_t value) override;
-  void SetPrimaryButtonRight(bool right) override;
-  void SetMouseReverseScroll(bool enabled) override;
-  void GetTouchDeviceStatus(GetTouchDeviceStatusCallback callback) override;
-  void GetTouchEventLog(const base::FilePath& out_dir,
-                        GetTouchEventLogCallback callback) override;
-  void SetTapToClickPaused(bool state) override;
-  void SetInternalTouchpadEnabled(
-      bool enabled,
-      SetInternalTouchpadEnabledCallback callback) override;
-  void SetTouchscreensEnabled(bool enabled) override;
-  void SetInternalKeyboardFilter(
-      bool enable_filter,
-      const std::vector<uint32_t>& allowed_keys) override;
-
- private:
-  ui::InputController* GetInputController();
-
-  // Notifies all KeyboardDeviceObservers.
-  void NotifyObservers();
-
-  // Notifies a single KeyboardDeviceObserver.
-  void NotifyObserver(mojom::KeyboardDeviceObserver* observer);
-
-  void BindInputDeviceControllerRequest(
-      mojom::InputDeviceControllerRequest request);
-
-  mojo::BindingSet<mojom::InputDeviceController> bindings_;
-  mojo::InterfacePtrSet<mojom::KeyboardDeviceObserver> observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(InputDeviceController);
-};
-
-}  // namespace ws
-
-#endif  // SERVICES_WS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CONTROLLER_H_
diff --git a/services/ws/public/cpp/input_devices/input_device_controller_client.cc b/services/ws/public/cpp/input_devices/input_device_controller_client.cc
deleted file mode 100644
index 4decb45..0000000
--- a/services/ws/public/cpp/input_devices/input_device_controller_client.cc
+++ /dev/null
@@ -1,141 +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 "services/ws/public/cpp/input_devices/input_device_controller_client.h"
-
-#include <utility>
-
-#include "base/bind_helpers.h"
-#include "services/service_manager/public/cpp/connector.h"
-
-namespace ws {
-
-InputDeviceControllerClient::InputDeviceControllerClient(
-    service_manager::Connector* connector,
-    const std::string& service_name)
-    : binding_(this) {
-  DCHECK(!service_name.empty());
-  connector->BindInterface(service_name, &input_device_controller_);
-  mojom::KeyboardDeviceObserverPtr ptr;
-  binding_.Bind(mojo::MakeRequest(&ptr));
-  input_device_controller_->AddKeyboardDeviceObserver(std::move(ptr));
-}
-
-InputDeviceControllerClient::~InputDeviceControllerClient() = default;
-
-void InputDeviceControllerClient::GetHasMouse(GetHasMouseCallback callback) {
-  input_device_controller_->GetHasMouse(std::move(callback));
-}
-
-void InputDeviceControllerClient::GetHasTouchpad(
-    GetHasTouchpadCallback callback) {
-  input_device_controller_->GetHasTouchpad(std::move(callback));
-}
-
-bool InputDeviceControllerClient::IsCapsLockEnabled() {
-  return keyboard_device_state_.is_caps_lock_enabled;
-}
-
-void InputDeviceControllerClient::SetCapsLockEnabled(bool enabled) {
-  keyboard_device_state_.is_caps_lock_enabled = enabled;
-  input_device_controller_->SetCapsLockEnabled(enabled);
-}
-
-void InputDeviceControllerClient::SetNumLockEnabled(bool enabled) {
-  input_device_controller_->SetNumLockEnabled(enabled);
-}
-
-bool InputDeviceControllerClient::IsAutoRepeatEnabled() {
-  return keyboard_device_state_.is_auto_repeat_enabled;
-}
-
-void InputDeviceControllerClient::SetAutoRepeatEnabled(bool enabled) {
-  keyboard_device_state_.is_auto_repeat_enabled = enabled;
-  input_device_controller_->SetAutoRepeatEnabled(enabled);
-}
-
-void InputDeviceControllerClient::SetAutoRepeatRate(base::TimeDelta delay,
-                                                    base::TimeDelta interval) {
-  input_device_controller_->SetAutoRepeatRate(delay, interval);
-}
-
-void InputDeviceControllerClient::SetKeyboardLayoutByName(
-    const std::string& layout_name) {
-  input_device_controller_->SetKeyboardLayoutByName(layout_name);
-}
-
-void InputDeviceControllerClient::SetTouchpadSensitivity(int value) {
-  input_device_controller_->SetTouchpadSensitivity(value);
-}
-
-void InputDeviceControllerClient::SetTapToClick(bool enable) {
-  input_device_controller_->SetTapToClick(enable);
-}
-
-void InputDeviceControllerClient::SetThreeFingerClick(bool enable) {
-  input_device_controller_->SetThreeFingerClick(enable);
-}
-
-void InputDeviceControllerClient::SetTapDragging(bool enable) {
-  input_device_controller_->SetTapDragging(enable);
-}
-
-void InputDeviceControllerClient::SetNaturalScroll(bool enable) {
-  input_device_controller_->SetNaturalScroll(enable);
-}
-
-void InputDeviceControllerClient::SetMouseSensitivity(int value) {
-  input_device_controller_->SetMouseSensitivity(value);
-}
-
-void InputDeviceControllerClient::SetPrimaryButtonRight(bool right) {
-  input_device_controller_->SetPrimaryButtonRight(right);
-}
-
-void InputDeviceControllerClient::SetMouseReverseScroll(bool enabled) {
-  input_device_controller_->SetMouseReverseScroll(enabled);
-}
-
-void InputDeviceControllerClient::GetTouchDeviceStatus(
-    GetTouchDeviceStatusCallback callback) {
-  input_device_controller_->GetTouchDeviceStatus(std::move(callback));
-}
-
-void InputDeviceControllerClient::GetTouchEventLog(
-    const base::FilePath& out_dir,
-    GetTouchEventLogCallback callback) {
-  input_device_controller_->GetTouchEventLog(out_dir, std::move(callback));
-}
-
-void InputDeviceControllerClient::SetTapToClickPaused(bool state) {
-  input_device_controller_->SetTapToClickPaused(state);
-}
-
-void InputDeviceControllerClient::SetTouchscreensEnabled(bool enable) {
-  input_device_controller_->SetTouchscreensEnabled(enable);
-}
-
-void InputDeviceControllerClient::SetInternalKeyboardFilter(
-    bool enable_filter,
-    const std::vector<ui::DomCode>& allowed_keys) {
-  std::vector<uint32_t> transport_keys(allowed_keys.size());
-  for (size_t i = 0; i < allowed_keys.size(); ++i)
-    transport_keys[i] = static_cast<uint32_t>(allowed_keys[i]);
-  input_device_controller_->SetInternalKeyboardFilter(enable_filter,
-                                                      transport_keys);
-}
-
-void InputDeviceControllerClient::SetInternalTouchpadEnabled(
-    bool enable,
-    SetInternalTouchpadEnabledCallback callback) {
-  input_device_controller_->SetInternalTouchpadEnabled(enable,
-                                                       std::move(callback));
-}
-
-void InputDeviceControllerClient::OnKeyboardStateChanged(
-    mojom::KeyboardDeviceStatePtr state) {
-  keyboard_device_state_ = *state;
-}
-
-}  // namespace ws
diff --git a/services/ws/public/cpp/input_devices/input_device_controller_client.h b/services/ws/public/cpp/input_devices/input_device_controller_client.h
deleted file mode 100644
index 596bdb4..0000000
--- a/services/ws/public/cpp/input_devices/input_device_controller_client.h
+++ /dev/null
@@ -1,96 +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 SERVICES_WS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CONTROLLER_CLIENT_H_
-#define SERVICES_WS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CONTROLLER_CLIENT_H_
-
-#include <string>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/ws/public/mojom/input_devices/input_device_controller.mojom.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace service_manager {
-class Connector;
-}
-
-namespace ui {
-enum class DomCode;
-}
-
-namespace ws {
-
-// InputDeviceControllerClient is mostly a call through to
-// mojom::InputDeviceController. It does a minimal amount of caching and is
-// itself a KeyboardDeviceObserver to maintain local keyboard state.
-class InputDeviceControllerClient : public mojom::KeyboardDeviceObserver {
- public:
-  // |service_Name| is the name of the service providing mojom::KeyboardDevice,
-  // generally use the default, unless a specific service is needed.
-  explicit InputDeviceControllerClient(
-      service_manager::Connector* connector,
-      const std::string& service_name = std::string());
-  ~InputDeviceControllerClient() override;
-
-  using GetHasMouseCallback = base::OnceCallback<void(bool)>;
-  void GetHasMouse(GetHasMouseCallback callback);
-
-  using GetHasTouchpadCallback = base::OnceCallback<void(bool)>;
-  void GetHasTouchpad(GetHasTouchpadCallback callback);
-
-  bool IsCapsLockEnabled();
-  void SetCapsLockEnabled(bool enabled);
-  void SetNumLockEnabled(bool enabled);
-  bool IsAutoRepeatEnabled();
-  void SetAutoRepeatEnabled(bool enabled);
-  void SetAutoRepeatRate(base::TimeDelta delay, base::TimeDelta interval);
-  void SetKeyboardLayoutByName(const std::string& layout_name);
-  void SetTouchpadSensitivity(int value);
-  void SetTapToClick(bool enabled);
-  void SetThreeFingerClick(bool enabled);
-  void SetTapDragging(bool enabled);
-  void SetNaturalScroll(bool enabled);
-  void SetMouseSensitivity(int value);
-  void SetPrimaryButtonRight(bool right);
-  void SetMouseReverseScroll(bool enabled);
-
-  using GetTouchDeviceStatusCallback =
-      base::OnceCallback<void(const std::string&)>;
-  void GetTouchDeviceStatus(GetTouchDeviceStatusCallback callback);
-
-  using GetTouchEventLogCallback =
-      base::OnceCallback<void(const std::vector<base::FilePath>&)>;
-  void GetTouchEventLog(const base::FilePath& out_dir,
-                        GetTouchEventLogCallback callback);
-  void SetTapToClickPaused(bool state);
-
-  void SetTouchscreensEnabled(bool enabled);
-  void SetInternalKeyboardFilter(bool enable_filter,
-                                 const std::vector<ui::DomCode>& allowed_keys);
-
-  // Sets whether the internal touch pad. Returns true if there is an internal
-  // touchpad.
-  using SetInternalTouchpadEnabledCallback = base::OnceCallback<void(bool)>;
-  void SetInternalTouchpadEnabled(bool enable,
-                                  SetInternalTouchpadEnabledCallback callback);
-
- private:
-  // mojom::KeyboardDeviceObserver:
-  void OnKeyboardStateChanged(mojom::KeyboardDeviceStatePtr state) override;
-
-  mojom::InputDeviceControllerPtr input_device_controller_;
-  mojom::KeyboardDeviceState keyboard_device_state_;
-  mojo::Binding<mojom::KeyboardDeviceObserver> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(InputDeviceControllerClient);
-};
-
-}  // namespace ws
-
-#endif  // SERVICES_WS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CONTROLLER_CLIENT_H_
diff --git a/services/ws/public/mojom/input_devices/BUILD.gn b/services/ws/public/mojom/input_devices/BUILD.gn
deleted file mode 100644
index ba75934..0000000
--- a/services/ws/public/mojom/input_devices/BUILD.gn
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/ui.gni")
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("input_devices") {
-  sources = [
-    "input_device_server.mojom",
-  ]
-
-  public_deps = [
-    "//ui/events/devices/mojo",
-  ]
-
-  if (is_chromeos) {
-    sources += [ "input_device_controller.mojom" ]
-    public_deps += [ "//mojo/public/mojom/base" ]
-  }
-}
diff --git a/services/ws/public/mojom/input_devices/OWNERS b/services/ws/public/mojom/input_devices/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/services/ws/public/mojom/input_devices/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/services/ws/public/mojom/input_devices/input_device_controller.mojom b/services/ws/public/mojom/input_devices/input_device_controller.mojom
deleted file mode 100644
index 6d97ad9..0000000
--- a/services/ws/public/mojom/input_devices/input_device_controller.mojom
+++ /dev/null
@@ -1,69 +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.
-
-module ws.mojom;
-
-import "mojo/public/mojom/base/file_path.mojom";
-import "mojo/public/mojom/base/time.mojom";
-import "ui/events/devices/mojo/input_devices.mojom";
-
-struct KeyboardDeviceState {
-  bool is_caps_lock_enabled;
-  bool is_auto_repeat_enabled;
-};
-
-// Notified when ever keyboard device state changes.
-interface KeyboardDeviceObserver {
-  // Called once when added, and subsequently any time the state changes.
-  OnKeyboardStateChanged(KeyboardDeviceState state);
-};
-
-// InputDeviceController is mojo wrapper for ui::InputController, see it for
-// details.
-interface InputDeviceController {
-  AddKeyboardDeviceObserver(KeyboardDeviceObserver observer);
-
-  GetHasTouchpad() => (bool has_touchpad);
-  GetHasMouse() => (bool has_mouse);
-
-  // Keyboard settings.
-  SetCapsLockEnabled(bool enabled);
-  SetNumLockEnabled(bool enabled);
-  SetAutoRepeatEnabled(bool enabled);
-  SetAutoRepeatRate(mojo_base.mojom.TimeDelta auto_repeat_delay,
-                    mojo_base.mojom.TimeDelta auto_repeat_interval);
-  SetKeyboardLayoutByName(string name);
-
-  // Touchpad settings.
-  SetTouchpadSensitivity(int32 value);
-  SetTapToClick(bool enabled);
-  SetThreeFingerClick(bool enabled);
-  SetTapDragging(bool enabled);
-  SetNaturalScroll(bool enabled);
-
-  // Mouse settings.
-  SetMouseSensitivity(int32 value);
-  SetPrimaryButtonRight(bool right);
-  SetMouseReverseScroll(bool enabled);
-
-  // Touchscreen log settings.
-  GetTouchDeviceStatus() => (string status);
-  GetTouchEventLog(mojo_base.mojom.FilePath out_dir) =>
-      (array<mojo_base.mojom.FilePath> results);
-
-  // Temporarily enable/disable Tap-to-click. Used to enhance the user
-  // experience in some use cases (e.g., typing, watching video).
-  SetTapToClickPaused(bool state);
-
-  // Sets the state of the internal touchpad. |result| is true if the change
-  // was applied.
-  SetInternalTouchpadEnabled(bool enabled) => (bool result);
-
-  SetTouchscreensEnabled(bool enabled);
-
-  // If |enable_filter| is true, all keys on the internal keyboard except
-  // |allowed_keys| are disabled. |allowed_keys| is a list of DomCodes. Any
-  // invalid codes are mapped to NONE.
-  SetInternalKeyboardFilter(bool enable_filter, array<uint32> allowed_keys);
-};
diff --git a/services/ws/public/mojom/input_devices/input_device_server.mojom b/services/ws/public/mojom/input_devices/input_device_server.mojom
deleted file mode 100644
index 4fe97c9..0000000
--- a/services/ws/public/mojom/input_devices/input_device_server.mojom
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module ws.mojom;
-
-import "ui/events/devices/mojo/input_devices.mojom";
-
-// Receives updates about changes to input-devices. See InputDeviceServer for
-// the expected behaviour.
-interface InputDeviceObserverMojo {
-  // Is called when the list of keyboards changes.
-  OnKeyboardDeviceConfigurationChanged(array<ui.mojom.InputDevice> devices);
-
-  // Is called when the list of touchscreens changes. If
-  // |touchscreen_target_display_ids_changed| is true, then only the
-  // |target_display_id| of the TouchscreenDevices has changed.
-  OnTouchscreenDeviceConfigurationChanged(
-      array<ui.mojom.TouchscreenDevice> devices,
-      bool touchscreen_target_display_ids_changed);
-
-  // Is called when the list of mice changes.
-  OnMouseDeviceConfigurationChanged(array<ui.mojom.InputDevice> devices);
-
-  // Is called when the list of touchpads changes.
-  OnTouchpadDeviceConfigurationChanged(array<ui.mojom.InputDevice> devices);
-
-  // Is called when the list of uncategorized input devices (besides keyboards,
-  // touchscreens, mice and touchpads) changes.
-  OnUncategorizedDeviceConfigurationChanged(
-      array<ui.mojom.InputDevice> devices);
-
-  // Is called once all of the input-device lists are available. This will
-  // always be the first call that an observer receives.
-  OnDeviceListsComplete(
-      array<ui.mojom.InputDevice> keyboard_devices,
-      array<ui.mojom.TouchscreenDevice> touchscreen_devices,
-      array<ui.mojom.InputDevice> mouse_devices,
-      array<ui.mojom.InputDevice> touchpad_devices,
-      array<ui.mojom.InputDevice> uncategorized_devices,
-      bool are_touchscreen_target_displays_valid);
-
-  // Is called when a stylus is removed or inserted into the device.
-  OnStylusStateChanged(ui.mojom.StylusState state);
-};
-
-// Sends updates about input-devices to observers.
-interface InputDeviceServer {
-  // Adds an InputDeviceObserverMojo in another process as an observer to get
-  // notified of changes to input-devices over Mojo IPC. If all input-device
-  // lists are complete when a new observer connects, the implementation will
-  // immediately call OnDeviceListsComplete() with the input-device lists. If
-  // not, the implementation will wait until all input-device lists are complete
-  // then call OnDeviceListsComplete() for all connected observers.
-  AddObserver(InputDeviceObserverMojo observer);
-};
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 1f43f44..f0138adf 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -6,993 +6,6 @@
       "all"
     ]
   },
-  "Chromium Mac 10.13": {
-    "gtest_tests": [
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "accessibility_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "angle_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "app_shell_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "base_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "base_util_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "blink_common_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "blink_fuzzer_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "blink_heap_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "blink_platform_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "webkit_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "blink_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "boringssl_crypto_tests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "boringssl_ssl_tests"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/mac_window_server_killers.browser_tests.filter",
-          "--gtest_shuffle"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 10
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--disable-blink-features=HTMLImports,ShadowDOMV0,CustomElementsV0",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/webui_html_imports_polyfill_browser_tests.filter"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "webui_html_imports_polyfill_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "browser_tests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "cacheinvalidation_unittests"
-      },
-      {
-        "args": [
-          "--gtest_filter=-*UsingRealWebcam*"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "capture_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "cast_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "cc_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "chrome_app_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "chromedriver_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "components_browsertests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "components_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 6
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
-          "--disable-perfetto",
-          "--gtest_filter=TracingControllerTest.*:BackgroundTracingManagerBrowserTest.*"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "nonperfetto_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "crashpad_tests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "cronet_tests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "cronet_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "crypto_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "device_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "display_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "events_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "extensions_browsertests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "extensions_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "filesystem_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "gcm_unit_tests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "gfx_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "gin_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "google_apis_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "gpu_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "headless_browsertests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "headless_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 3
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
-        "args": [
-          "--disable-blink-features=HTMLImports,ShadowDOMV0,CustomElementsV0",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/webui_html_imports_polyfill_interactive_ui_tests.filter"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "webui_html_imports_polyfill_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "ipc_tests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "jingle_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "latency_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "libjingle_xmpp_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "media_blink_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "media_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "media_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "message_center_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "midi_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "mojo_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "nacl_loader_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "native_theme_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "net_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "pdf_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "perfetto_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "ppapi_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "printing_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "remoting_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "sandbox_mac_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "service_manager_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "services_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "shell_dialogs_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "skia_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "snapshot_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "sql_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "storage_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "sync_integration_tests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "ui_base_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "ui_touch_selection_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "unit_tests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "url_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "views_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "viz_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "wtf_unittests"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "isolate_name": "blink_python_tests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "blink_python_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
-        "args": [
-          "--test-type=integration"
-        ],
-        "isolate_name": "chromedriver_py_tests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_py_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
-        "isolate_name": "chromedriver_replay_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_replay_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=components_perftests"
-        ],
-        "isolate_name": "components_perftests",
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "components_perftests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
-        "isolate_name": "content_shell_crash_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "content_shell_crash_test",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
-        "isolate_name": "flatbuffers_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "flatbuffers_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
-        "isolate_name": "grit_python_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "grit_python_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
-        "isolate_name": "mac_signing_tests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mac_signing_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
-        "isolate_name": "metrics_python_tests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "metrics_python_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
-        "isolate_name": "telemetry_gpu_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_gpu_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "idempotent": false
-        }
-      },
-      {
-        "isolate_name": "telemetry_perf_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_perf_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "idempotent": false,
-          "shards": 12
-        }
-      },
-      {
-        "args": [
-          "--jobs=1",
-          "--extra-browser-args=--disable-gpu"
-        ],
-        "isolate_name": "telemetry_unittests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "idempotent": false,
-          "shards": 4
-        }
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=views_perftests"
-        ],
-        "isolate_name": "views_perftests",
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "views_perftests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      }
-    ]
-  },
   "Jumbo Linux x64": {
     "additional_compile_targets": [
       "all"
@@ -25911,7 +24924,9 @@
       {
         "args": [
           "--build-revision=${got_revision}",
-          "--enable-logging"
+          "--enable-logging",
+          "--test-launcher-jobs=1",
+          "--test-launcher-print-test-stdio=always"
         ],
         "experiment_percentage": 100,
         "merge": {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index bff487c..2aadec8 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -130,15 +130,6 @@
           'shards': 20,
         },
       },
-      # chromium.fyi
-      'Chromium Mac 10.13': {
-        # A subset of tests seem to cause WindowServer deaths on VMs.
-        # crbug.com/828031 et al.
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/mac_window_server_killers.browser_tests.filter',
-          '--gtest_shuffle',
-        ],
-      },
       'mac-dummy-rel': {
         # A subset of tests seem to cause WindowServer deaths on VMs.
         # crbug.com/828031 et al.
@@ -901,7 +892,6 @@
       'Win7 Tests (1)',  # For swarming capacity reasons.
       'Win10 Tests x64 (dbg)',  # Matches browser_tests.
       # Only run network service tests on Mac 10.12 for capacity reasons.
-      'Chromium Mac 10.13',
       'Mac10.10 Tests',
       'Mac10.11 Tests',
       'Mac10.13 Tests',
@@ -934,7 +924,6 @@
       'Win7 Tests (1)',  # For swarming capacity reasons.
       'Win10 Tests x64 (dbg)',  # Matches components_browsertests.
       # Only run network service tests on Mac 10.12 for capacity reasons.
-      'Chromium Mac 10.13',
       'Mac10.10 Tests',
       'Mac10.11 Tests',
       'Mac10.13 Tests',
@@ -956,7 +945,6 @@
       'Win7 Tests (1)',  # For swarming capacity reasons.
       'Win10 Tests x64 (dbg)',  # flaky: https://crbug.com/852786
       # Only run network service tests on Mac 10.12 for capacity reasons.
-      'Chromium Mac 10.13',
       'Mac10.10 Tests',
       'Mac10.11 Tests',
       'Mac10.13 Tests',
@@ -977,7 +965,6 @@
       'Win7 Tests (1)',  # For swarming capacity reasons.
       'Win10 Tests x64 (dbg)',  # Matches extensions_browsertests.
       # Only run network service tests on Mac 10.12 for capacity reasons.
-      'Chromium Mac 10.13',
       'Mac10.10 Tests',
       'Mac10.11 Tests',
       'Mac10.13 Tests',
@@ -1004,7 +991,6 @@
       # chromium.win
       'Win7 Tests (1)',  # For swarming capacity reasons.
       # Only run network service tests on Mac 10.12 for capacity reasons.
-      'Chromium Mac 10.13',
       'Mac10.10 Tests',
       'Mac10.11 Tests',
       'Mac10.13 Tests',
@@ -1687,8 +1673,6 @@
   },
   'webkit_layout_tests': {
     'remove_from': [
-      # chromium.fyi
-      'Chromium Mac 10.13',
       # chromium.linux
       'Linux Tests (dbg)(1)(32)', # 32-bit linux is unsupported
       # chromium.win
@@ -1759,7 +1743,7 @@
       'mac10.13-blink-rel-dummy': {
         'swarming': {
           'dimension_sets': [
-            { # This should match Chromium Mac 10.13 on chromium.fyi.
+            { # This should match "Mac10.13 Tests" on the main waterfall.
               'gpu': '8086:0a2e',
               'hidpi': '0',
               'os': 'Mac-10.13.6',
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 688e281..88922304 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4128,6 +4128,8 @@
         'args': [
           '--build-revision=${got_revision}',
           '--enable-logging',
+          '--test-launcher-jobs=1',
+          '--test-launcher-print-test-stdio=always'
         ],
         'experiment_percentage': 100,
         'swarming': {
@@ -4592,16 +4594,6 @@
       'telemetry_perf_unittests_isolated_scripts',
     ],
 
-    # chromium_mac_gtests + additional suites.
-    'chromium_mac_fyi_gtests': [
-      'chromium_gtests',
-      'chromium_gtests_for_devices_with_graphical_output',
-      'mac_specific_chromium_gtests',
-      'non_android_chromium_gtests',
-      'non_android_and_cast_and_chromeos_chromium_gtests',
-      'non_linux_chromium_gtests',
-    ],
-
     'chromium_mac_gtests': [
       'chromium_gtests',
       'chromium_gtests_for_devices_with_graphical_output',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 0813d03..e16d60c 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1272,12 +1272,6 @@
           'all',
         ],
       },
-      'Chromium Mac 10.13': {
-        'test_suites': {
-          'gtest_tests': 'chromium_mac_fyi_gtests',
-          'isolated_scripts': 'chromium_mac_rel_isolated_scripts',
-        },
-      },
       'Jumbo Linux x64': {
         'additional_compile_targets': [
           'all',
@@ -1857,7 +1851,7 @@
             'mac_10.14_beta',
         ],
         'test_suites': {
-          'gtest_tests': 'chromium_mac_fyi_gtests',
+          'gtest_tests': 'chromium_mac_gtests',
           'isolated_scripts': 'chromium_mac_rel_isolated_scripts',
         },
       },
diff --git a/third_party/blink/public/platform/modules/mediastream/secure_display_link_tracker.h b/third_party/blink/public/platform/modules/mediastream/secure_display_link_tracker.h
index 995879f9..2118977 100644
--- a/third_party/blink/public/platform/modules/mediastream/secure_display_link_tracker.h
+++ b/third_party/blink/public/platform/modules/mediastream/secure_display_link_tracker.h
@@ -5,10 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_SECURE_DISPLAY_LINK_TRACKER_H_
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_SECURE_DISPLAY_LINK_TRACKER_H_
 
-#include <algorithm>
-#include <vector>
-
-#include "base/stl_util.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
@@ -23,18 +20,18 @@
   void Add(T* link, bool is_link_secure);
   void Remove(T* link);
   void Update(T* link, bool is_link_secure);
-  bool is_capturing_secure() const { return insecure_links_.empty(); }
+  bool is_capturing_secure() const { return insecure_links_.IsEmpty(); }
 
  private:
   // Record every insecure links.
-  std::vector<T*> insecure_links_;
+  Vector<T*> insecure_links_;
 
   DISALLOW_COPY_AND_ASSIGN(SecureDisplayLinkTracker);
 };
 
 template <typename T>
 void SecureDisplayLinkTracker<T>::Add(T* link, bool is_link_secure) {
-  DCHECK(!base::Contains(insecure_links_, link));
+  DCHECK(!insecure_links_.Contains(link));
 
   if (!is_link_secure)
     insecure_links_.push_back(link);
@@ -42,17 +39,17 @@
 
 template <typename T>
 void SecureDisplayLinkTracker<T>::Remove(T* link) {
-  auto it = std::find(insecure_links_.begin(), insecure_links_.end(), link);
-  if (it != insecure_links_.end())
-    insecure_links_.erase(it);
+  auto it = insecure_links_.Find(link);
+  if (it != kNotFound)
+    insecure_links_.EraseAt(it);
 }
 
 template <typename T>
 void SecureDisplayLinkTracker<T>::Update(T* link, bool is_link_secure) {
-  auto it = std::find(insecure_links_.begin(), insecure_links_.end(), link);
-  if (it != insecure_links_.end()) {
+  auto it = insecure_links_.Find(link);
+  if (it != kNotFound) {
     if (is_link_secure)
-      insecure_links_.erase(it);
+      insecure_links_.EraseAt(it);
     return;
   }
   Add(link, is_link_secure);
diff --git a/third_party/blink/renderer/bindings/core/v8/script_controller.cc b/third_party/blink/renderer/bindings/core/v8/script_controller.cc
index 512b5c6..c4f700f 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_controller.cc
@@ -66,7 +66,6 @@
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
index 8eae7ca8..647f70e 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
@@ -67,7 +67,6 @@
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
diff --git a/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter.py b/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter.py
index b2b67886..a55a922 100644
--- a/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter.py
+++ b/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter.py
@@ -11,7 +11,6 @@
     # This list should be sorted by length.
     'WebSocket',
     'String16',
-    'CString',
     'Float32',
     'Float64',
     'Base64',
diff --git a/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter_test.py b/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter_test.py
index 19fdadf0..85ba650b 100644
--- a/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter_test.py
+++ b/third_party/blink/renderer/build/scripts/blinkbuild/name_style_converter_test.py
@@ -53,7 +53,6 @@
         self.assertEqual(tokenize_name('CDATASection'), ['CDATA', 'Section'])
 
         self.assertEqual(tokenize_name('ASCIICType'), ['ASCII', 'CType'])
-        self.assertEqual(tokenize_name('CString'), ['CString'])
 
         self.assertEqual(tokenize_name('HTMLDListElement'), ['HTML', 'DList', 'Element'])
         self.assertEqual(tokenize_name('HTMLOListElement'), ['HTML', 'OList', 'Element'])
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 7236476..45e3759d 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -712,6 +712,8 @@
     "$blink_core_output_dir/css/properties/longhands/internal_visited_border_right_color.h",
     "$blink_core_output_dir/css/properties/longhands/internal_visited_border_top_color.cc",
     "$blink_core_output_dir/css/properties/longhands/internal_visited_border_top_color.h",
+    "$blink_core_output_dir/css/properties/longhands/internal_visited_caret_color.cc",
+    "$blink_core_output_dir/css/properties/longhands/internal_visited_caret_color.h",
     "$blink_core_output_dir/css/properties/longhands/internal_visited_color.cc",
     "$blink_core_output_dir/css/properties/longhands/internal_visited_color.h",
     "$blink_core_output_dir/css/properties/longhands/internal_visited_text_decoration_color.cc",
@@ -1723,6 +1725,7 @@
 jumbo_source_set("unit_tests") {
   testonly = true
   sources = [
+    "clipboard/clipboard_utilities_test.cc",
     "content_capture/content_capture_test.cc",
     "css/css_test_helpers.cc",
     "css/css_test_helpers.h",
diff --git a/third_party/blink/renderer/core/animation/color_property_functions.cc b/third_party/blink/renderer/core/animation/color_property_functions.cc
index 8c1a172..34c59dc 100644
--- a/third_party/blink/renderer/core/animation/color_property_functions.cc
+++ b/third_party/blink/renderer/core/animation/color_property_functions.cc
@@ -76,9 +76,9 @@
     case CSSPropertyID::kCaretColor:
       // TODO(rego): "auto" value for caret-color should not interpolate
       // (http://crbug.com/676295).
-      if (style.VisitedLinkCaretColor().IsAutoColor())
+      if (style.InternalVisitedCaretColor().IsAutoColor())
         return StyleColor::CurrentColor();
-      return style.VisitedLinkCaretColor().ToStyleColor();
+      return style.InternalVisitedCaretColor().ToStyleColor();
     case CSSPropertyID::kColor:
       return style.InternalVisitedColor();
     case CSSPropertyID::kOutlineColor:
@@ -178,7 +178,7 @@
       style.SetInternalVisitedBorderTopColor(color);
       return;
     case CSSPropertyID::kCaretColor:
-      return style.SetVisitedLinkCaretColor(color);
+      return style.SetInternalVisitedCaretColor(color);
     case CSSPropertyID::kColor:
       style.SetInternalVisitedColor(color);
       return;
diff --git a/third_party/blink/renderer/core/clipboard/clipboard_utilities.cc b/third_party/blink/renderer/core/clipboard/clipboard_utilities.cc
index a2eec822..b7628cf 100644
--- a/third_party/blink/renderer/core/clipboard/clipboard_utilities.cc
+++ b/third_party/blink/renderer/core/clipboard/clipboard_utilities.cc
@@ -65,9 +65,15 @@
 }
 
 static String EscapeForHTML(const String& str) {
-  std::string output =
-      net::EscapeForHTML(StringUTF8Adaptor(str).AsStringPiece());
-  return String(output.c_str());
+  // net::EscapeForHTML can work on 8-bit Latin-1 strings as well as 16-bit
+  // strings.
+  if (str.Is8Bit()) {
+    auto result = net::EscapeForHTML(
+        {reinterpret_cast<const char*>(str.Characters8()), str.length()});
+    return String(result.data(), result.size());
+  }
+  auto result = net::EscapeForHTML({str.Characters16(), str.length()});
+  return String(result.data(), result.size());
 }
 
 String URLToImageMarkup(const KURL& url, const String& title) {
diff --git a/third_party/blink/renderer/core/clipboard/clipboard_utilities_test.cc b/third_party/blink/renderer/core/clipboard/clipboard_utilities_test.cc
new file mode 100644
index 0000000..a033875
--- /dev/null
+++ b/third_party/blink/renderer/core/clipboard/clipboard_utilities_test.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/clipboard/clipboard_utilities.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+TEST(ClipboardUtilitiesTest, URLToImageMarkupNonASCII) {
+  // U+00E7 "Latin Small Letter C with Cedilla" is outside ASCII.
+  // It has the UTF-8 encoding 0xC3 0xA7, but Blink interprets 8-bit string
+  // literals as Latin-1 in most cases.
+  String markup_with_non_ascii =
+      URLToImageMarkup(KURL(NullURL(),
+                            "http://test.example/fran\xe7"
+                            "ais.png"),
+                       "Fran\xe7"
+                       "ais");
+  EXPECT_EQ(
+      "<img src=\"http://test.example/fran%C3%A7ais.png\" alt=\"Fran\xe7"
+      "ais\"/>",
+      markup_with_non_ascii);
+  EXPECT_EQ(
+      "<img src=\"http://test.example/fran%C3%A7ais.png\" alt=\"Fran\xc3\xa7"
+      "ais\"/>",
+      markup_with_non_ascii.Utf8());
+}
+
+TEST(ClipboardUtilitiesTest, URLToImageMarkupEmbeddedNull) {
+  // Null characters, though strange, should also work.
+  const char kURLWithNull[] = "http://test.example/\0.png";
+  const char kTitleWithNull[] = "\0";
+  const char kExpectedOutputWithNull[] =
+      "<img src=\"http://test.example/%00.png\" alt=\"\0\"/>";
+  EXPECT_EQ(
+      String(kExpectedOutputWithNull, sizeof(kExpectedOutputWithNull) - 1),
+      URLToImageMarkup(
+          KURL(NullURL(), String(kURLWithNull, sizeof(kURLWithNull) - 1)),
+          String(kTitleWithNull, sizeof(kTitleWithNull) - 1)));
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/clipboard/system_clipboard.cc b/third_party/blink/renderer/core/clipboard/system_clipboard.cc
index c8f57fa..ad2ab35 100644
--- a/third_party/blink/renderer/core/clipboard/system_clipboard.cc
+++ b/third_party/blink/renderer/core/clipboard/system_clipboard.cc
@@ -72,18 +72,17 @@
 uint64_t SystemClipboard::SequenceNumber() {
   if (!IsValidBufferType(buffer_))
     return 0;
-
   uint64_t result = 0;
   clipboard_->GetSequenceNumber(buffer_, &result);
   return result;
 }
 
 Vector<String> SystemClipboard::ReadAvailableTypes() {
+  if (!IsValidBufferType(buffer_))
+    return {};
   Vector<String> types;
-  if (IsValidBufferType(buffer_)) {
-    bool unused;
-    clipboard_->ReadAvailableTypes(buffer_, &types, &unused);
-  }
+  bool contains_filenames;  // Unused argument.
+  clipboard_->ReadAvailableTypes(buffer_, &types, &contains_filenames);
   return types;
 }
 
@@ -152,9 +151,10 @@
 }
 
 SkBitmap SystemClipboard::ReadImage(mojom::ClipboardBuffer buffer) {
+  if (!IsValidBufferType(buffer))
+    return SkBitmap();
   SkBitmap image;
-  if (IsValidBufferType(buffer))
-    clipboard_->ReadImage(buffer, &image);
+  clipboard_->ReadImage(buffer, &image);
   return image;
 }
 
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 68cb7777..4478259 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -5162,6 +5162,23 @@
       priority: "High",
     },
     {
+      name: "-internal-visited-caret-color",
+      visited_property_for: "caret-color",
+      property_methods: ["ColorIncludingFallback"],
+      inherited: true,
+      field_group: "*",
+      field_template: "external",
+      include_paths: ["third_party/blink/renderer/platform/graphics/color.h"],
+      default_value: "Color()",
+      type_name: "Color",
+      converter: "ConvertStyleAutoColor",
+      computed_style_custom_functions: ["getter", "setter"],
+      style_builder_template: "visited_color",
+      style_builder_template_args: {
+        initial_color: "StyleAutoColor::AutoColor",
+      },
+    },
+    {
       name: "-internal-visited-background-color",
       visited_property_for: "background-color",
       property_methods: ["ColorIncludingFallback"],
diff --git a/third_party/blink/renderer/core/css/css_property_equality.cc b/third_party/blink/renderer/core/css/css_property_equality.cc
index 3efea4e..4c6f06260 100644
--- a/third_party/blink/renderer/core/css/css_property_equality.cc
+++ b/third_party/blink/renderer/core/css/css_property_equality.cc
@@ -132,7 +132,7 @@
       return DataEquivalent(a.BoxShadow(), b.BoxShadow());
     case CSSPropertyID::kCaretColor:
       return a.CaretColor() == b.CaretColor() &&
-             a.VisitedLinkCaretColor() == b.VisitedLinkCaretColor();
+             a.InternalVisitedCaretColor() == b.InternalVisitedCaretColor();
     case CSSPropertyID::kClip:
       return a.Clip() == b.Clip();
     case CSSPropertyID::kColor:
diff --git a/third_party/blink/renderer/core/css/css_property_value_set.cc b/third_party/blink/renderer/core/css/css_property_value_set.cc
index a628fec..1e4ae80 100644
--- a/third_party/blink/renderer/core/css/css_property_value_set.cc
+++ b/third_party/blink/renderer/core/css/css_property_value_set.cc
@@ -37,7 +37,6 @@
 
 #ifndef NDEBUG
 #include <stdio.h>
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #endif
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/css/css_style_declaration.cc b/third_party/blink/renderer/core/css/css_style_declaration.cc
index 4307bee8..d251d2b5 100644
--- a/third_party/blink/renderer/core/css/css_style_declaration.cc
+++ b/third_party/blink/renderer/core/css/css_style_declaration.cc
@@ -171,7 +171,7 @@
     return false;
   // We create the ExceptionState manually due to performance issues: adding
   // [RaisesException] to the IDL causes the bindings layer to expensively
-  // create a CString to set the ExceptionState's |property_name| argument,
+  // create a std::string to set the ExceptionState's |property_name| argument,
   // while we can use CSSProperty::GetPropertyName() here (see bug 829408).
   ExceptionState exception_state(
       script_state->GetIsolate(), ExceptionState::kSetterContext,
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index 9cb559c..e6421ab 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -178,6 +178,7 @@
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_border_left_color.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_border_right_color.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_border_top_color.h"
+#include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_caret_color.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_color.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_text_decoration_color.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_text_emphasis_color.h"
@@ -1643,15 +1644,13 @@
 const blink::Color CaretColor::ColorIncludingFallback(
     bool visited_link,
     const ComputedStyle& style) const {
-  StyleAutoColor auto_color =
-      visited_link ? style.VisitedLinkCaretColor() : style.CaretColor();
+  DCHECK(!visited_link);
+  StyleAutoColor auto_color = style.CaretColor();
   // TODO(rego): We may want to adjust the caret color if it's the same as
   // the background to ensure good visibility and contrast.
   StyleColor result = auto_color.IsAutoColor() ? StyleColor::CurrentColor()
                                                : auto_color.ToStyleColor();
-  if (!result.IsCurrentColor())
-    return result.GetColor();
-  return visited_link ? style.InternalVisitedColor() : style.GetColor();
+  return result.Resolve(style.GetColor());
 }
 
 const CSSValue* CaretColor::CSSValueFromComputedStyleInternal(
@@ -1671,31 +1670,17 @@
 }
 
 void CaretColor::ApplyInitial(StyleResolverState& state) const {
-  StyleAutoColor color = StyleAutoColor::AutoColor();
-  if (state.ApplyPropertyToRegularStyle())
-    state.Style()->SetCaretColor(color);
-  if (state.ApplyPropertyToVisitedLinkStyle())
-    state.Style()->SetVisitedLinkCaretColor(color);
+  state.Style()->SetCaretColor(StyleAutoColor::AutoColor());
 }
 
 void CaretColor::ApplyInherit(StyleResolverState& state) const {
-  StyleAutoColor color = state.ParentStyle()->CaretColor();
-  if (state.ApplyPropertyToRegularStyle())
-    state.Style()->SetCaretColor(color);
-  if (state.ApplyPropertyToVisitedLinkStyle())
-    state.Style()->SetVisitedLinkCaretColor(color);
+  state.Style()->SetCaretColor(state.ParentStyle()->CaretColor());
 }
 
 void CaretColor::ApplyValue(StyleResolverState& state,
                             const CSSValue& value) const {
-  if (state.ApplyPropertyToRegularStyle()) {
-    state.Style()->SetCaretColor(
-        StyleBuilderConverter::ConvertStyleAutoColor(state, value));
-  }
-  if (state.ApplyPropertyToVisitedLinkStyle()) {
-    state.Style()->SetVisitedLinkCaretColor(
-        StyleBuilderConverter::ConvertStyleAutoColor(state, value, true));
-  }
+  state.Style()->SetCaretColor(
+      StyleBuilderConverter::ConvertStyleAutoColor(state, value));
 }
 
 const CSSValue* Clear::CSSValueFromComputedStyleInternal(
@@ -3729,6 +3714,16 @@
       style.InternalVisitedColor());
 }
 
+const blink::Color InternalVisitedCaretColor::ColorIncludingFallback(
+    bool visited_link,
+    const ComputedStyle& style) const {
+  DCHECK(visited_link);
+  StyleAutoColor auto_color = style.InternalVisitedCaretColor();
+  StyleColor result = auto_color.IsAutoColor() ? StyleColor::CurrentColor()
+                                               : auto_color.ToStyleColor();
+  return result.Resolve(style.InternalVisitedColor());
+}
+
 const blink::Color InternalVisitedBorderRightColor::ColorIncludingFallback(
     bool visited_link,
     const ComputedStyle& style) const {
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index c4737b3..a811d653 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -159,7 +159,6 @@
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/hash_functions.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_position.h"
 
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index 25634af4..d0a43cd4 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -121,7 +121,6 @@
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/core/dom/presentation_attribute_style.cc b/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
index 6198225..0d77d76 100644
--- a/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
+++ b/third_party/blink/renderer/core/dom/presentation_attribute_style.cc
@@ -43,7 +43,6 @@
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/wtf/hash_functions.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/dom/range.cc b/third_party/blink/renderer/core/dom/range.cc
index e6b942d4..b040510 100644
--- a/third_party/blink/renderer/core/dom/range.cc
+++ b/third_party/blink/renderer/core/dom/range.cc
@@ -60,7 +60,6 @@
 #include "third_party/blink/renderer/platform/geometry/float_quad.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/dom/text.cc b/third_party/blink/renderer/core/dom/text.cc
index 4ea9d0d..7a16def1 100644
--- a/third_party/blink/renderer/core/dom/text.cc
+++ b/third_party/blink/renderer/core/dom/text.cc
@@ -42,7 +42,6 @@
 #include "third_party/blink/renderer/core/svg_names.h"
 #include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/editing/frame_selection.cc b/third_party/blink/renderer/core/editing/frame_selection.cc
index 1c973b8..6296c4c 100644
--- a/third_party/blink/renderer/core/editing/frame_selection.cc
+++ b/third_party/blink/renderer/core/editing/frame_selection.cc
@@ -84,7 +84,6 @@
 #include "third_party/blink/renderer/platform/geometry/float_quad.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
 #include "third_party/blink/renderer/platform/text/unicode_utilities.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 #define EDIT_DEBUG 0
 
diff --git a/third_party/blink/renderer/core/editing/position.cc b/third_party/blink/renderer/core/editing/position.cc
index f2c5a94e..eb060bf 100644
--- a/third_party/blink/renderer/core/editing/position.cc
+++ b/third_party/blink/renderer/core/editing/position.cc
@@ -29,7 +29,6 @@
 #include <ostream>  // NOLINT
 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
 #include "third_party/blink/renderer/core/editing/text_affinity.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/editing/visible_position.cc b/third_party/blink/renderer/core/editing/visible_position.cc
index 0078e35..e2d8c4e 100644
--- a/third_party/blink/renderer/core/editing/visible_position.cc
+++ b/third_party/blink/renderer/core/editing/visible_position.cc
@@ -41,7 +41,6 @@
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/geometry/float_quad.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/editing/visible_selection.cc b/third_party/blink/renderer/core/editing/visible_selection.cc
index 48384ba6..6ce08a7c7 100644
--- a/third_party/blink/renderer/core/editing/visible_selection.cc
+++ b/third_party/blink/renderer/core/editing/visible_selection.cc
@@ -38,7 +38,6 @@
 #include "third_party/blink/renderer/platform/geometry/layout_point.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
index f8059b4..d5f21f5 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -96,7 +96,6 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
 #include "third_party/blink/renderer/platform/network/http_parsers.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "v8/include/v8.h"
 
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl_test.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl_test.cc
index e3449dc..8332bb21 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl_test.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl_test.cc
@@ -39,7 +39,6 @@
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/testing/document_interface_broker_test_helpers.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 using testing::_;
diff --git a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc
index 78995f4..3ba267b 100644
--- a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc
+++ b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc
@@ -51,7 +51,6 @@
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 using blink::url_test_helpers::ToKURL;
diff --git a/third_party/blink/renderer/core/fileapi/file_reader.cc b/third_party/blink/renderer/core/fileapi/file_reader.cc
index 597edc7a..5aeef60 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader.cc
+++ b/third_party/blink/renderer/core/fileapi/file_reader.cc
@@ -45,7 +45,6 @@
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/frame/frame_serializer.cc b/third_party/blink/renderer/core/frame/frame_serializer.cc
index fb7a716..aa2eff3 100644
--- a/third_party/blink/renderer/core/frame/frame_serializer.cc
+++ b/third_party/blink/renderer/core/frame/frame_serializer.cc
@@ -65,7 +65,6 @@
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/mhtml/serialized_resource.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/core/frame/use_counter_helper.cc b/third_party/blink/renderer/core/frame/use_counter_helper.cc
index 0ff48ba..0e01512 100644
--- a/third_party/blink/renderer/core/frame/use_counter_helper.cc
+++ b/third_party/blink/renderer/core/frame/use_counter_helper.cc
@@ -1259,6 +1259,7 @@
     case CSSPropertyID::kInternalVisitedBorderLeftColor:
     case CSSPropertyID::kInternalVisitedBorderRightColor:
     case CSSPropertyID::kInternalVisitedBorderTopColor:
+    case CSSPropertyID::kInternalVisitedCaretColor:
     case CSSPropertyID::kInternalVisitedColor:
     case CSSPropertyID::kInternalVisitedTextDecorationColor:
     case CSSPropertyID::kInternalVisitedTextEmphasisColor:
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc
index ddbb318..a3f5f49 100644
--- a/third_party/blink/renderer/core/html/html_element.cc
+++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -81,7 +81,6 @@
 #include "third_party/blink/renderer/platform/text/bidi_text_run.h"
 #include "third_party/blink/renderer/platform/text/text_run_iterator.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/html/link_rel_attribute_test.cc b/third_party/blink/renderer/core/html/link_rel_attribute_test.cc
index 4ed754f..acb04e6 100644
--- a/third_party/blink/renderer/core/html/link_rel_attribute_test.cc
+++ b/third_party/blink/renderer/core/html/link_rel_attribute_test.cc
@@ -31,7 +31,6 @@
 #include "third_party/blink/renderer/core/html/link_rel_attribute.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index 19ae6fa..9860a85 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -107,7 +107,6 @@
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 #ifndef LOG_MEDIA_EVENTS
diff --git a/third_party/blink/renderer/core/html/media/media_fragment_uri_parser.h b/third_party/blink/renderer/core/html/media/media_fragment_uri_parser.h
index bf245513..a61157d 100644
--- a/third_party/blink/renderer/core/html/media/media_fragment_uri_parser.h
+++ b/third_party/blink/renderer/core/html/media/media_fragment_uri_parser.h
@@ -28,7 +28,6 @@
 
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc
index 5fb686f..fa4f9a9 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner_fuzzer.cc
@@ -71,7 +71,7 @@
           TokenPreloadScanner::ScannerType::kMainDocument);
 
   TextResourceDecoderForFuzzing decoder(fuzzed_data);
-  CString bytes = fuzzed_data.ConsumeRemainingBytes();
+  std::string bytes = fuzzed_data.ConsumeRemainingBytes();
   String decoded_bytes = decoder.Decode(bytes.data(), bytes.length());
   scanner->AppendToEnd(decoded_bytes);
   bool has_csp_meta_tag_unused = false;
diff --git a/third_party/blink/renderer/core/html/parser/text_resource_decoder_fuzzer.cc b/third_party/blink/renderer/core/html/parser/text_resource_decoder_fuzzer.cc
index 95139539..344c455 100644
--- a/third_party/blink/renderer/core/html/parser/text_resource_decoder_fuzzer.cc
+++ b/third_party/blink/renderer/core/html/parser/text_resource_decoder_fuzzer.cc
@@ -14,7 +14,7 @@
   static BlinkFuzzerTestSupport test_support = BlinkFuzzerTestSupport();
   FuzzedDataProvider fuzzed_data(data, size);
   TextResourceDecoderForFuzzing decoder(fuzzed_data);
-  CString bytes = fuzzed_data.ConsumeRemainingBytes();
+  std::string bytes = fuzzed_data.ConsumeRemainingBytes();
   decoder.Decode(bytes.data(), bytes.length());
   decoder.Flush();
   return 0;
diff --git a/third_party/blink/renderer/core/html/track/vtt/buffered_line_reader_test.cc b/third_party/blink/renderer/core/html/track/vtt/buffered_line_reader_test.cc
index 1ca8589..9e06b5e 100644
--- a/third_party/blink/renderer/core/html/track/vtt/buffered_line_reader_test.cc
+++ b/third_party/blink/renderer/core/html/track/vtt/buffered_line_reader_test.cc
@@ -33,7 +33,6 @@
 #include "base/stl_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/input/fallback_cursor_event_manager.cc b/third_party/blink/renderer/core/input/fallback_cursor_event_manager.cc
index 2de24b1..64ab5bd 100644
--- a/third_party/blink/renderer/core/input/fallback_cursor_event_manager.cc
+++ b/third_party/blink/renderer/core/input/fallback_cursor_event_manager.cc
@@ -264,7 +264,8 @@
 
 void FallbackCursorEventManager::HandleMouseMoveEvent(const WebMouseEvent& e) {
   DCHECK(RuntimeEnabledFeatures::FallbackCursorModeEnabled());
-  DCHECK(is_fallback_cursor_mode_on_);
+  // TODO(crbug.com/953393): reenable after bug is fixed.
+  // DCHECK(is_fallback_cursor_mode_on_);
 
   InvalidateCurrentScrollableIfNeeded();
   ScrollableArea* scrollable = CurrentScrollingScrollableArea();
@@ -289,7 +290,8 @@
 
 void FallbackCursorEventManager::HandleMousePressEvent(const WebMouseEvent& e) {
   DCHECK(RuntimeEnabledFeatures::FallbackCursorModeEnabled());
-  DCHECK(is_fallback_cursor_mode_on_);
+  // TODO(crbug.com/953393): reenable after bug is fixed.
+  // DCHECK(is_fallback_cursor_mode_on_);
 
   ResetCurrentScrollable();
 
diff --git a/third_party/blink/renderer/core/inspector/dom_patch_support.cc b/third_party/blink/renderer/core/inspector/dom_patch_support.cc
index 110f2a1..49384b0f 100644
--- a/third_party/blink/renderer/core/inspector/dom_patch_support.cc
+++ b/third_party/blink/renderer/core/inspector/dom_patch_support.cc
@@ -53,7 +53,6 @@
 #include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
 #include "third_party/blink/renderer/platform/wtf/text/base64.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/inspector/inspect_tools.cc b/third_party/blink/renderer/core/inspector/inspect_tools.cc
index 3a858776..9ce7f0ab 100644
--- a/third_party/blink/renderer/core/inspector/inspect_tools.cc
+++ b/third_party/blink/renderer/core/inspector/inspect_tools.cc
@@ -344,8 +344,8 @@
 
 // NearbyDistanceTool ----------------------------------------------------------
 
-CString NearbyDistanceTool::GetDataResourceName() {
-  return "inspect_tool_distances.html";
+std::string NearbyDistanceTool::GetDataResourceName() {
+  return std::string("inspect_tool_distances.html");
 }
 
 bool NearbyDistanceTool::HandleMouseDown(const WebMouseEvent& event,
@@ -414,8 +414,8 @@
   overlay_->EvaluateInOverlay("drawViewSize", "");
 }
 
-CString ShowViewSizeTool::GetDataResourceName() {
-  return "inspect_tool_viewport_size.html";
+std::string ShowViewSizeTool::GetDataResourceName() {
+  return std::string("inspect_tool_viewport_size.html");
 }
 
 bool ShowViewSizeTool::ForwardEventsToOverlay() {
@@ -431,8 +431,8 @@
   client.SetCursorOverridden(true);
 }
 
-CString ScreenshotTool::GetDataResourceName() {
-  return "inspect_tool_screenshot.html";
+std::string ScreenshotTool::GetDataResourceName() {
+  return std::string("inspect_tool_screenshot.html");
 }
 
 void ScreenshotTool::Dispatch(const String& message) {
@@ -501,8 +501,8 @@
 
 // PausedInDebuggerTool --------------------------------------------------------
 
-CString PausedInDebuggerTool::GetDataResourceName() {
-  return "inspect_tool_paused.html";
+std::string PausedInDebuggerTool::GetDataResourceName() {
+  return std::string("inspect_tool_paused.html");
 }
 
 void PausedInDebuggerTool::Draw(float scale) {
diff --git a/third_party/blink/renderer/core/inspector/inspect_tools.h b/third_party/blink/renderer/core/inspector/inspect_tools.h
index 2bc42c5..755bca3 100644
--- a/third_party/blink/renderer/core/inspector/inspect_tools.h
+++ b/third_party/blink/renderer/core/inspector/inspect_tools.h
@@ -95,7 +95,7 @@
   NearbyDistanceTool() = default;
 
  private:
-  CString GetDataResourceName() override;
+  std::string GetDataResourceName() override;
   bool HandleMouseDown(const WebMouseEvent& event,
                        bool* swallow_next_mouse_up) override;
   bool HandleMouseMove(const WebMouseEvent& event) override;
@@ -115,7 +115,7 @@
 
  private:
   bool ForwardEventsToOverlay() override;
-  CString GetDataResourceName() override;
+  std::string GetDataResourceName() override;
   void Draw(float scale) override;
   DISALLOW_COPY_AND_ASSIGN(ShowViewSizeTool);
 };
@@ -127,7 +127,7 @@
   ScreenshotTool() = default;
 
  private:
-  CString GetDataResourceName() override;
+  std::string GetDataResourceName() override;
   void DoInit() override;
   void Dispatch(const String& message) override;
 
@@ -143,7 +143,7 @@
       : v8_session_(v8_session), message_(message) {}
 
  private:
-  CString GetDataResourceName() override;
+  std::string GetDataResourceName() override;
   void Draw(float scale) override;
   void Dispatch(const String& message) override;
   v8_inspector::V8InspectorSession* v8_session_;
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
index 75570e8..f59dd57e 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
@@ -95,7 +95,6 @@
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/text/text_run.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_concatenate.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
index ae49f3f5..969717e 100644
--- a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
@@ -85,7 +85,6 @@
 #include "third_party/blink/renderer/core/xml/xpath_result.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
index 70a371f..730c152f 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
@@ -114,8 +114,8 @@
   DoInit();
 }
 
-CString InspectTool::GetDataResourceName() {
-  return "inspect_tool_highlight.html";
+std::string InspectTool::GetDataResourceName() {
+  return std::string("inspect_tool_highlight.html");
 }
 
 bool InspectTool::HandleInputEvent(LocalFrameView* frame_view,
@@ -409,7 +409,7 @@
   resize_timer_.Stop();
   resize_timer_active_ = false;
   frame_overlay_.reset();
-  frame_resource_name_ = CString();
+  frame_resource_name_ = std::string();
   PickTheRightTool();
   SetNeedsUnbufferedInput(false);
   return Response::OK();
@@ -899,7 +899,7 @@
   data->Append(Platform::Current()->GetDataResource("inspect_tool_common.js"));
   data->Append("</script>", static_cast<size_t>(9));
   data->Append(
-      Platform::Current()->GetDataResource(frame_resource_name_.data()));
+      Platform::Current()->GetDataResource(frame_resource_name_.c_str()));
 
   frame->ForceSynchronousDocumentInstall("text/html", data);
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
index 8b987be..54c54e4 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
@@ -76,7 +76,7 @@
  public:
   virtual ~InspectTool() = default;
   void Init(InspectorOverlayAgent* overlay, OverlayFrontend* frontend);
-  virtual CString GetDataResourceName();
+  virtual std::string GetDataResourceName();
   virtual bool HandleInputEvent(LocalFrameView* frame_view,
                                 const WebInputEvent& input_event,
                                 bool* swallow_next_mouse_up);
@@ -215,7 +215,7 @@
   Member<WebLocalFrameImpl> frame_impl_;
   Member<InspectedFrames> inspected_frames_;
   Member<Page> overlay_page_;
-  CString frame_resource_name_;
+  std::string frame_resource_name_;
   Member<InspectorOverlayChromeClient> overlay_chrome_client_;
   Member<InspectorOverlayHost> overlay_host_;
   bool resize_timer_active_;
diff --git a/third_party/blink/renderer/core/layout/api/line_layout_inline.h b/third_party/blink/renderer/core/layout/api/line_layout_inline.h
index 5f705679..ab9d90c 100644
--- a/third_party/blink/renderer/core/layout/api/line_layout_inline.h
+++ b/third_party/blink/renderer/core/layout/api/line_layout_inline.h
@@ -66,9 +66,9 @@
   LineBoxList* LineBoxes() { return ToInline()->MutableLineBoxes(); }
 
   bool HitTestCulledInline(HitTestResult& result,
-                           const HitTestLocation& location_in_container,
+                           const HitTestLocation& hit_test_location,
                            const PhysicalOffset& accumulated_offset) {
-    return ToInline()->HitTestCulledInline(result, location_in_container,
+    return ToInline()->HitTestCulledInline(result, hit_test_location,
                                            accumulated_offset);
   }
 
diff --git a/third_party/blink/renderer/core/layout/api/line_layout_item.h b/third_party/blink/renderer/core/layout/api/line_layout_item.h
index 1ef5c956..9aa5bffa 100644
--- a/third_party/blink/renderer/core/layout/api/line_layout_item.h
+++ b/third_party/blink/renderer/core/layout/api/line_layout_item.h
@@ -234,9 +234,9 @@
   }
 
   bool HitTestAllPhases(HitTestResult& result,
-                        const HitTestLocation& location_in_container,
+                        const HitTestLocation& hit_test_location,
                         const PhysicalOffset& accumulated_offset) {
-    return layout_object_->HitTestAllPhases(result, location_in_container,
+    return layout_object_->HitTestAllPhases(result, hit_test_location,
                                             accumulated_offset);
   }
 
diff --git a/third_party/blink/renderer/core/layout/geometry/physical_rect.h b/third_party/blink/renderer/core/layout/geometry/physical_rect.h
index a5476da..18f0a8f 100644
--- a/third_party/blink/renderer/core/layout/geometry/physical_rect.h
+++ b/third_party/blink/renderer/core/layout/geometry/physical_rect.h
@@ -190,6 +190,14 @@
     return PhysicalRect(offset, size);
   }
 
+  // This is faster than EnclosingRect(). Can be used in situation that we
+  // prefer performance to accuracy and haven't observed problems caused by the
+  // tiny error (< LayoutUnit::Epsilon()).
+  static PhysicalRect FastAndLossyFromFloatRect(const FloatRect& rect) {
+    return PhysicalRect(LayoutUnit(rect.X()), LayoutUnit(rect.Y()),
+                        LayoutUnit(rect.Width()), LayoutUnit(rect.Height()));
+  }
+
   explicit PhysicalRect(const IntRect& r)
       : offset(r.Location()), size(r.Size()) {}
 
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index 4febfcd..259148f 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -1203,34 +1203,33 @@
 
 bool LayoutBlock::IsPointInOverflowControl(
     HitTestResult& result,
-    const PhysicalOffset& location_in_container,
+    const PhysicalOffset& hit_test_location,
     const PhysicalOffset& accumulated_offset) const {
   if (!ScrollsOverflow())
     return false;
 
   return Layer()->GetScrollableArea()->HitTestOverflowControls(
-      result, RoundedIntPoint(location_in_container - accumulated_offset));
+      result, RoundedIntPoint(hit_test_location - accumulated_offset));
 }
 
 bool LayoutBlock::HitTestOverflowControl(
     HitTestResult& result,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& adjusted_location) {
   if (VisibleToHitTestRequest(result.GetHitTestRequest()) &&
-      IsPointInOverflowControl(result, location_in_container.Point(),
+      IsPointInOverflowControl(result, hit_test_location.Point(),
                                adjusted_location)) {
-    UpdateHitTestResult(result,
-                        location_in_container.Point() - adjusted_location);
+    UpdateHitTestResult(result, hit_test_location.Point() - adjusted_location);
     // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet.
     if (result.AddNodeToListBasedTestResult(
-            NodeForHitTest(), location_in_container) == kStopHitTesting)
+            NodeForHitTest(), hit_test_location) == kStopHitTesting)
       return true;
   }
   return false;
 }
 
 bool LayoutBlock::HitTestChildren(HitTestResult& result,
-                                  const HitTestLocation& location_in_container,
+                                  const HitTestLocation& hit_test_location,
                                   const PhysicalOffset& accumulated_offset,
                                   HitTestAction hit_test_action) {
   // We may use legacy code to hit-test the anonymous fieldset content wrapper
@@ -1252,21 +1251,23 @@
         (may_contain_rendered_legend && child->IsRenderedLegend()))
       continue;
 
+    PhysicalOffset child_accumulated_offset =
+        scrolled_offset + child->PhysicalLocation(this);
     bool did_hit;
     if (child->IsFloating()) {
       if (hit_test_action != kHitTestFloat || !IsLayoutNGObject())
         continue;
       // Hit-test the floats in regular tree order if this is LayoutNG. Only
       // legacy layout uses the FloatingObjects list.
-      did_hit = child->HitTestAllPhases(result, location_in_container,
-                                        scrolled_offset);
+      did_hit = child->HitTestAllPhases(result, hit_test_location,
+                                        child_accumulated_offset);
     } else {
-      did_hit = child->NodeAtPoint(result, location_in_container,
-                                   scrolled_offset, child_hit_test);
+      did_hit = child->NodeAtPoint(result, hit_test_location,
+                                   child_accumulated_offset, child_hit_test);
     }
     if (did_hit) {
       UpdateHitTestResult(result,
-                          location_in_container.Point() - accumulated_offset);
+                          hit_test_location.Point() - accumulated_offset);
       return true;
     }
   }
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h
index a549156..824aa9b6 100644
--- a/third_party/blink/renderer/core/layout/layout_block.h
+++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -427,7 +427,7 @@
                               const HitTestLocation&,
                               const PhysicalOffset& adjusted_location) override;
   bool HitTestChildren(HitTestResult&,
-                       const HitTestLocation& location_in_container,
+                       const HitTestLocation&,
                        const PhysicalOffset& accumulated_offset,
                        HitTestAction) override;
 
@@ -500,7 +500,7 @@
   bool TryLayoutDoingPositionedMovementOnly();
 
   bool IsPointInOverflowControl(HitTestResult&,
-                                const PhysicalOffset& location_in_container,
+                                const PhysicalOffset&,
                                 const PhysicalOffset& accumulated_offset) const;
 
   void ComputeBlockPreferredLogicalWidths(LayoutUnit& min_logical_width,
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index cf996c0..eebd6d4 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -4189,11 +4189,10 @@
                                         : LayoutBlock::NodeForHitTest();
 }
 
-bool LayoutBlockFlow::HitTestChildren(
-    HitTestResult& result,
-    const HitTestLocation& location_in_container,
-    const PhysicalOffset& accumulated_offset,
-    HitTestAction hit_test_action) {
+bool LayoutBlockFlow::HitTestChildren(HitTestResult& result,
+                                      const HitTestLocation& hit_test_location,
+                                      const PhysicalOffset& accumulated_offset,
+                                      HitTestAction hit_test_action) {
   PhysicalOffset scrolled_offset = accumulated_offset;
   if (HasOverflowClip())
     scrolled_offset -= PhysicalOffset(ScrolledContentOffset());
@@ -4202,19 +4201,18 @@
     // Hit-test the floats using the FloatingObjects list if we're in legacy
     // layout. LayoutNG, on the other hand, just hit-tests floats in regular
     // tree order.
-    if (HitTestFloats(result, location_in_container, scrolled_offset))
+    if (HitTestFloats(result, hit_test_location, scrolled_offset))
       return true;
   }
 
   if (ChildrenInline()) {
-    if (line_boxes_.HitTest(LineLayoutBoxModel(this), result,
-                            location_in_container, scrolled_offset,
-                            hit_test_action)) {
+    if (line_boxes_.HitTest(LineLayoutBoxModel(this), result, hit_test_location,
+                            scrolled_offset, hit_test_action)) {
       UpdateHitTestResult(result,
-                          location_in_container.Point() - accumulated_offset);
+                          hit_test_location.Point() - accumulated_offset);
       return true;
     }
-  } else if (LayoutBlock::HitTestChildren(result, location_in_container,
+  } else if (LayoutBlock::HitTestChildren(result, hit_test_location,
                                           accumulated_offset,
                                           hit_test_action)) {
     return true;
@@ -4223,10 +4221,9 @@
   return false;
 }
 
-bool LayoutBlockFlow::HitTestFloats(
-    HitTestResult& result,
-    const HitTestLocation& location_in_container,
-    const PhysicalOffset& accumulated_offset) {
+bool LayoutBlockFlow::HitTestFloats(HitTestResult& result,
+                                    const HitTestLocation& hit_test_location,
+                                    const PhysicalOffset& accumulated_offset) {
   if (!floating_objects_)
     return false;
 
@@ -4238,15 +4235,16 @@
     if (floating_object.ShouldPaint() &&
         // TODO(wangxianzhu): Should this be a DCHECK?
         !floating_object.GetLayoutObject()->HasSelfPaintingLayer()) {
-      PhysicalOffset child_point = accumulated_offset;
-      child_point +=
+      PhysicalOffset child_accumulated_offset = accumulated_offset;
+      child_accumulated_offset +=
           PhysicalOffset(XPositionForFloatIncludingMargin(floating_object),
                          YPositionForFloatIncludingMargin(floating_object));
-      child_point -= floating_object.GetLayoutObject()->PhysicalLocation();
       if (floating_object.GetLayoutObject()->HitTestAllPhases(
-              result, location_in_container, child_point)) {
-        UpdateHitTestResult(result,
-                            location_in_container.Point() - child_point);
+              result, hit_test_location, child_accumulated_offset)) {
+        PhysicalOffset result_offset =
+            child_accumulated_offset -
+            floating_object.GetLayoutObject()->PhysicalLocation();
+        UpdateHitTestResult(result, hit_test_location.Point() - result_offset);
         return true;
       }
     }
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h
index 9ae466b..c18351a 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -532,7 +532,7 @@
 
   Node* NodeForHitTest() const final;
   bool HitTestChildren(HitTestResult&,
-                       const HitTestLocation& location_in_container,
+                       const HitTestLocation&,
                        const PhysicalOffset& accumulated_offset,
                        HitTestAction) override;
 
@@ -581,7 +581,7 @@
                             bool make_child_paint_other_floats);
 
   bool HitTestFloats(HitTestResult&,
-                     const HitTestLocation& location_in_container,
+                     const HitTestLocation&,
                      const PhysicalOffset& accumulated_offset);
 
   void ClearFloats(EClear);
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 8588667..e28e351 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -1584,7 +1584,7 @@
 
 // Hit Testing
 bool LayoutBox::HitTestAllPhases(HitTestResult& result,
-                                 const HitTestLocation& location_in_container,
+                                 const HitTestLocation& hit_test_location,
                                  const PhysicalOffset& accumulated_offset,
                                  HitTestFilter hit_test_filter) {
   // Check if we need to do anything at all.
@@ -1602,24 +1602,22 @@
     }
 
     PhysicalRect adjusted_overflow_box = overflow_box;
-    adjusted_overflow_box.Move(accumulated_offset + PhysicalLocation());
-    if (!location_in_container.Intersects(adjusted_overflow_box))
+    adjusted_overflow_box.Move(accumulated_offset);
+    if (!hit_test_location.Intersects(adjusted_overflow_box))
       return false;
   }
-  return LayoutObject::HitTestAllPhases(result, location_in_container,
+  return LayoutObject::HitTestAllPhases(result, hit_test_location,
                                         accumulated_offset, hit_test_filter);
 }
 
 bool LayoutBox::NodeAtPoint(HitTestResult& result,
-                            const HitTestLocation& location_in_container,
+                            const HitTestLocation& hit_test_location,
                             const PhysicalOffset& accumulated_offset,
                             HitTestAction action) {
-  PhysicalOffset adjusted_location = accumulated_offset + PhysicalLocation();
-
   bool should_hit_test_self = IsInSelfHitTestingPhase(action);
 
   if (should_hit_test_self && HasOverflowClip() &&
-      HitTestOverflowControl(result, location_in_container, adjusted_location))
+      HitTestOverflowControl(result, hit_test_location, accumulated_offset))
     return true;
 
   bool skip_children = (result.GetHitTestRequest().GetStopNode() == this);
@@ -1628,24 +1626,24 @@
     // foreground rect for intersection if a layer is self painting,
     // so only do the overflow clip check here for non-self-painting layers.
     if (!HasSelfPaintingLayer() &&
-        !location_in_container.Intersects(OverflowClipRect(
-            adjusted_location, kExcludeOverlayScrollbarSizeForHitTesting))) {
+        !hit_test_location.Intersects(OverflowClipRect(
+            accumulated_offset, kExcludeOverlayScrollbarSizeForHitTesting))) {
       skip_children = true;
     }
     if (!skip_children && StyleRef().HasBorderRadius()) {
-      PhysicalRect bounds_rect(adjusted_location, Size());
-      skip_children = !location_in_container.Intersects(
+      PhysicalRect bounds_rect(accumulated_offset, Size());
+      skip_children = !hit_test_location.Intersects(
           StyleRef().GetRoundedInnerBorderFor(bounds_rect.ToLayoutRect()));
     }
   }
 
-  if (!skip_children && HitTestChildren(result, location_in_container,
-                                        adjusted_location, action)) {
+  if (!skip_children &&
+      HitTestChildren(result, hit_test_location, accumulated_offset, action)) {
     return true;
   }
 
   if (StyleRef().HasBorderRadius() &&
-      HitTestClippedOutByBorder(location_in_container, adjusted_location))
+      HitTestClippedOutByBorder(hit_test_location, accumulated_offset))
     return false;
 
   // Now hit test ourselves.
@@ -1658,12 +1656,12 @@
     } else {
       bounds_rect = PhysicalBorderBoxRect();
     }
-    bounds_rect.Move(adjusted_location);
-    if (location_in_container.Intersects(bounds_rect)) {
+    bounds_rect.Move(accumulated_offset);
+    if (hit_test_location.Intersects(bounds_rect)) {
       UpdateHitTestResult(result,
-                          location_in_container.Point() - adjusted_location);
+                          hit_test_location.Point() - accumulated_offset);
       if (result.AddNodeToListBasedTestResult(NodeForHitTest(),
-                                              location_in_container,
+                                              hit_test_location,
                                               bounds_rect) == kStopHitTesting)
         return true;
     }
@@ -1673,14 +1671,20 @@
 }
 
 bool LayoutBox::HitTestChildren(HitTestResult& result,
-                                const HitTestLocation& location_in_container,
+                                const HitTestLocation& hit_test_location,
                                 const PhysicalOffset& accumulated_offset,
                                 HitTestAction action) {
   for (LayoutObject* child = SlowLastChild(); child;
        child = child->PreviousSibling()) {
-    if ((!child->HasLayer() ||
-         !ToLayoutBoxModelObject(child)->Layer()->IsSelfPaintingLayer()) &&
-        child->NodeAtPoint(result, location_in_container, accumulated_offset,
+    if (child->HasLayer() &&
+        ToLayoutBoxModelObject(child)->Layer()->IsSelfPaintingLayer())
+      continue;
+
+    PhysicalOffset child_accumulated_offset = accumulated_offset;
+    if (child->IsBox())
+      child_accumulated_offset += ToLayoutBox(child)->PhysicalLocation(this);
+
+    if (child->NodeAtPoint(result, hit_test_location, child_accumulated_offset,
                            action))
       return true;
   }
@@ -1689,11 +1693,11 @@
 }
 
 bool LayoutBox::HitTestClippedOutByBorder(
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& border_box_location) const {
   PhysicalRect border_rect = PhysicalBorderBoxRect();
   border_rect.Move(border_box_location);
-  return !location_in_container.Intersects(
+  return !hit_test_location.Intersects(
       StyleRef().GetRoundedBorderFor(border_rect.ToLayoutRect()));
 }
 
@@ -5889,25 +5893,6 @@
   return ToLayoutBox(container);
 }
 
-PhysicalOffset LayoutBox::PhysicalLocation(
-    const LayoutBox* flipped_blocks_container) const {
-  const LayoutBox* container_box;
-  if (flipped_blocks_container) {
-    DCHECK_EQ(flipped_blocks_container, LocationContainer());
-    container_box = flipped_blocks_container;
-  } else {
-    container_box = LocationContainer();
-  }
-  if (!container_box || !container_box->HasFlippedBlocksWritingMode())
-    return PhysicalOffset(Location());
-
-  // The child is going to add in its x(), so we have to make sure it ends up in
-  // the right place.
-  return PhysicalOffset(
-      container_box->Size().Width() - Size().Width() - Location().X(),
-      Location().Y());
-}
-
 bool LayoutBox::HasRelativeLogicalWidth() const {
   return StyleRef().LogicalWidth().IsPercentOrCalc() ||
          StyleRef().LogicalMinWidth().IsPercentOrCalc() ||
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 8f02ac4..a735a69 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -768,11 +768,11 @@
   }
 
   bool HitTestAllPhases(HitTestResult&,
-                        const HitTestLocation& location_in_container,
+                        const HitTestLocation&,
                         const PhysicalOffset& accumulated_offset,
                         HitTestFilter = kHitTestAll) final;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
@@ -1331,7 +1331,11 @@
   // Passing |flipped_blocks_container| causes flipped-block flipping w.r.t.
   // that container, or LocationContainer() otherwise.
   PhysicalOffset PhysicalLocation(
-      const LayoutBox* flipped_blocks_container = nullptr) const;
+      const LayoutBox* flipped_blocks_container = nullptr) const {
+    return PhysicalLocationInternal(flipped_blocks_container
+                                        ? flipped_blocks_container
+                                        : LocationContainer());
+  }
 
   // Convert a local rect in this box's blocks direction into parent's blocks
   // direction, for parent to accumulate layout or visual overflow.
@@ -1461,7 +1465,7 @@
   void ClearCustomLayoutChild();
 
   bool HitTestClippedOutByBorder(
-      const HitTestLocation& location_in_container,
+      const HitTestLocation&,
       const PhysicalOffset& border_box_location) const;
 
   // Returns true if the box intersects the viewport visible to the user.
@@ -1614,7 +1618,7 @@
     return false;
   }
   virtual bool HitTestChildren(HitTestResult&,
-                               const HitTestLocation& location_in_container,
+                               const HitTestLocation&,
                                const PhysicalOffset& accumulated_offset,
                                HitTestAction);
 
@@ -1778,6 +1782,17 @@
     return FlipForWritingMode(position, width);
   }
 
+  PhysicalOffset PhysicalLocationInternal(
+      const LayoutBox* container_box) const {
+    DCHECK_EQ(container_box, LocationContainer());
+    if (LIKELY(!container_box || !container_box->HasFlippedBlocksWritingMode()))
+      return PhysicalOffset(Location());
+
+    return PhysicalOffset(
+        container_box->Size().Width() - Size().Width() - Location().X(),
+        Location().Y());
+  }
+
   // The CSS border box rect for this box.
   //
   // The rectangle is in LocationContainer's physical coordinates in flipped
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.cc b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
index 4f8c294b..312eca4 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_content.cc
+++ b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
@@ -140,16 +140,16 @@
 
 bool LayoutEmbeddedContent::NodeAtPointOverEmbeddedContentView(
     HitTestResult& result,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     HitTestAction action) {
   bool had_result = result.InnerNode();
-  bool inside = LayoutReplaced::NodeAtPoint(result, location_in_container,
+  bool inside = LayoutReplaced::NodeAtPoint(result, hit_test_location,
                                             accumulated_offset, action);
 
   // Check to see if we are really over the EmbeddedContentView itself (and not
   // just in the border/padding area).
-  if ((inside || location_in_container.IsRectBasedTest()) && !had_result &&
+  if ((inside || hit_test_location.IsRectBasedTest()) && !had_result &&
       result.InnerNode() == GetNode()) {
     result.SetIsOverEmbeddedContentView(
         PhysicalContentBoxRect().Contains(result.LocalPoint()));
@@ -159,14 +159,14 @@
 
 bool LayoutEmbeddedContent::NodeAtPoint(
     HitTestResult& result,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     HitTestAction action) {
   auto* local_frame_view = DynamicTo<LocalFrameView>(ChildFrameView());
   bool skip_contents = (result.GetHitTestRequest().GetStopNode() == this ||
                         !result.GetHitTestRequest().AllowsChildFrameContent());
   if (!local_frame_view || skip_contents) {
-    return NodeAtPointOverEmbeddedContentView(result, location_in_container,
+    return NodeAtPointOverEmbeddedContentView(result, hit_test_location,
                                               accumulated_offset, action);
   }
 
@@ -179,7 +179,7 @@
       !local_frame_view->GetFrame().GetDocument() ||
       local_frame_view->GetFrame().GetDocument()->Lifecycle().GetState() <
           DocumentLifecycle::kCompositingClean) {
-    return NodeAtPointOverEmbeddedContentView(result, location_in_container,
+    return NodeAtPointOverEmbeddedContentView(result, hit_test_location,
                                               accumulated_offset, action);
   }
 
@@ -191,12 +191,10 @@
 
     if (VisibleToHitTestRequest(result.GetHitTestRequest()) &&
         child_layout_view) {
-      PhysicalOffset adjusted_location =
-          accumulated_offset + PhysicalLocation();
       PhysicalOffset content_offset(BorderLeft() + PaddingLeft(),
                                     BorderTop() + PaddingTop());
       HitTestLocation new_hit_test_location(
-          location_in_container, -adjusted_location - content_offset);
+          hit_test_location, -accumulated_offset - content_offset);
       HitTestRequest new_hit_test_request(
           result.GetHitTestRequest().GetType() |
               HitTestRequest::kChildFrameHitTest,
@@ -225,12 +223,12 @@
       // iframe element itself if the hit-test rect is totally within the
       // iframe.
       if (is_inside_child_frame) {
-        if (!location_in_container.IsRectBasedTest())
+        if (!hit_test_location.IsRectBasedTest())
           return true;
         HitTestResult point_over_embedded_content_view_result = result;
         bool point_over_embedded_content_view =
             NodeAtPointOverEmbeddedContentView(
-                point_over_embedded_content_view_result, location_in_container,
+                point_over_embedded_content_view_result, hit_test_location,
                 accumulated_offset, action);
         if (point_over_embedded_content_view)
           return true;
@@ -240,7 +238,7 @@
     }
   }
 
-  return NodeAtPointOverEmbeddedContentView(result, location_in_container,
+  return NodeAtPointOverEmbeddedContentView(result, hit_test_location,
                                             accumulated_offset, action);
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.h b/third_party/blink/renderer/core/layout/layout_embedded_content.h
index 57bab2f..1869147 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_content.h
+++ b/third_party/blink/renderer/core/layout/layout_embedded_content.h
@@ -42,7 +42,7 @@
   bool RequiresAcceleratedCompositing() const;
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
@@ -86,7 +86,7 @@
 
   bool NodeAtPointOverEmbeddedContentView(
       HitTestResult&,
-      const HitTestLocation& location_in_container,
+      const HitTestLocation&,
       const PhysicalOffset& accumulated_offset,
       HitTestAction);
 
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 88927931..397c35b4 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -283,7 +283,7 @@
 
 bool LayoutFlexibleBox::HitTestChildren(
     HitTestResult& result,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     HitTestAction hit_test_action) {
   if (hit_test_action != kHitTestForeground)
@@ -298,11 +298,13 @@
     if (child->HasSelfPaintingLayer())
       continue;
 
-    bool child_hit =
-        child->HitTestAllPhases(result, location_in_container, scrolled_offset);
+    PhysicalOffset child_accumulated_offset =
+        scrolled_offset + child->PhysicalLocation(this);
+    bool child_hit = child->HitTestAllPhases(result, hit_test_location,
+                                             child_accumulated_offset);
     if (child_hit) {
       UpdateHitTestResult(result,
-                          location_in_container.Point() - accumulated_offset);
+                          hit_test_location.Point() - accumulated_offset);
       return true;
     }
   }
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 5bd017e..157d375 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.h
@@ -104,7 +104,7 @@
       LayoutUnit& max_logical_width) const override;
 
   bool HitTestChildren(HitTestResult&,
-                       const HitTestLocation& location_in_container,
+                       const HitTestLocation&,
                        const PhysicalOffset& accumulated_offset,
                        HitTestAction) override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_flow_thread.cc b/third_party/blink/renderer/core/layout/layout_flow_thread.cc
index 2b32aac3..118511a 100644
--- a/third_party/blink/renderer/core/layout/layout_flow_thread.cc
+++ b/third_party/blink/renderer/core/layout/layout_flow_thread.cc
@@ -179,12 +179,12 @@
 }
 
 bool LayoutFlowThread::NodeAtPoint(HitTestResult& result,
-                                   const HitTestLocation& location_in_container,
+                                   const HitTestLocation& hit_test_location,
                                    const PhysicalOffset& accumulated_offset,
                                    HitTestAction hit_test_action) {
   if (hit_test_action == kHitTestBlockBackground)
     return false;
-  return LayoutBlockFlow::NodeAtPoint(result, location_in_container,
+  return LayoutBlockFlow::NodeAtPoint(result, hit_test_location,
                                       accumulated_offset, hit_test_action);
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_flow_thread.h b/third_party/blink/renderer/core/layout/layout_flow_thread.h
index dd5ae74..a574018 100644
--- a/third_party/blink/renderer/core/layout/layout_flow_thread.h
+++ b/third_party/blink/renderer/core/layout/layout_flow_thread.h
@@ -125,7 +125,7 @@
                        NGOutlineType) const override;
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) final;
 
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc
index e7746d07..8e2bda7 100644
--- a/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -293,12 +293,12 @@
 }
 
 bool LayoutImage::NodeAtPoint(HitTestResult& result,
-                              const HitTestLocation& location_in_container,
+                              const HitTestLocation& hit_test_location,
                               const PhysicalOffset& accumulated_offset,
                               HitTestAction hit_test_action) {
   HitTestResult temp_result(result);
   bool inside = LayoutReplaced::NodeAtPoint(
-      temp_result, location_in_container, accumulated_offset, hit_test_action);
+      temp_result, hit_test_location, accumulated_offset, hit_test_action);
 
   if (!inside && result.GetHitTestRequest().ListBased())
     result.Append(temp_result);
diff --git a/third_party/blink/renderer/core/layout/layout_image.h b/third_party/blink/renderer/core/layout/layout_image.h
index 3c33ab25..f934265 100644
--- a/third_party/blink/renderer/core/layout/layout_image.h
+++ b/third_party/blink/renderer/core/layout/layout_image.h
@@ -125,7 +125,7 @@
 
   void ImageNotifyFinished(ImageResourceContent*) final;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) final;
 
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index bf04a3df..dbb4096 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -1018,7 +1018,7 @@
 }
 
 bool LayoutInline::NodeAtPoint(HitTestResult& result,
-                               const HitTestLocation& location_in_container,
+                               const HitTestLocation& hit_test_location,
                                const PhysicalOffset& accumulated_offset,
                                HitTestAction hit_test_action) {
   if (ContainingNGBlockFlow()) {
@@ -1037,28 +1037,27 @@
       PhysicalOffset adjusted_location =
           accumulated_offset + fragment->InlineOffsetToContainerBox();
       if (NGBoxFragmentPainter(*fragment).NodeAtPoint(
-              result, location_in_container, adjusted_location,
-              hit_test_action))
+              result, hit_test_location, adjusted_location, hit_test_action))
         return true;
     }
     return false;
   }
 
   return LineBoxes()->HitTest(LineLayoutBoxModel(this), result,
-                              location_in_container, accumulated_offset,
+                              hit_test_location, accumulated_offset,
                               hit_test_action);
 }
 
 bool LayoutInline::HitTestCulledInline(
     HitTestResult& result,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     const NGPaintFragment* container_fragment) {
   DCHECK(container_fragment || !AlwaysCreateLineBoxes());
   if (!VisibleToHitTestRequest(result.GetHitTestRequest()))
     return false;
 
-  HitTestLocation adjusted_location(location_in_container, -accumulated_offset);
+  HitTestLocation adjusted_location(hit_test_location, -accumulated_offset);
   Region region_result;
   bool intersected = false;
   auto yield = [&adjusted_location, &region_result,
diff --git a/third_party/blink/renderer/core/layout/layout_inline.h b/third_party/blink/renderer/core/layout/layout_inline.h
index 2219dc13..565b0f42 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.h
+++ b/third_party/blink/renderer/core/layout/layout_inline.h
@@ -233,7 +233,7 @@
   // rects to be from descendant fragments of |parent_fragment|.
   // In legacy, |parent_fragment| is always null, and all rects are regenerated.
   bool HitTestCulledInline(HitTestResult&,
-                           const HitTestLocation& location_in_container,
+                           const HitTestLocation&,
                            const PhysicalOffset& accumulated_offset,
                            const NGPaintFragment* parent_fragment = nullptr);
 
@@ -332,7 +332,7 @@
   void Paint(const PaintInfo&) const final;
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) final;
 
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
index fbce94a..13220f6d 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
@@ -167,12 +167,12 @@
 
 bool LayoutMultiColumnSpannerPlaceholder::NodeAtPoint(
     HitTestResult& result,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     HitTestAction action) {
   return !layout_object_in_flow_thread_->HasSelfPaintingLayer() &&
-         layout_object_in_flow_thread_->NodeAtPoint(
-             result, location_in_container, accumulated_offset, action);
+         layout_object_in_flow_thread_->NodeAtPoint(result, hit_test_location,
+                                                    accumulated_offset, action);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
index e1e0bf2..c4018fb 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
@@ -68,7 +68,7 @@
                             LogicalExtentComputedValues&) const override;
   void Paint(const PaintInfo&) const override;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 254caa0..bf1e8f32 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -926,9 +926,8 @@
     // parent. Therefore, we must mark parent chain for layout.
     if (layout_box->GetCachedLayoutResult() &&
         layout_box->GetCachedLayoutResult()
-                ->PhysicalFragment()
-                .OutOfFlowPositionedDescendants()
-                .size() > 0)
+            ->PhysicalFragment()
+            .HasOutOfFlowPositionedDescendants())
       return false;
   }
 
@@ -3288,32 +3287,31 @@
   return CompositingReason::kNone;
 }
 
-bool LayoutObject::HitTestAllPhases(
-    HitTestResult& result,
-    const HitTestLocation& location_in_container,
-    const PhysicalOffset& accumulated_offset,
-    HitTestFilter hit_test_filter) {
+bool LayoutObject::HitTestAllPhases(HitTestResult& result,
+                                    const HitTestLocation& hit_test_location,
+                                    const PhysicalOffset& accumulated_offset,
+                                    HitTestFilter hit_test_filter) {
   bool inside = false;
   if (hit_test_filter != kHitTestSelf) {
     // First test the foreground layer (lines and inlines).
-    inside = NodeAtPoint(result, location_in_container, accumulated_offset,
+    inside = NodeAtPoint(result, hit_test_location, accumulated_offset,
                          kHitTestForeground);
 
     // Test floats next.
     if (!inside)
-      inside = NodeAtPoint(result, location_in_container, accumulated_offset,
+      inside = NodeAtPoint(result, hit_test_location, accumulated_offset,
                            kHitTestFloat);
 
     // Finally test to see if the mouse is in the background (within a child
     // block's background).
     if (!inside)
-      inside = NodeAtPoint(result, location_in_container, accumulated_offset,
+      inside = NodeAtPoint(result, hit_test_location, accumulated_offset,
                            kHitTestChildBlockBackgrounds);
   }
 
   // See if the mouse is inside us but not any of our descendants
   if (hit_test_filter != kHitTestDescendants && !inside)
-    inside = NodeAtPoint(result, location_in_container, accumulated_offset,
+    inside = NodeAtPoint(result, hit_test_location, accumulated_offset,
                          kHitTestBlockBackground);
 
   return inside;
@@ -3343,8 +3341,8 @@
 }
 
 bool LayoutObject::NodeAtPoint(HitTestResult&,
-                               const HitTestLocation& /*locationInContainer*/,
-                               const PhysicalOffset& /*accumulatedOffset*/,
+                               const HitTestLocation&,
+                               const PhysicalOffset&,
                                HitTestAction) {
   return false;
 }
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index c812777a..9595ab2 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -1441,13 +1441,16 @@
   CompositingState GetCompositingState() const;
   virtual CompositingReasons AdditionalCompositingReasons() const;
 
-  // |accumulated_offset| is accumulated physical offset from the same origin as
-  // |location_in_container|, not including the offset of the current object.
-  // The caller just ensures |location_in_container| and |accumulated_offset|
-  // are in the same coordinate space. The implementation should not assume any
-  // specific coordinate space of them.
+  // |accumulated_offset| is accumulated physical offset of this object from
+  // the same origin as |hit_test_location|. The caller just ensures that
+  // |hit_test_location| and |accumulated_offset| are in the same coordinate
+  // space that is transform-compatible with this object (i.e. we can add 2d
+  // local offset to it without considering transforms). The implementation
+  // should not assume any specific coordinate space of them. The local offset
+  // of |hit_test_location| in this object can be calculated by
+  // |hit_test_location.Point() - accumulated_offset|.
   virtual bool HitTestAllPhases(HitTestResult&,
-                                const HitTestLocation& location_in_container,
+                                const HitTestLocation& hit_test_location,
                                 const PhysicalOffset& accumulated_offset,
                                 HitTestFilter = kHitTestAll);
   // Returns the node that is ultimately added to the hit test result. Some
@@ -1456,9 +1459,10 @@
   // node be consistent between point- and list-based hit test results.
   virtual Node* NodeForHitTest() const;
   virtual void UpdateHitTestResult(HitTestResult&, const PhysicalOffset&) const;
-  // See HitTestAllPhases for explanation of |accumulated_offset|.
+  // See HitTestAllPhases() for explanation of |hit_test_location| and
+  // |accumulated_offset|.
   virtual bool NodeAtPoint(HitTestResult&,
-                           const HitTestLocation& location_in_container,
+                           const HitTestLocation& hit_test_location,
                            const PhysicalOffset& accumulated_offset,
                            HitTestAction);
 
diff --git a/third_party/blink/renderer/core/layout/layout_table.cc b/third_party/blink/renderer/core/layout/layout_table.cc
index 2b451f3..0a6a93a 100644
--- a/third_party/blink/renderer/core/layout/layout_table.cc
+++ b/third_party/blink/renderer/core/layout/layout_table.cc
@@ -1614,24 +1614,24 @@
 }
 
 bool LayoutTable::NodeAtPoint(HitTestResult& result,
-                              const HitTestLocation& location_in_container,
+                              const HitTestLocation& hit_test_location,
                               const PhysicalOffset& accumulated_offset,
                               HitTestAction action) {
-  PhysicalOffset adjusted_location = accumulated_offset + PhysicalLocation();
-
   // Check kids first.
   bool skip_children = (result.GetHitTestRequest().GetStopNode() == this);
   if (!skip_children &&
       (!HasOverflowClip() ||
-       location_in_container.Intersects(OverflowClipRect(adjusted_location)))) {
+       hit_test_location.Intersects(OverflowClipRect(accumulated_offset)))) {
     for (LayoutObject* child = LastChild(); child;
          child = child->PreviousSibling()) {
       if (child->IsBox() && !ToLayoutBox(child)->HasSelfPaintingLayer() &&
           (child->IsTableSection() || child->IsTableCaption())) {
-        if (child->NodeAtPoint(result, location_in_container, adjusted_location,
-                               action)) {
-          UpdateHitTestResult(
-              result, location_in_container.Point() - adjusted_location);
+        PhysicalOffset child_accumulated_offset =
+            accumulated_offset + ToLayoutBox(child)->PhysicalLocation(this);
+        if (child->NodeAtPoint(result, hit_test_location,
+                               child_accumulated_offset, action)) {
+          UpdateHitTestResult(result,
+                              hit_test_location.Point() - accumulated_offset);
           return true;
         }
       }
@@ -1639,14 +1639,13 @@
   }
 
   // Check our bounds next.
-  PhysicalRect bounds_rect(adjusted_location, Size());
+  PhysicalRect bounds_rect(accumulated_offset, Size());
   if (VisibleToHitTestRequest(result.GetHitTestRequest()) &&
       (action == kHitTestBlockBackground ||
        action == kHitTestChildBlockBackground) &&
-      location_in_container.Intersects(bounds_rect)) {
-    UpdateHitTestResult(result,
-                        location_in_container.Point() - adjusted_location);
-    if (result.AddNodeToListBasedTestResult(GetNode(), location_in_container,
+      hit_test_location.Intersects(bounds_rect)) {
+    UpdateHitTestResult(result, hit_test_location.Point() - accumulated_offset);
+    if (result.AddNodeToListBasedTestResult(GetNode(), hit_test_location,
                                             bounds_rect) == kStopHitTesting)
       return true;
   }
diff --git a/third_party/blink/renderer/core/layout/layout_table.h b/third_party/blink/renderer/core/layout/layout_table.h
index 845e4ac..1428eec 100644
--- a/third_party/blink/renderer/core/layout/layout_table.h
+++ b/third_party/blink/renderer/core/layout/layout_table.h
@@ -448,7 +448,7 @@
                                      LayoutUnit& max_width) const override;
   void ComputePreferredLogicalWidths() override;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_table_row.cc b/third_party/blink/renderer/core/layout/layout_table_row.cc
index 7e0641c2..82d9a23a 100644
--- a/third_party/blink/renderer/core/layout/layout_table_row.cc
+++ b/third_party/blink/renderer/core/layout/layout_table_row.cc
@@ -227,23 +227,26 @@
 
 // Hit Testing
 bool LayoutTableRow::NodeAtPoint(HitTestResult& result,
-                                 const HitTestLocation& location_in_container,
+                                 const HitTestLocation& hit_test_location,
                                  const PhysicalOffset& accumulated_offset,
                                  HitTestAction action) {
+  // The row and the cells are all located in the section.
+  const auto* section = Section();
+  PhysicalOffset section_accumulated_offset =
+      accumulated_offset - PhysicalLocation(section);
+
   // Table rows cannot ever be hit tested.  Effectively they do not exist.
   // Just forward to our children always.
   for (LayoutTableCell* cell = LastCell(); cell; cell = cell->PreviousCell()) {
-    // FIXME: We have to skip over inline flows, since they can show up inside
-    // table rows at the moment (a demoted inline <form> for example). If we
-    // ever implement a table-specific hit-test method (which we should do for
-    // performance reasons anyway), then we can remove this check.
-    if (!cell->HasSelfPaintingLayer()) {
-      if (cell->NodeAtPoint(result, location_in_container, accumulated_offset,
-                            action)) {
-        UpdateHitTestResult(result,
-                            location_in_container.Point() - accumulated_offset);
-        return true;
-      }
+    if (cell->HasSelfPaintingLayer())
+      continue;
+    PhysicalOffset cell_accumulated_offset =
+        section_accumulated_offset + cell->PhysicalLocation(section);
+    if (cell->NodeAtPoint(result, hit_test_location, cell_accumulated_offset,
+                          action)) {
+      UpdateHitTestResult(
+          result, hit_test_location.Point() - section_accumulated_offset);
+      return true;
     }
   }
 
diff --git a/third_party/blink/renderer/core/layout/layout_table_row.h b/third_party/blink/renderer/core/layout/layout_table_row.h
index b69b2f01..8be60231 100644
--- a/third_party/blink/renderer/core/layout/layout_table_row.h
+++ b/third_party/blink/renderer/core/layout/layout_table_row.h
@@ -100,7 +100,7 @@
   }
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_table_section.cc b/third_party/blink/renderer/core/layout/layout_table_section.cc
index f58f5756..fffb5b3 100644
--- a/third_party/blink/renderer/core/layout/layout_table_section.cc
+++ b/third_party/blink/renderer/core/layout/layout_table_section.cc
@@ -1786,36 +1786,29 @@
 }
 
 // Hit Testing
-bool LayoutTableSection::NodeAtPoint(
-    HitTestResult& result,
-    const HitTestLocation& location_in_container,
-    const PhysicalOffset& accumulated_offset,
-    HitTestAction action) {
+bool LayoutTableSection::NodeAtPoint(HitTestResult& result,
+                                     const HitTestLocation& hit_test_location,
+                                     const PhysicalOffset& accumulated_offset,
+                                     HitTestAction action) {
   // If we have no children then we have nothing to do.
   if (!FirstRow())
     return false;
 
+  DCHECK(!HasOverflowClip());
+
   // Table sections cannot ever be hit tested.  Effectively they do not exist.
   // Just forward to our children always.
-  PhysicalOffset adjusted_location = accumulated_offset + PhysicalLocation();
-
-  if (HasOverflowClip() &&
-      !location_in_container.Intersects(OverflowClipRect(adjusted_location)))
-    return false;
-
   if (HasVisuallyOverflowingCell()) {
     for (LayoutTableRow* row = LastRow(); row; row = row->PreviousRow()) {
-      // FIXME: We have to skip over inline flows, since they can show up inside
-      // table rows at the moment (a demoted inline <form> for example). If we
-      // ever implement a table-specific hit-test method (which we should do for
-      // performance reasons anyway), then we can remove this check.
-      if (!row->HasSelfPaintingLayer()) {
-        if (row->NodeAtPoint(result, location_in_container, adjusted_location,
-                             action)) {
-          UpdateHitTestResult(
-              result, location_in_container.Point() - adjusted_location);
-          return true;
-        }
+      if (row->HasSelfPaintingLayer())
+        continue;
+      PhysicalOffset row_accumulated_offset =
+          accumulated_offset + row->PhysicalLocation(this);
+      if (row->NodeAtPoint(result, hit_test_location, row_accumulated_offset,
+                           action)) {
+        UpdateHitTestResult(result,
+                            hit_test_location.Point() - accumulated_offset);
+        return true;
       }
     }
     return false;
@@ -1823,8 +1816,8 @@
 
   RecalcCellsIfNeeded();
 
-  PhysicalRect hit_test_rect = location_in_container.BoundingBox();
-  hit_test_rect.Move(-adjusted_location);
+  PhysicalRect hit_test_rect = hit_test_location.BoundingBox();
+  hit_test_rect.Move(-accumulated_offset);
 
   LayoutRect table_aligned_rect =
       LogicalRectForWritingModeAndDirection(hit_test_rect);
@@ -1846,10 +1839,12 @@
       for (unsigned i = grid_cell.Cells().size(); i;) {
         --i;
         LayoutTableCell* cell = grid_cell.Cells()[i];
+        PhysicalOffset cell_accumulated_offset =
+            accumulated_offset + cell->PhysicalLocation(this);
         if (static_cast<LayoutObject*>(cell)->NodeAtPoint(
-                result, location_in_container, adjusted_location, action)) {
-          UpdateHitTestResult(
-              result, location_in_container.Point() - adjusted_location);
+                result, hit_test_location, cell_accumulated_offset, action)) {
+          UpdateHitTestResult(result,
+                              hit_test_location.Point() - accumulated_offset);
           return true;
         }
       }
diff --git a/third_party/blink/renderer/core/layout/layout_table_section.h b/third_party/blink/renderer/core/layout/layout_table_section.h
index cf6bec0..2870e1e 100644
--- a/third_party/blink/renderer/core/layout/layout_table_section.h
+++ b/third_party/blink/renderer/core/layout/layout_table_section.h
@@ -296,7 +296,7 @@
  protected:
   void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_text_control.cc b/third_party/blink/renderer/core/layout/layout_text_control.cc
index 887c63c..05e17b9 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_control.cc
@@ -126,14 +126,13 @@
 
 void LayoutTextControl::HitInnerEditorElement(
     HitTestResult& result,
-    const PhysicalOffset& point_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset) {
   HTMLElement* inner_editor = InnerEditorElement();
   if (!inner_editor->GetLayoutObject())
     return;
 
-  PhysicalOffset adjusted_location = accumulated_offset + PhysicalLocation();
-  PhysicalOffset local_point = point_in_container - adjusted_location -
+  PhysicalOffset local_point = hit_test_location.Point() - accumulated_offset -
                                inner_editor->GetLayoutBox()->PhysicalLocation();
   if (HasOverflowClip())
     local_point += PhysicalOffset(ScrolledContentOffset());
diff --git a/third_party/blink/renderer/core/layout/layout_text_control.h b/third_party/blink/renderer/core/layout/layout_text_control.h
index ffe5021..643c76a3 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control.h
+++ b/third_party/blink/renderer/core/layout/layout_text_control.h
@@ -57,7 +57,7 @@
   void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
 
   void HitInnerEditorElement(HitTestResult&,
-                             const PhysicalOffset& point_in_container,
+                             const HitTestLocation&,
                              const PhysicalOffset& accumulated_offset);
 
   int TextBlockLogicalWidth() const;
diff --git a/third_party/blink/renderer/core/layout/layout_text_control_multi_line.cc b/third_party/blink/renderer/core/layout/layout_text_control_multi_line.cc
index 75f9419..ef3a634 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control_multi_line.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_control_multi_line.cc
@@ -38,21 +38,20 @@
 
 bool LayoutTextControlMultiLine::NodeAtPoint(
     HitTestResult& result,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     HitTestAction hit_test_action) {
-  if (!LayoutTextControl::NodeAtPoint(result, location_in_container,
+  if (!LayoutTextControl::NodeAtPoint(result, hit_test_location,
                                       accumulated_offset, hit_test_action))
     return false;
 
+  const LayoutObject* stop_node = result.GetHitTestRequest().GetStopNode();
+  if (stop_node && stop_node->NodeForHitTest() == result.InnerNode())
+    return true;
+
   if (result.InnerNode() == GetNode() ||
-      result.InnerNode() == InnerEditorElement()) {
-    const LayoutObject* stop_node = result.GetHitTestRequest().GetStopNode();
-    if (!stop_node || stop_node->NodeForHitTest() != result.InnerNode()) {
-      HitInnerEditorElement(result, location_in_container.Point(),
-                            accumulated_offset);
-    }
-  }
+      result.InnerNode() == InnerEditorElement())
+    HitInnerEditorElement(result, hit_test_location, accumulated_offset);
 
   return true;
 }
diff --git a/third_party/blink/renderer/core/layout/layout_text_control_multi_line.h b/third_party/blink/renderer/core/layout/layout_text_control_multi_line.h
index 2a5ca716..67401f8 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control_multi_line.h
+++ b/third_party/blink/renderer/core/layout/layout_text_control_multi_line.h
@@ -40,7 +40,7 @@
   }
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc b/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
index 64542ad..135c0ce4 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
@@ -138,13 +138,17 @@
 
 bool LayoutTextControlSingleLine::NodeAtPoint(
     HitTestResult& result,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     HitTestAction hit_test_action) {
-  if (!LayoutTextControl::NodeAtPoint(result, location_in_container,
+  if (!LayoutTextControl::NodeAtPoint(result, hit_test_location,
                                       accumulated_offset, hit_test_action))
     return false;
 
+  const LayoutObject* stop_node = result.GetHitTestRequest().GetStopNode();
+  if (stop_node && stop_node->NodeForHitTest() == result.InnerNode())
+    return true;
+
   // Say that we hit the inner text element if
   //  - we hit a node inside the inner text element,
   //  - we hit the <input> element (e.g. we're over the border or padding), or
@@ -153,19 +157,18 @@
   if (result.InnerNode()->IsDescendantOf(InnerEditorElement()) ||
       result.InnerNode() == GetNode() ||
       (container && container == result.InnerNode())) {
-    PhysicalOffset point_in_parent = location_in_container.Point();
+    PhysicalOffset inner_editor_accumulated_offset = accumulated_offset;
     if (container && EditingViewPortElement()) {
       if (EditingViewPortElement()->GetLayoutBox()) {
-        point_in_parent -=
+        inner_editor_accumulated_offset +=
             EditingViewPortElement()->GetLayoutBox()->PhysicalLocation();
       }
-      if (container->GetLayoutBox())
-        point_in_parent -= container->GetLayoutBox()->PhysicalLocation();
+      if (container->GetLayoutBox()) {
+        inner_editor_accumulated_offset +=
+            container->GetLayoutBox()->PhysicalLocation();
+      }
     }
-    const LayoutObject* stop_node = result.GetHitTestRequest().GetStopNode();
-    if (!stop_node || stop_node->NodeForHitTest() != result.InnerNode()) {
-      HitInnerEditorElement(result, point_in_parent, accumulated_offset);
-    }
+    HitInnerEditorElement(result, hit_test_location, accumulated_offset);
   }
   return true;
 }
diff --git a/third_party/blink/renderer/core/layout/layout_text_control_single_line.h b/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
index e890670c..8916592 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
+++ b/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
@@ -57,7 +57,7 @@
   void UpdateLayout() override;
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) final;
 
diff --git a/third_party/blink/renderer/core/layout/line/ellipsis_box.cc b/third_party/blink/renderer/core/layout/line/ellipsis_box.cc
index d3844258..0dc0d846 100644
--- a/third_party/blink/renderer/core/layout/line/ellipsis_box.cc
+++ b/third_party/blink/renderer/core/layout/line/ellipsis_box.cc
@@ -49,7 +49,7 @@
 }
 
 bool EllipsisBox::NodeAtPoint(HitTestResult& result,
-                              const HitTestLocation& location_in_container,
+                              const HitTestLocation& hit_test_location,
                               const PhysicalOffset& accumulated_offset,
                               LayoutUnit line_top,
                               LayoutUnit line_bottom) {
@@ -57,11 +57,11 @@
   PhysicalRect bounds_rect(adjusted_location, Size());
   if (VisibleToHitTestRequest(result.GetHitTestRequest()) &&
       bounds_rect.Intersects(
-          HitTestLocation::RectForPoint(location_in_container.Point()))) {
+          HitTestLocation::RectForPoint(hit_test_location.Point()))) {
     GetLineLayoutItem().UpdateHitTestResult(
-        result, location_in_container.Point() - adjusted_location);
+        result, hit_test_location.Point() - adjusted_location);
     if (result.AddNodeToListBasedTestResult(GetLineLayoutItem().GetNode(),
-                                            location_in_container,
+                                            hit_test_location,
                                             bounds_rect) == kStopHitTesting)
       return true;
   }
diff --git a/third_party/blink/renderer/core/layout/line/ellipsis_box.h b/third_party/blink/renderer/core/layout/line/ellipsis_box.h
index 41e1c80..a38a07d 100644
--- a/third_party/blink/renderer/core/layout/line/ellipsis_box.h
+++ b/third_party/blink/renderer/core/layout/line/ellipsis_box.h
@@ -57,7 +57,7 @@
              LayoutUnit line_top,
              LayoutUnit line_bottom) const override;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    LayoutUnit line_top,
                    LayoutUnit line_bottom) override;
diff --git a/third_party/blink/renderer/core/layout/line/inline_box.cc b/third_party/blink/renderer/core/layout/line/inline_box.cc
index af27b8f0..ce4ee01 100644
--- a/third_party/blink/renderer/core/layout/line/inline_box.cc
+++ b/third_party/blink/renderer/core/layout/line/inline_box.cc
@@ -239,15 +239,20 @@
 }
 
 bool InlineBox::NodeAtPoint(HitTestResult& result,
-                            const HitTestLocation& location_in_container,
+                            const HitTestLocation& hit_test_location,
                             const PhysicalOffset& accumulated_offset,
                             LayoutUnit /* lineTop */,
                             LayoutUnit /* lineBottom */) {
   // Hit test all phases of replaced elements atomically, as though the replaced
   // element established its own stacking context. (See Appendix E.2, section
   // 6.4 on inline block/table elements in the CSS2.1 specification.)
-  return GetLineLayoutItem().HitTestAllPhases(result, location_in_container,
-                                              accumulated_offset);
+  PhysicalOffset layout_item_accumulated_offset = accumulated_offset;
+  if (GetLineLayoutItem().IsBox()) {
+    layout_item_accumulated_offset +=
+        LineLayoutBox(GetLineLayoutItem()).PhysicalLocation();
+  }
+  return GetLineLayoutItem().HitTestAllPhases(result, hit_test_location,
+                                              layout_item_accumulated_offset);
 }
 
 const RootInlineBox& InlineBox::Root() const {
diff --git a/third_party/blink/renderer/core/layout/line/inline_box.h b/third_party/blink/renderer/core/layout/line/inline_box.h
index 8d5f587..bd7a4bc 100644
--- a/third_party/blink/renderer/core/layout/line/inline_box.h
+++ b/third_party/blink/renderer/core/layout/line/inline_box.h
@@ -102,7 +102,7 @@
                      LayoutUnit line_top,
                      LayoutUnit line_bottom) const;
   virtual bool NodeAtPoint(HitTestResult&,
-                           const HitTestLocation& location_in_container,
+                           const HitTestLocation&,
                            const PhysicalOffset& accumulated_offset,
                            LayoutUnit line_top,
                            LayoutUnit line_bottom);
diff --git a/third_party/blink/renderer/core/layout/line/inline_flow_box.cc b/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
index 61c9dc82..909f16a 100644
--- a/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
+++ b/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
@@ -1354,14 +1354,14 @@
 }
 
 bool InlineFlowBox::NodeAtPoint(HitTestResult& result,
-                                const HitTestLocation& location_in_container,
+                                const HitTestLocation& hit_test_location,
                                 const PhysicalOffset& accumulated_offset,
                                 LayoutUnit line_top,
                                 LayoutUnit line_bottom) {
   PhysicalRect overflow_rect =
       PhysicalVisualOverflowRect(line_top, line_bottom);
   overflow_rect.Move(accumulated_offset);
-  if (!location_in_container.Intersects(overflow_rect))
+  if (!hit_test_location.Intersects(overflow_rect))
     return false;
 
   // We need to hit test both our inline children (Inline Boxes) and culled
@@ -1377,10 +1377,10 @@
     // Layers will handle hit testing themselves.
     if (!curr->BoxModelObject() ||
         !curr->BoxModelObject().HasSelfPaintingLayer()) {
-      if (curr->NodeAtPoint(result, location_in_container, accumulated_offset,
+      if (curr->NodeAtPoint(result, hit_test_location, accumulated_offset,
                             line_top, line_bottom)) {
         GetLineLayoutItem().UpdateHitTestResult(
-            result, location_in_container.Point() - accumulated_offset);
+            result, hit_test_location.Point() - accumulated_offset);
         return true;
       }
     }
@@ -1411,7 +1411,7 @@
 
       if (culled_parent.IsLayoutInline() &&
           LineLayoutInline(culled_parent)
-              .HitTestCulledInline(result, location_in_container,
+              .HitTestCulledInline(result, hit_test_location,
                                    accumulated_offset))
         return true;
 
@@ -1421,8 +1421,7 @@
 
   if (GetLineLayoutItem().IsBox() &&
       ToLayoutBox(LineLayoutAPIShim::LayoutObjectFrom(GetLineLayoutItem()))
-          ->HitTestClippedOutByBorder(location_in_container,
-                                      overflow_rect.offset))
+          ->HitTestClippedOutByBorder(hit_test_location, overflow_rect.offset))
     return false;
 
   if (GetLineLayoutItem().StyleRef().HasBorderRadius()) {
@@ -1432,7 +1431,7 @@
     FloatRoundedRect border =
         GetLineLayoutItem().StyleRef().GetRoundedBorderFor(
             border_rect, IncludeLogicalLeftEdge(), IncludeLogicalRightEdge());
-    if (!location_in_container.Intersects(border))
+    if (!hit_test_location.Intersects(border))
       return false;
   }
 
@@ -1446,13 +1445,13 @@
   // Pixel snap hit testing.
   rect = PhysicalRect(PixelSnappedIntRect(rect));
   if (VisibleToHitTestRequest(result.GetHitTestRequest()) &&
-      location_in_container.Intersects(rect)) {
+      hit_test_location.Intersects(rect)) {
     // Don't add in m_topLeft here, we want coords in the containing block's
     // coordinate space.
     GetLineLayoutItem().UpdateHitTestResult(
-        result, location_in_container.Point() - accumulated_offset);
+        result, hit_test_location.Point() - accumulated_offset);
     if (result.AddNodeToListBasedTestResult(GetLineLayoutItem().GetNode(),
-                                            location_in_container,
+                                            hit_test_location,
                                             rect) == kStopHitTesting)
       return true;
   }
diff --git a/third_party/blink/renderer/core/layout/line/inline_flow_box.h b/third_party/blink/renderer/core/layout/line/inline_flow_box.h
index 587ddd1..4055260 100644
--- a/third_party/blink/renderer/core/layout/line/inline_flow_box.h
+++ b/third_party/blink/renderer/core/layout/line/inline_flow_box.h
@@ -129,7 +129,7 @@
              LayoutUnit line_top,
              LayoutUnit line_bottom) const override;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    LayoutUnit line_top,
                    LayoutUnit line_bottom) override;
diff --git a/third_party/blink/renderer/core/layout/line/inline_text_box.cc b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
index 75b321e..98caacb 100644
--- a/third_party/blink/renderer/core/layout/line/inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
@@ -430,7 +430,7 @@
 }
 
 bool InlineTextBox::NodeAtPoint(HitTestResult& result,
-                                const HitTestLocation& location_in_container,
+                                const HitTestLocation& hit_test_location,
                                 const PhysicalOffset& accumulated_offset,
                                 LayoutUnit /* lineTop */,
                                 LayoutUnit /*lineBottom*/) {
@@ -441,11 +441,11 @@
   box_origin += accumulated_offset;
   PhysicalRect rect(box_origin, Size());
   if (VisibleToHitTestRequest(result.GetHitTestRequest()) &&
-      location_in_container.Intersects(rect)) {
+      hit_test_location.Intersects(rect)) {
     GetLineLayoutItem().UpdateHitTestResult(
-        result, location_in_container.Point() - accumulated_offset);
+        result, hit_test_location.Point() - accumulated_offset);
     if (result.AddNodeToListBasedTestResult(GetLineLayoutItem().GetNode(),
-                                            location_in_container,
+                                            hit_test_location,
                                             rect) == kStopHitTesting)
       return true;
   }
diff --git a/third_party/blink/renderer/core/layout/line/inline_text_box.h b/third_party/blink/renderer/core/layout/line/inline_text_box.h
index 15796a2..f281287 100644
--- a/third_party/blink/renderer/core/layout/line/inline_text_box.h
+++ b/third_party/blink/renderer/core/layout/line/inline_text_box.h
@@ -159,7 +159,7 @@
              LayoutUnit line_top,
              LayoutUnit line_bottom) const override;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    LayoutUnit line_top,
                    LayoutUnit line_bottom) override;
diff --git a/third_party/blink/renderer/core/layout/line/line_box_list.cc b/third_party/blink/renderer/core/layout/line/line_box_list.cc
index ad9d23cc..9d9d861f 100644
--- a/third_party/blink/renderer/core/layout/line/line_box_list.cc
+++ b/third_party/blink/renderer/core/layout/line/line_box_list.cc
@@ -203,7 +203,7 @@
 
 bool LineBoxList::HitTest(LineLayoutBoxModel layout_object,
                           HitTestResult& result,
-                          const HitTestLocation& location_in_container,
+                          const HitTestLocation& hit_test_location,
                           const PhysicalOffset& accumulated_offset,
                           HitTestAction hit_test_action) const {
   if (hit_test_action != kHitTestForeground)
@@ -217,8 +217,8 @@
   if (!First())
     return false;
 
-  const PhysicalOffset& point = location_in_container.Point();
-  IntRect hit_search_bounding_box = location_in_container.EnclosingIntRect();
+  const PhysicalOffset& point = hit_test_location.Point();
+  IntRect hit_search_bounding_box = hit_test_location.EnclosingIntRect();
 
   CullRect cull_rect(
       First()->IsHorizontal()
@@ -240,11 +240,11 @@
             curr->LogicalBottomVisualOverflow(root.LineBottom()), cull_rect,
             accumulated_offset)) {
       bool inside =
-          curr->NodeAtPoint(result, location_in_container, accumulated_offset,
+          curr->NodeAtPoint(result, hit_test_location, accumulated_offset,
                             root.LineTop(), root.LineBottom());
       if (inside) {
         layout_object.UpdateHitTestResult(
-            result, location_in_container.Point() - accumulated_offset);
+            result, hit_test_location.Point() - accumulated_offset);
         return true;
       }
     }
diff --git a/third_party/blink/renderer/core/layout/line/line_box_list.h b/third_party/blink/renderer/core/layout/line/line_box_list.h
index 49f7d23..5d3e457a 100644
--- a/third_party/blink/renderer/core/layout/line/line_box_list.h
+++ b/third_party/blink/renderer/core/layout/line/line_box_list.h
@@ -154,7 +154,7 @@
 
   bool HitTest(LineLayoutBoxModel,
                HitTestResult&,
-               const HitTestLocation& location_in_container,
+               const HitTestLocation&,
                const PhysicalOffset& accumulated_offset,
                HitTestAction) const;
   bool AnyLineIntersectsRect(LineLayoutBoxModel,
diff --git a/third_party/blink/renderer/core/layout/line/root_inline_box.cc b/third_party/blink/renderer/core/layout/line/root_inline_box.cc
index 205cbc4..a60dcaf 100644
--- a/third_party/blink/renderer/core/layout/line/root_inline_box.cc
+++ b/third_party/blink/renderer/core/layout/line/root_inline_box.cc
@@ -181,20 +181,20 @@
 }
 
 bool RootInlineBox::NodeAtPoint(HitTestResult& result,
-                                const HitTestLocation& location_in_container,
+                                const HitTestLocation& hit_test_location,
                                 const PhysicalOffset& accumulated_offset,
                                 LayoutUnit line_top,
                                 LayoutUnit line_bottom) {
   if (HasEllipsisBox() && VisibleToHitTestRequest(result.GetHitTestRequest())) {
-    if (GetEllipsisBox()->NodeAtPoint(result, location_in_container,
+    if (GetEllipsisBox()->NodeAtPoint(result, hit_test_location,
                                       accumulated_offset, line_top,
                                       line_bottom)) {
       GetLineLayoutItem().UpdateHitTestResult(
-          result, location_in_container.Point() - accumulated_offset);
+          result, hit_test_location.Point() - accumulated_offset);
       return true;
     }
   }
-  return InlineFlowBox::NodeAtPoint(result, location_in_container,
+  return InlineFlowBox::NodeAtPoint(result, hit_test_location,
                                     accumulated_offset, line_top, line_bottom);
 }
 
diff --git a/third_party/blink/renderer/core/layout/line/root_inline_box.h b/third_party/blink/renderer/core/layout/line/root_inline_box.h
index 02812a2..73b8be8 100644
--- a/third_party/blink/renderer/core/layout/line/root_inline_box.h
+++ b/third_party/blink/renderer/core/layout/line/root_inline_box.h
@@ -139,7 +139,7 @@
              LayoutUnit line_top,
              LayoutUnit line_bottom) const override;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    LayoutUnit line_top,
                    LayoutUnit line_bottom) override;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index f950521..945c20b3 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -998,9 +998,8 @@
     return nullptr;
 
   // Propagating OOF needs re-layout.
-  if (!cached_layout_result->PhysicalFragment()
-           .OutOfFlowPositionedDescendants()
-           .IsEmpty())
+  if (cached_layout_result->PhysicalFragment()
+          .HasOutOfFlowPositionedDescendants())
     return nullptr;
 
   // Cached fragments are not for intermediate layout.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index 121de94..184634a4 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -1229,7 +1229,7 @@
   // fragmentainer break. In that case the floats associated with this line will
   // already have been processed.
   NGInlineItemResult* item_result = AddItem(item, line_info);
-  ComputeCanBreakAfter(item_result, auto_wrap_, break_iterator_);
+  item_result->can_break_after = auto_wrap_;
   MoveToNextOf(item);
 
   // If we are currently computing our min/max-content size simply append to
@@ -1543,6 +1543,8 @@
   // most cases where our support for rewinding positioned floats is not great
   // yet (see below.)
   while (item_results[new_end].item->Type() == NGInlineItem::kFloating) {
+    // We assume floats can break after, or this may cause an infinite loop.
+    DCHECK(item_results[new_end].can_break_after);
     ++new_end;
     if (new_end == item_results.size()) {
       position_ = line_info->ComputeWidth();
@@ -1555,6 +1557,8 @@
   for (unsigned i = item_results.size(); i > new_end;) {
     NGInlineItemResult& rewind = item_results[--i];
     if (rewind.positioned_float) {
+      // We assume floats can break after, or this may cause an infinite loop.
+      DCHECK(rewind.can_break_after);
       // TODO(kojii): We do not have mechanism to remove once positioned floats
       // yet, and that rewinding them may lay it out twice. For now, prohibit
       // rewinding positioned floats. This may results in incorrect layout, but
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
index caf78a0..747f3f13 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
@@ -99,9 +99,7 @@
   const NGPhysicalFragment* fragment = nullptr;
   if (const NGLayoutResult* layout_result = child->layout_result.get()) {
     // Need to propagate OOF descendants in this inline-block child.
-    if (!layout_result->PhysicalFragment()
-             .OutOfFlowPositionedDescendants()
-             .IsEmpty())
+    if (layout_result->PhysicalFragment().HasOutOfFlowPositionedDescendants())
       return;
     fragment = &layout_result->PhysicalFragment();
   } else {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
index 0ac7582..2c37e28 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
@@ -66,7 +66,7 @@
   base_direction_ = static_cast<unsigned>(builder->base_direction_);
   has_hanging_ = builder->hang_inline_size_ != 0;
   has_propagated_descendants_ = has_floating_descendants_ ||
-                                !oof_positioned_descendants_.IsEmpty() ||
+                                HasOutOfFlowPositionedDescendants() ||
                                 builder->unpositioned_list_marker_;
 }
 
@@ -120,7 +120,7 @@
 }
 
 const NGPhysicalFragment* NGPhysicalLineBoxFragment::FirstLogicalLeaf() const {
-  if (Children().IsEmpty())
+  if (Children().empty())
     return nullptr;
   // TODO(xiaochengh): This isn't correct for mixed Bidi. Fix it. Besides, we
   // should compute and store it during layout.
@@ -130,7 +130,7 @@
              DynamicTo<NGPhysicalContainerFragment>(runner)) {
     if (runner->IsBlockFormattingContextRoot())
       break;
-    if (runner_as_container->Children().IsEmpty())
+    if (runner_as_container->Children().empty())
       break;
     runner = direction == TextDirection::kLtr
                  ? runner_as_container->Children().front().get()
@@ -141,7 +141,7 @@
 }
 
 const NGPhysicalFragment* NGPhysicalLineBoxFragment::LastLogicalLeaf() const {
-  if (Children().IsEmpty())
+  if (Children().empty())
     return nullptr;
   // TODO(xiaochengh): This isn't correct for mixed Bidi. Fix it. Besides, we
   // should compute and store it during layout.
@@ -151,7 +151,7 @@
              DynamicTo<NGPhysicalContainerFragment>(runner)) {
     if (runner->IsBlockFormattingContextRoot())
       break;
-    if (runner_as_container->Children().IsEmpty())
+    if (runner_as_container->Children().empty())
       break;
     runner = direction == TextDirection::kLtr
                  ? runner_as_container->Children().back().get()
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index e775663..79b3726c 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -160,7 +160,7 @@
   // - out of flow fragments whose css container is inline box.
   // TODO(layout-dev) Transfroms also need to be applied to compute overflow
   // correctly. NG is not yet transform-aware. crbug.com/855965
-  if (!physical_fragment->Children().IsEmpty()) {
+  if (!physical_fragment->Children().empty()) {
     for (const auto& child : physical_fragment->Children()) {
       PhysicalRect child_scrollable_overflow;
       if (child->IsOutOfFlowPositioned()) {
@@ -280,36 +280,33 @@
 }
 
 template <typename Base>
-bool LayoutNGMixin<Base>::NodeAtPoint(
-    HitTestResult& result,
-    const HitTestLocation& location_in_container,
-    const PhysicalOffset& accumulated_offset,
-    HitTestAction action) {
+bool LayoutNGMixin<Base>::NodeAtPoint(HitTestResult& result,
+                                      const HitTestLocation& hit_test_location,
+                                      const PhysicalOffset& accumulated_offset,
+                                      HitTestAction action) {
   const NGPaintFragment* paint_fragment = PaintFragment();
   if (!paint_fragment) {
-    return LayoutBlockFlow::NodeAtPoint(result, location_in_container,
+    return LayoutBlockFlow::NodeAtPoint(result, hit_test_location,
                                         accumulated_offset, action);
   }
 
-  const PhysicalOffset physical_offset =
-      accumulated_offset + Base::PhysicalLocation();
   if (!this->IsEffectiveRootScroller()) {
     // Check if we need to do anything at all.
     // If we have clipping, then we can't have any spillout.
     PhysicalRect overflow_box = Base::HasOverflowClip()
                                     ? Base::PhysicalBorderBoxRect()
                                     : Base::PhysicalVisualOverflowRect();
-    overflow_box.Move(physical_offset);
-    if (!location_in_container.Intersects(overflow_box))
+    overflow_box.Move(accumulated_offset);
+    if (!hit_test_location.Intersects(overflow_box))
       return false;
   }
   if (Base::IsInSelfHitTestingPhase(action) && Base::HasOverflowClip() &&
-      Base::HitTestOverflowControl(result, location_in_container,
-                                   physical_offset))
+      Base::HitTestOverflowControl(result, hit_test_location,
+                                   accumulated_offset))
     return true;
 
   return NGBoxFragmentPainter(*paint_fragment)
-      .NodeAtPoint(result, location_in_container, physical_offset, action);
+      .NodeAtPoint(result, hit_test_location, accumulated_offset, action);
 }
 
 template <typename Base>
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
index 15e6d5a..53d3b9b 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -44,7 +44,7 @@
   void Paint(const PaintInfo&) const final;
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) final;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index aee15ed..31b6213 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -950,10 +950,7 @@
          To<LayoutBlock>(box_)->CreatesNewFormattingContext());
 
   scoped_refptr<const NGLayoutResult> layout_result =
-      box_->IsOutOfFlowPositioned()
-          ? CachedLayoutResultForOutOfFlowPositioned(
-                constraint_space.PercentageResolutionSize())
-          : box_->GetCachedLayoutResult();
+      box_->GetCachedLayoutResult();
 
   // We need to force a layout on the child if the constraint space given will
   // change the layout.
@@ -1031,6 +1028,23 @@
     layout_result = builder.ToBoxFragment();
 
     box_->SetCachedLayoutResult(*layout_result, /* break_token */ nullptr);
+  } else if (layout_result) {
+    // OOF-positioned nodes have a two-tier cache, and their layout results
+    // must always contain the correct percentage resolution size.
+    // See |NGBlockNode::CachedLayoutResultForOutOfFlowPositioned|.
+    const NGConstraintSpace& old_space =
+        layout_result->GetConstraintSpaceForCaching();
+    bool needs_cached_result_update =
+        IsOutOfFlowPositioned() &&
+        constraint_space.PercentageResolutionSize() !=
+            old_space.PercentageResolutionSize();
+    if (needs_cached_result_update) {
+      scoped_refptr<const NGLayoutResult> new_result =
+          base::AdoptRef(new NGLayoutResult(*layout_result, constraint_space,
+                                            layout_result->BfcLineOffset(),
+                                            layout_result->BfcBlockOffset()));
+      box_->SetCachedLayoutResult(*new_result, /* break_token */ nullptr);
+    }
   }
 
   UpdateShapeOutsideInfoIfNeeded(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index 8e45280..43a50cd1c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -19,8 +19,9 @@
   // Collect the child's out of flow descendants.
   // child_offset is offset of inline_start/block_start vertex.
   // Candidates need offset of top/left vertex.
-  const auto& out_of_flow_descendants = child.OutOfFlowPositionedDescendants();
-  if (!out_of_flow_descendants.IsEmpty()) {
+  if (child.HasOutOfFlowPositionedDescendants()) {
+    const auto& out_of_flow_descendants =
+        child.OutOfFlowPositionedDescendants();
     LogicalOffset top_left_offset;
     PhysicalSize child_size = child.Size();
     switch (GetWritingMode()) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
index 497fd2e..52c4cc5 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
@@ -17,7 +17,8 @@
 namespace {
 
 struct SameSizeAsNGPhysicalContainerFragment : NGPhysicalFragment {
-  Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
+  std::unique_ptr<Vector<NGOutOfFlowPositionedDescendant>>
+      oof_positioned_descendants_;
   void* pointer;
   wtf_size_t size;
 };
@@ -36,7 +37,10 @@
     unsigned sub_type)
     : NGPhysicalFragment(builder, type, sub_type),
       oof_positioned_descendants_(
-          std::move(builder->oof_positioned_descendants_)),
+          builder->oof_positioned_descendants_.IsEmpty()
+              ? nullptr
+              : new Vector<NGOutOfFlowPositionedDescendant>(
+                    std::move(builder->oof_positioned_descendants_))),
       buffer_(buffer),
       num_children_(builder->children_.size()) {
   has_floating_descendants_ = builder->has_floating_descendants_;
@@ -151,7 +155,7 @@
     if (!descendant_line_box->Size().IsEmpty()) {
       outline_rects->emplace_back(additional_offset,
                                   descendant_line_box->Size().ToLayoutSize());
-    } else if (descendant_line_box->Children().IsEmpty()) {
+    } else if (descendant_line_box->Children().empty()) {
       // Special-case for when the first continuation does not generate
       // fragments. NGInlineLayoutAlgorithm suppresses box fragments when the
       // line is "empty". When there is a continuation from the LayoutInline,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
index d79c9f5..b65ab45 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
@@ -5,6 +5,7 @@
 #ifndef NGPhysicalContainerFragment_h
 #define NGPhysicalContainerFragment_h
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_link.h"
@@ -20,38 +21,14 @@
 
 class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment {
  public:
-  class ChildLinkListBase {
+  // Same as |base::span<const NGLink>|, except that each |NGLink| has the
+  // latest generation of post-layout. See
+  // |NGPhysicalFragment::UpdatedFragment()| for more details.
+  class PostLayoutChildLinkList {
    public:
-    ChildLinkListBase(wtf_size_t count, const NGLink* buffer)
+    PostLayoutChildLinkList(wtf_size_t count, const NGLink* buffer)
         : count_(count), buffer_(buffer) {}
 
-    wtf_size_t size() const { return count_; }
-    bool IsEmpty() const { return count_ == 0; }
-
-   protected:
-    wtf_size_t count_;
-    const NGLink* buffer_;
-  };
-
-  class ChildLinkList : public ChildLinkListBase {
-   public:
-    using ChildLinkListBase::ChildLinkListBase;
-
-    const NGLink& operator[](wtf_size_t idx) const { return buffer_[idx]; }
-    const NGLink& front() const { return buffer_[0]; }
-    const NGLink& back() const { return buffer_[count_ - 1]; }
-
-    const NGLink* begin() const { return buffer_; }
-    const NGLink* end() const { return begin() + count_; }
-  };
-
-  // Same as |ChildLinkList|, except that each |NGLink| has the latest
-  // generation of post-layout. See |NGPhysicalFragment::UpdatedFragment()| for
-  // more details.
-  class PostLayoutChildLinkList : public ChildLinkListBase {
-   public:
-    using ChildLinkListBase::ChildLinkListBase;
-
     class ConstIterator {
       STACK_ALLOCATED();
 
@@ -95,6 +72,13 @@
     }
     const NGLink front() const { return (*this)[0]; }
     const NGLink back() const { return (*this)[count_ - 1]; }
+
+    wtf_size_t size() const { return count_; }
+    bool empty() const { return count_ == 0; }
+
+   private:
+    wtf_size_t count_;
+    const NGLink* buffer_;
   };
 
   ~NGPhysicalContainerFragment();
@@ -104,8 +88,8 @@
   // Note, children in this collection maybe old generations. Items in this
   // collection are safe, but their children (grandchildren of |this|) maybe
   // from deleted nodes or LayoutObjects. Also see |PostLayoutChildren()|.
-  ChildLinkList Children() const {
-    return ChildLinkList(num_children_, buffer_);
+  base::span<const NGLink> Children() const {
+    return base::make_span(buffer_, num_children_);
   }
 
   // Similar to |Children()| but all children are the latest generation of
@@ -130,9 +114,18 @@
     return depends_on_percentage_block_size_;
   }
 
-  const Vector<NGOutOfFlowPositionedDescendant>&
-  OutOfFlowPositionedDescendants() const {
-    return oof_positioned_descendants_;
+  bool HasOutOfFlowPositionedDescendants() const {
+    DCHECK(!oof_positioned_descendants_ ||
+           !oof_positioned_descendants_->IsEmpty());
+    return oof_positioned_descendants_.get();
+  }
+
+  base::span<NGOutOfFlowPositionedDescendant> OutOfFlowPositionedDescendants()
+      const {
+    if (!HasOutOfFlowPositionedDescendants())
+      return base::span<NGOutOfFlowPositionedDescendant>();
+    return {oof_positioned_descendants_->data(),
+            oof_positioned_descendants_->size()};
   }
 
  protected:
@@ -157,7 +150,8 @@
 
   static bool DependsOnPercentageBlockSize(const NGContainerFragmentBuilder&);
 
-  Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
+  const std::unique_ptr<Vector<NGOutOfFlowPositionedDescendant>>
+      oof_positioned_descendants_;
 
   // Because flexible arrays need to be the last member in a class, the actual
   // storage is in the subclass and we just keep a pointer to it here.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
index ed81dd98..9890603 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
@@ -87,8 +87,8 @@
   const auto previous_child_fragments =
       To<NGPhysicalBoxFragment>(previous_result_.PhysicalFragment()).Children();
 
-  const auto* it = previous_child_fragments.begin();
-  const auto* end = previous_child_fragments.end();
+  auto it = previous_child_fragments.begin();
+  auto end = previous_child_fragments.end();
 
   // We may have a list-marker as our first child. This may have been
   // propagated up to this container by an arbitrary child. As we don't know
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_block.h b/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
index 2297aa1..8c8dfbf 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
@@ -79,7 +79,7 @@
   void UpdateFromStyle() final;
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
index fdec0f16..a4a3895 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
@@ -174,13 +174,12 @@
   GetElement()->SetNeedsResizeObserverUpdate();
 }
 
-bool LayoutSVGContainer::NodeAtPoint(
-    HitTestResult& result,
-    const HitTestLocation& location_in_container,
-    const PhysicalOffset& accumulated_offset,
-    HitTestAction hit_test_action) {
+bool LayoutSVGContainer::NodeAtPoint(HitTestResult& result,
+                                     const HitTestLocation& hit_test_location,
+                                     const PhysicalOffset& accumulated_offset,
+                                     HitTestAction hit_test_action) {
   DCHECK_EQ(accumulated_offset, PhysicalOffset());
-  TransformedHitTestLocation local_location(location_in_container,
+  TransformedHitTestLocation local_location(hit_test_location,
                                             LocalToSVGParentTransform());
   if (!local_location)
     return false;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
index 13f46a3..ba23efa4 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
@@ -83,7 +83,7 @@
   FloatRect StrokeBoundingBox() const final { return stroke_bounding_box_; }
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
index a6da9a007..1acb46c 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
@@ -127,11 +127,11 @@
 
 bool LayoutSVGForeignObject::NodeAtPointFromSVG(
     HitTestResult& result,
-    const HitTestLocation& location_in_parent,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     HitTestAction) {
   DCHECK_EQ(accumulated_offset, PhysicalOffset());
-  TransformedHitTestLocation local_location(location_in_parent,
+  TransformedHitTestLocation local_location(hit_test_location,
                                             LocalSVGTransform());
   if (!local_location)
     return false;
@@ -161,11 +161,11 @@
 
 bool LayoutSVGForeignObject::NodeAtPoint(
     HitTestResult& result,
-    const HitTestLocation& location_in_parent,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     HitTestAction hit_test_action) {
   // Skip LayoutSVGBlock's override.
-  return LayoutBlockFlow::NodeAtPoint(result, location_in_parent,
+  return LayoutBlockFlow::NodeAtPoint(result, hit_test_location,
                                       accumulated_offset, hit_test_action);
 }
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
index ad8d49f..6f01462 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
@@ -58,7 +58,7 @@
                      MapCoordinatesFlags mode = 0) const final {}
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) final;
 };
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
index fd21b64..6f2de06 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
@@ -175,7 +175,7 @@
 }
 
 bool LayoutSVGImage::NodeAtPoint(HitTestResult& result,
-                                 const HitTestLocation& location_in_container,
+                                 const HitTestLocation& hit_test_location,
                                  const PhysicalOffset& accumulated_offset,
                                  HitTestAction hit_test_action) {
   DCHECK_EQ(accumulated_offset, PhysicalOffset());
@@ -190,7 +190,7 @@
   if (hit_rules.require_visible && style.Visibility() != EVisibility::kVisible)
     return false;
 
-  TransformedHitTestLocation local_location(location_in_container,
+  TransformedHitTestLocation local_location(hit_test_location,
                                             LocalToSVGParentTransform());
   if (!local_location)
     return false;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_image.h b/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
index a8d0ba62..b28f212 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
@@ -70,7 +70,7 @@
   bool UpdateBoundingBox();
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_parent,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index ee8582b..129cd50 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -465,13 +465,11 @@
 }
 
 bool LayoutSVGRoot::NodeAtPoint(HitTestResult& result,
-                                const HitTestLocation& location_in_container,
+                                const HitTestLocation& hit_test_location,
                                 const PhysicalOffset& accumulated_offset,
                                 HitTestAction hit_test_action) {
-  PhysicalOffset adjusted_location = accumulated_offset + PhysicalLocation();
-
-  HitTestLocation local_border_box_location(location_in_container,
-                                            -adjusted_location);
+  HitTestLocation local_border_box_location(hit_test_location,
+                                            -accumulated_offset);
 
   // Only test SVG content if the point is in our content box, or in case we
   // don't clip to the viewport, the visual overflow rect.
@@ -506,10 +504,10 @@
     // detect hits on the background of a <div> element.
     // If we'd return true here in the 'Foreground' phase, we are not able to
     // detect these hits anymore.
-    PhysicalRect bounds_rect(accumulated_offset + PhysicalLocation(), Size());
-    if (location_in_container.Intersects(bounds_rect)) {
+    PhysicalRect bounds_rect(accumulated_offset, Size());
+    if (hit_test_location.Intersects(bounds_rect)) {
       UpdateHitTestResult(result, local_border_box_location.Point());
-      if (result.AddNodeToListBasedTestResult(GetNode(), location_in_container,
+      if (result.AddNodeToListBasedTestResult(GetNode(), hit_test_location,
                                               bounds_rect) == kStopHitTesting)
         return true;
     }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.h b/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
index e88b67ce..fba084ea 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
@@ -138,7 +138,7 @@
   }
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
index 21f5f2c..a9e2489 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
@@ -349,7 +349,7 @@
 }
 
 bool LayoutSVGShape::NodeAtPoint(HitTestResult& result,
-                                 const HitTestLocation& location_in_parent,
+                                 const HitTestLocation& hit_test_location,
                                  const PhysicalOffset& accumulated_offset,
                                  HitTestAction hit_test_action) {
   DCHECK_EQ(accumulated_offset, PhysicalOffset());
@@ -365,7 +365,7 @@
   if (hit_rules.require_visible && style.Visibility() != EVisibility::kVisible)
     return false;
 
-  TransformedHitTestLocation local_location(location_in_parent,
+  TransformedHitTestLocation local_location(hit_test_location,
                                             LocalToSVGParentTransform());
   if (!local_location)
     return false;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
index c944680..b2563c7 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
@@ -160,7 +160,7 @@
   void Paint(const PaintInfo&) const final;
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_parent,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) final;
   bool HitTestShape(const HitTestRequest&,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index 48b5a8c8..34c734a 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -317,7 +317,7 @@
 }
 
 bool LayoutSVGText::NodeAtPoint(HitTestResult& result,
-                                const HitTestLocation& location_in_parent,
+                                const HitTestLocation& hit_test_location,
                                 const PhysicalOffset& accumulated_offset,
                                 HitTestAction hit_test_action) {
   DCHECK_EQ(accumulated_offset, PhysicalOffset());
@@ -325,7 +325,7 @@
   if (hit_test_action != kHitTestForeground)
     return false;
 
-  TransformedHitTestLocation local_location(location_in_parent,
+  TransformedHitTestLocation local_location(hit_test_location,
                                             LocalToSVGParentTransform());
   if (!local_location)
     return false;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.h b/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
index 7cd7a44..2360fe04 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
@@ -75,7 +75,7 @@
 
   void Paint(const PaintInfo&) const override;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_parent,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
   PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.cc
index 000a274e..7e4fc9e 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.cc
@@ -77,15 +77,15 @@
 
 bool LayoutSVGViewportContainer::NodeAtPoint(
     HitTestResult& result,
-    const HitTestLocation& location_in_parent,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     HitTestAction action) {
   // Respect the viewport clip which is in parent coordinates.
   if (SVGLayoutSupport::IsOverflowHidden(*this)) {
-    if (!location_in_parent.Intersects(viewport_))
+    if (!hit_test_location.Intersects(viewport_))
       return false;
   }
-  return LayoutSVGContainer::NodeAtPoint(result, location_in_parent,
+  return LayoutSVGContainer::NodeAtPoint(result, hit_test_location,
                                          accumulated_offset, action);
 }
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h
index 6116679a..c7a32b4 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h
@@ -57,7 +57,7 @@
   SVGTransformChange CalculateLocalTransform() override;
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_parent,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) final;
 
diff --git a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
index 66cef56..632ab791 100644
--- a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
@@ -277,7 +277,7 @@
 }
 
 bool SVGInlineTextBox::HitTestFragments(
-    const HitTestLocation& location_in_container) const {
+    const HitTestLocation& hit_test_location) const {
   auto line_layout_item = LineLayoutSVGInlineText(GetLineLayoutItem());
   const SimpleFontData* font_data = line_layout_item.ScaledFont().PrimaryFont();
   DCHECK(font_data);
@@ -289,14 +289,14 @@
                    line_layout_item.ScalingFactor();
   for (const SVGTextFragment& fragment : text_fragments_) {
     FloatQuad fragment_quad = fragment.BoundingQuad(baseline);
-    if (location_in_container.Intersects(fragment_quad))
+    if (hit_test_location.Intersects(fragment_quad))
       return true;
   }
   return false;
 }
 
 bool SVGInlineTextBox::NodeAtPoint(HitTestResult& result,
-                                   const HitTestLocation& location_in_container,
+                                   const HitTestLocation& hit_test_location,
                                    const PhysicalOffset& accumulated_offset,
                                    LayoutUnit,
                                    LayoutUnit) {
@@ -318,12 +318,12 @@
     // Currently SVGInlineTextBox doesn't flip in blocks direction.
     PhysicalRect rect{PhysicalOffset(Location()), PhysicalSize(Size())};
     rect.Move(accumulated_offset);
-    if (location_in_container.Intersects(rect)) {
-      if (HitTestFragments(location_in_container)) {
+    if (hit_test_location.Intersects(rect)) {
+      if (HitTestFragments(hit_test_location)) {
         line_layout_item.UpdateHitTestResult(
-            result, location_in_container.Point() - accumulated_offset);
+            result, hit_test_location.Point() - accumulated_offset);
         if (result.AddNodeToListBasedTestResult(line_layout_item.GetNode(),
-                                                location_in_container,
+                                                hit_test_location,
                                                 rect) == kStopHitTesting)
           return true;
       }
diff --git a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h
index f61d9b3..e2fd77f 100644
--- a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h
+++ b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h
@@ -97,9 +97,9 @@
                                       const ComputedStyle&,
                                       const Font&) const final;
 
-  bool HitTestFragments(const HitTestLocation& location_in_container) const;
+  bool HitTestFragments(const HitTestLocation& hit_test_location) const;
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    LayoutUnit line_top,
                    LayoutUnit line_bottom) override;
diff --git a/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.cc b/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.cc
index cf7a017e..240be07 100644
--- a/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.cc
+++ b/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.cc
@@ -195,7 +195,7 @@
 }
 
 bool SVGRootInlineBox::NodeAtPoint(HitTestResult& result,
-                                   const HitTestLocation& location_in_container,
+                                   const HitTestLocation& hit_test_location,
                                    const PhysicalOffset& accumulated_offset,
                                    LayoutUnit line_top,
                                    LayoutUnit line_bottom) {
@@ -203,7 +203,7 @@
   for (InlineBox* leaf = LastLeafChild(); leaf; leaf = leaf->PrevLeafChild()) {
     if (!leaf->IsSVGInlineTextBox())
       continue;
-    if (leaf->NodeAtPoint(result, location_in_container, accumulated_offset,
+    if (leaf->NodeAtPoint(result, hit_test_location, accumulated_offset,
                           line_top, line_bottom))
       return true;
   }
diff --git a/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h b/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h
index e62b52c2..8f741b84 100644
--- a/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h
+++ b/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h
@@ -48,7 +48,7 @@
   InlineBox* ClosestLeafChildForPosition(const PhysicalOffset&);
 
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation&,
                    const PhysicalOffset& accumulated_offset,
                    LayoutUnit line_top,
                    LayoutUnit line_bottom) final;
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 8f729e2..18b734b1 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -111,7 +111,6 @@
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/core/loader/history_item.cc b/third_party/blink/renderer/core/loader/history_item.cc
index 974a37c6..9bf4ae2 100644
--- a/third_party/blink/renderer/core/loader/history_item.cc
+++ b/third_party/blink/renderer/core/loader/history_item.cc
@@ -34,7 +34,6 @@
 #include "third_party/blink/renderer/platform/network/encoded_form_data.h"
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/loader/progress_tracker.cc b/third_party/blink/renderer/core/loader/progress_tracker.cc
index 23998db..3a0ae51 100644
--- a/third_party/blink/renderer/core/loader/progress_tracker.cc
+++ b/third_party/blink/renderer/core/loader/progress_tracker.cc
@@ -38,7 +38,6 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc
index ff9f75f3..e5a6fb9 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -107,7 +107,6 @@
 #include "third_party/blink/renderer/platform/web_test_support.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_concatenate.h"
 
diff --git a/third_party/blink/renderer/core/page/frame_tree.cc b/third_party/blink/renderer/core/page/frame_tree.cc
index 6ddc6d4..b35e797e 100644
--- a/third_party/blink/renderer/core/page/frame_tree.cc
+++ b/third_party/blink/renderer/core/page/frame_tree.cc
@@ -32,7 +32,6 @@
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 using std::swap;
diff --git a/third_party/blink/renderer/core/page/page_popup_client.h b/third_party/blink/renderer/core/page/page_popup_client.h
index 62822b6..98ee6143 100644
--- a/third_party/blink/renderer/core/page/page_popup_client.h
+++ b/third_party/blink/renderer/core/page/page_popup_client.h
@@ -34,7 +34,6 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/geometry/int_rect.h"
 #include "third_party/blink/renderer/platform/shared_buffer.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/core/paint/clip_rect.cc b/third_party/blink/renderer/core/paint/clip_rect.cc
index f4f80c1..bfb3c2ef 100644
--- a/third_party/blink/renderer/core/paint/clip_rect.cc
+++ b/third_party/blink/renderer/core/paint/clip_rect.cc
@@ -34,21 +34,24 @@
 namespace blink {
 
 ClipRect::ClipRect()
-    : rect_(LayoutRect::InfiniteIntRect()),
+    : rect_(PhysicalRect::InfiniteIntRect()),
       has_radius_(false),
       is_infinite_(true) {}
 
-ClipRect::ClipRect(const FloatClipRect& rect)
-    : rect_(PhysicalRect::EnclosingRect(rect.Rect())),
-      has_radius_(rect.HasRadius()),
-      is_infinite_(rect.IsInfinite()) {}
+ClipRect::ClipRect(const FloatClipRect& rect) {
+  SetRectInternal(rect);
+}
 
 void ClipRect::SetRect(const FloatClipRect& rect) {
   if (rect.IsInfinite() && IsInfinite())
     return;
-  rect_ = PhysicalRect::EnclosingRect(rect.Rect());
+  SetRectInternal(rect);
+}
+
+void ClipRect::SetRectInternal(const FloatClipRect& rect) {
   has_radius_ = rect.HasRadius();
   is_infinite_ = rect.IsInfinite();
+  rect_ = PhysicalRect::FastAndLossyFromFloatRect(rect.Rect());
 }
 
 void ClipRect::SetRect(const PhysicalRect& rect) {
diff --git a/third_party/blink/renderer/core/paint/clip_rect.h b/third_party/blink/renderer/core/paint/clip_rect.h
index 8813c67..74cc585 100644
--- a/third_party/blink/renderer/core/paint/clip_rect.h
+++ b/third_party/blink/renderer/core/paint/clip_rect.h
@@ -84,6 +84,8 @@
   String ToString() const;
 
  private:
+  void SetRectInternal(const FloatClipRect&);
+
   PhysicalRect rect_;
   bool has_radius_ : 1;
   bool is_infinite_ : 1;
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 2215aa6..6d2285ec 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -68,7 +68,7 @@
 bool HitTestCulledInlineAncestors(HitTestResult& result,
                                   const NGPaintFragment& fragment,
                                   const NGPaintFragment* previous_sibling,
-                                  const HitTestLocation& location_in_container,
+                                  const HitTestLocation& hit_test_location,
                                   const PhysicalOffset& physical_offset) {
   DCHECK(fragment.Parent());
   DCHECK(fragment.PhysicalFragment().IsInline());
@@ -105,7 +105,7 @@
 
     if (culled_parent->IsLayoutInline() &&
         ToLayoutInline(culled_parent)
-            ->HitTestCulledInline(result, location_in_container,
+            ->HitTestCulledInline(result, hit_test_location,
                                   fallback_accumulated_offset, &parent))
       return true;
 
@@ -982,11 +982,10 @@
   return action == kHitTestForeground;
 }
 
-bool NGBoxFragmentPainter::NodeAtPoint(
-    HitTestResult& result,
-    const HitTestLocation& location_in_container,
-    const PhysicalOffset& physical_offset,
-    HitTestAction action) {
+bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result,
+                                       const HitTestLocation& hit_test_location,
+                                       const PhysicalOffset& physical_offset,
+                                       HitTestAction action) {
   const PhysicalSize& size = box_fragment_.Size();
   const ComputedStyle& style = box_fragment_.Style();
 
@@ -995,7 +994,7 @@
   // TODO(layout-dev): Add support for hit testing overflow controls once we
   // overflow has been implemented.
   // if (hit_test_self && HasOverflowClip() &&
-  //   HitTestOverflowControl(result, location_in_container, physical_offset))
+  //   HitTestOverflowControl(result, hit_test_location, physical_offset))
   // return true;
 
   bool skip_children = result.GetHitTestRequest().GetStopNode() ==
@@ -1005,13 +1004,13 @@
     // foreground rect for intersection if a layer is self painting,
     // so only do the overflow clip check here for non-self-painting layers.
     if (!box_fragment_.HasSelfPaintingLayer() &&
-        !location_in_container.Intersects(PhysicalFragment().OverflowClipRect(
+        !hit_test_location.Intersects(PhysicalFragment().OverflowClipRect(
             physical_offset, kExcludeOverlayScrollbarSizeForHitTesting))) {
       skip_children = true;
     }
     if (!skip_children && style.HasBorderRadius()) {
       PhysicalRect bounds_rect(physical_offset, size);
-      skip_children = !location_in_container.Intersects(
+      skip_children = !hit_test_location.Intersects(
           style.GetRoundedInnerBorderFor(bounds_rect.ToLayoutRect()));
     }
   }
@@ -1022,14 +1021,14 @@
       scrolled_offset -=
           PhysicalOffset(PhysicalFragment().ScrolledContentOffset());
     }
-    if (HitTestChildren(result, box_fragment_.Children(), location_in_container,
+    if (HitTestChildren(result, box_fragment_.Children(), hit_test_location,
                         scrolled_offset, action)) {
       return true;
     }
   }
 
   if (style.HasBorderRadius() &&
-      HitTestClippedOutByBorder(location_in_container, physical_offset))
+      HitTestClippedOutByBorder(hit_test_location, physical_offset))
     return false;
 
   // Now hit test ourselves.
@@ -1040,13 +1039,13 @@
       bounds_rect = box_fragment_.SelfInkOverflow();
       bounds_rect.Move(physical_offset);
     }
-    if (location_in_container.Intersects(bounds_rect)) {
+    if (hit_test_location.Intersects(bounds_rect)) {
       Node* node = box_fragment_.NodeForHitTest();
       if (!result.InnerNode() && node) {
-        PhysicalOffset point = location_in_container.Point() - physical_offset;
+        PhysicalOffset point = hit_test_location.Point() - physical_offset;
         result.SetNodeAndPosition(node, point);
       }
-      if (result.AddNodeToListBasedTestResult(node, location_in_container,
+      if (result.AddNodeToListBasedTestResult(node, hit_test_location,
                                               bounds_rect) == kStopHitTesting) {
         return true;
       }
@@ -1064,7 +1063,7 @@
 bool NGBoxFragmentPainter::HitTestTextFragment(
     HitTestResult& result,
     const NGPaintFragment& text_paint_fragment,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& physical_offset,
     HitTestAction action) {
   if (action != kHitTestForeground)
@@ -1085,16 +1084,16 @@
 
   if (FragmentVisibleToHitTestRequest(text_paint_fragment,
                                       result.GetHitTestRequest()) &&
-      location_in_container.Intersects(rect)) {
+      hit_test_location.Intersects(rect)) {
     Node* node = text_paint_fragment.NodeForHitTest();
     if (!result.InnerNode() && node) {
-      PhysicalOffset point = location_in_container.Point() - physical_offset +
+      PhysicalOffset point = hit_test_location.Point() - physical_offset +
                              text_paint_fragment.InlineOffsetToContainerBox();
       result.SetNodeAndPosition(node, point);
     }
 
-    if (result.AddNodeToListBasedTestResult(node, location_in_container,
-                                            rect) == kStopHitTesting) {
+    if (result.AddNodeToListBasedTestResult(node, hit_test_location, rect) ==
+        kStopHitTesting) {
       return true;
     }
   }
@@ -1106,10 +1105,10 @@
 bool NGBoxFragmentPainter::HitTestLineBoxFragment(
     HitTestResult& result,
     const NGPaintFragment& fragment,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& physical_offset,
     HitTestAction action) {
-  if (HitTestChildren(result, fragment.Children(), location_in_container,
+  if (HitTestChildren(result, fragment.Children(), hit_test_location,
                       physical_offset, action))
     return true;
 
@@ -1121,38 +1120,36 @@
 
   const PhysicalOffset overflow_location =
       fragment.SelfInkOverflow().offset + physical_offset;
-  if (HitTestClippedOutByBorder(location_in_container, overflow_location))
+  if (HitTestClippedOutByBorder(hit_test_location, overflow_location))
     return false;
 
   const PhysicalSize size = fragment.Size();
   const PhysicalRect bounds_rect(physical_offset, size);
   const ComputedStyle& containing_box_style = box_fragment_.Style();
   if (containing_box_style.HasBorderRadius() &&
-      !location_in_container.Intersects(
-          containing_box_style.GetRoundedBorderFor(
-              bounds_rect.ToLayoutRect()))) {
+      !hit_test_location.Intersects(containing_box_style.GetRoundedBorderFor(
+          bounds_rect.ToLayoutRect()))) {
     return false;
   }
 
   // Now hit test ourselves.
-  if (!location_in_container.Intersects(bounds_rect))
+  if (!hit_test_location.Intersects(bounds_rect))
     return false;
 
   Node* node = fragment.NodeForHitTest();
   if (!result.InnerNode() && node) {
-    const PhysicalOffset point = location_in_container.Point() -
-                                 physical_offset +
+    const PhysicalOffset point = hit_test_location.Point() - physical_offset +
                                  fragment.InlineOffsetToContainerBox();
     result.SetNodeAndPosition(node, point);
   }
-  return result.AddNodeToListBasedTestResult(node, location_in_container,
+  return result.AddNodeToListBasedTestResult(node, hit_test_location,
                                              bounds_rect) == kStopHitTesting;
 }
 
 bool NGBoxFragmentPainter::HitTestChildBoxFragment(
     HitTestResult& result,
     const NGPaintFragment& paint_fragment,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& physical_offset,
     HitTestAction action) {
   const NGPhysicalFragment& fragment = paint_fragment.PhysicalFragment();
@@ -1172,7 +1169,7 @@
     DCHECK(!fragment.IsAtomicInline());
     DCHECK(!fragment.IsFloating());
     return NGBoxFragmentPainter(paint_fragment)
-        .NodeAtPoint(result, location_in_container, physical_offset, action);
+        .NodeAtPoint(result, hit_test_location, physical_offset, action);
   }
 
   if (fragment.IsInline() && action != kHitTestForeground)
@@ -1180,27 +1177,22 @@
 
   LayoutBox* const layout_box = ToLayoutBox(fragment.GetMutableLayoutObject());
 
-  // The |accumulated_offset| parameter of legacy hit testing functions doesn't
-  // include the object itself's offset.
-  const PhysicalOffset fallback_accumulated_offset =
-      physical_offset - layout_box->PhysicalLocation();
-
   // https://www.w3.org/TR/CSS22/zindex.html#painting-order
   // Hit test all phases of inline blocks, inline tables, replaced elements and
   // non-positioned floats as if they created their own stacking contexts.
   const bool should_hit_test_all_phases =
       fragment.IsAtomicInline() || fragment.IsFloating();
   return should_hit_test_all_phases
-             ? layout_box->HitTestAllPhases(result, location_in_container,
-                                            fallback_accumulated_offset)
-             : layout_box->NodeAtPoint(result, location_in_container,
-                                       fallback_accumulated_offset, action);
+             ? layout_box->HitTestAllPhases(result, hit_test_location,
+                                            physical_offset)
+             : layout_box->NodeAtPoint(result, hit_test_location,
+                                       physical_offset, action);
 }
 
 bool NGBoxFragmentPainter::HitTestChildren(
     HitTestResult& result,
     NGPaintFragment::ChildList children,
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& accumulated_offset,
     HitTestAction action) {
   Vector<NGPaintFragment*, 16> child_vector;
@@ -1217,15 +1209,15 @@
     bool stop_hit_testing = false;
     if (fragment.Type() == NGPhysicalFragment::kFragmentBox) {
       stop_hit_testing = HitTestChildBoxFragment(
-          result, *child, location_in_container, child_physical_offset, action);
+          result, *child, hit_test_location, child_physical_offset, action);
 
     } else if (fragment.Type() == NGPhysicalFragment::kFragmentLineBox) {
       stop_hit_testing = HitTestLineBoxFragment(
-          result, *child, location_in_container, child_physical_offset, action);
+          result, *child, hit_test_location, child_physical_offset, action);
 
     } else if (fragment.Type() == NGPhysicalFragment::kFragmentText) {
-      stop_hit_testing = HitTestTextFragment(
-          result, *child, location_in_container, child_physical_offset, action);
+      stop_hit_testing = HitTestTextFragment(result, *child, hit_test_location,
+                                             child_physical_offset, action);
     }
     if (stop_hit_testing)
       return true;
@@ -1236,8 +1228,7 @@
     // Hit test culled inline boxes between |fragment| and its parent fragment.
     const NGPaintFragment* previous_sibling = i ? child_vector[i - 1] : nullptr;
     if (HitTestCulledInlineAncestors(result, *child, previous_sibling,
-                                     location_in_container,
-                                     child_physical_offset))
+                                     hit_test_location, child_physical_offset))
       return true;
   }
 
@@ -1245,13 +1236,13 @@
 }
 
 bool NGBoxFragmentPainter::HitTestClippedOutByBorder(
-    const HitTestLocation& location_in_container,
+    const HitTestLocation& hit_test_location,
     const PhysicalOffset& border_box_location) const {
   const ComputedStyle& style = box_fragment_.Style();
   PhysicalRect rect(PhysicalOffset(), PhysicalFragment().Size());
   rect.Move(border_box_location);
   const NGBorderEdges& border_edges = BorderEdges();
-  return !location_in_container.Intersects(style.GetRoundedBorderFor(
+  return !hit_test_location.Intersects(style.GetRoundedBorderFor(
       rect.ToLayoutRect(), border_edges.line_left, border_edges.line_right));
 }
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
index 3606414..097916c 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
@@ -40,10 +40,10 @@
 
   // Hit tests this box fragment.
   // @param physical_offset Physical offset of this box fragment in the
-  // coordinate space of |location_in_container|.
+  // coordinate space of |hit_test_location|.
   // TODO(eae): Change to take a HitTestResult pointer instead as it mutates.
   bool NodeAtPoint(HitTestResult&,
-                   const HitTestLocation& location_in_container,
+                   const HitTestLocation& hit_test_location,
                    const PhysicalOffset& physical_offset,
                    HitTestAction);
 
@@ -120,7 +120,7 @@
   // container has 'overflow: scroll'.
   bool HitTestChildren(HitTestResult&,
                        NGPaintFragment::ChildList,
-                       const HitTestLocation& location_in_container,
+                       const HitTestLocation& hit_test_location,
                        const PhysicalOffset& physical_offset,
                        HitTestAction);
 
@@ -130,7 +130,7 @@
   // paint layer.
   bool HitTestChildBoxFragment(HitTestResult&,
                                const NGPaintFragment&,
-                               const HitTestLocation& location_in_container,
+                               const HitTestLocation& hit_test_location,
                                const PhysicalOffset& physical_offset,
                                HitTestAction);
 
@@ -138,7 +138,7 @@
   // @param physical_offset Physical offset of the text fragment in paint layer.
   bool HitTestTextFragment(HitTestResult&,
                            const NGPaintFragment&,
-                           const HitTestLocation& location_in_container,
+                           const HitTestLocation& hit_test_location,
                            const PhysicalOffset& physical_offset,
                            HitTestAction);
 
@@ -147,7 +147,7 @@
   // layer.
   bool HitTestLineBoxFragment(HitTestResult&,
                               const NGPaintFragment&,
-                              const HitTestLocation& location_in_container,
+                              const HitTestLocation& hit_test_location,
                               const PhysicalOffset& physical_offset,
                               HitTestAction);
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
index 9829e3a..7317732a 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -38,8 +38,6 @@
 //   placeholders for displaying them.
 class CORE_EXPORT NGPaintFragment : public RefCounted<NGPaintFragment>,
                                     public DisplayItemClient {
-  USING_FAST_MALLOC(NGPaintFragment);
-
  public:
   NGPaintFragment(scoped_refptr<const NGPhysicalFragment>,
                   PhysicalOffset offset,
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 2a746f4..e9dd61a 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -94,7 +94,6 @@
 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
@@ -2158,7 +2157,6 @@
     // Next we want to see if the mouse pos is inside the child LayoutObjects of
     // the layer. Check every fragment in reverse order.
     if (IsSelfPaintingLayer()) {
-      offset = -LayoutBoxPhysicalLocation();
       // Hit test with a temporary HitTestResult, because we only want to commit
       // to 'result' if we know we're frontmost.
       HitTestResult temp_result(result.GetHitTestRequest(),
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h
index 10a3e86..180fc18 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -957,12 +957,6 @@
       const PhysicalOffset* offset_from_root = nullptr,
       const PhysicalOffset& sub_pixel_accumulation = PhysicalOffset()) const;
 
-  PhysicalOffset LayoutBoxPhysicalLocation() const {
-    return GetLayoutObject().IsBox()
-               ? ToLayoutBox(GetLayoutObject()).PhysicalLocation()
-               : PhysicalOffset();
-  }
-
   enum TransparencyClipBoxBehavior {
     kPaintingTransparencyClipBox,
     kHitTestingTransparencyClipBox
diff --git a/third_party/blink/renderer/core/paint/paint_layer_clipper.cc b/third_party/blink/renderer/core/paint/paint_layer_clipper.cc
index b368608..0f24a00 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_clipper.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_clipper.cc
@@ -248,7 +248,7 @@
     clipped_rect_in_local_space.MoveBy(
         -FloatPoint(layer_.GetLayoutObject().FirstFragment().PaintOffset()));
 
-    return PhysicalRect::EnclosingRect(clipped_rect_in_local_space);
+    return PhysicalRect::FastAndLossyFromFloatRect(clipped_rect_in_local_space);
   }
 
   PhysicalRect layer_bounds;
@@ -289,7 +289,7 @@
           fragment_data.PreTransform(),
           context.root_fragment->LocalBorderBoxProperties().Transform(),
           float_bounds);
-      layer_bounds = PhysicalRect::EnclosingRect(float_bounds);
+      layer_bounds = PhysicalRect::FastAndLossyFromFloatRect(float_bounds);
       layer_bounds.offset -= context.root_fragment->PaintOffset();
     }
   }
diff --git a/third_party/blink/renderer/core/resize_observer/resize_observer.idl b/third_party/blink/renderer/core/resize_observer/resize_observer.idl
index 11ccfc8..8e09fdd 100644
--- a/third_party/blink/renderer/core/resize_observer/resize_observer.idl
+++ b/third_party/blink/renderer/core/resize_observer/resize_observer.idl
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://wicg.github.io/ResizeObserver/#resize-observer-callback
+// https://drafts.csswg.org/resize-observer-1/#resize-observer-callback
 
 callback ResizeObserverCallback = void (sequence<ResizeObserverEntry> entries, ResizeObserver observer);
 
-// https://wicg.github.io/ResizeObserver/#resize-observer-interface
+// https://drafts.csswg.org/resize-observer-1/#resize-observer-interface
 
 [
+    Exposed=Window,
     ActiveScriptWrappable,
     Constructor(ResizeObserverCallback callback),
     MeasureAs=ResizeObserver_Constructor,
diff --git a/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl b/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl
index 835d47f..969b0f5 100644
--- a/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl
+++ b/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://wicg.github.io/ResizeObserver/#resize-observer-entry-interface
+// https://drafts.csswg.org/resize-observer-1/#resize-observer-entry-interface
 
+[Exposed=Window]
 interface ResizeObserverEntry {
     readonly attribute Element target;
     readonly attribute DOMRectReadOnly contentRect;
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index a227a31..84acefe 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -106,6 +106,7 @@
 class InternalVisitedBorderLeftColor;
 class InternalVisitedBorderRightColor;
 class InternalVisitedBorderTopColor;
+class InternalVisitedCaretColor;
 class InternalVisitedColor;
 class InternalVisitedTextDecorationColor;
 class InternalVisitedTextEmphasisColor;
@@ -204,6 +205,7 @@
   friend class css_longhand::InternalVisitedBorderLeftColor;
   friend class css_longhand::InternalVisitedBorderRightColor;
   friend class css_longhand::InternalVisitedBorderTopColor;
+  friend class css_longhand::InternalVisitedCaretColor;
   friend class css_longhand::InternalVisitedColor;
   friend class css_longhand::InternalVisitedTextDecorationColor;
   friend class css_longhand::InternalVisitedTextEmphasisColor;
@@ -2404,10 +2406,10 @@
     SetInternalVisitedTextStrokeColorIsCurrentColorInternal(
         color.IsCurrentColor());
   }
-  void SetVisitedLinkCaretColor(const StyleAutoColor& color) {
-    SetVisitedLinkCaretColorInternal(color.Resolve(Color()));
-    SetVisitedLinkCaretColorIsCurrentColorInternal(color.IsCurrentColor());
-    SetVisitedLinkCaretColorIsAutoInternal(color.IsAutoColor());
+  void SetInternalVisitedCaretColor(const StyleAutoColor& color) {
+    SetInternalVisitedCaretColorInternal(color.Resolve(Color()));
+    SetInternalVisitedCaretColorIsCurrentColorInternal(color.IsCurrentColor());
+    SetInternalVisitedCaretColorIsAutoInternal(color.IsAutoColor());
   }
 
   static bool IsDisplayBlockContainer(EDisplay display) {
@@ -2512,12 +2514,12 @@
                : StyleColor(TextStrokeColorInternal());
   }
   Color InternalVisitedColor() const { return InternalVisitedColorInternal(); }
-  StyleAutoColor VisitedLinkCaretColor() const {
-    if (VisitedLinkCaretColorIsCurrentColorInternal())
+  StyleAutoColor InternalVisitedCaretColor() const {
+    if (InternalVisitedCaretColorIsCurrentColorInternal())
       return StyleAutoColor::CurrentColor();
-    if (VisitedLinkCaretColorIsAutoInternal())
+    if (InternalVisitedCaretColorIsAutoInternal())
       return StyleAutoColor::AutoColor();
-    return StyleAutoColor(VisitedLinkCaretColorInternal());
+    return StyleAutoColor(InternalVisitedCaretColorInternal());
   }
   StyleColor InternalVisitedBackgroundColor() const {
     return InternalVisitedBackgroundColorInternal();
diff --git a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
index 1b06181..d606ca1 100644
--- a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
+++ b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
@@ -450,8 +450,8 @@
             field_dependencies: ["caret-color"]
           },
           {
-            method: "VisitedLinkCaretColor()",
-            field_dependencies: ["VisitedLinkCaretColor"]
+            method: "InternalVisitedCaretColor()",
+            field_dependencies: ["-internal-visited-caret-color"]
           },
         ]
     },
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index 44d5945..3223d713 100644
--- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -286,16 +286,6 @@
       computed_style_custom_functions: ["setter"],
     },
     {
-      name: "VisitedLinkCaretColor",
-      inherited: true,
-      field_template: "external",
-      type_name: "Color",
-      include_paths: ["third_party/blink/renderer/platform/graphics/color.h"],
-      default_value: "Color()",
-      field_group: "*",
-      computed_style_custom_functions: ["getter", "setter"],
-    },
-    {
       name: "CursorData",
       inherited: true,
       field_template: "external",
@@ -388,7 +378,7 @@
       computed_style_custom_functions: ["getter", "setter"],
     },
     {
-      name: "VisitedLinkCaretColorIsCurrentColor",
+      name: "InternalVisitedCaretColorIsCurrentColor",
       inherited: true,
       field_template: "primitive",
       type_name: "bool",
@@ -397,7 +387,7 @@
       computed_style_custom_functions: ["getter", "setter"],
     },
     {
-      name: "VisitedLinkCaretColorIsAuto",
+      name: "InternalVisitedCaretColorIsAuto",
       inherited: true,
       field_template: "primitive",
       type_name: "bool",
diff --git a/third_party/blink/renderer/core/xml/parser/xml_document_parser.h b/third_party/blink/renderer/core/xml/parser/xml_document_parser.h
index e202fa6..42e7943 100644
--- a/third_party/blink/renderer/core/xml/parser/xml_document_parser.h
+++ b/third_party/blink/renderer/core/xml/parser/xml_document_parser.h
@@ -39,7 +39,6 @@
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/xml/xsl_style_sheet_libxslt.cc b/third_party/blink/renderer/core/xml/xsl_style_sheet_libxslt.cc
index 13dffcdc..4219352 100644
--- a/third_party/blink/renderer/core/xml/xsl_style_sheet_libxslt.cc
+++ b/third_party/blink/renderer/core/xml/xsl_style_sheet_libxslt.cc
@@ -33,7 +33,6 @@
 #include "third_party/blink/renderer/core/xml/xslt_processor.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc b/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
index 7f5a4dd..abeb923 100644
--- a/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
+++ b/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
@@ -50,7 +50,6 @@
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/utf8.h"
 
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
index 465a82d..5b20d15 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -92,7 +92,6 @@
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
index 01fdfd1..7c5119a 100644
--- a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
+++ b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
@@ -148,30 +148,30 @@
   return AssertCacheStorage(security_origin, frames, caches, result);
 }
 
-CString CacheStorageErrorString(mojom::blink::CacheStorageError error) {
+std::string CacheStorageErrorString(mojom::blink::CacheStorageError error) {
   switch (error) {
     case mojom::blink::CacheStorageError::kErrorNotImplemented:
-      return CString("not implemented.");
+      return std::string("not implemented.");
     case mojom::blink::CacheStorageError::kErrorNotFound:
-      return CString("not found.");
+      return std::string("not found.");
     case mojom::blink::CacheStorageError::kErrorExists:
-      return CString("cache already exists.");
+      return std::string("cache already exists.");
     case mojom::blink::CacheStorageError::kErrorQuotaExceeded:
-      return CString("quota exceeded.");
+      return std::string("quota exceeded.");
     case mojom::blink::CacheStorageError::kErrorCacheNameNotFound:
-      return CString("cache not found.");
+      return std::string("cache not found.");
     case mojom::blink::CacheStorageError::kErrorQueryTooLarge:
-      return CString("operation too large.");
+      return std::string("operation too large.");
     case mojom::blink::CacheStorageError::kErrorStorage:
-      return CString("storage failure.");
+      return std::string("storage failure.");
     case mojom::blink::CacheStorageError::kErrorDuplicateOperation:
-      return CString("duplicate operation.");
+      return std::string("duplicate operation.");
     case mojom::blink::CacheStorageError::kSuccess:
       // This function should only be called upon error.
       break;
   }
   NOTREACHED();
-  return "";
+  return std::string();
 }
 
 CachedResponseType ResponseTypeToString(
diff --git a/third_party/blink/renderer/modules/encoding/text_encoder.cc b/third_party/blink/renderer/modules/encoding/text_encoder.cc
index 548289c..356fb08 100644
--- a/third_party/blink/renderer/modules/encoding/text_encoder.cc
+++ b/third_party/blink/renderer/modules/encoding/text_encoder.cc
@@ -34,7 +34,6 @@
 #include "third_party/blink/renderer/modules/encoding/encoding.h"
 #include "third_party/blink/renderer/modules/encoding/text_encoder_encode_into_result.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc b/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc
index 380115f..f290a10c 100644
--- a/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc
+++ b/third_party/blink/renderer/modules/encoding/text_encoder_stream.cc
@@ -19,7 +19,6 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/to_v8.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_codec.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
@@ -65,7 +64,7 @@
     }
 
     DOMUint8Array* array =
-        CreateDOMUint8ArrayFromTwoCStringsConcatenated(prefix, result);
+        CreateDOMUint8ArrayFromTwoStdStringsConcatenated(prefix, result);
     controller->Enqueue(ToV8(array, script_state_), exception_state);
   }
 
@@ -98,7 +97,7 @@
     return std::string(kRawBytes, sizeof(kRawBytes));
   }
 
-  static DOMUint8Array* CreateDOMUint8ArrayFromTwoCStringsConcatenated(
+  static DOMUint8Array* CreateDOMUint8ArrayFromTwoStdStringsConcatenated(
       const std::string& string1,
       const std::string& string2) {
     const wtf_size_t length1 = static_cast<wtf_size_t>(string1.length());
diff --git a/third_party/blink/renderer/modules/filesystem/dom_file_path.cc b/third_party/blink/renderer/modules/filesystem/dom_file_path.cc
index d1ca351..1f05e81 100644
--- a/third_party/blink/renderer/modules/filesystem/dom_file_path.cc
+++ b/third_party/blink/renderer/modules/filesystem/dom_file_path.cc
@@ -30,7 +30,6 @@
 
 #include "third_party/blink/renderer/modules/filesystem/dom_file_path.h"
 
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
index 90ebf5b..a01b179a 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -15,7 +15,6 @@
 #include "third_party/blink/renderer/platform/json/json_parser.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/modules/mediasource/media_source.cc b/third_party/blink/renderer/modules/mediasource/media_source.cc
index bcfe346e..2519e7c 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source.cc
+++ b/third_party/blink/renderer/modules/mediasource/media_source.cc
@@ -52,7 +52,6 @@
 #include "third_party/blink/renderer/platform/network/mime/content_type.h"
 #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 using blink::WebMediaSource;
 using blink::WebSourceBuffer;
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.cc b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
index b6fc8729..980bb8d 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area.cc
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
@@ -629,8 +629,8 @@
       if (input.Is8Bit()) {
         // This code is copied from WTF::String::Utf8(), except the vector
         // doesn't have a stack-allocated capacity.
-        // We do this because there isn't a way to transform the CString we get
-        // from WTF::String::Utf8() to a Vector without an extra copy.
+        // We do this because there isn't a way to transform the std::string we
+        // get from WTF::String::Utf8() to a Vector without an extra copy.
         if (length > std::numeric_limits<unsigned>::max() / 3)
           return Vector<uint8_t>();
         Vector<uint8_t> buffer_vector(length * 3);
diff --git a/third_party/blink/renderer/modules/webdatabase/sql_statement.cc b/third_party/blink/renderer/modules/webdatabase/sql_statement.cc
index f35c954..5daf639 100644
--- a/third_party/blink/renderer/modules/webdatabase/sql_statement.cc
+++ b/third_party/blink/renderer/modules/webdatabase/sql_statement.cc
@@ -38,7 +38,6 @@
 #include "third_party/blink/renderer/modules/webdatabase/sql_transaction.h"
 #include "third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h"
 #include "third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/webdatabase/sql_statement_backend.cc b/third_party/blink/renderer/modules/webdatabase/sql_statement_backend.cc
index 4473669..7110120 100644
--- a/third_party/blink/renderer/modules/webdatabase/sql_statement_backend.cc
+++ b/third_party/blink/renderer/modules/webdatabase/sql_statement_backend.cc
@@ -34,7 +34,6 @@
 #include "third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h"
 #include "third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.h"
 #include "third_party/blink/renderer/modules/webdatabase/storage_log.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 // The Life-Cycle of a SQLStatement i.e. Who's keeping the SQLStatement alive?
 // ==========================================================================
diff --git a/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc b/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc
index 34a88205..2523802 100644
--- a/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc
+++ b/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.cc
@@ -68,7 +68,7 @@
     open_error_message_ =
         db_ ? sqlite3_errmsg(db_) : "sqlite_open returned null";
     DLOG(ERROR) << "SQLite database failed to load from " << filename
-                << "\nCause - " << open_error_message_.data();
+                << "\nCause - " << open_error_message_;
     return false;
   }
 
@@ -128,7 +128,7 @@
 
   opening_thread_ = 0;
   open_error_ = SQLITE_ERROR;
-  open_error_message_ = CString();
+  open_error_message_ = std::string();
 }
 
 void SQLiteDatabase::SetMaximumSize(int64_t size) {
@@ -266,8 +266,8 @@
 const char* SQLiteDatabase::LastErrorMsg() {
   if (db_)
     return sqlite3_errmsg(db_);
-  return open_error_message_.IsNull() ? kNotOpenErrorMessage
-                                      : open_error_message_.data();
+  return open_error_message_.empty() ? kNotOpenErrorMessage
+                                     : open_error_message_.c_str();
 }
 
 int SQLiteDatabase::AuthorizerFunction(void* user_data,
diff --git a/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h b/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h
index a3bdd07..1d3ebdd7 100644
--- a/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h
+++ b/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_database.h
@@ -30,7 +30,6 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/threading.h"
 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
@@ -147,7 +146,7 @@
   Mutex database_closing_mutex_;
 
   int open_error_;
-  CString open_error_message_;
+  std::string open_error_message_;
 
   int last_changes_count_;
 
diff --git a/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.cc b/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.cc
index 10e4689..d91fbf0 100644
--- a/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.cc
+++ b/third_party/blink/renderer/modules/webdatabase/sqlite/sqlite_statement.cc
@@ -29,7 +29,6 @@
 #include "third_party/blink/renderer/modules/webdatabase/sqlite/sql_log.h"
 #include "third_party/blink/renderer/modules/webdatabase/sqlite/sql_value.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/sqlite/sqlite3.h"
 
 // SQLite 3.6.16 makes sqlite3_prepare_v2 automatically retry preparing the
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket.cc b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
index a3da2cf..ade68bc 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket.cc
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
@@ -66,7 +66,6 @@
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
index 41bf413..7210df4 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
@@ -22,7 +22,6 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.cc b/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.cc
index 2339e11..75baf21 100644
--- a/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.cc
+++ b/third_party/blink/renderer/modules/websockets/web_pepper_socket_impl.cc
@@ -41,7 +41,6 @@
 #include "third_party/blink/renderer/modules/websockets/web_pepper_socket_channel_client_proxy.h"
 #include "third_party/blink/renderer/modules/websockets/websocket_channel.h"
 #include "third_party/blink/renderer/modules/websockets/websocket_channel_impl.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
index 0942ce9..a28dc458 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
@@ -295,7 +295,7 @@
 }
 
 void WebSocketChannelImpl::Send(const std::string& message) {
-  NETWORK_DVLOG(1) << this << " Send(" << message << ") (CString argument)";
+  NETWORK_DVLOG(1) << this << " Send(" << message << ") (std::string argument)";
   probe::DidSendWebSocketMessage(execution_context_, identifier_,
                                  WebSocketOpCode::kOpCodeText, true,
                                  message.c_str(), message.length());
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
index fd35395..47bac2f 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
@@ -46,7 +46,6 @@
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
diff --git a/third_party/blink/renderer/platform/audio/hrtf_elevation.h b/third_party/blink/renderer/platform/audio/hrtf_elevation.h
index cc4a7a9..61b0a45e 100644
--- a/third_party/blink/renderer/platform/audio/hrtf_elevation.h
+++ b/third_party/blink/renderer/platform/audio/hrtf_elevation.h
@@ -35,7 +35,6 @@
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/platform/audio/hrtf_kernel.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/blob/blob_data.cc b/third_party/blink/renderer/platform/blob/blob_data.cc
index 70275114..5575623 100644
--- a/third_party/blink/renderer/platform/blob/blob_data.cc
+++ b/third_party/blink/renderer/platform/blob/blob_data.cc
@@ -50,7 +50,6 @@
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/uuid.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/line_ending.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/platform/exported/web_string.cc b/third_party/blink/renderer/platform/exported/web_string.cc
index 63f1fe1..1ec1fbc 100644
--- a/third_party/blink/renderer/platform/exported/web_string.cc
+++ b/third_party/blink/renderer/platform/exported/web_string.cc
@@ -34,7 +34,6 @@
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/platform/fonts/font_cache.h b/third_party/blink/renderer/platform/fonts/font_cache.h
index 886405d..19eea65 100644
--- a/third_party/blink/renderer/platform/fonts/font_cache.h
+++ b/third_party/blink/renderer/platform/fonts/font_cache.h
@@ -50,7 +50,6 @@
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/unicode.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/skia/include/core/SkFontMgr.h"
@@ -219,7 +218,7 @@
 #if defined(OS_LINUX)
   struct PlatformFallbackFont {
     String name;
-    CString filename;
+    std::string filename;
     int fontconfig_interface_id;
     int ttc_index;
     bool is_bold;
diff --git a/third_party/blink/renderer/platform/fonts/font_face_creation_params.h b/third_party/blink/renderer/platform/fonts/font_face_creation_params.h
index 46887c6..5989a0d4 100644
--- a/third_party/blink/renderer/platform/fonts/font_face_creation_params.h
+++ b/third_party/blink/renderer/platform/fonts/font_face_creation_params.h
@@ -52,14 +52,14 @@
   FontFaceCreationParams()
       : creation_type_(kCreateFontByFamily),
         family_(AtomicString()),
-        filename_(CString()),
+        filename_(std::string()),
         fontconfig_interface_id_(0),
         ttc_index_(0) {}
 
   explicit FontFaceCreationParams(AtomicString family)
       : creation_type_(kCreateFontByFamily),
         family_(family),
-        filename_(CString()),
+        filename_(std::string()),
         fontconfig_interface_id_(0),
         ttc_index_(0) {
 #if defined(OS_WIN)
@@ -73,7 +73,7 @@
 #endif
   }
 
-  FontFaceCreationParams(CString filename,
+  FontFaceCreationParams(const std::string& filename,
                          int fontconfig_interface_id,
                          int ttc_index = 0)
       : creation_type_(kCreateFontByFciIdAndTtcIndex),
@@ -86,7 +86,7 @@
     DCHECK_EQ(creation_type_, kCreateFontByFamily);
     return family_;
   }
-  CString Filename() const {
+  std::string Filename() const {
     DCHECK_EQ(creation_type_, kCreateFontByFciIdAndTtcIndex);
     return filename_;
   }
@@ -107,7 +107,7 @@
       // over a network or permanently stored and only used for the runtime of
       // Chromium, this is not a concern.
       hasher.AddCharacters(reinterpret_cast<const LChar*>(filename_.data()),
-                           filename_.length());
+                           static_cast<unsigned>(filename_.length()));
       hasher.AddCharacters(reinterpret_cast<const LChar*>(&ttc_index_),
                            sizeof(ttc_index_));
       hasher.AddCharacters(
@@ -129,7 +129,7 @@
  private:
   FontFaceCreationType creation_type_;
   AtomicString family_;
-  CString filename_;
+  std::string filename_;
   int fontconfig_interface_id_;
   int ttc_index_;
 };
diff --git a/third_party/blink/renderer/platform/fonts/font_platform_data.h b/third_party/blink/renderer/platform/fonts/font_platform_data.h
index 8e5f1b2..4a6a60e 100644
--- a/third_party/blink/renderer/platform/fonts/font_platform_data.h
+++ b/third_party/blink/renderer/platform/fonts/font_platform_data.h
@@ -41,7 +41,6 @@
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/hash_table_deleted_value_type.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_impl.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "third_party/skia/include/core/SkFont.h"
diff --git a/third_party/blink/renderer/platform/fonts/linux/font_cache_linux.cc b/third_party/blink/renderer/platform/fonts/linux/font_cache_linux.cc
index 04c1970..3f17a81c 100644
--- a/third_party/blink/renderer/platform/fonts/linux/font_cache_linux.cc
+++ b/third_party/blink/renderer/platform/fonts/linux/font_cache_linux.cc
@@ -30,7 +30,6 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/fonts/font_platform_data.h"
 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "ui/gfx/font_fallback_linux.h"
 
 namespace blink {
@@ -60,8 +59,8 @@
     Platform::Current()->GetSandboxSupport()->GetFallbackFontForCharacter(
         c, preferred_locale, &web_fallback_font);
     fallback_font->name = web_fallback_font.name;
-    fallback_font->filename = CString(web_fallback_font.filename.Data(),
-                                      web_fallback_font.filename.size());
+    fallback_font->filename = std::string(web_fallback_font.filename.Data(),
+                                          web_fallback_font.filename.size());
     fallback_font->fontconfig_interface_id =
         web_fallback_font.fontconfig_interface_id;
     fallback_font->ttc_index = web_fallback_font.ttc_index;
@@ -73,8 +72,7 @@
         gfx::GetFallbackFontForChar(c, locale);
     fallback_font->name = String::FromUTF8(fallback_data.name.data(),
                                            fallback_data.name.length());
-    fallback_font->filename =
-        CString(fallback_data.filename.data(), fallback_data.filename.length());
+    fallback_font->filename = fallback_data.filename;
     fallback_font->fontconfig_interface_id = 0;
     fallback_font->ttc_index = fallback_data.ttc_index;
     fallback_font->is_bold = fallback_data.is_bold;
diff --git a/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc b/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc
index 2ce9881f..51bdbb7 100644
--- a/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc
+++ b/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc
@@ -49,7 +49,6 @@
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/skia/include/core/SkFontMgr.h"
 #include "third_party/skia/include/core/SkStream.h"
 #include "third_party/skia/include/core/SkTypeface.h"
diff --git a/third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.cc b/third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.cc
index 6a606dd..bbb336a6 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.cc
@@ -8,7 +8,6 @@
 
 #include "base/memory/ptr_util.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/graphics/image_frame_generator.cc b/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
index 5bba6d2..c76a4a160 100644
--- a/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
+++ b/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
@@ -61,7 +61,7 @@
 ImageFrameGenerator::ImageFrameGenerator(const SkISize& full_size,
                                          bool is_multi_frame,
                                          const ColorBehavior& color_behavior,
-                                         std::vector<SkISize> supported_sizes)
+                                         Vector<SkISize> supported_sizes)
     : full_size_(full_size),
       decoder_color_behavior_(color_behavior),
       is_multi_frame_(is_multi_frame),
@@ -263,12 +263,15 @@
     : generator_(generator), client_id_(client_id) {
   {
     MutexLocker lock(generator_->generator_mutex_);
-    ClientMutex* client_mutex = nullptr;
     auto it = generator_->mutex_map_.find(client_id_);
-    if (it == generator_->mutex_map_.end())
-      client_mutex = &generator_->mutex_map_[client_id];
-    else
-      client_mutex = &it->second;
+    ClientMutex* client_mutex;
+    if (it == generator_->mutex_map_.end()) {
+      auto result = generator_->mutex_map_.insert(
+          client_id_, std::make_unique<ClientMutex>());
+      client_mutex = result.stored_value->value.get();
+    } else {
+      client_mutex = it->value.get();
+    }
     client_mutex->ref_count++;
     mutex_ = &client_mutex->mutex;
   }
@@ -282,9 +285,9 @@
   MutexLocker lock(generator_->generator_mutex_);
   auto it = generator_->mutex_map_.find(client_id_);
   DCHECK(it != generator_->mutex_map_.end());
-  it->second.ref_count--;
+  it->value->ref_count--;
 
-  if (it->second.ref_count == 0)
+  if (it->value->ref_count == 0)
     generator_->mutex_map_.erase(it);
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/image_frame_generator.h b/third_party/blink/renderer/platform/graphics/image_frame_generator.h
index 7b1d20a..45d21544 100644
--- a/third_party/blink/renderer/platform/graphics/image_frame_generator.h
+++ b/third_party/blink/renderer/platform/graphics/image_frame_generator.h
@@ -35,6 +35,7 @@
 #include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
@@ -67,7 +68,7 @@
       const SkISize& full_size,
       bool is_multi_frame,
       const ColorBehavior& color_behavior,
-      std::vector<SkISize> supported_sizes) {
+      Vector<SkISize> supported_sizes) {
     return base::AdoptRef(new ImageFrameGenerator(
         full_size, is_multi_frame, color_behavior, std::move(supported_sizes)));
   }
@@ -131,7 +132,7 @@
   ImageFrameGenerator(const SkISize& full_size,
                       bool is_multi_frame,
                       const ColorBehavior&,
-                      std::vector<SkISize> supported_sizes);
+                      Vector<SkISize> supported_sizes);
 
   friend class ImageFrameGeneratorTest;
   friend class DeferredImageDecoderTest;
@@ -147,7 +148,7 @@
   // Parameters used to create internal ImageDecoder objects.
   const ColorBehavior decoder_color_behavior_;
   const bool is_multi_frame_;
-  const std::vector<SkISize> supported_sizes_;
+  const Vector<SkISize> supported_sizes_;
 
   // Prevents concurrent access to all variables below.
   mutable Mutex generator_mutex_;
@@ -161,10 +162,15 @@
     int ref_count = 0;
     Mutex mutex;
   };
-  // Note that it is necessary to use unordered_map here to ensure that
-  // references to entries in the map, stored in ClientMutexLocker, remain valid
-  // across insertions into the map.
-  std::unordered_map<cc::PaintImage::GeneratorClientId, ClientMutex> mutex_map_;
+
+  // Note that it is necessary to use HashMap here to ensure that references
+  // to entries in the map, stored in ClientMutexLocker, remain valid across
+  // insertions into the map.
+  HashMap<cc::PaintImage::GeneratorClientId,
+          std::unique_ptr<ClientMutex>,
+          WTF::IntHash<cc::PaintImage::GeneratorClientId>,
+          WTF::UnsignedWithZeroKeyHashTraits<cc::PaintImage::GeneratorClientId>>
+      mutex_map_;
 
   std::unique_ptr<ImageDecoderFactory> image_decoder_factory_;
 
diff --git a/third_party/blink/renderer/platform/graphics/image_frame_generator_test.cc b/third_party/blink/renderer/platform/graphics/image_frame_generator_test.cc
index d1d3c3d..d1e5cd6 100644
--- a/third_party/blink/renderer/platform/graphics/image_frame_generator_test.cc
+++ b/third_party/blink/renderer/platform/graphics/image_frame_generator_test.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/renderer/platform/shared_buffer.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
@@ -120,7 +121,7 @@
       UseMockImageDecoderFactory();
     }
   }
-  void SetSupportedSizes(std::vector<SkISize> sizes) {
+  void SetSupportedSizes(Vector<SkISize> sizes) {
     generator_ = nullptr;
     generator_ = ImageFrameGenerator::Create(
         FullSize(), true, ColorBehavior::Ignore(), std::move(sizes));
@@ -142,9 +143,8 @@
 TEST_F(ImageFrameGeneratorTest, GetSupportedSizes) {
   ASSERT_TRUE(FullSize() == SkISize::Make(100, 100));
 
-  std::vector<SkISize> supported_sizes = {SkISize::Make(2, 2),
-                                          SkISize::Make(50, 50),
-                                          SkISize::Make(75, 75), FullSize()};
+  Vector<SkISize> supported_sizes = {SkISize::Make(2, 2), SkISize::Make(50, 50),
+                                     SkISize::Make(75, 75), FullSize()};
   SetSupportedSizes(supported_sizes);
 
   struct Test {
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.h b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
index 271f119..4085c2b 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
@@ -214,7 +214,7 @@
   bool IsDecodedSizeAvailable() const { return !failed_ && size_available_; }
 
   virtual IntSize Size() const { return size_; }
-  virtual std::vector<SkISize> GetSupportedDecodeSizes() const { return {}; }
+  virtual Vector<SkISize> GetSupportedDecodeSizes() const { return {}; }
 
   // Decoders which downsample images should override this method to
   // return the actual decoded size.
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
index 68fc36e..010fe43 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
@@ -529,13 +529,13 @@
           // the original size won't exceed the memory limit (see
           // |max_decoded_bytes_| in ImageDecoder) or something less than
           // |g_scale_denominator| otherwise to ensure the image is downscaled.
-          std::vector<SkISize> sizes;
+          Vector<SkISize> sizes;
           if (max_numerator == g_scale_denominator &&
               ShouldDecodeToOriginalSize()) {
             sizes.push_back(
                 SkISize::Make(info_.image_width, info_.image_height));
           } else {
-            sizes.reserve(max_numerator);
+            sizes.ReserveCapacity(max_numerator);
             for (int numerator = 1; numerator <= max_numerator; ++numerator) {
               info_.scale_num = numerator;
               jpeg_calc_output_dimensions(&info_);
@@ -918,7 +918,7 @@
 }
 
 bool JPEGImageDecoder::ShouldGenerateAllSizes() const {
-  return supported_decode_sizes_.empty();
+  return supported_decode_sizes_.IsEmpty();
 }
 
 bool JPEGImageDecoder::CanDecodeToYUV() {
@@ -954,11 +954,11 @@
   image_planes_ = std::move(image_planes);
 }
 
-void JPEGImageDecoder::SetSupportedDecodeSizes(std::vector<SkISize> sizes) {
+void JPEGImageDecoder::SetSupportedDecodeSizes(Vector<SkISize> sizes) {
   supported_decode_sizes_ = std::move(sizes);
 }
 
-std::vector<SkISize> JPEGImageDecoder::GetSupportedDecodeSizes() const {
+Vector<SkISize> JPEGImageDecoder::GetSupportedDecodeSizes() const {
   // DCHECK IsDecodedSizeAvailable instead of IsSizeAvailable, since the latter
   // has side effects of actually doing the decode.
   DCHECK(IsDecodedSizeAvailable());
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h
index 669eb71..9f69965b 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h
@@ -49,7 +49,7 @@
   bool CanDecodeToYUV() override;
   void DecodeToYUV() override;
   void SetImagePlanes(std::unique_ptr<ImagePlanes>) override;
-  std::vector<SkISize> GetSupportedDecodeSizes() const override;
+  Vector<SkISize> GetSupportedDecodeSizes() const override;
   bool HasImagePlanes() const { return image_planes_.get(); }
 
   bool OutputScanlines();
@@ -62,7 +62,7 @@
   }
   void SetDecodedSize(unsigned width, unsigned height);
 
-  void SetSupportedDecodeSizes(std::vector<SkISize> sizes);
+  void SetSupportedDecodeSizes(Vector<SkISize> sizes);
   void SetDecodeToYuvForTesting(bool decode_to_yuv) {
     decode_to_yuv_for_testing_ = decode_to_yuv;
   }
@@ -80,7 +80,7 @@
   std::unique_ptr<JPEGImageReader> reader_;
   std::unique_ptr<ImagePlanes> image_planes_;
   IntSize decoded_size_;
-  std::vector<SkISize> supported_decode_sizes_;
+  Vector<SkISize> supported_decode_sizes_;
   bool decode_to_yuv_for_testing_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(JPEGImageDecoder);
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
index cae38b4..c243cf6 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
@@ -327,7 +327,7 @@
   decoder->SetData(data.get(), true);
   // This will decode the size and needs to be called to avoid DCHECKs
   ASSERT_TRUE(decoder->IsSizeAvailable());
-  std::vector<SkISize> expected_sizes = {
+  Vector<SkISize> expected_sizes = {
       SkISize::Make(32, 32),   SkISize::Make(64, 64),   SkISize::Make(96, 96),
       SkISize::Make(128, 128), SkISize::Make(160, 160), SkISize::Make(192, 192),
       SkISize::Make(224, 224), SkISize::Make(256, 256)};
@@ -355,7 +355,7 @@
   decoder->SetData(data.get(), true);
   // This will decode the size and needs to be called to avoid DCHECKs
   ASSERT_TRUE(decoder->IsSizeAvailable());
-  std::vector<SkISize> expected_sizes = {
+  Vector<SkISize> expected_sizes = {
       SkISize::Make(34, 25),   SkISize::Make(68, 50),   SkISize::Make(102, 75),
       SkISize::Make(136, 100), SkISize::Make(170, 125), SkISize::Make(204, 150),
       SkISize::Make(238, 175), SkISize::Make(272, 200)};
@@ -387,7 +387,7 @@
   decoder->SetData(data.get(), true);
   // This will decode the size and needs to be called to avoid DCHECKs
   ASSERT_TRUE(decoder->IsSizeAvailable());
-  std::vector<SkISize> expected_sizes = {
+  Vector<SkISize> expected_sizes = {
       SkISize::Make(35, 26),   SkISize::Make(69, 52),   SkISize::Make(104, 78),
       SkISize::Make(138, 104), SkISize::Make(172, 130), SkISize::Make(207, 156),
       SkISize::Make(241, 182)};
@@ -444,7 +444,7 @@
   decoder->SetData(data.get(), true);
   // This will decode the size and needs to be called to avoid DCHECKs
   ASSERT_TRUE(decoder->IsSizeAvailable());
-  std::vector<SkISize> expected_sizes = {
+  Vector<SkISize> expected_sizes = {
       SkISize::Make(32, 32), SkISize::Make(64, 64), SkISize::Make(96, 96),
       SkISize::Make(128, 128)};
   auto sizes = decoder->GetSupportedDecodeSizes();
diff --git a/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h b/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h
index 5d8d61d..e95e9ee5 100644
--- a/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h
+++ b/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h
@@ -8,18 +8,8 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
-// Conversion from CString to TraceValue so that trace arguments can be strings.
-template <>
-struct base::trace_event::TraceValue::Helper<WTF::CString> {
-  static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
-  static inline void SetValue(TraceValue* v, const WTF::CString& value) {
-    v->as_string = value.data();
-  }
-};
-
 namespace blink {
 namespace trace_event {
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc b/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
index eb34884..6dfb407 100644
--- a/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
@@ -33,7 +33,6 @@
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.cc b/third_party/blink/renderer/platform/loader/fetch/resource.cc
index e51e348..229888c5 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -55,7 +55,6 @@
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 6e8e053..1a953c7a 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -74,7 +74,6 @@
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
 #include "third_party/blink/renderer/platform/weborigin/security_violation_reporting_policy.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/wtf.h"
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
index 11023a15..f6189cf 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -44,7 +44,6 @@
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/platform/network/encoded_form_data.cc b/third_party/blink/renderer/platform/network/encoded_form_data.cc
index 5ea53af..6745608 100644
--- a/third_party/blink/renderer/platform/network/encoded_form_data.cc
+++ b/third_party/blink/renderer/platform/network/encoded_form_data.cc
@@ -24,7 +24,6 @@
 #include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/network/form_data_encoder.h"
 #include "third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/network/form_data_encoder.cc b/third_party/blink/renderer/platform/network/form_data_encoder.cc
index 0954362..dfcc868 100644
--- a/third_party/blink/renderer/platform/network/form_data_encoder.cc
+++ b/third_party/blink/renderer/platform/network/form_data_encoder.cc
@@ -27,7 +27,6 @@
 
 #include <limits>
 #include "base/rand_util.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/network/http_parsers.cc b/third_party/blink/renderer/platform/network/http_parsers.cc
index c722063e..3832a230 100644
--- a/third_party/blink/renderer/platform/network/http_parsers.cc
+++ b/third_party/blink/renderer/platform/network/http_parsers.cc
@@ -43,7 +43,6 @@
 #include "third_party/blink/renderer/platform/wtf/date_math.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/parsing_utilities.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
diff --git a/third_party/blink/renderer/platform/testing/fuzzed_data_provider.cc b/third_party/blink/renderer/platform/testing/fuzzed_data_provider.cc
index a2bb3a2..2a9f311 100644
--- a/third_party/blink/renderer/platform/testing/fuzzed_data_provider.cc
+++ b/third_party/blink/renderer/platform/testing/fuzzed_data_provider.cc
@@ -16,9 +16,9 @@
   return String::FromUTF8WithLatin1Fallback(str.data(), str.length());
 }
 
-CString FuzzedDataProvider::ConsumeRemainingBytes() {
+std::string FuzzedDataProvider::ConsumeRemainingBytes() {
   std::vector<char> bytes = provider_.ConsumeRemainingBytes<char>();
-  return CString(bytes.data(), bytes.size());
+  return std::string(bytes.data(), bytes.size());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/testing/fuzzed_data_provider.h b/third_party/blink/renderer/platform/testing/fuzzed_data_provider.h
index 47ca6eb8a..f9a8734 100644
--- a/third_party/blink/renderer/platform/testing/fuzzed_data_provider.h
+++ b/third_party/blink/renderer/platform/testing/fuzzed_data_provider.h
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "base/test/fuzzed_data_provider.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
@@ -25,7 +24,7 @@
   String ConsumeRandomLengthString(size_t max_length);
 
   // Returns a String containing all remaining bytes of the input data.
-  CString ConsumeRemainingBytes();
+  std::string ConsumeRemainingBytes();
 
   // Returns a bool, or false when no data remains.
   bool ConsumeBool() { return provider_.ConsumeBool(); }
diff --git a/third_party/blink/renderer/platform/text/date_time_format_test.cc b/third_party/blink/renderer/platform/text/date_time_format_test.cc
index f2b12ed..44133b02 100644
--- a/third_party/blink/renderer/platform/text/date_time_format_test.cc
+++ b/third_party/blink/renderer/platform/text/date_time_format_test.cc
@@ -26,7 +26,6 @@
 #include "third_party/blink/renderer/platform/text/date_time_format.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/text/locale_icu.h b/third_party/blink/renderer/platform/text/locale_icu.h
index ec2cbfc..c0708d5 100644
--- a/third_party/blink/renderer/platform/text/locale_icu.h
+++ b/third_party/blink/renderer/platform/text/locale_icu.h
@@ -37,7 +37,6 @@
 #include "third_party/blink/renderer/platform/text/date_components.h"
 #include "third_party/blink/renderer/platform/text/platform_locale.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/text/locale_mac_test.mm b/third_party/blink/renderer/platform/text/locale_mac_test.mm
index 94481b16..093dc93 100644
--- a/third_party/blink/renderer/platform/text/locale_mac_test.mm
+++ b/third_party/blink/renderer/platform/text/locale_mac_test.mm
@@ -33,7 +33,6 @@
 #include "third_party/blink/renderer/platform/text/date_components.h"
 #include "third_party/blink/renderer/platform/wtf/date_math.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/text/locale_win_test.cc b/third_party/blink/renderer/platform/text/locale_win_test.cc
index 1ea7ca5..d614168 100644
--- a/third_party/blink/renderer/platform/text/locale_win_test.cc
+++ b/third_party/blink/renderer/platform/text/locale_win_test.cc
@@ -35,7 +35,6 @@
 #include "third_party/blink/renderer/platform/text/date_components.h"
 #include "third_party/blink/renderer/platform/wtf/date_math.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator_internal_icu.cc b/third_party/blink/renderer/platform/text/text_break_iterator_internal_icu.cc
index d5162b74..3c57470 100644
--- a/third_party/blink/renderer/platform/text/text_break_iterator_internal_icu.cc
+++ b/third_party/blink/renderer/platform/text/text_break_iterator_internal_icu.cc
@@ -23,7 +23,6 @@
 
 #include "third_party/blink/renderer/platform/language.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/text_codec_fuzzer.cc b/third_party/blink/renderer/platform/text_codec_fuzzer.cc
index e69046b..86d618c 100644
--- a/third_party/blink/renderer/platform/text_codec_fuzzer.cc
+++ b/third_party/blink/renderer/platform/text_codec_fuzzer.cc
@@ -6,7 +6,6 @@
 
 #include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
 #include "third_party/blink/renderer/platform/testing/fuzzed_data_provider.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
 
@@ -46,36 +45,37 @@
 #endif
       "");
 
-  FuzzedDataProvider fuzzedData(data, size);
+  FuzzedDataProvider fuzzed_data(data, size);
 
   // Initialize metadata using the fuzzed data.
-  bool stopOnError = fuzzedData.ConsumeBool();
-  WTF::UnencodableHandling unencodableHandling =
-      fuzzedData.PickValueInArray(kUnencodableHandlingOptions);
-  WTF::FlushBehavior flushBehavior =
-      fuzzedData.PickValueInArray(kFlushBehavior);
+  bool stop_on_error = fuzzed_data.ConsumeBool();
+  WTF::UnencodableHandling unencodable_handling =
+      fuzzed_data.PickValueInArray(kUnencodableHandlingOptions);
+  WTF::FlushBehavior flush_behavior =
+      fuzzed_data.PickValueInArray(kFlushBehavior);
 
   // Now, use the rest of the fuzzy data to stress test decoding and encoding.
-  const CString byteString = fuzzedData.ConsumeRemainingBytes();
+  const std::string byte_string = fuzzed_data.ConsumeRemainingBytes();
   std::unique_ptr<TextCodec> codec = NewTextCodec(encoding);
 
   // Treat as bytes-off-the-wire.
-  bool sawError;
-  const String decoded = codec->Decode(byteString.data(), byteString.length(),
-                                       flushBehavior, stopOnError, sawError);
+  bool saw_error;
+  const String decoded =
+      codec->Decode(byte_string.data(), byte_string.length(), flush_behavior,
+                    stop_on_error, saw_error);
 
   // Treat as blink 8-bit string (latin1).
   if (size % sizeof(LChar) == 0) {
     std::unique_ptr<TextCodec> codec = NewTextCodec(encoding);
-    codec->Encode(reinterpret_cast<const LChar*>(byteString.data()),
-                  byteString.length() / sizeof(LChar), unencodableHandling);
+    codec->Encode(reinterpret_cast<const LChar*>(byte_string.data()),
+                  byte_string.length() / sizeof(LChar), unencodable_handling);
   }
 
   // Treat as blink 16-bit string (utf-16) if there are an even number of bytes.
   if (size % sizeof(UChar) == 0) {
     std::unique_ptr<TextCodec> codec = NewTextCodec(encoding);
-    codec->Encode(reinterpret_cast<const UChar*>(byteString.data()),
-                  byteString.length() / sizeof(UChar), unencodableHandling);
+    codec->Encode(reinterpret_cast<const UChar*>(byte_string.data()),
+                  byte_string.length() / sizeof(UChar), unencodable_handling);
   }
 
   if (decoded.IsNull())
@@ -83,10 +83,11 @@
 
   // Round trip the bytes (aka encode the decoded bytes).
   if (decoded.Is8Bit()) {
-    codec->Encode(decoded.Characters8(), decoded.length(), unencodableHandling);
+    codec->Encode(decoded.Characters8(), decoded.length(),
+                  unencodable_handling);
   } else {
     codec->Encode(decoded.Characters16(), decoded.length(),
-                  unencodableHandling);
+                  unencodable_handling);
   }
   return 0;
 }
diff --git a/third_party/blink/renderer/platform/weborigin/kurl.cc b/third_party/blink/renderer/platform/weborigin/kurl.cc
index d90bd58e..32e4c690 100644
--- a/third_party/blink/renderer/platform/weborigin/kurl.cc
+++ b/third_party/blink/renderer/platform/weborigin/kurl.cc
@@ -32,7 +32,6 @@
 #include "third_party/blink/renderer/platform/weborigin/known_ports.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_statics.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
diff --git a/third_party/blink/renderer/platform/weborigin/kurl_test.cc b/third_party/blink/renderer/platform/weborigin/kurl_test.cc
index fc97171..d254daa1 100644
--- a/third_party/blink/renderer/platform/weborigin/kurl_test.cc
+++ b/third_party/blink/renderer/platform/weborigin/kurl_test.cc
@@ -38,7 +38,6 @@
 #include "base/stl_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "url/url_util.h"
 
diff --git a/third_party/blink/renderer/platform/wtf/BUILD.gn b/third_party/blink/renderer/platform/wtf/BUILD.gn
index ade34d0..be01b657 100644
--- a/third_party/blink/renderer/platform/wtf/BUILD.gn
+++ b/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -120,8 +120,6 @@
     "text/base64.cc",
     "text/base64.h",
     "text/character_names.h",
-    "text/cstring.cc",
-    "text/cstring.h",
     "text/integer_to_string_conversion.h",
     "text/line_ending.cc",
     "text/line_ending.h",
@@ -301,7 +299,6 @@
     "scoped_logger_test.cc",
     "testing/run_all_tests.cc",
     "text/atomic_string_test.cc",
-    "text/cstring_test.cc",
     "text/integer_to_string_conversion_test.cc",
     "text/line_ending_test.cc",
     "text/string_buffer_test.cc",
diff --git a/third_party/blink/renderer/platform/wtf/README.md b/third_party/blink/renderer/platform/wtf/README.md
index 5889044..2925ab7 100644
--- a/third_party/blink/renderer/platform/wtf/README.md
+++ b/third_party/blink/renderer/platform/wtf/README.md
@@ -43,7 +43,7 @@
 
 * **Strings**
 
-  [String], [AtomicString], [StringBuilder], [CString]
+  [String], [AtomicString], [StringBuilder]
 
 * **Reference counting**
 
@@ -93,7 +93,6 @@
 [String]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/wtf/text/wtf_string.h
 [AtomicString]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/wtf/text/atomic_string.h
 [StringBuilder]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/wtf/text/string_builder.h
-[CString]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/wtf/text/cstring.h
 [RefCounted]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/wtf/ref_counted.h
 [allocator.h]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/wtf/allocator.h
 [functional.h]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/wtf/functional.h
diff --git a/third_party/blink/renderer/platform/wtf/decimal_test.cc b/third_party/blink/renderer/platform/wtf/decimal_test.cc
index 288af1d..ae73eded 100644
--- a/third_party/blink/renderer/platform/wtf/decimal_test.cc
+++ b/third_party/blink/renderer/platform/wtf/decimal_test.cc
@@ -35,7 +35,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/wtf/forward.h b/third_party/blink/renderer/platform/wtf/forward.h
index d039c7f..71c3214 100644
--- a/third_party/blink/renderer/platform/wtf/forward.h
+++ b/third_party/blink/renderer/platform/wtf/forward.h
@@ -45,7 +45,6 @@
 class AtomicString;
 class BigInt64Array;
 class BigUint64Array;
-class CString;
 class Float32Array;
 class Float64Array;
 class Int8Array;
@@ -72,7 +71,6 @@
 using WTF::AtomicString;
 using WTF::BigInt64Array;
 using WTF::BigUint64Array;
-using WTF::CString;
 using WTF::Float32Array;
 using WTF::Float64Array;
 using WTF::Int8Array;
diff --git a/third_party/blink/renderer/platform/wtf/pod_red_black_tree.h b/third_party/blink/renderer/platform/wtf/pod_red_black_tree.h
index c401ebed..b35c2e1 100644
--- a/third_party/blink/renderer/platform/wtf/pod_red_black_tree.h
+++ b/third_party/blink/renderer/platform/wtf/pod_red_black_tree.h
@@ -78,7 +78,6 @@
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/pod_free_list_arena.h"
 #ifndef NDEBUG
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #endif
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string.h b/third_party/blink/renderer/platform/wtf/text/atomic_string.h
index a1da6c9..3c2f1e5 100644
--- a/third_party/blink/renderer/platform/wtf/text/atomic_string.h
+++ b/third_party/blink/renderer/platform/wtf/text/atomic_string.h
@@ -27,7 +27,7 @@
 #include "build/build_config.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/hash_table_deleted_value_type.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string_cf.cc b/third_party/blink/renderer/platform/wtf/text/atomic_string_cf.cc
index 9a6442d1..82a3bb31 100644
--- a/third_party/blink/renderer/platform/wtf/text/atomic_string_cf.cc
+++ b/third_party/blink/renderer/platform/wtf/text/atomic_string_cf.cc
@@ -31,7 +31,6 @@
 #if defined(OS_MACOSX)
 
 #include <CoreFoundation/CoreFoundation.h>
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace WTF {
 
diff --git a/third_party/blink/renderer/platform/wtf/text/base64.h b/third_party/blink/renderer/platform/wtf/text/base64.h
index de547689..e221b528 100644
--- a/third_party/blink/renderer/platform/wtf/text/base64.h
+++ b/third_party/blink/renderer/platform/wtf/text/base64.h
@@ -27,7 +27,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_BASE64_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_BASE64_H_
 
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "third_party/blink/renderer/platform/wtf/wtf_export.h"
@@ -45,7 +44,7 @@
 WTF_EXPORT void Base64Encode(const Vector<char>&,
                              Vector<char>&,
                              Base64EncodePolicy = kBase64DoNotInsertLFs);
-WTF_EXPORT void Base64Encode(const CString&,
+WTF_EXPORT void Base64Encode(const std::string&,
                              Vector<char>&,
                              Base64EncodePolicy = kBase64DoNotInsertLFs);
 WTF_EXPORT String Base64Encode(const char*,
@@ -100,10 +99,10 @@
   Base64Encode(in.data(), in.size(), out, policy);
 }
 
-inline void Base64Encode(const CString& in,
+inline void Base64Encode(const std::string& in,
                          Vector<char>& out,
                          Base64EncodePolicy policy) {
-  Base64Encode(in.data(), in.length(), out, policy);
+  Base64Encode(in.c_str(), static_cast<unsigned>(in.length()), out, policy);
 }
 
 inline String Base64Encode(const Vector<char>& in, Base64EncodePolicy policy) {
diff --git a/third_party/blink/renderer/platform/wtf/text/cstring.cc b/third_party/blink/renderer/platform/wtf/text/cstring.cc
deleted file mode 100644
index 23b1db6..0000000
--- a/third_party/blink/renderer/platform/wtf/text/cstring.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2003, 2006, 2008, 2009, 2010, 2012 Apple Inc. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
-
-#include <string.h>
-#include "base/numerics/checked_math.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
-#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/ascii_ctype.h"
-
-namespace WTF {
-
-scoped_refptr<CStringImpl> CStringImpl::CreateUninitialized(size_t length,
-                                                            char*& data) {
-  wtf_size_t length_in_unsigned = SafeCast<wtf_size_t>(length);
-  base::CheckedNumeric<size_t> size = length_in_unsigned;
-  // The +1 is for the terminating NUL character.
-  size += sizeof(CStringImpl) + 1;
-  CStringImpl* buffer = static_cast<CStringImpl*>(Partitions::BufferMalloc(
-      size.ValueOrDie(), WTF_HEAP_PROFILER_TYPE_NAME(CStringImpl)));
-  data = reinterpret_cast<char*>(buffer + 1);
-  data[length] = '\0';
-  return base::AdoptRef(new (buffer) CStringImpl(length_in_unsigned));
-}
-
-void CStringImpl::operator delete(void* ptr) {
-  Partitions::BufferFree(ptr);
-}
-
-CString::CString(const char* chars, size_t length) {
-  if (!chars) {
-    DCHECK_EQ(length, 0u);
-    return;
-  }
-  char* data;
-  buffer_ = CStringImpl::CreateUninitialized(length, data);
-  memcpy(data, chars, length);
-}
-
-bool CString::IsSafeToSendToAnotherThread() const {
-  return !buffer_ || buffer_->HasOneRef();
-}
-
-bool operator==(const CString& a, const CString& b) {
-  if (a.IsNull() != b.IsNull())
-    return false;
-  if (a.length() != b.length())
-    return false;
-  return !memcmp(a.data(), b.data(), a.length());
-}
-
-bool operator==(const CString& a, const char* b) {
-  if (a.IsNull() != !b)
-    return false;
-  if (!b)
-    return true;
-  return !strcmp(a.data(), b);
-}
-
-std::ostream& operator<<(std::ostream& ostream, const CString& string) {
-  if (string.IsNull())
-    return ostream << "<null>";
-
-  ostream << '"';
-  for (size_t index = 0; index < string.length(); ++index) {
-    // Print shorthands for select cases.
-    char character = string.data()[index];
-    switch (character) {
-      case '\t':
-        ostream << "\\t";
-        break;
-      case '\n':
-        ostream << "\\n";
-        break;
-      case '\r':
-        ostream << "\\r";
-        break;
-      case '"':
-        ostream << "\\\"";
-        break;
-      case '\\':
-        ostream << "\\\\";
-        break;
-      default:
-        if (IsASCIIPrintable(character)) {
-          ostream << character;
-        } else {
-          // Print "\xHH" for control or non-ASCII characters.
-          ostream << "\\x";
-          if (character >= 0 && character < 0x10)
-            ostream << "0";
-          ostream.setf(std::ios_base::hex, std::ios_base::basefield);
-          ostream.setf(std::ios::uppercase);
-          ostream << (character & 0xff);
-        }
-        break;
-    }
-  }
-  return ostream << '"';
-}
-
-}  // namespace WTF
diff --git a/third_party/blink/renderer/platform/wtf/text/cstring.h b/third_party/blink/renderer/platform/wtf/text/cstring.h
deleted file mode 100644
index 243c766..0000000
--- a/third_party/blink/renderer/platform/wtf/text/cstring.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2003, 2006, 2008, 2009, 2010, 2012 Apple Inc. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_CSTRING_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_CSTRING_H_
-
-#include <string.h>
-
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/partition_allocator.h"
-#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
-#include "third_party/blink/renderer/platform/wtf/wtf_export.h"
-#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
-
-namespace WTF {
-
-// CStringImpl is an immutable ref-counted storage for the characters in a
-// CString. It's analogous to a StringImpl but may contain any arbitrary
-// sequence of bytes. The data is always allocated 1 longer than length() and is
-// null terminated.
-class WTF_EXPORT CStringImpl : public RefCounted<CStringImpl> {
- public:
-  // CStringImpls are allocated out of the WTF buffer partition.
-  void* operator new(size_t, void* ptr) { return ptr; }
-  void operator delete(void*);
-
-  static scoped_refptr<CStringImpl> CreateUninitialized(size_t length,
-                                                        char*& data);
-
-  const char* data() const { return reinterpret_cast<const char*>(this + 1); }
-  wtf_size_t length() const { return length_; }
-
- private:
-  explicit CStringImpl(unsigned length) : length_(length) {}
-
-  const unsigned length_;
-
-  DISALLOW_COPY_AND_ASSIGN(CStringImpl);
-};
-
-// A container for an immutable ref-counted null-terminated char array. This is
-// analogous to a WTF::String but does not require the contained bytes to be
-// valid Latin1 or UTF-16. Instead a CString can contain any arbitrary bytes.
-class WTF_EXPORT CString {
-  USING_FAST_MALLOC(CString);
-
- public:
-  // Construct a null string, distinguishable from an empty string.
-  CString() = default;
-
-  // Construct a string from arbitrary bytes.
-  CString(const char* chars) : CString(chars, chars ? strlen(chars) : 0) {}
-  CString(const char*, size_t length);
-
-  // Construct a string referencing an existing buffer.
-  CString(CStringImpl* buffer) : buffer_(buffer) {}
-  CString(scoped_refptr<CStringImpl> buffer) : buffer_(std::move(buffer)) {}
-
-  static CString CreateUninitialized(wtf_size_t length, char*& data) {
-    return CStringImpl::CreateUninitialized(length, data);
-  }
-
-  // The bytes of the string, always NUL terminated. May be null.
-  const char* data() const { return buffer_ ? buffer_->data() : nullptr; }
-
-  // The length of the data(), *not* including the NUL terminator.
-  wtf_size_t length() const { return buffer_ ? buffer_->length() : 0; }
-
-  bool IsNull() const { return !buffer_; }
-
-  bool IsSafeToSendToAnotherThread() const;
-
-  CStringImpl* Impl() const { return buffer_.get(); }
-
- private:
-  scoped_refptr<CStringImpl> buffer_;
-};
-
-WTF_EXPORT bool operator==(const CString& a, const CString& b);
-inline bool operator!=(const CString& a, const CString& b) {
-  return !(a == b);
-}
-WTF_EXPORT bool operator==(const CString& a, const char* b);
-inline bool operator!=(const CString& a, const char* b) {
-  return !(a == b);
-}
-
-// Pretty printer for gtest and base/logging.*.  It prepends and appends
-// double-quotes, and escapes characters other than ASCII printables.
-WTF_EXPORT std::ostream& operator<<(std::ostream&, const CString&);
-
-}  // namespace WTF
-
-using WTF::CString;
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_CSTRING_H_
diff --git a/third_party/blink/renderer/platform/wtf/text/cstring_test.cc b/third_party/blink/renderer/platform/wtf/text/cstring_test.cc
deleted file mode 100644
index 14dd97a7..0000000
--- a/third_party/blink/renderer/platform/wtf/text/cstring_test.cc
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include <sstream>
-
-namespace WTF {
-
-namespace {
-
-CString PrintedString(const CString& string) {
-  std::ostringstream output;
-  output << string;
-  const std::string& result = output.str();
-  return CString(result.data(), result.length());
-}
-
-}  // anonymous namespace
-
-TEST(CStringTest, NullStringConstructor) {
-  CString string;
-  EXPECT_TRUE(string.IsNull());
-  EXPECT_EQ(static_cast<const char*>(nullptr), string.data());
-  EXPECT_EQ(static_cast<size_t>(0), string.length());
-
-  CString string_from_char_pointer(static_cast<const char*>(nullptr));
-  EXPECT_TRUE(string_from_char_pointer.IsNull());
-  EXPECT_EQ(static_cast<const char*>(nullptr), string_from_char_pointer.data());
-  EXPECT_EQ(static_cast<size_t>(0), string_from_char_pointer.length());
-
-  CString string_from_char_and_length(static_cast<const char*>(nullptr), 0);
-  EXPECT_TRUE(string_from_char_and_length.IsNull());
-  EXPECT_EQ(static_cast<const char*>(nullptr),
-            string_from_char_and_length.data());
-  EXPECT_EQ(static_cast<size_t>(0), string_from_char_and_length.length());
-}
-
-TEST(CStringTest, EmptyEmptyConstructor) {
-  const char* empty_string = "";
-  CString string(empty_string);
-  EXPECT_FALSE(string.IsNull());
-  EXPECT_EQ(static_cast<size_t>(0), string.length());
-  EXPECT_EQ(0, string.data()[0]);
-
-  CString string_with_length(empty_string, 0);
-  EXPECT_FALSE(string_with_length.IsNull());
-  EXPECT_EQ(static_cast<size_t>(0), string_with_length.length());
-  EXPECT_EQ(0, string_with_length.data()[0]);
-}
-
-TEST(CStringTest, EmptyRegularConstructor) {
-  const char* reference_string = "WebKit";
-
-  CString string(reference_string);
-  EXPECT_FALSE(string.IsNull());
-  EXPECT_EQ(strlen(reference_string), string.length());
-  EXPECT_EQ(reference_string, string);
-
-  CString string_with_length(reference_string, 6);
-  EXPECT_FALSE(string_with_length.IsNull());
-  EXPECT_EQ(strlen(reference_string), string_with_length.length());
-  EXPECT_EQ(reference_string, string_with_length);
-}
-
-TEST(CStringTest, UninitializedConstructor) {
-  char* buffer;
-  CString empty_string = CString::CreateUninitialized(0, buffer);
-  EXPECT_FALSE(empty_string.IsNull());
-  EXPECT_EQ(buffer, empty_string.data());
-  EXPECT_EQ(0, buffer[0]);
-
-  const size_t kLength = 25;
-  CString uninitialized_string = CString::CreateUninitialized(kLength, buffer);
-  EXPECT_FALSE(uninitialized_string.IsNull());
-  EXPECT_EQ(buffer, uninitialized_string.data());
-  EXPECT_EQ(0, uninitialized_string.data()[kLength]);
-}
-
-TEST(CStringTest, ZeroTerminated) {
-  const char* reference_string = "WebKit";
-  CString string_with_length(reference_string, 3);
-  EXPECT_EQ(0, string_with_length.data()[3]);
-}
-
-TEST(CStringTest, Comparison) {
-  // Comparison with another CString.
-  CString a;
-  CString b;
-  EXPECT_TRUE(a == b);
-  EXPECT_FALSE(a != b);
-  a = "a";
-  b = CString();
-  EXPECT_FALSE(a == b);
-  EXPECT_TRUE(a != b);
-  a = "a";
-  b = "b";
-  EXPECT_FALSE(a == b);
-  EXPECT_TRUE(a != b);
-  a = "a";
-  b = "a";
-  EXPECT_TRUE(a == b);
-  EXPECT_FALSE(a != b);
-  a = "a";
-  b = "aa";
-  EXPECT_FALSE(a == b);
-  EXPECT_TRUE(a != b);
-  a = "";
-  b = "";
-  EXPECT_TRUE(a == b);
-  EXPECT_FALSE(a != b);
-  a = "";
-  b = CString();
-  EXPECT_FALSE(a == b);
-  EXPECT_TRUE(a != b);
-  a = "a";
-  b = "";
-  EXPECT_FALSE(a == b);
-  EXPECT_TRUE(a != b);
-
-  // Comparison with a const char*.
-  CString c;
-  const char* d = nullptr;
-  EXPECT_TRUE(c == d);
-  EXPECT_FALSE(c != d);
-  c = "c";
-  d = nullptr;
-  EXPECT_FALSE(c == d);
-  EXPECT_TRUE(c != d);
-  c = CString();
-  d = "d";
-  EXPECT_FALSE(c == d);
-  EXPECT_TRUE(c != d);
-  c = "c";
-  d = "d";
-  EXPECT_FALSE(c == d);
-  EXPECT_TRUE(c != d);
-  c = "c";
-  d = "c";
-  EXPECT_TRUE(c == d);
-  EXPECT_FALSE(c != d);
-  c = "c";
-  d = "cc";
-  EXPECT_FALSE(c == d);
-  EXPECT_TRUE(c != d);
-  c = "cc";
-  d = "c";
-  EXPECT_FALSE(c == d);
-  EXPECT_TRUE(c != d);
-  c = "";
-  d = "";
-  EXPECT_TRUE(c == d);
-  EXPECT_FALSE(c != d);
-  c = "";
-  d = nullptr;
-  EXPECT_FALSE(c == d);
-  EXPECT_TRUE(c != d);
-  c = CString();
-  d = "";
-  EXPECT_FALSE(c == d);
-  EXPECT_TRUE(c != d);
-  c = "a";
-  d = "";
-  EXPECT_FALSE(c == d);
-  EXPECT_TRUE(c != d);
-  c = "";
-  d = "b";
-  EXPECT_FALSE(c == d);
-  EXPECT_TRUE(c != d);
-}
-
-TEST(CStringTest, Printer) {
-  EXPECT_EQ("<null>", PrintedString(CString()));
-  EXPECT_EQ("\"abc\"", PrintedString("abc"));
-  EXPECT_EQ("\"\\t\\n\\r\\\"\\\\\"", PrintedString("\t\n\r\"\\"));
-  EXPECT_EQ("\"\\xFF\\x00\\x01xyz\"",
-            PrintedString(CString("\xff\0\x01xyz", 6)));
-}
-
-}  // namespace WTF
diff --git a/third_party/blink/renderer/platform/wtf/text/line_ending.cc b/third_party/blink/renderer/platform/wtf/text/line_ending.cc
index f2e2826a..5a8784a 100644
--- a/third_party/blink/renderer/platform/wtf/text/line_ending.cc
+++ b/third_party/blink/renderer/platform/wtf/text/line_ending.cc
@@ -33,7 +33,6 @@
 
 #include "build/build_config.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc b/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc
index 6784019..e3f6b1b 100644
--- a/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc
+++ b/third_party/blink/renderer/platform/wtf/text/string_builder_test.cc
@@ -35,7 +35,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace WTF {
diff --git a/third_party/blink/renderer/platform/wtf/text/string_impl.cc b/third_party/blink/renderer/platform/wtf/text/string_impl.cc
index 0be863a..91319c3 100644
--- a/third_party/blink/renderer/platform/wtf/text/string_impl.cc
+++ b/third_party/blink/renderer/platform/wtf/text/string_impl.cc
@@ -35,7 +35,6 @@
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_table.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_to_number.h"
diff --git a/third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h b/third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h
index c2f2c75c..05eabe5 100644
--- a/third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h
+++ b/third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h
@@ -32,7 +32,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_STRING_UTF8_ADAPTOR_H_
 
 #include "base/strings/string_piece.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/wtf_export.h"
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc
index c5f037c..810d1cd 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc
@@ -34,7 +34,6 @@
 #include "base/memory/ptr_util.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
 #include "third_party/blink/renderer/platform/wtf/threading.h"
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc
index 4299686..bab2c16 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc
@@ -27,7 +27,6 @@
 
 #include <memory>
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_replacement_test.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_replacement_test.cc
index 99c93dc..0fe72b40 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_replacement_test.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_replacement_test.cc
@@ -8,7 +8,6 @@
 
 #include "base/stl_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_codec.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.cc
index 2e7cbf9..b2ffa7a0 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.cc
@@ -27,7 +27,6 @@
 
 #include <memory>
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.cc
index 4d12afff..0687d22 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.cc
@@ -27,7 +27,6 @@
 
 #include <memory>
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
@@ -163,9 +162,6 @@
 
   std::string result(length * 2, '\0');
 
-  // FIXME: CString is not a reasonable data structure for encoded UTF-16, which
-  // will have null characters inside it. Perhaps the result of encode should
-  // not be a CString.
   if (little_endian_) {
     for (wtf_size_t i = 0; i < length; ++i) {
       UChar c = characters[i];
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc
index 54ac1ed..6874eca 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc
@@ -29,7 +29,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/numerics/checked_math.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h"
 
diff --git a/third_party/blink/renderer/platform/wtf/text/text_encoding.cc b/third_party/blink/renderer/platform/wtf/text/text_encoding.cc
index b7ecbf0..ee02d3b 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_encoding.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_encoding.cc
@@ -29,7 +29,6 @@
 
 #include <memory>
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/threading.h"
diff --git a/third_party/blink/renderer/platform/wtf/text/text_encoding_registry.cc b/third_party/blink/renderer/platform/wtf/text/text_encoding_registry.cc
index d1806a77..5b1ce61 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_encoding_registry.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_encoding_registry.cc
@@ -33,7 +33,6 @@
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/ascii_ctype.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_codec_icu.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_codec_latin1.h"
diff --git a/third_party/blink/renderer/platform/wtf/text/wtf_string.cc b/third_party/blink/renderer/platform/wtf/text/wtf_string.cc
index bfe5020..9e76d9a 100644
--- a/third_party/blink/renderer/platform/wtf/text/wtf_string.cc
+++ b/third_party/blink/renderer/platform/wtf/text/wtf_string.cc
@@ -31,7 +31,6 @@
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/ascii_ctype.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/unicode.h"
 #include "third_party/blink/renderer/platform/wtf/text/utf8.h"
@@ -472,11 +471,11 @@
   // Allocate a buffer big enough to hold all the characters
   // (an individual UTF-16 UChar can only expand to 3 UTF-8 bytes).
   // Optimization ideas, if we find this function is hot:
-  //  * We could speculatively create a CStringImpl to contain 'length'
+  //  * We could speculatively create a std::string to contain 'length'
   //    characters, and resize if necessary (i.e. if the buffer contains
   //    non-ascii characters). (Alternatively, scan the buffer first for
   //    ascii characters, so we know this will be sufficient).
-  //  * We could allocate a CStringImpl with an appropriate size to
+  //  * We could allocate a std::string with an appropriate size to
   //    have a good chance of being able to write the string into the
   //    buffer without reallocing (say, 1.5 x length).
   if (length > std::numeric_limits<unsigned>::max() / 3)
@@ -612,10 +611,6 @@
   return FromUTF8(string, strlen(reinterpret_cast<const char*>(string)));
 }
 
-String String::FromUTF8(const CString& s) {
-  return FromUTF8(s.data());
-}
-
 String String::FromUTF8(base::StringPiece s) {
   return FromUTF8(reinterpret_cast<const LChar*>(s.data()), s.size());
 }
diff --git a/third_party/blink/renderer/platform/wtf/text/wtf_string.h b/third_party/blink/renderer/platform/wtf/text/wtf_string.h
index 7cfc8cc5..f90ecfca 100644
--- a/third_party/blink/renderer/platform/wtf/text/wtf_string.h
+++ b/third_party/blink/renderer/platform/wtf/text/wtf_string.h
@@ -42,7 +42,6 @@
 
 namespace WTF {
 
-class CString;
 struct StringHash;
 
 enum UTF8ConversionMode {
@@ -519,7 +518,6 @@
   static String FromUTF8(const char* s) WARN_UNUSED_RESULT {
     return FromUTF8(reinterpret_cast<const LChar*>(s));
   }
-  static String FromUTF8(const CString&) WARN_UNUSED_RESULT;
   static String FromUTF8(base::StringPiece) WARN_UNUSED_RESULT;
 
   // Tries to convert the passed in string to UTF-8, but will fall back to
@@ -696,7 +694,6 @@
 
 WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(String)
 
-using WTF::CString;
 using WTF::kStrictUTF8Conversion;
 using WTF::kStrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD;
 using WTF::String;
diff --git a/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc b/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
index 6722593..4c7ad2b4 100644
--- a/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
+++ b/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
@@ -30,7 +30,6 @@
 #include "base/stl_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 
 namespace WTF {
 
@@ -458,38 +457,37 @@
   EXPECT_TRUE(null_string.IsNull());
 }
 
-CString ToCStringThroughPrinter(const String& string) {
+std::string ToStdStringThroughPrinter(const String& string) {
   std::ostringstream output;
   output << string;
-  const std::string& result = output.str();
-  return CString(result.data(), result.length());
+  return output.str();
 }
 
 TEST(StringTest, StringPrinter) {
-  EXPECT_EQ(CString("\"Hello!\""), ToCStringThroughPrinter("Hello!"));
-  EXPECT_EQ(CString("\"\\\"\""), ToCStringThroughPrinter("\""));
-  EXPECT_EQ(CString("\"\\\\\""), ToCStringThroughPrinter("\\"));
-  EXPECT_EQ(
-      CString("\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\""),
-      ToCStringThroughPrinter(String("\x00\x01\x02\x03\x04\x05\x06\x07", 8u)));
-  EXPECT_EQ(
-      CString("\"\\u0008\\t\\n\\u000B\\u000C\\r\\u000E\\u000F\""),
-      ToCStringThroughPrinter(String("\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", 8u)));
-  EXPECT_EQ(
-      CString("\"\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\""),
-      ToCStringThroughPrinter(String("\x10\x11\x12\x13\x14\x15\x16\x17", 8u)));
-  EXPECT_EQ(
-      CString("\"\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F\""),
-      ToCStringThroughPrinter(String("\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", 8u)));
-  EXPECT_EQ(CString("\"\\u007F\\u0080\\u0081\""),
-            ToCStringThroughPrinter("\x7F\x80\x81"));
-  EXPECT_EQ(CString("\"\""), ToCStringThroughPrinter(g_empty_string));
-  EXPECT_EQ(CString("<null>"), ToCStringThroughPrinter(String()));
+  EXPECT_EQ("\"Hello!\"", ToStdStringThroughPrinter("Hello!"));
+  EXPECT_EQ("\"\\\"\"", ToStdStringThroughPrinter("\""));
+  EXPECT_EQ("\"\\\\\"", ToStdStringThroughPrinter("\\"));
+  EXPECT_EQ("\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\"",
+            ToStdStringThroughPrinter(
+                String("\x00\x01\x02\x03\x04\x05\x06\x07", 8u)));
+  EXPECT_EQ("\"\\u0008\\t\\n\\u000B\\u000C\\r\\u000E\\u000F\"",
+            ToStdStringThroughPrinter(
+                String("\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", 8u)));
+  EXPECT_EQ("\"\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\"",
+            ToStdStringThroughPrinter(
+                String("\x10\x11\x12\x13\x14\x15\x16\x17", 8u)));
+  EXPECT_EQ("\"\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F\"",
+            ToStdStringThroughPrinter(
+                String("\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", 8u)));
+  EXPECT_EQ("\"\\u007F\\u0080\\u0081\"",
+            ToStdStringThroughPrinter("\x7F\x80\x81"));
+  EXPECT_EQ("\"\"", ToStdStringThroughPrinter(g_empty_string));
+  EXPECT_EQ("<null>", ToStdStringThroughPrinter(String()));
 
   static const UChar kUnicodeSample[] = {0x30C6, 0x30B9,
                                          0x30C8};  // "Test" in Japanese.
-  EXPECT_EQ(CString("\"\\u30C6\\u30B9\\u30C8\""),
-            ToCStringThroughPrinter(
+  EXPECT_EQ("\"\\u30C6\\u30B9\\u30C8\"",
+            ToStdStringThroughPrinter(
                 String(kUnicodeSample, base::size(kUnicodeSample))));
 }
 
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 7cbc16d3..d27f098a 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -397,9 +397,10 @@
             'base::(scoped_nsobject|ScopedCFTypeRef)',
         ],
         'disallowed': [
-            '.+',
             ('base::Bind(|Once|Repeating)',
              'Use WTF::Bind or WTF::BindRepeating.'),
+            ('std::(map)',
+             'Use WTF containers like WTF::HashMap instead of the banned std containers.'),
         ],
     },
     {
@@ -817,10 +818,10 @@
 def _check_entries_for_identifier(entries, identifier):
     """Check if an identifier is allowed"""
     for entry in entries:
-        if entry['allowed'].match(identifier):
-            return True
         if entry['disallowed'].match(identifier):
             return False
+        if entry['allowed'].match(identifier):
+            return True
     # Disallow by default.
     return False
 
diff --git a/third_party/blink/tools/gdb/blink.py b/third_party/blink/tools/gdb/blink.py
index 82279c5c..1259e40 100644
--- a/third_party/blink/tools/gdb/blink.py
+++ b/third_party/blink/tools/gdb/blink.py
@@ -112,19 +112,6 @@
     def to_string(self):
         return self.val['string_']
 
-
-class WTFCStringPrinter(StringPrinter):
-    "Print a WTF::CString"
-    def to_string(self):
-        # The CString holds a buffer, which is a refptr to a WTF::CStringBuffer.
-        buf_ptr = self.val['buffer_']['ptr_']
-        if not buf_ptr:
-            return 0
-        data = (buf_ptr + 1).cast(gdb.lookup_type('char').pointer())
-        length = self.val['buffer_']['ptr_']['length_']
-        return ''.join([chr((data + i).dereference()) for i in range(length)])
-
-
 class WTFStringImplPrinter(StringPrinter):
     "Print a WTF::StringImpl"
     def get_length(self):
@@ -377,7 +364,6 @@
     pretty_printers = (
         (re.compile("^WTF::Vector<.*>$"), WTFVectorPrinter),
         (re.compile("^WTF::AtomicString$"), WTFAtomicStringPrinter),
-        (re.compile("^WTF::CString$"), WTFCStringPrinter),
         (re.compile("^WTF::String$"), WTFStringPrinter),
         (re.compile("^WTF::StringImpl$"), WTFStringImplPrinter),
         (re.compile("^blink::KURL$"), blinkKURLPrinter),
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index c3f0f19..fae176a 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -5388,7 +5388,6 @@
 crbug.com/922951 fast/scroll-snap/snaps-for-different-key-granularity.html [ Skip ]
 crbug.com/922951 fast/text/international/inline-plaintext-relayout-with-leading-neutrals.html [ Skip ]
 crbug.com/922951 http/tests/cache/subresource-fragment-identifier.html [ Skip ]
-crbug.com/922951 http/tests/devtools/audits/audits-successful-run.js [ Skip ]
 crbug.com/922951 http/tests/devtools/tracing-session-id.js [ Skip ]
 crbug.com/922951 http/tests/devtools/tracing/console-timeline.js [ Skip ]
 crbug.com/922951 http/tests/devtools/tracing/timeline-network-received-data.js [ Skip ]
@@ -5840,3 +5839,6 @@
 
 # Sheriff 2019-06-10
 crbug.com/972516 [ Win ] netinfo/gc-unused-listeners.html [ Pass Failure ]
+
+# Sheriff 2019-06-13
+crbug.com/973692 [ Mac ] external/wpt/css/css-text/parsing/hyphens-computed.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-chrome-bug-001.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-chrome-bug-001.html
new file mode 100644
index 0000000..3e8899a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-chrome-bug-001.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<html>
+<head>
+  <link rel="help" href="https://www.w3.org/TR/css-position-3/#def-cb">
+  <link rel="help" href="https://crbug.com/970171">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+<style>
+  #container {
+    position: relative;
+    border: 1px solid black;
+  }
+  .narrow {
+    width: 200px;
+    height: 300px;
+  }
+  .wide {
+    width: 300px;
+    height: 200px;
+  }
+  #target {
+    background: green;
+    position: absolute;
+    width: 50px;
+    height: 30px;
+    left: 50%;
+    top: 50%;
+    margin-left: -25px;
+    margin-top: -15px;
+  }
+</style>
+</head>
+<body>
+<div id="container" class="narrow">
+  <button id="target"></button>
+</div>
+<script>
+  test( t => {
+    let container = document.querySelector("#container");
+    let target = document.querySelector("#target");
+    document.body.offsetTop;
+    // start off narrow
+    let narrow_left = target.offsetLeft;
+    let narrow_top = target.offsetTop;
+    // make it wide
+    container.classList.toggle("narrow");
+    container.classList.toggle("wide");
+    document.body.offsetTop;
+    // make it narrow again
+    container.classList.toggle("narrow");
+    container.classList.toggle("wide");
+    document.body.offsetTop;
+    assert_equals(target.offsetLeft, narrow_left);
+    assert_equals(target.offsetTop, narrow_top);
+  }, "absolute positioned button with percentage top gets positioned");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-word-crash-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-word-crash-001.html
new file mode 100644
index 0000000..894a6f3a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-word-crash-001.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<title>Test float + nbsp + break-word does not freeze</title>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=972421">
+<link rel="author" title="Koji Ishii" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+div {
+  font-size: 10px;
+  width: 10ch;
+  border: 2px solid blue;
+}
+float {
+  float: left;
+}
+.nowrap > div {
+  white-space: nowrap;
+}
+.break-word {
+  word-break: break-word;
+}
+</style>
+<body>
+  <section>
+    <div>123456<float></float>654321</div>
+    <div>123456<float></float>&nbsp;654321</div>
+  </section>
+  <section class="nowrap">
+    <div>123456<float></float>654321</div>
+    <div>123456<float></float>&nbsp;654321</div>
+  </section>
+  <section class="break-word">
+    <div>123456<float></float>654321</div>
+    <div>123456<float></float>&nbsp;654321</div>
+  </section>
+<script>test(() => {
+    document.body.offsetTop;  // layout should not freeze.
+});</script>
+</body>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/cookies-protocol-test-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/cookies-protocol-test-expected.txt
index 76e05cfa..93e4f66 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/cookies-protocol-test-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/cookies-protocol-test-expected.txt
@@ -119,6 +119,12 @@
 
 Running test: deleteAllCookies
 
+Running test: setCookiesWithInvalidCookie
+Adding multiple cookies
+Num of cookies 0
+
+Running test: deleteAllCookies
+
 Running test: deleteCookieByURL
 Adding multiple cookies
 Num of cookies 2
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/cookies-protocol-test.js b/third_party/blink/web_tests/http/tests/inspector-protocol/cookies-protocol-test.js
index ee51083..a676f6d6 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/cookies-protocol-test.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/cookies-protocol-test.js
@@ -170,6 +170,12 @@
 
     deleteAllCookies,
 
+    async function setCookiesWithInvalidCookie() {
+      await setCookies([{url: '', name: 'foo', value: 'bar1'}]);
+    },
+
+    deleteAllCookies,
+
     async function deleteCookieByURL() {
       await setCookies([{name: 'cookie1', value: '.domain', url: 'http://www.chromium.org/path' },
                         {name: 'cookie2', value: '.domain', url: 'http://www.chromium.org/path', expires: Date.now() + 1000 }]);
diff --git a/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml b/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
index 981e90ae..a521701 100644
--- a/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
+++ b/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
@@ -237,7 +237,7 @@
 
   </interface>
 
-  <interface name="zcr_remote_surface_v1" version="19">
+  <interface name="zcr_remote_surface_v1" version="20">
     <description summary="A desktop window">
       An interface that may be implemented by a wl_surface, for
       implementations that provide a desktop-style user interface
@@ -996,6 +996,26 @@
       <arg name="height" type="int"/>
     </request>
 
+    <!-- Version 20 additions -->
+
+    <request name="block_ime" since="20">
+      <description summary="block server side IME">
+	Block server side IME and always send key events through Wayland.
+
+	For some client, it's possible that server side IME is connected to the
+	client through other mechanism e.g. ime.mojom. When set_ime_blocked
+	is requested, server side IME should give up handling key events and
+	forward those events through Wayland protocol.
+      </description>
+    </request>
+
+    <request name="unblock_ime" since="20">
+      <description summary="unblock host side IME">
+	Unblock server side IME. Some events can be handled by server side IME,
+	while others can still be sent through Wayland protocol. See the
+	description of set_ime_blocked for detail.
+      </description>
+    </request>
   </interface>
 
   <interface name="zcr_notification_surface_v1" version="16">
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index b3cc064..09faee2 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -222,7 +222,6 @@
       'Linux x64 Goma Latest Client LocalOutputCache': 'release_bot',
 
       'mac-hermetic-upgrade-rel': 'release_bot',
-      'Chromium Mac 10.13': 'release_bot',
 
       'Mac Builder (dbg) Goma Canary (clobber)': 'debug_bot',
       'Mac Builder (dbg) Goma Canary': 'debug_bot',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index c0250060..58c67bff 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -47511,6 +47511,7 @@
       label="Exceeded maximum number of navigation restarts or a redirect
              loop was detected"/>
   <int value="10" label="(DEPRECATED IN M74) Disallowed by PreviewsState"/>
+  <int value="11" label="The chrome-proxy header is invalid"/>
 </enum>
 
 <enum name="PreviewsServerLitePageServerResponse">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 791938d..30d5d9d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -20472,6 +20472,59 @@
   </summary>
 </histogram>
 
+<histogram name="ContentSuggestions.Feed.VisualElement.Clicked" units="index"
+    expires_after="2020-07-01">
+  <owner>gangwu@chromium.org</owner>
+  <owner>fgorski@chromium.org</owner>
+  <summary>
+    Android: The position of a clicked element in the stream not accounting for
+    header views. The top being 0. Position does not change after initial
+    layout. Specifically the position does not update if dismisses/removes are
+    performed. This is similar to NewTabPage.ContentSuggestions.Opened, but
+    records the specific elementType that was clicked.
+  </summary>
+</histogram>
+
+<histogram
+    name="ContentSuggestions.Feed.VisualElement.Clicked.TimeSinceElementFetched"
+    units="ms" expires_after="2020-07-01">
+  <owner>gangwu@chromium.org</owner>
+  <owner>fgorski@chromium.org</owner>
+  <summary>
+    Android: The time since the content was made available on the device. This
+    could be the time for when this content was retrieved from the server or the
+    time the data was pushed to the device. Recorded when the user clicks the
+    element.
+  </summary>
+</histogram>
+
+<histogram name="ContentSuggestions.Feed.VisualElement.Viewed" units="index"
+    expires_after="2020-07-01">
+  <owner>gangwu@chromium.org</owner>
+  <owner>fgorski@chromium.org</owner>
+  <summary>
+    Android: The position of a viewed element in the stream not accounting for
+    header views. The top being 0. Position does not change after initial
+    layout. Specifically the position does not update if dismisses/removes are
+    performed. This is similar to NewTabPage.ContentSuggestions.Shown, but
+    records the view after it has been on the screen for 500 milliseconds of
+    time instead of on predraw.
+  </summary>
+</histogram>
+
+<histogram
+    name="ContentSuggestions.Feed.VisualElement.Viewed.TimeSinceElementFetched"
+    units="ms" expires_after="2020-07-01">
+  <owner>gangwu@chromium.org</owner>
+  <owner>fgorski@chromium.org</owner>
+  <summary>
+    Android: The time since the content was made available on the device. This
+    could be the time for when this content was retrieved from the server or the
+    time the data was pushed to the device. Recorded when the element has been
+    on the screen for 500 milliseconds.
+  </summary>
+</histogram>
+
 <histogram
     name="ContentSuggestions.Feed.ZeroStateRefreshCompleted.ContentCount"
     units="count" expires_after="2020-02-25">
@@ -45101,6 +45154,15 @@
   </summary>
 </histogram>
 
+<histogram name="GPU.GrContextMemoryKb" units="KB" expires_after="2019-10-01">
+  <owner>enne@chromium.org</owner>
+  <owner>khushalsagar@chromium.org</owner>
+  <summary>
+    Kilobytes of memory used by Skia in the gpu process. This is recorded after
+    every block of commands in the raster decoder.
+  </summary>
+</histogram>
+
 <histogram name="GPU.InForceCompositingModeFieldTrial" enum="BooleanEnabled"
     expires_after="2017-05-25">
   <obsolete>
@@ -100397,6 +100459,16 @@
   </summary>
 </histogram>
 
+<histogram name="Previews.HintCacheStore.OnLoadHint.FetchedHintExpired"
+    enum="BooleanExpired" expires_after="M80">
+  <owner>mcrouse@chromium.org</owner>
+  <owner>dougarnett@chromium.org</owner>
+  <summary>
+    Records that a fetched hint loaded from the store has expired. If expired,
+    the hint is not provided.
+  </summary>
+</histogram>
+
 <histogram name="Previews.HintsFetcher.GetHintsRequest.HostCount"
     units="total host count" expires_after="M79">
   <owner>mcrouse@chromium.org</owner>
@@ -139561,7 +139633,11 @@
 </histogram>
 
 <histogram name="VirtualKeyboard.ControllerStateTransitionIsValid"
-    enum="BooleanValid">
+    enum="BooleanValid" expires_after="2019-06-12">
+  <obsolete>
+    Deprecated 2019/6 because it's equivalent to VirtualKeyboard.
+    ControllerStateTransition.
+  </obsolete>
   <owner>oka@chromium.org</owner>
   <summary>
     Validity of a state transtion. This is equivalent to the positiveness of
@@ -151557,6 +151633,20 @@
   <affected-histogram name="Favicons.DownloadAttempts"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="FeedElementType" separator=".">
+  <suffix name="CardLargeImage" label="Card with a large image"/>
+  <suffix name="CardSmallImage" label="Card with a small image"/>
+  <suffix name="InterestHeader" label="Interest header"/>
+  <suffix name="Tooltip" label="Tooltip"/>
+  <suffix name="UnknownElementType" label="Unknown element type"/>
+  <affected-histogram name="ContentSuggestions.Feed.VisualElement.Clicked"/>
+  <affected-histogram
+      name="ContentSuggestions.Feed.VisualElement.Clicked.TimeSinceElementFetched"/>
+  <affected-histogram name="ContentSuggestions.Feed.VisualElement.Viewed"/>
+  <affected-histogram
+      name="ContentSuggestions.Feed.VisualElement.Viewed.TimeSinceElementFetched"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="FeedIsSynthetic" separator="." ordering="suffix">
   <suffix name="NotSynthetic"
       label="Continuations that require making remote requests to fetch more
diff --git a/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py b/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py
index e3731fb2..c0d6dfd9 100644
--- a/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py
+++ b/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py
@@ -16,6 +16,8 @@
 
 CARDBOARD_PATH = os.path.join('chrome', 'android', 'shared_preference_files',
                               'test', 'vr_cardboard_skipdon_setupcomplete.json')
+WEBXR_CONSENT_DIALOG_DISABLE_FLAG = (
+    '--disable-xr-device-consent-prompt-for-testing')
 
 
 class SharedVrPageStateFactory(shared_page_state.SharedPageState):
@@ -62,6 +64,8 @@
     super(_SharedVrPageState, self).__init__(
         test, finder_options, story_set, possible_browser)
     self._story_set = story_set
+    self._finder_options.AppendExtraBrowserArgs(
+        [WEBXR_CONSENT_DIALOG_DISABLE_FLAG])
 
   @property
   def recording_wpr(self):
diff --git a/ui/base/cursor/cursor.cc b/ui/base/cursor/cursor.cc
index 6dc54dc..be37579 100644
--- a/ui/base/cursor/cursor.cc
+++ b/ui/base/cursor/cursor.cc
@@ -71,8 +71,6 @@
          device_scale_factor_ == cursor.device_scale_factor_ &&
          custom_hotspot_ == cursor.custom_hotspot_ &&
          (native_type_ != CursorType::kCustom ||
-          custom_bitmap_.getGenerationID() ==
-              cursor.custom_bitmap_.getGenerationID() ||
           gfx::BitmapsAreEqual(custom_bitmap_, cursor.custom_bitmap_));
 }
 
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index 715a1ea..90feab1 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -513,8 +513,6 @@
       "blink/web_input_event_traits_unittest.cc",
       "blink/web_input_event_unittest.cc",
       "cocoa/events_mac_unittest.mm",
-      "devices/mojo/device_struct_traits_unittest.cc",
-      "devices/mojo/touch_device_transform_struct_traits_unittest.cc",
       "event_dispatcher_unittest.cc",
       "event_processor_unittest.cc",
       "event_rewriter_unittest.cc",
@@ -567,7 +565,6 @@
       "//ui/display",
       "//ui/events/blink",
       "//ui/events/devices",
-      "//ui/events/devices/mojo:test_interfaces",
       "//ui/events/gestures/blink",
       "//ui/events/mojo:interfaces",
       "//ui/events/platform",
diff --git a/ui/events/devices/mojo/BUILD.gn b/ui/events/devices/mojo/BUILD.gn
deleted file mode 100644
index ee7bc48..0000000
--- a/ui/events/devices/mojo/BUILD.gn
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("mojo") {
-  sources = [
-    "input_devices.mojom",
-    "touch_device_transform.mojom",
-  ]
-
-  public_deps = [
-    "//ui/gfx/geometry/mojo",
-    "//ui/gfx/mojo",
-  ]
-}
-
-mojom("test_interfaces") {
-  sources = [
-    "device_struct_traits_test.mojom",
-  ]
-
-  public_deps = [
-    ":mojo",
-  ]
-}
diff --git a/ui/events/devices/mojo/DEPS b/ui/events/devices/mojo/DEPS
deleted file mode 100644
index ef8ad28..0000000
--- a/ui/events/devices/mojo/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+mojo/public",
-]
diff --git a/ui/events/devices/mojo/OWNERS b/ui/events/devices/mojo/OWNERS
deleted file mode 100644
index e75daf74..0000000
--- a/ui/events/devices/mojo/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
-
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/ui/events/devices/mojo/device_struct_traits_test.mojom b/ui/events/devices/mojo/device_struct_traits_test.mojom
deleted file mode 100644
index 9f88a89..0000000
--- a/ui/events/devices/mojo/device_struct_traits_test.mojom
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module ui.mojom;
-
-import "ui/events/devices/mojo/input_devices.mojom";
-
-// All functions on this interface echo their arguments to test StructTraits
-// serialization and deserialization.
-interface DeviceStructTraitsTest {
-  [Sync]
-  EchoInputDevice(InputDevice in) => (InputDevice out);
-
-  [Sync]
-  EchoTouchscreenDevice(TouchscreenDevice in) => (TouchscreenDevice out);
-};
diff --git a/ui/events/devices/mojo/device_struct_traits_unittest.cc b/ui/events/devices/mojo/device_struct_traits_unittest.cc
deleted file mode 100644
index b6d6096..0000000
--- a/ui/events/devices/mojo/device_struct_traits_unittest.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/test/scoped_task_environment.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/devices/input_device.h"
-#include "ui/events/devices/mojo/device_struct_traits_test.mojom.h"
-#include "ui/events/devices/touchscreen_device.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace ui {
-
-namespace {
-
-class DeviceStructTraitsTest : public testing::Test,
-                               public mojom::DeviceStructTraitsTest {
- public:
-  DeviceStructTraitsTest() {}
-
- protected:
-  mojom::DeviceStructTraitsTestPtr GetTraitsTestProxy() {
-    mojom::DeviceStructTraitsTestPtr proxy;
-    traits_test_bindings_.AddBinding(this, mojo::MakeRequest(&proxy));
-    return proxy;
-  }
-
- private:
-  // mojom::DeviceStructTraitsTest:
-  void EchoInputDevice(const InputDevice& in,
-                       EchoInputDeviceCallback callback) override {
-    std::move(callback).Run(in);
-  }
-
-  void EchoTouchscreenDevice(const TouchscreenDevice& in,
-                             EchoTouchscreenDeviceCallback callback) override {
-    std::move(callback).Run(in);
-  }
-
-  base::test::ScopedTaskEnvironment
-      scoped_task_environment_;  // A MessageLoop is needed for mojo IPC to
-                                 // work.
-  mojo::BindingSet<mojom::DeviceStructTraitsTest> traits_test_bindings_;
-
-  DISALLOW_COPY_AND_ASSIGN(DeviceStructTraitsTest);
-};
-
-}  // namespace
-
-TEST_F(DeviceStructTraitsTest, InputDevice) {
-  InputDevice input(15,                     // id
-                    INPUT_DEVICE_INTERNAL,  // type
-                    "Input Device");        // name
-  input.sys_path = base::FilePath::FromUTF8Unsafe("/dev/input/event14");
-  input.vendor_id = 1000;
-  input.product_id = 2000;
-
-  mojom::DeviceStructTraitsTestPtr proxy = GetTraitsTestProxy();
-  InputDevice output;
-  proxy->EchoInputDevice(input, &output);
-
-  EXPECT_EQ(input.id, output.id);
-  EXPECT_EQ(input.type, output.type);
-  EXPECT_EQ(input.name, output.name);
-  EXPECT_EQ(input.sys_path, output.sys_path);
-  EXPECT_EQ(input.vendor_id, output.vendor_id);
-  EXPECT_EQ(input.product_id, output.product_id);
-}
-
-TEST_F(DeviceStructTraitsTest, TouchscreenDevice) {
-  TouchscreenDevice input(10,                    // id
-                          INPUT_DEVICE_UNKNOWN,  // type
-                          "Touchscreen Device",  // name
-                          gfx::Size(123, 456),   // size
-                          3,                     // touch_points
-                          true);                 // has_stylus
-  // Not setting sys_path intentionally.
-  input.vendor_id = 0;
-  input.product_id = 0;
-
-  mojom::DeviceStructTraitsTestPtr proxy = GetTraitsTestProxy();
-  TouchscreenDevice output;
-  proxy->EchoTouchscreenDevice(input, &output);
-
-  EXPECT_EQ(input.id, output.id);
-  EXPECT_EQ(input.type, output.type);
-  EXPECT_EQ(input.name, output.name);
-  EXPECT_EQ(input.sys_path, output.sys_path);
-  EXPECT_EQ(input.vendor_id, output.vendor_id);
-  EXPECT_EQ(input.product_id, output.product_id);
-  EXPECT_EQ(input.size, output.size);
-  EXPECT_EQ(input.touch_points, output.touch_points);
-  EXPECT_EQ(input.has_stylus, output.has_stylus);
-}
-
-}  // namespace ui
diff --git a/ui/events/devices/mojo/input_device.typemap b/ui/events/devices/mojo/input_device.typemap
deleted file mode 100644
index 992418b9..0000000
--- a/ui/events/devices/mojo/input_device.typemap
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//ui/events/devices/mojo/input_devices.mojom"
-public_headers = [
-  "//ui/events/devices/input_device.h",
-  "//ui/events/devices/stylus_state.h",
-  "//ui/events/devices/touchscreen_device.h",
-]
-traits_headers = [ "//ui/events/devices/mojo/input_device_struct_traits.h" ]
-sources = [
-  "//ui/events/devices/mojo/input_device_struct_traits.cc",
-]
-public_deps = [
-  "//ui/events/devices",
-]
-deps = [
-  "//ui/gfx/geometry",
-  "//ui/gfx/geometry/mojo:struct_traits",
-]
-
-type_mappings = [
-  "ui.mojom.InputDeviceType=ui::InputDeviceType",
-  "ui.mojom.InputDevice=ui::InputDevice",
-  "ui.mojom.StylusState=ui::StylusState",
-  "ui.mojom.TouchscreenDevice=ui::TouchscreenDevice",
-]
diff --git a/ui/events/devices/mojo/input_device_struct_traits.cc b/ui/events/devices/mojo/input_device_struct_traits.cc
deleted file mode 100644
index edae74a..0000000
--- a/ui/events/devices/mojo/input_device_struct_traits.cc
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/devices/mojo/input_device_struct_traits.h"
-
-#include "base/logging.h"
-#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
-
-namespace mojo {
-
-ui::mojom::InputDeviceType
-EnumTraits<ui::mojom::InputDeviceType, ui::InputDeviceType>::ToMojom(
-    ui::InputDeviceType type) {
-  switch (type) {
-    case ui::INPUT_DEVICE_INTERNAL:
-      return ui::mojom::InputDeviceType::INPUT_DEVICE_INTERNAL;
-    case ui::INPUT_DEVICE_USB:
-      return ui::mojom::InputDeviceType::INPUT_DEVICE_USB;
-    case ui::INPUT_DEVICE_BLUETOOTH:
-      return ui::mojom::InputDeviceType::INPUT_DEVICE_BLUETOOTH;
-    case ui::INPUT_DEVICE_UNKNOWN:
-      return ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN;
-  }
-  NOTREACHED();
-  return ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN;
-}
-
-bool EnumTraits<ui::mojom::InputDeviceType, ui::InputDeviceType>::FromMojom(
-    ui::mojom::InputDeviceType type,
-    ui::InputDeviceType* output) {
-  switch (type) {
-    case ui::mojom::InputDeviceType::INPUT_DEVICE_INTERNAL:
-      *output = ui::INPUT_DEVICE_INTERNAL;
-      break;
-    case ui::mojom::InputDeviceType::INPUT_DEVICE_USB:
-      *output = ui::INPUT_DEVICE_USB;
-      break;
-    case ui::mojom::InputDeviceType::INPUT_DEVICE_BLUETOOTH:
-      *output = ui::INPUT_DEVICE_BLUETOOTH;
-      break;
-    case ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN:
-      *output = ui::INPUT_DEVICE_UNKNOWN;
-      break;
-    default:
-      // Who knows what values might come over the wire, fail if invalid.
-      return false;
-  }
-  return true;
-}
-
-bool StructTraits<ui::mojom::InputDeviceDataView, ui::InputDevice>::Read(
-    ui::mojom::InputDeviceDataView data,
-    ui::InputDevice* out) {
-  out->id = data.id();
-
-  if (!data.ReadType(&out->type))
-    return false;
-
-  if (!data.ReadName(&out->name))
-    return false;
-
-  std::string sys_path_string;
-  if (!data.ReadSysPath(&sys_path_string))
-    return false;
-  out->sys_path = base::FilePath::FromUTF8Unsafe(sys_path_string);
-
-  out->vendor_id = data.vendor_id();
-  out->product_id = data.product_id();
-
-  return true;
-}
-
-ui::mojom::StylusState
-EnumTraits<ui::mojom::StylusState, ui::StylusState>::ToMojom(
-    ui::StylusState type) {
-  switch (type) {
-    case ui::StylusState::REMOVED:
-      return ui::mojom::StylusState::REMOVED;
-    case ui::StylusState::INSERTED:
-      return ui::mojom::StylusState::INSERTED;
-  }
-  NOTREACHED();
-  return ui::mojom::StylusState::INSERTED;
-}
-
-bool EnumTraits<ui::mojom::StylusState, ui::StylusState>::FromMojom(
-    ui::mojom::StylusState type,
-    ui::StylusState* output) {
-  switch (type) {
-    case ui::mojom::StylusState::REMOVED:
-      *output = ui::StylusState::REMOVED;
-      break;
-    case ui::mojom::StylusState::INSERTED:
-      *output = ui::StylusState::INSERTED;
-      break;
-    default:
-      // Who knows what values might come over the wire, fail if invalid.
-      return false;
-  }
-  return true;
-}
-
-bool StructTraits<ui::mojom::TouchscreenDeviceDataView, ui::TouchscreenDevice>::
-    Read(ui::mojom::TouchscreenDeviceDataView data,
-         ui::TouchscreenDevice* out) {
-  if (!data.ReadInputDevice(static_cast<ui::InputDevice*>(out)))
-    return false;
-
-  if (!data.ReadSize(&out->size))
-    return false;
-
-  out->touch_points = data.touch_points();
-  out->has_stylus = data.has_stylus();
-
-  return true;
-}
-
-}  // namespace mojo
diff --git a/ui/events/devices/mojo/input_device_struct_traits.h b/ui/events/devices/mojo/input_device_struct_traits.h
deleted file mode 100644
index 18b1365..0000000
--- a/ui/events/devices/mojo/input_device_struct_traits.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_DEVICES_MOJO_INPUT_DEVICE_STRUCT_TRAITS_H_
-#define UI_EVENTS_DEVICES_MOJO_INPUT_DEVICE_STRUCT_TRAITS_H_
-
-#include <string>
-
-#include "ui/events/devices/input_device.h"
-#include "ui/events/devices/mojo/input_devices.mojom.h"
-#include "ui/events/devices/stylus_state.h"
-#include "ui/events/devices/touchscreen_device.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace mojo {
-
-template <>
-struct EnumTraits<ui::mojom::InputDeviceType, ui::InputDeviceType> {
-  static ui::mojom::InputDeviceType ToMojom(ui::InputDeviceType type);
-  static bool FromMojom(ui::mojom::InputDeviceType type,
-                        ui::InputDeviceType* output);
-};
-
-template <>
-struct StructTraits<ui::mojom::InputDeviceDataView, ui::InputDevice> {
-  static int32_t id(const ui::InputDevice& device) { return device.id; }
-
-  static ui::InputDeviceType type(const ui::InputDevice& device) {
-    return device.type;
-  }
-
-  static const std::string& name(const ui::InputDevice& device) {
-    return device.name;
-  }
-
-  static bool enabled(const ui::InputDevice& device) { return device.enabled; }
-
-  static std::string sys_path(const ui::InputDevice& device) {
-    return device.sys_path.AsUTF8Unsafe();
-  }
-
-  static uint32_t vendor_id(const ui::InputDevice& device) {
-    return device.vendor_id;
-  }
-
-  static uint32_t product_id(const ui::InputDevice& device) {
-    return device.product_id;
-  }
-
-  static bool Read(ui::mojom::InputDeviceDataView data, ui::InputDevice* out);
-};
-
-template <>
-struct EnumTraits<ui::mojom::StylusState, ui::StylusState> {
-  static ui::mojom::StylusState ToMojom(ui::StylusState type);
-  static bool FromMojom(ui::mojom::StylusState type, ui::StylusState* output);
-};
-
-template <>
-struct StructTraits<ui::mojom::TouchscreenDeviceDataView,
-                    ui::TouchscreenDevice> {
-  static const ui::InputDevice& input_device(
-      const ui::TouchscreenDevice& device) {
-    return static_cast<const ui::InputDevice&>(device);
-  }
-
-  static const gfx::Size& size(const ui::TouchscreenDevice& device) {
-    return device.size;
-  }
-
-  static int32_t touch_points(const ui::TouchscreenDevice& device) {
-    return device.touch_points;
-  }
-
-  static bool has_stylus(const ui::TouchscreenDevice& device) {
-    return device.has_stylus;
-  }
-
-  static bool Read(ui::mojom::TouchscreenDeviceDataView data,
-                   ui::TouchscreenDevice* out);
-};
-
-}  // namespace mojo
-
-#endif  // UI_EVENTS_DEVICES_MOJO_INPUT_DEVICE_STRUCT_TRAITS_H_
diff --git a/ui/events/devices/mojo/input_devices.mojom b/ui/events/devices/mojo/input_devices.mojom
deleted file mode 100644
index 2671cec..0000000
--- a/ui/events/devices/mojo/input_devices.mojom
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module ui.mojom;
-
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-// Corresponds to ui::InputDeviceType
-enum InputDeviceType {
-  INPUT_DEVICE_INTERNAL,
-  INPUT_DEVICE_USB,
-  INPUT_DEVICE_BLUETOOTH,
-  INPUT_DEVICE_UNKNOWN,
-};
-
-// Corresponds to ui::InputDevice.
-struct InputDevice {
-  int32 id;
-  InputDeviceType type;
-  string name;
-  bool enabled;
-  string sys_path;
-  uint16 vendor_id;
-  uint16 product_id;
-};
-
-// Corresponds to ui::StylusState.
-enum StylusState { REMOVED, INSERTED };
-
-// Corresponds to ui::TouchscreenDevice.
-struct TouchscreenDevice {
-  // Base class.
-  InputDevice input_device;
-
-  gfx.mojom.Size size;
-  int32 touch_points;
-  bool has_stylus;
-};
\ No newline at end of file
diff --git a/ui/events/devices/mojo/touch_device_transform.mojom b/ui/events/devices/mojo/touch_device_transform.mojom
deleted file mode 100644
index 5b8e9c2..0000000
--- a/ui/events/devices/mojo/touch_device_transform.mojom
+++ /dev/null
@@ -1,14 +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.
-
-module ui.mojom;
-
-import "ui/gfx/mojo/transform.mojom";
-
-struct TouchDeviceTransform {
-  int64 display_id;
-  int32 device_id;
-  gfx.mojom.Transform transform;
-  double radius_scale;
-};
diff --git a/ui/events/devices/mojo/touch_device_transform.typemap b/ui/events/devices/mojo/touch_device_transform.typemap
deleted file mode 100644
index 689eb3b..0000000
--- a/ui/events/devices/mojo/touch_device_transform.typemap
+++ /dev/null
@@ -1,14 +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.
-
-mojom = "//ui/events/devices/mojo/touch_device_transform.mojom"
-public_headers = [ "//ui/events/devices/touch_device_transform.h" ]
-traits_headers =
-    [ "//ui/events/devices/mojo/touch_device_transform_struct_traits.h" ]
-deps = []
-public_deps = [
-  "//ui/gfx",
-  "//ui/gfx/mojo",
-]
-type_mappings = [ "ui.mojom.TouchDeviceTransform=ui::TouchDeviceTransform" ]
diff --git a/ui/events/devices/mojo/touch_device_transform_struct_traits.h b/ui/events/devices/mojo/touch_device_transform_struct_traits.h
deleted file mode 100644
index b9dd450..0000000
--- a/ui/events/devices/mojo/touch_device_transform_struct_traits.h
+++ /dev/null
@@ -1,46 +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 UI_DISPLAY_MANAGER_CHROMEOS_MOJO_TOUCH_DEVICE_TRANSFORM_STRUCT_TRAITS_H_
-#define UI_DISPLAY_MANAGER_CHROMEOS_MOJO_TOUCH_DEVICE_TRANSFORM_STRUCT_TRAITS_H_
-
-#include <stdint.h>
-
-#include "ui/events/devices/mojo/touch_device_transform.mojom.h"
-#include "ui/events/devices/touch_device_transform.h"
-#include "ui/gfx/mojo/transform_struct_traits.h"
-
-namespace mojo {
-
-template <>
-struct StructTraits<ui::mojom::TouchDeviceTransformDataView,
-                    ui::TouchDeviceTransform> {
- public:
-  static int64_t display_id(const ui::TouchDeviceTransform& r) {
-    return r.display_id;
-  }
-  static int32_t device_id(const ui::TouchDeviceTransform& r) {
-    return r.device_id;
-  }
-  static const gfx::Transform& transform(const ui::TouchDeviceTransform& r) {
-    return r.transform;
-  }
-  static double radius_scale(const ui::TouchDeviceTransform& r) {
-    return r.radius_scale;
-  }
-
-  static bool Read(ui::mojom::TouchDeviceTransformDataView data,
-                   ui::TouchDeviceTransform* out) {
-    out->display_id = data.display_id();
-    out->device_id = data.device_id();
-    if (!data.ReadTransform(&(out->transform)))
-      return false;
-    out->radius_scale = data.radius_scale();
-    return true;
-  }
-};
-
-}  // namespace mojo
-
-#endif  // UI_DISPLAY_MANAGER_CHROMEOS_MOJO_TOUCH_DEVICE_TRANSFORM_STRUCT_TRAITS_H_
diff --git a/ui/events/devices/mojo/touch_device_transform_struct_traits_unittest.cc b/ui/events/devices/mojo/touch_device_transform_struct_traits_unittest.cc
deleted file mode 100644
index c9453d5..0000000
--- a/ui/events/devices/mojo/touch_device_transform_struct_traits_unittest.cc
+++ /dev/null
@@ -1,30 +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 "ui/events/devices/mojo/touch_device_transform_struct_traits.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/devices/mojo/touch_device_transform.mojom.h"
-#include "ui/events/devices/touch_device_transform.h"
-
-namespace ui {
-
-TEST(TouchDeviceTransformStructTraitsTest, SerializeAndDeserialize) {
-  TouchDeviceTransform touch_device_transform;
-  touch_device_transform.display_id = 101;
-  touch_device_transform.device_id = 202;
-  touch_device_transform.transform =
-      gfx::Transform(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
-  touch_device_transform.radius_scale = 4;
-  TouchDeviceTransform deserialized;
-  ASSERT_TRUE(mojom::TouchDeviceTransform::Deserialize(
-      mojom::TouchDeviceTransform::Serialize(&touch_device_transform),
-      &deserialized));
-  EXPECT_EQ(touch_device_transform.display_id, deserialized.display_id);
-  EXPECT_EQ(touch_device_transform.device_id, deserialized.device_id);
-  EXPECT_EQ(touch_device_transform.transform, deserialized.transform);
-  EXPECT_EQ(touch_device_transform.radius_scale, deserialized.radius_scale);
-}
-
-}  // namespace ui
diff --git a/ui/events/devices/mojo/typemaps.gni b/ui/events/devices/mojo/typemaps.gni
deleted file mode 100644
index 727e53f..0000000
--- a/ui/events/devices/mojo/typemaps.gni
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-typemaps = [
-  "//ui/events/devices/mojo/input_device.typemap",
-  "//ui/events/devices/mojo/touch_device_transform.typemap",
-]
diff --git a/ui/file_manager/file_manager/foreground/elements/activity_complete.js b/ui/file_manager/file_manager/foreground/elements/xf_activity_complete.js
similarity index 100%
rename from ui/file_manager/file_manager/foreground/elements/activity_complete.js
rename to ui/file_manager/file_manager/foreground/elements/xf_activity_complete.js
diff --git a/ui/file_manager/file_manager/foreground/elements/circular_progress.js b/ui/file_manager/file_manager/foreground/elements/xf_circular_progress.js
similarity index 100%
rename from ui/file_manager/file_manager/foreground/elements/circular_progress.js
rename to ui/file_manager/file_manager/foreground/elements/xf_circular_progress.js
diff --git a/ui/file_manager/file_manager/foreground/elements/display_panel.js b/ui/file_manager/file_manager/foreground/elements/xf_display_panel.js
similarity index 100%
rename from ui/file_manager/file_manager/foreground/elements/display_panel.js
rename to ui/file_manager/file_manager/foreground/elements/xf_display_panel.js
diff --git a/ui/file_manager/file_manager/foreground/elements/panel_item.js b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
similarity index 100%
rename from ui/file_manager/file_manager/foreground/elements/panel_item.js
rename to ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 3d5baa1..103a275 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -707,6 +707,7 @@
       "sequential_id_generator_unittest.cc",
       "shadow_value_unittest.cc",
       "skbitmap_operations_unittest.cc",
+      "skia_util_unittest.cc",
       "skia_vector_animation_unittest.cc",
       "skrect_conversion_unittest.cc",
       "transform_util_unittest.cc",
diff --git a/ui/gfx/skia_util.cc b/ui/gfx/skia_util.cc
index 4379e76..7f9269b 100644
--- a/ui/gfx/skia_util.cc
+++ b/ui/gfx/skia_util.cc
@@ -95,16 +95,23 @@
 }
 
 bool BitmapsAreEqual(const SkBitmap& bitmap1, const SkBitmap& bitmap2) {
-  void* addr1 = NULL;
-  void* addr2 = NULL;
-  size_t size1 = 0;
-  size_t size2 = 0;
+  if (bitmap1.isNull() != bitmap2.isNull() ||
+      bitmap1.dimensions() != bitmap2.dimensions())
+    return false;
 
-  addr1 = bitmap1.getAddr32(0, 0);
-  size1 = bitmap1.computeByteSize();
+  if (bitmap1.getGenerationID() == bitmap2.getGenerationID() ||
+      (bitmap1.empty() && bitmap2.empty()))
+    return true;
 
-  addr2 = bitmap2.getAddr32(0, 0);
-  size2 = bitmap2.computeByteSize();
+  // Calling getAddr32() on null or empty bitmaps will assert. The conditions
+  // above should return early if either bitmap is empty or null.
+  DCHECK(!bitmap1.isNull() && !bitmap2.isNull());
+  DCHECK(!bitmap1.empty() && !bitmap2.empty());
+
+  void* addr1 = bitmap1.getAddr32(0, 0);
+  void* addr2 = bitmap2.getAddr32(0, 0);
+  size_t size1 = bitmap1.computeByteSize();
+  size_t size2 = bitmap2.computeByteSize();
 
   return (size1 == size2) && (0 == memcmp(addr1, addr2, size1));
 }
diff --git a/ui/gfx/skia_util_unittest.cc b/ui/gfx/skia_util_unittest.cc
new file mode 100644
index 0000000..34ce1261
--- /dev/null
+++ b/ui/gfx/skia_util_unittest.cc
@@ -0,0 +1,47 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/skia_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace gfx {
+
+TEST(SkiaUtilTest, BitmapsAreEqual) {
+  SkBitmap a, b;
+  EXPECT_TRUE(gfx::BitmapsAreEqual(a, b));  // Both bitmaps are null.
+
+  a.allocN32Pixels(0, 0);
+  EXPECT_FALSE(gfx::BitmapsAreEqual(a, b));  // isNull() differs.
+  b.allocN32Pixels(10, 0);
+  EXPECT_FALSE(gfx::BitmapsAreEqual(a, b));  // Dimensions differ.
+  a.allocN32Pixels(0, 10);
+  EXPECT_FALSE(gfx::BitmapsAreEqual(a, b));  // Dimensions still differ.
+  b.allocN32Pixels(0, 10);
+  EXPECT_TRUE(gfx::BitmapsAreEqual(a, b));  // Dimensions equal (but empty).
+  a.allocN32Pixels(10, 10);
+  EXPECT_FALSE(gfx::BitmapsAreEqual(a, b));  // Dimensions differ.
+  b.allocN32Pixels(10, 10);
+  EXPECT_TRUE(gfx::BitmapsAreEqual(a, b));  // Dimensions equal (non-empty).
+
+  a.eraseColor(SK_ColorRED);
+  EXPECT_FALSE(gfx::BitmapsAreEqual(a, b));  // Contents differ.
+  b.eraseColor(SK_ColorGREEN);
+  EXPECT_FALSE(gfx::BitmapsAreEqual(a, b));  // Contents still differ.
+  b.eraseColor(SK_ColorRED);
+  EXPECT_TRUE(gfx::BitmapsAreEqual(a, b));  // Contents equal.
+
+  a.eraseColor(SK_ColorBLUE);
+  EXPECT_FALSE(gfx::BitmapsAreEqual(a, b));  // Contents differ.
+  b = a;
+  EXPECT_TRUE(gfx::BitmapsAreEqual(a, b));  // Generation ids equal.
+
+  a.reset();
+  EXPECT_FALSE(gfx::BitmapsAreEqual(a, b));  // isNull() differs.
+  b.reset();
+  EXPECT_TRUE(gfx::BitmapsAreEqual(a, b));  // Both bitmaps are null.
+}
+
+}  // namespace gfx
diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.mm b/ui/views/cocoa/native_widget_mac_ns_window_host.mm
index 05348c8b..99d591f 100644
--- a/ui/views/cocoa/native_widget_mac_ns_window_host.mm
+++ b/ui/views/cocoa/native_widget_mac_ns_window_host.mm
@@ -502,6 +502,16 @@
   UpdateLocalWindowFrame(bounds);
   GetNSWindowMojo()->SetBounds(
       bounds, native_widget_mac_->GetWidget()->GetMinimumSize());
+
+  if (remote_ns_window_ptr_) {
+    gfx::Rect window_in_screen =
+        gfx::ScreenRectFromNSRect([in_process_ns_window_ frame]);
+    gfx::Rect content_in_screen =
+        gfx::ScreenRectFromNSRect([in_process_ns_window_
+            contentRectForFrameRect:[in_process_ns_window_ frame]]);
+
+    OnWindowGeometryChanged(window_in_screen, content_in_screen);
+  }
 }
 
 void NativeWidgetMacNSWindowHost::SetFullscreen(bool fullscreen) {
@@ -998,12 +1008,13 @@
 
   // Note we can't use new_window_bounds_in_screen.size(), since it includes the
   // titlebar for the purposes of detecting a window move.
-  if (content_has_resized)
+  if (content_has_resized) {
     native_widget_mac_->GetWidget()->OnNativeWidgetSizeChanged(
         content_bounds_in_screen_.size());
 
-  // Update the compositor surface and layer size.
-  UpdateCompositorProperties();
+    // Update the compositor surface and layer size.
+    UpdateCompositorProperties();
+  }
 }
 
 void NativeWidgetMacNSWindowHost::OnWindowFullscreenTransitionStart(
diff --git a/ui/wm/core/DEPS b/ui/wm/core/DEPS
index 80d9039..101e3b8 100644
--- a/ui/wm/core/DEPS
+++ b/ui/wm/core/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   "+third_party/skia",
-  "+services/ws/public",
   "+ui/aura",
   "+ui/base/accelerators",
   "+ui/base/cursor",
diff --git a/ui/wm/test/DEPS b/ui/wm/test/DEPS
index c024b8c8..ec69df0 100644
--- a/ui/wm/test/DEPS
+++ b/ui/wm/test/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+services/ws/public",
   "+ui/aura",
   "+ui/base/resource/resource_bundle.h",
   "+ui/base/ui_base_paths.h",