diff --git a/DEPS b/DEPS
index 365cf1d..393ed56c 100644
--- a/DEPS
+++ b/DEPS
@@ -133,7 +133,7 @@
   # 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': 'b595027bab397770e0f3e6c78cc17ceed9eaf6cd',
+  'v8_revision': '90dd5c15e452371cf815d7dc773b96853bc7924b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -141,7 +141,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'd5ff4fadd867f7adee0e8f88e37230ce61d109c5',
+  'angle_revision': 'a7440a2273f304c5b02148c050f4a5e9172ae977',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -149,7 +149,7 @@
   # 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': '7f7405ec47e9ca045d6bf391a05a423e5f1338e9',
+  'pdfium_revision': 'c75ce35aa1a75ab3aed909dad553a46719db2f48',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -196,7 +196,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': 'dc3ad63a09b8ca5e3f79ecb2f4794c1da6ced43b',
+  'catapult_revision': '6145021beb12262bfb569601fd431b8d2de76c9d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -268,7 +268,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': '20b0c33913e45cd3d553b42a43b75b27af817833',
+  'dawn_revision': 'cf52d711fbcbc7aa66e40c7524258d80d5efe444',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -767,7 +767,7 @@
   },
 
   'src/third_party/breakpad/breakpad':
-    Var('chromium_git') + '/breakpad/breakpad.git' + '@' + '19a8433a604e6105575c08529fc8e0b2947f5af5',
+    Var('chromium_git') + '/breakpad/breakpad.git' + '@' + '232c45abee1753785ae32938589eede535bdb06d',
 
   'src/third_party/byte_buddy': {
       'packages': [
@@ -805,7 +805,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '4206f6a183ae23c0f0dc402e04631ec6ab5a2216',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'e255b9cdc43dd9a434abd2136e4e3fd9afb070f0',
       'condition': 'checkout_linux',
   },
 
@@ -830,7 +830,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0b62ed79ed5049332f58c06dbdb8e8bc4105010e',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1fb046306b9ebe160eeacc7843ee1ddd15a47ffa',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1172,7 +1172,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '71cac8bfa4a8126c400d08ce0517771f5c29537b',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '86820d1f3a7d486e40bbaeda455b030d71f07c40',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1343,7 +1343,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '688fbfe33779392aa210d67d4aa12cb012f112c2',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'e9d2b4efdd5dddaa3a476c0ac2a9cf9125b39929',
+    Var('webrtc_git') + '/src.git' + '@' + '6fdbba3a0381a5b828d5c466bcacfbe9e7a44dff',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1384,7 +1384,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8342a7f2fc299ccd32d5335f335316049654629a',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c0eaf0c733e8f3d5071647fe36035e368f217c4a',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_feature_list_creator.cc b/android_webview/browser/aw_feature_list_creator.cc
index 28f2c20..6ea8ebadd 100644
--- a/android_webview/browser/aw_feature_list_creator.cc
+++ b/android_webview/browser/aw_feature_list_creator.cc
@@ -170,12 +170,6 @@
       std::vector<std::string>(), /*low_entropy_provider=*/nullptr,
       std::make_unique<base::FeatureList>(), aw_field_trials_.get(),
       &ignored_safe_seed_manager);
-
-  // Activate a study which exercises permanent-consistency, to test the launch
-  // of permanent-consistency support in WebView.
-  // TODO(crbug/917537): Remove this after m73.
-  base::FieldTrialList::FindFullName("AndroidWebViewConsistencyTest");
-  base::FieldTrialList::FindFullName("AndroidWebViewSessionConsistencyTest");
 }
 
 void AwFeatureListCreator::CreateFeatureListAndFieldTrials() {
diff --git a/ash/DEPS b/ash/DEPS
index 7b96327..1270d40 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -59,8 +59,9 @@
   "+chromeos/audio",
   "+chromeos/components/multidevice/logging/logging.h",
   "+chromeos/constants",
+  # TODO(stevenjb): Eliminate this. http://crbug.com/940810
+  "+chromeos/dbus/audio",
   "+chromeos/dbus/biod/biod_client.h",
-  "+chromeos/dbus/cras_audio_client.h",
   "+chromeos/dbus/dbus_thread_manager.h",
   "+chromeos/dbus/fake_power_manager_client.h",
   "+chromeos/dbus/hammerd",
@@ -68,7 +69,7 @@
   "+chromeos/dbus/power_manager",
   "+chromeos/dbus/shill_device_client.h",
   "+chromeos/dbus/system_clock",
-  # TODO(jamescook): Eliminate this. http://crbug.com/644355
+  # TODO(stevenjb): Eliminate this. http://crbug.com/644355
   "+chromeos/network",
   "+chromeos/services/assistant/public" ,
   "+chromeos/services/assistant/test_support",
diff --git a/ash/components/shortcut_viewer/views/keyboard_shortcut_view.cc b/ash/components/shortcut_viewer/views/keyboard_shortcut_view.cc
index 154898f..c190e27 100644
--- a/ash/components/shortcut_viewer/views/keyboard_shortcut_view.cc
+++ b/ash/components/shortcut_viewer/views/keyboard_shortcut_view.cc
@@ -89,11 +89,27 @@
   illustration_view->AddChildView(text);
 }
 
-views::ScrollView* CreateScrollView(std::unique_ptr<views::View> content_view) {
-  views::ScrollView* const scroller = new views::ScrollView();
+class ShortcutsListScrollView : public views::ScrollView {
+ public:
+  ShortcutsListScrollView() = default;
+  ~ShortcutsListScrollView() override = default;
+
+  // views::View:
+  void OnFocus() override { SetHasFocusIndicator(true); }
+
+  void OnBlur() override { SetHasFocusIndicator(false); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ShortcutsListScrollView);
+};
+
+ShortcutsListScrollView* CreateScrollView(
+    std::unique_ptr<views::View> content_view) {
+  ShortcutsListScrollView* const scroller = new ShortcutsListScrollView();
   scroller->set_draw_overflow_indicator(false);
   scroller->ClipHeightTo(0, 0);
   scroller->SetContents(std::move(content_view));
+  scroller->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
   return scroller;
 }
 
diff --git a/ash/system/unified/unified_slider_bubble_controller.cc b/ash/system/unified/unified_slider_bubble_controller.cc
index aa793bc..f88ce28 100644
--- a/ash/system/unified/unified_slider_bubble_controller.cc
+++ b/ash/system/unified/unified_slider_bubble_controller.cc
@@ -167,9 +167,9 @@
   init_params.anchor_rect = tray_->shelf()->GetSystemTrayAnchorRect();
   // Decrease bottom and right insets to compensate for the adjustment of
   // the respective edges in Shelf::GetSystemTrayAnchorRect().
-  init_params.insets =
-      gfx::Insets(kUnifiedMenuPadding, kUnifiedMenuPadding,
-                  kUnifiedMenuPadding - 1, kUnifiedMenuPadding - 1);
+  init_params.insets = gfx::Insets(
+      kUnifiedMenuPadding, kUnifiedMenuPadding, kUnifiedMenuPadding - 1,
+      kUnifiedMenuPadding - (base::i18n::IsRTL() ? 0 : 1));
   init_params.corner_radius = kUnifiedTrayCornerRadius;
   init_params.has_shadow = false;
 
diff --git a/ash/system/unified/unified_system_tray_bubble.cc b/ash/system/unified/unified_system_tray_bubble.cc
index 57cd0d5..e535c91 100644
--- a/ash/system/unified/unified_system_tray_bubble.cc
+++ b/ash/system/unified/unified_system_tray_bubble.cc
@@ -84,9 +84,9 @@
   init_params.anchor_rect = tray->shelf()->GetSystemTrayAnchorRect();
   // Decrease bottom and right insets to compensate for the adjustment of
   // the respective edges in Shelf::GetSystemTrayAnchorRect().
-  init_params.insets =
-      gfx::Insets(kUnifiedMenuPadding, kUnifiedMenuPadding,
-                  kUnifiedMenuPadding - 1, kUnifiedMenuPadding - 1);
+  init_params.insets = gfx::Insets(
+      kUnifiedMenuPadding, kUnifiedMenuPadding, kUnifiedMenuPadding - 1,
+      kUnifiedMenuPadding - (base::i18n::IsRTL() ? 0 : 1));
   init_params.corner_radius = kUnifiedTrayCornerRadius;
   init_params.has_shadow = false;
   init_params.show_by_click = show_by_click;
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index fe561bc..635b3ad 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -31,7 +31,7 @@
 #include "base/strings/string_split.h"
 #include "base/token.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/cras_audio_client.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_policy_controller.h"
 #include "chromeos/network/network_handler.h"
diff --git a/ash/wm/overview/overview_controller.cc b/ash/wm/overview/overview_controller.cc
index 5c12e00d..86e680d 100644
--- a/ash/wm/overview/overview_controller.cc
+++ b/ash/wm/overview/overview_controller.cc
@@ -478,6 +478,7 @@
     split_view_controller->EndSplitView();
     if (IsSelecting())
       ToggleOverview();
+    MaximizeIfSnapped(active_window);
     ::wm::ActivateWindow(active_window);
     base::RecordAction(
         base::UserMetricsAction("Tablet_LongPressOverviewButtonExitSplitView"));
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index dc4f0bcf..3f1c3bc 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -388,7 +388,7 @@
   overview_session_ = nullptr;
 
   while (!window_list_.empty())
-    RemoveItem(window_list_.back().get(), /*reposition=*/false);
+    RemoveItem(window_list_.back().get());
 
   // HomeLauncherGestureHandler will handle fading/sliding |shield_widget_| in
   // this exit mode.
@@ -604,24 +604,20 @@
     PositionWindows(animate);
 }
 
-void OverviewGrid::RemoveItem(OverviewItem* overview_item, bool reposition) {
+void OverviewGrid::RemoveItem(OverviewItem* overview_item) {
   auto* window = overview_item->GetWindow();
   // Use reverse iterator to be efficiently when removing all.
   auto iter = std::find_if(window_list_.rbegin(), window_list_.rend(),
                            [window](std::unique_ptr<OverviewItem>& item) {
                              return item->GetWindow() == window;
                            });
-  if (iter != window_list_.rend()) {
-    window_observer_.Remove(window);
-    window_state_observer_.Remove(wm::GetWindowState(window));
-    // Erase from the list first because deleting OverviewItem can lead to
-    // iterating through the |window_list_|.
-    std::unique_ptr<OverviewItem> tmp = std::move(*iter);
-    window_list_.erase(std::next(iter).base());
-  }
-
-  if (reposition)
-    PositionWindows(/*animate=*/true);
+  DCHECK(iter != window_list_.rend());
+  window_observer_.Remove(window);
+  window_state_observer_.Remove(wm::GetWindowState(window));
+  // Erase from the list first because deleting OverviewItem can lead to
+  // iterating through the |window_list_|.
+  std::unique_ptr<OverviewItem> tmp = std::move(*iter);
+  window_list_.erase(std::next(iter).base());
 }
 
 void OverviewGrid::SetBoundsAndUpdatePositions(const gfx::Rect& bounds) {
@@ -787,10 +783,8 @@
   // happen in the primary display.
   // The |drop_target_widget_| may not in the same display as
   // |dragged_window|, which will cause |drop_target_item| to be null.
-  if (drop_target_item) {
-    overview_session_->RemoveOverviewItem(drop_target_item,
-                                          /*reposition=*/false);
-  }
+  if (drop_target_item)
+    overview_session_->RemoveItem(drop_target_item);
   drop_target_widget_.reset();
 
   // Called to reset caption and title visibility after dragging.
diff --git a/ash/wm/overview/overview_grid.h b/ash/wm/overview/overview_grid.h
index 3c7eaabd..332940b4 100644
--- a/ash/wm/overview/overview_grid.h
+++ b/ash/wm/overview/overview_grid.h
@@ -98,9 +98,9 @@
   // reposition with animation.
   void AddItem(aura::Window* window, bool reposition, bool animate);
 
-  // Removes |overview_item| from the grid. If |reposition| is true, reposition
-  // all window items in the grid after removing the item.
-  void RemoveItem(OverviewItem* overview_item, bool reposition);
+  // Removes |overview_item| from the grid. |overview_item| cannot already be
+  // absent from the grid. No items are repositioned, and there is no animation.
+  void RemoveItem(OverviewItem* overview_item);
 
   // Sets bounds for the window grid and positions all windows in the grid.
   void SetBoundsAndUpdatePositions(const gfx::Rect& bounds_in_screen);
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index 5b5cdb3..9e865e6f 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -28,6 +28,7 @@
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_transient_descendant_iterator.h"
+#include "ash/wm/wm_event.h"
 #include "base/auto_reset.h"
 #include "base/metrics/user_metrics.h"
 #include "ui/compositor/layer_animation_sequence.h"
@@ -145,6 +146,17 @@
 }
 
 void OverviewItem::RestoreWindow(bool reset_transform) {
+  // TODO(oshima): SplitViewController has its own logic to adjust the
+  // target state in |SplitViewController::OnOverviewModeEnding|.
+  // Unify the mechanism to control it and remove ifs.
+  if (Shell::Get()
+          ->tablet_mode_controller()
+          ->IsTabletModeWindowManagerEnabled() &&
+      !Shell::Get()->split_view_controller()->IsSplitViewModeActive() &&
+      reset_transform) {
+    MaximizeIfSnapped(GetWindow());
+  }
+
   caption_container_view_->ResetEventDelegate();
   transform_window_.RestoreWindow(
       reset_transform, overview_session_->enter_exit_overview_type());
@@ -253,7 +265,7 @@
 
 void OverviewItem::SetBounds(const gfx::RectF& target_bounds,
                              OverviewAnimationType animation_type) {
-  if (in_bounds_update_)
+  if (in_bounds_update_ || !Shell::Get()->overview_controller()->IsSelecting())
     return;
 
   // Do not animate if the resulting bounds does not change. The original
@@ -675,6 +687,10 @@
                                          const gfx::Rect& old_bounds,
                                          const gfx::Rect& new_bounds,
                                          ui::PropertyChangeReason reason) {
+  // Do not keep the overview bounds if we're shutting down.
+  if (!Shell::Get()->overview_controller()->IsSelecting())
+    return;
+
   if (reason == ui::PropertyChangeReason::NOT_FROM_ANIMATION) {
     if (window == GetWindow()) {
       transform_window_.ResizeMinimizedWidgetIfNeeded();
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index 34949b42..4376153 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -183,6 +183,8 @@
 // constructed object.
 void OverviewSession::Init(const WindowList& windows,
                            const WindowList& hide_windows) {
+  Shell::Get()->AddShellObserver(this);
+
   hide_overview_windows_ =
       std::make_unique<ScopedOverviewHideWindows>(std::move(hide_windows));
   if (restore_focus_window_)
@@ -288,6 +290,7 @@
 // restoring_minimized_windows() on a partially destructed object.
 void OverviewSession::Shutdown() {
   Shell::Get()->RemovePreTargetHandler(this);
+  Shell::Get()->RemoveShellObserver(this);
 
   // Stop observing screen metrics changes first to avoid auto-positioning
   // windows in response to work area changes from window activation.
@@ -464,18 +467,18 @@
   ::wm::ActivateWindow(GetOverviewFocusWindow());
 }
 
-void OverviewSession::RemoveOverviewItem(OverviewItem* item, bool reposition) {
-  if (item->GetWindow()->HasObserver(this)) {
-    item->GetWindow()->RemoveObserver(this);
-    observed_windows_.erase(item->GetWindow());
-    if (item->GetWindow() == restore_focus_window_)
+void OverviewSession::RemoveItem(OverviewItem* overview_item) {
+  if (overview_item->GetWindow()->HasObserver(this)) {
+    overview_item->GetWindow()->RemoveObserver(this);
+    observed_windows_.erase(overview_item->GetWindow());
+    if (overview_item->GetWindow() == restore_focus_window_)
       restore_focus_window_ = nullptr;
   }
 
-  // Remove |item| from the corresponding grid.
+  // Remove |overview_item| from the corresponding grid.
   for (std::unique_ptr<OverviewGrid>& grid : grid_list_) {
-    if (grid->GetOverviewItemContaining(item->GetWindow())) {
-      grid->RemoveItem(item, reposition);
+    if (grid->GetOverviewItemContaining(overview_item->GetWindow())) {
+      grid->RemoveItem(overview_item);
       --num_items_;
       break;
     }
@@ -817,6 +820,11 @@
   event->StopPropagation();
 }
 
+void OverviewSession::OnShellDestroying() {
+  // Cancel selection will call |Shutodnw()|, which will remove observer.
+  CancelSelection();
+}
+
 void OverviewSession::OnSplitViewStateChanged(
     SplitViewController::State previous_state,
     SplitViewController::State state) {
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index 7eb9cf5d..c0daa82 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "ash/ash_export.h"
+#include "ash/shell_observer.h"
 #include "ash/wm/overview/scoped_overview_hide_windows.h"
 #include "ash/wm/splitview/split_view_controller.h"
 #include "base/containers/flat_set.h"
@@ -50,6 +51,7 @@
 class ASH_EXPORT OverviewSession : public display::DisplayObserver,
                                    public aura::WindowObserver,
                                    public ui::EventHandler,
+                                   public ShellObserver,
                                    public SplitViewController::Observer {
  public:
   enum Direction { LEFT, UP, RIGHT, DOWN };
@@ -147,14 +149,12 @@
   // then added to the overview.
   void AddItem(aura::Window* window, bool reposition, bool animate);
 
-  // Removes the overview item from the overview grid. And if
-  // |reposition| is true, re-position all windows in the target overview grid.
-  // This may be called in two scenarioes: 1) when a user drags an overview item
-  // to snap to one side of the screen, the item should be removed from the
-  // overview grid; 2) when a window (not from overview) ends its dragging while
-  // overview is open, the drop target should be removed. Note in both cases,
-  // the windows in the window grid do not need to be repositioned.
-  void RemoveOverviewItem(OverviewItem* item, bool reposition);
+  // Removes |overview_item| from the corresponding overview grid. This may be
+  // called in two scenarioes: 1) when a user drags an overview item to snap to
+  // one side of the screen, the item should be removed from the overview grid;
+  // 2) when a window (not from overview) ends its dragging while overview is
+  // open, the drop target should be removed.
+  void RemoveItem(OverviewItem* overview_item);
 
   void InitiateDrag(OverviewItem* item, const gfx::PointF& location_in_screen);
   void Drag(OverviewItem* item, const gfx::PointF& location_in_screen);
@@ -268,6 +268,9 @@
   // ui::EventHandler:
   void OnKeyEvent(ui::KeyEvent* event) override;
 
+  // ShelObserver:
+  void OnShellDestroying() override;
+
   // SplitViewController::Observer:
   void OnSplitViewStateChanged(SplitViewController::State previous_state,
                                SplitViewController::State state) override;
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc
index da5f3af..3fa6edf 100644
--- a/ash/wm/overview/overview_utils.cc
+++ b/ash/wm/overview/overview_utils.cc
@@ -10,6 +10,7 @@
 #include "ash/home_screen/home_screen_controller.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/scoped_animation_disabler.h"
 #include "ash/shell.h"
 #include "ash/wm/overview/cleanup_animation_observer.h"
 #include "ash/wm/overview/overview_controller.h"
@@ -19,6 +20,7 @@
 #include "ash/wm/splitview/split_view_utils.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_transient_descendant_iterator.h"
+#include "ash/wm/wm_event.h"
 #include "base/no_destructor.h"
 #include "third_party/skia/include/pathops/SkPathOps.h"
 #include "ui/aura/window.h"
@@ -304,4 +306,13 @@
   return false;
 }
 
+void MaximizeIfSnapped(aura::Window* window) {
+  auto* window_state = wm::GetWindowState(window);
+  if (window_state && window_state->IsSnapped()) {
+    ScopedAnimationDisabler disabler(window);
+    wm::WMEvent event(wm::WM_EVENT_MAXIMIZE);
+    window_state->OnWMEvent(&event);
+  }
+}
+
 }  // namespace ash
diff --git a/ash/wm/overview/overview_utils.h b/ash/wm/overview/overview_utils.h
index 5d412d8..a7a1c73 100644
--- a/ash/wm/overview/overview_utils.h
+++ b/ash/wm/overview/overview_utils.h
@@ -81,6 +81,9 @@
 // Checks if we are currently in sliding up on the shelf to hide overview mode.
 bool IsSlidingOutOverviewFromShelf();
 
+// Maximize the window if it is snapped without animation.
+void MaximizeIfSnapped(aura::Window* window);
+
 }  // namespace ash
 
 #endif  // ASH_WM_OVERVIEW_OVERVIEW_UTILS_H_
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index d71b9c3..6e266a5 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -856,8 +856,7 @@
         // is unavailable to retrieve outside this function after
         // OnOverviewEnding is notified.
         overview_item->RestoreWindow(/*reset_transform=*/false);
-        overview_session->RemoveOverviewItem(overview_item.get(),
-                                             /*reposition=*/false);
+        overview_session->RemoveItem(overview_item.get());
         SnapWindow(window, (default_snap_position_ == LEFT) ? RIGHT : LEFT);
         // If ending overview causes a window to snap, also do not do exiting
         // overview animation.
@@ -1253,7 +1252,7 @@
     // this will be need to updated.
     TabletModeWindowState::UpdateWindowPosition(
         wm::GetWindowState(insert_overview_window), /*animate=*/false);
-    InsertWindowToOverview(insert_overview_window);
+    InsertWindowToOverview(insert_overview_window, /*animate=*/false);
   }
 }
 
@@ -1302,7 +1301,8 @@
     // If there is no snapped window at this moment, ends split view mode. Note
     // this will update overview window grid bounds if the overview mode is
     // active at the moment.
-    EndSplitView();
+    EndSplitView(window_drag ? EndReason::kWindowDragStarted
+                             : EndReason::kNormal);
   } else {
     // If there is still one snapped window after minimizing/closing one snapped
     // window, update its snap state and open overview window grid.
@@ -1594,7 +1594,7 @@
   // repositioned in this case as they have been positioned to the right place
   // during dragging.
   item->RestoreWindow(/*reset_transform=*/false);
-  overview_session->RemoveOverviewItem(item, /*reposition=*/false);
+  overview_session->RemoveItem(item);
 }
 
 void SplitViewController::UpdateSnappingWindowTransformedBounds(
@@ -1605,10 +1605,11 @@
   }
 }
 
-void SplitViewController::InsertWindowToOverview(aura::Window* window) {
+void SplitViewController::InsertWindowToOverview(aura::Window* window,
+                                                 bool animate) {
   if (!window || !GetOverviewSession())
     return;
-  GetOverviewSession()->AddItem(window, /*reposition=*/true, /*animate=*/true);
+  GetOverviewSession()->AddItem(window, /*reposition=*/true, animate);
 }
 
 void SplitViewController::StartOverview(bool window_drag) {
@@ -1701,6 +1702,16 @@
     // Note SnapWindow() might put the previous window that was snapped at the
     // |desired_snap_position| in overview.
     SnapWindow(window, desired_snap_position);
+    // Reapply the bounds update because the bounds might have been
+    // modified by dragging operation.
+    // TODO(oshima): WindowState already gets notified when drag ends. Refactor
+    // WindowState so that each state implementation can take action when
+    // drag ends.
+    const wm::WMEvent event(desired_snap_position == SplitViewController::LEFT
+                                ? wm::WM_EVENT_SNAP_LEFT
+                                : wm::WM_EVENT_SNAP_RIGHT);
+    wm::GetWindowState(window)->OnWMEvent(&event);
+
     if (!was_splitview_active) {
       // If splitview mode was not active before snapping the dragged
       // window, snap the initiator window to the other side of the screen
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 5b6ecdcd..2d6cef1 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -64,12 +64,14 @@
 
   // Why splitview was ended. For now, all reasons will be kNormal except when
   // the home launcher button is pressed, an unsnappable window just got
-  // activated, or the active user session changed.
+  // activated, the active user session changed, or the window dragging
+  // started.
   enum class EndReason {
     kNormal = 0,
     kHomeLauncherPressed,
     kUnsnappableWindowActivated,
     kActiveUserChanged,
+    kWindowDragStarted,
   };
 
   class Observer {
@@ -349,7 +351,7 @@
 
   // Inserts |window| into overview window grid if overview mode is active. Do
   // nothing if overview mode is inactive at the moment.
-  void InsertWindowToOverview(aura::Window* window);
+  void InsertWindowToOverview(aura::Window* window, bool animate = true);
 
   // Starts/Ends overview mode if the overview mode is inactive/active.
   void StartOverview(bool window_drag = false);
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index fe9fed1..f9ba055 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -2465,7 +2465,11 @@
   // for the |dragged_window|.
   std::unique_ptr<WindowResizer> StartDrag(aura::Window* dragged_window,
                                            aura::Window* source_window) {
+    // Drag operation activates the window first, then activates the dragged
+    // window.  Emulate this behavior.
+    wm::ActivateWindow(source_window);
     SetIsInTabDragging(dragged_window, /*is_dragging=*/true, source_window);
+    wm::ActivateWindow(dragged_window);
     std::unique_ptr<WindowResizer> resizer = CreateResizerForTest(
         dragged_window, dragged_window->bounds().origin(), HTCAPTION);
     GetBrowserWindowDragController(resizer.get())
@@ -3184,9 +3188,8 @@
   OverviewGrid* current_grid =
       overview_session->GetGridWithRootWindow(window2->GetRootWindow());
   ASSERT_TRUE(current_grid);
-  overview_session->RemoveOverviewItem(
-      current_grid->GetOverviewItemContaining(window2.get()),
-      /*reposition=*/false);
+  overview_session->RemoveItem(
+      current_grid->GetOverviewItemContaining(window2.get()));
 
   resizer = StartDrag(window2.get(), window1.get());
   ASSERT_TRUE(resizer.get());
@@ -3223,9 +3226,8 @@
   // 2.b. The dragged window can snap to the other side of the splitscreen,
   // causing overview mode to end.
   // Remove |window1| from overview first before tab dragging.
-  overview_session->RemoveOverviewItem(
-      current_grid->GetOverviewItemContaining(window1.get()),
-      /*reposition=*/false);
+  overview_session->RemoveItem(
+      current_grid->GetOverviewItemContaining(window1.get()));
   resizer = StartDrag(window1.get(), window2.get());
   ASSERT_TRUE(resizer.get());
   DragWindowTo(resizer.get(), gfx::Point(600, 500));
@@ -3806,12 +3808,15 @@
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
+  auto* window_state1 = wm::GetWindowState(window1.get());
+  auto* window_state2 = wm::GetWindowState(window2.get());
 
   // Drags |window2| to overview.
   std::unique_ptr<WindowResizer> resizer =
       StartDrag(window2.get(), window2.get());
   gfx::Rect drop_target_bounds = GetDropTargetBoundsDuringDrag(window1.get());
   DragWindowTo(resizer.get(), drop_target_bounds.CenterPoint());
+  EXPECT_TRUE(window_state2->IsSnapped());
   CompleteDrag(std::move(resizer));
   OverviewController* selector_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(selector_controller->IsSelecting());
@@ -3819,18 +3824,22 @@
       window2.get()));
   EXPECT_EQ(split_view_controller()->state(),
             SplitViewController::LEFT_SNAPPED);
+  EXPECT_TRUE(window_state2->IsSnapped());
 
   // Drags |window1| by a small distance. Both splitview and overview should be
   // ended and |window1| is the active window and above |window2|.
   resizer = StartDrag(window1.get(), window1.get());
   DragWindowTo(resizer.get(), gfx::Point(10, 10));
+  EXPECT_TRUE(window_state1->IsSnapped());
+  EXPECT_TRUE(window_state2->IsSnapped());
+
   CompleteDrag(std::move(resizer));
   EXPECT_FALSE(selector_controller->IsSelecting());
   EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive());
-  EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMaximized());
-  EXPECT_TRUE(wm::GetWindowState(window2.get())->IsMaximized());
-  EXPECT_TRUE(wm::GetWindowState(window1.get())->IsActive());
-  EXPECT_FALSE(wm::GetWindowState(window2.get())->IsActive());
+  EXPECT_TRUE(window_state1->IsMaximized());
+  EXPECT_TRUE(window_state2->IsMaximized());
+  EXPECT_TRUE(window_state1->IsActive());
+  EXPECT_FALSE(window_state2->IsActive());
   // |window1| should above |window2|.
   const aura::Window::Windows windows = window1->parent()->children();
   auto window1_layer = std::find(windows.begin(), windows.end(), window1.get());
@@ -4055,6 +4064,9 @@
   DragWindowTo(resizer.get(), gfx::Point(100, 200));
   EXPECT_EQ(window1->bounds(), snapped_bounds1);
   EXPECT_EQ(window2->bounds(), snapped_bounds2);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::BOTH_SNAPPED);
+
   CompleteDrag(std::move(resizer));
   // In this case |window3| is supposed to merge back its source window
   // |window1|, so we only test the source window's bounds here.
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
index 83f6cabbe..a8b59a5 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -17,6 +17,7 @@
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/overview/overview_session.h"
+#include "ash/wm/overview/overview_utils.h"
 #include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/splitview/split_view_utils.h"
 #include "ash/wm/tablet_mode/scoped_skip_user_session_blocked_check.h"
@@ -83,8 +84,9 @@
     window->RemoveObserver(this);
   added_windows_.clear();
   Shell::Get()->RemoveShellObserver(this);
-  display::Screen::GetScreen()->RemoveObserver(this);
   Shell::Get()->session_controller()->RemoveObserver(this);
+  Shell::Get()->overview_controller()->RemoveObserver(this);
+  display::Screen::GetScreen()->RemoveObserver(this);
   EnableBackdropBehindTopWindowOnEachDisplay(false);
   RemoveWindowCreationObservers();
   ArrangeWindowsForDesktopMode(was_in_overview);
@@ -118,6 +120,27 @@
     window_state_map_.erase(it);
 }
 
+void TabletModeWindowManager::OnOverviewModeEndingAnimationComplete(
+    bool canceled) {
+  if (canceled)
+    return;
+
+  auto* split_view_controller = Shell::Get()->split_view_controller();
+
+  // Maximize all snapped windows upon exiting overview mode except snapped
+  // windows in splitview mode. Note the snapped window might not be tracked in
+  // our |window_state_map_|.
+  MruWindowTracker::WindowList windows =
+      Shell::Get()->mru_window_tracker()->BuildWindowListIgnoreModal();
+  for (auto* window : windows) {
+    if (split_view_controller->left_window() != window &&
+        split_view_controller->right_window() != window) {
+      MaximizeIfSnapped(window);
+    }
+  }
+}
+
+// ShellObserver:
 void TabletModeWindowManager::OnSplitViewModeEnded() {
   switch (Shell::Get()->split_view_controller()->end_reason()) {
     case SplitViewController::EndReason::kNormal:
@@ -125,6 +148,7 @@
       break;
     case SplitViewController::EndReason::kHomeLauncherPressed:
     case SplitViewController::EndReason::kActiveUserChanged:
+    case SplitViewController::EndReason::kWindowDragStarted:
       // For the case of kHomeLauncherPressed, the home launcher will minimize
       // the snapped windows after ending splitview, so avoid maximizing them
       // here. For the case of kActiveUserChanged, the snapped windows will be
@@ -138,14 +162,8 @@
   // window might not be tracked in our |window_state_map_|.
   MruWindowTracker::WindowList windows =
       Shell::Get()->mru_window_tracker()->BuildWindowListIgnoreModal();
-  for (auto* window : windows) {
-    wm::WindowState* window_state = wm::GetWindowState(window);
-    if (window_state->IsSnapped()) {
-      ScopedAnimationDisabler disable(window);
-      wm::WMEvent event(wm::WM_EVENT_MAXIMIZE);
-      window_state->OnWMEvent(&event);
-    }
-  }
+  for (auto* window : windows)
+    MaximizeIfSnapped(window);
 }
 
 void TabletModeWindowManager::OnWindowDestroying(aura::Window* window) {
@@ -337,6 +355,7 @@
   display::Screen::GetScreen()->AddObserver(this);
   Shell::Get()->AddShellObserver(this);
   Shell::Get()->session_controller()->AddObserver(this);
+  Shell::Get()->overview_controller()->AddObserver(this);
   accounts_since_entering_tablet_.insert(
       Shell::Get()->session_controller()->GetActiveAccountId());
   event_handler_ = std::make_unique<wm::TabletModeEventHandler>();
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.h b/ash/wm/tablet_mode/tablet_mode_window_manager.h
index 55dff17..b6452464 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.h
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.h
@@ -15,6 +15,7 @@
 #include "ash/session/session_observer.h"
 #include "ash/shell_observer.h"
 #include "ash/wm/mru_window_tracker.h"
+#include "ash/wm/overview/overview_observer.h"
 #include "ash/wm/splitview/split_view_controller.h"
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
@@ -41,6 +42,7 @@
 // original state.
 class ASH_EXPORT TabletModeWindowManager : public aura::WindowObserver,
                                            public display::DisplayObserver,
+                                           public OverviewObserver,
                                            public ShellObserver,
                                            public SessionObserver {
  public:
@@ -59,6 +61,9 @@
   // Called from a window state object when it gets destroyed.
   void WindowStateDestroyed(aura::Window* window);
 
+  // OverviewObserver:
+  void OnOverviewModeEndingAnimationComplete(bool canceled) override;
+
   // ShellObserver:
   void OnSplitViewModeEnded() override;
 
diff --git a/base/test/fuzzed_data_provider.h b/base/test/fuzzed_data_provider.h
index 19e829f..33d1c00 100644
--- a/base/test/fuzzed_data_provider.h
+++ b/base/test/fuzzed_data_provider.h
@@ -12,6 +12,7 @@
 #include <algorithm>
 #include <cstring>
 #include <string>
+#include <type_traits>
 #include <utility>
 #include <vector>
 
@@ -171,6 +172,16 @@
     return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
   }
 
+  // Return an enum value. The enum must start at 0 and be contiguous. It must
+  // also contain kMaxValue aliased to its largest (inclusive) value. Such as:
+  // enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
+  template <typename T>
+  T ConsumeEnum() {
+    static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
+    return static_cast<T>(ConsumeIntegralInRange<uint32_t>(
+        0, static_cast<uint32_t>(T::kMaxValue)));
+  }
+
   // Reports the remaining bytes available for fuzzed input.
   size_t remaining_bytes() { return remaining_bytes_; }
 
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index b4c72e2..4c89f57 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8916737669163559168
\ No newline at end of file
+8916712100220639312
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 5a44181d..cf6090e 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8916742152396029840
\ No newline at end of file
+8916731962316481504
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/permission_dialog.xml b/chrome/android/java/res/layout/permission_dialog.xml
index cd44504..51189b5 100644
--- a/chrome/android/java/res/layout/permission_dialog.xml
+++ b/chrome/android/java/res/layout/permission_dialog.xml
@@ -4,17 +4,19 @@
      found in the LICENSE file.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:orientation="vertical"
     android:gravity="start"
-    style="@style/AlertDialogContent" >
+    style="@style/AlertDialogContent">
 
-    <TextView
+    <org.chromium.chrome.browser.widget.TextViewWithCompoundDrawables
         android:id="@+id/text"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center_vertical"
         android:textDirection="locale"
-        android:textSize="@dimen/dialog_text_size"
         android:paddingBottom="24dp"
-        android:drawablePadding="8dp" />
+        android:drawablePadding="8dp"
+        android:textAppearance="@style/TextAppearance.BlackBody"
+        app:chromeDrawableTint="@color/default_icon_color_blue" />
 </LinearLayout>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index fac9f9d4..71d60b1 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -495,7 +495,6 @@
          https://www.google.com/design/spec/components/dialogs.html#dialogs-simple-dialogs -->
     <dimen name="dialog_width_unit">56dp</dimen>  <!-- MD dialog widths are multiples of this. -->
     <dimen name="dialog_header_margin">14dp</dimen>
-    <dimen name="dialog_text_size">14sp</dimen>
     <dimen name="separator_height">1dp</dimen>
 
     <!-- Modern List Item dimensions -->
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java
index 19523421..49fb997e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java
@@ -223,6 +223,7 @@
     }
 
     private void detachLayoutIfNecessary() {
+        if (mSideSlideLayout == null) return;
         cancelDetachLayoutRunnable();
         if (mSideSlideLayout.getParent() != null) {
             mParentView.removeView(mSideSlideLayout);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java
index 81f60c06..696ffcb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java
@@ -223,7 +223,7 @@
         long time = config.getDataReductionLastUpdateTime() - days * DateUtils.DAY_IN_MILLIS;
         for (int i = history.length - days, bucket = 0; i < history.length; i++, bucket++) {
             NetworkStats.Entry entry = new NetworkStats.Entry();
-            entry.rxBytes = history[i];
+            entry.rxBytes = Math.max(history[i], 0);
             long startTime = time + (DateUtils.DAY_IN_MILLIS * bucket);
             // Spread each day's record over the first hour of the day.
             networkStatsHistory.recordData(startTime, startTime + DateUtils.HOUR_IN_MILLIS, entry);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java
index a816f68c..9a5430d8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java
@@ -105,27 +105,44 @@
         switchObserverToTab(tabModelSelector.getCurrentTab());
     }
 
+    /** Notify PageViewObserver that {@code fqdn} was just suspended or un-suspended. */
+    public void notifySiteSuspensionChanged(String fqdn, boolean isSuspended) {
+        if (mLastFqdn != null && mLastFqdn.equals(fqdn)) {
+            if (isSuspended) {
+                SuspendedTab.from(mCurrentTab).show(fqdn);
+                return;
+            }
+
+            SuspendedTab suspendedTab = SuspendedTab.get(mCurrentTab);
+            if (suspendedTab != null && !isSuspended && suspendedTab.getFqdn().equals(fqdn)) {
+                suspendedTab.removeIfPresent();
+                mCurrentTab.reload();
+            }
+        }
+    }
+
     private void updateUrl(String newUrl) {
         String newFqdn = newUrl == null ? "" : Uri.parse(newUrl).getHost();
-
         boolean didSuspend = false;
+        boolean sameDomain = mLastFqdn != null && mLastFqdn.equals(newFqdn);
+
         if (newFqdn != null && mSuspensionTracker.isWebsiteSuspended(newFqdn)) {
-            SuspendedTab.create(mCurrentTab).show();
+            SuspendedTab.from(mCurrentTab).show(newFqdn);
             didSuspend = true;
         }
 
-        if (mLastFqdn != null && mLastFqdn.equals(newFqdn)) return;
+        if (sameDomain) return;
 
         if (mLastFqdn != null) {
             mEventTracker.addWebsiteEvent(new WebsiteEvent(
                     System.currentTimeMillis(), mLastFqdn, WebsiteEvent.EventType.STOP));
             reportToPlatformIfDomainIsTracked("reportUsageStop", mLastFqdn);
-            mLastFqdn = null;
         }
 
+        mLastFqdn = newFqdn;
+
         if (!URLUtil.isHttpUrl(newUrl) && !URLUtil.isHttpsUrl(newUrl) || didSuspend) return;
 
-        mLastFqdn = newFqdn;
         mEventTracker.addWebsiteEvent(new WebsiteEvent(
                 System.currentTimeMillis(), mLastFqdn, WebsiteEvent.EventType.START));
         reportToPlatformIfDomainIsTracked("reportUsageStart", mLastFqdn);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspendedTab.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspendedTab.java
index dab2b05..e3c7061 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspendedTab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspendedTab.java
@@ -15,6 +15,7 @@
 import android.widget.LinearLayout.LayoutParams;
 import android.widget.TextView;
 
+import org.chromium.base.UserData;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
@@ -24,43 +25,70 @@
  * Represents the suspension page presented when a user tries to visit a site whose fully-qualified
  * domain name (FQDN) has been suspended via Digital Wellbeing.
  */
-public class SuspendedTab extends EmptyTabObserver {
+public class SuspendedTab extends EmptyTabObserver implements UserData {
     private static final String DIGITAL_WELLBEING_DASHBOARD_ACTION =
             "com.google.android.apps.wellbeing.action.APP_USAGE_DASHBOARD";
+    private static final Class<SuspendedTab> USER_DATA_KEY = SuspendedTab.class;
+
+    public static SuspendedTab from(Tab tab) {
+        SuspendedTab suspendedTab = get(tab);
+        if (suspendedTab == null) {
+            suspendedTab = tab.getUserDataHost().setUserData(USER_DATA_KEY, new SuspendedTab(tab));
+        }
+        return suspendedTab;
+    }
+
+    public static SuspendedTab get(Tab tab) {
+        return tab.getUserDataHost().getUserData(USER_DATA_KEY);
+    }
 
     private final Tab mTab;
     private View mView;
-
-    public static SuspendedTab create(Tab tab) {
-        return new SuspendedTab(tab);
-    }
+    private String mFqdn;
 
     private SuspendedTab(Tab tab) {
         mTab = tab;
-        mTab.addObserver(this);
     }
 
     /**
      * Show the suspended tab UI within the root view of the associated tab. This will stop loading
-     * of mTab so that the page is not also rendered.
+     * of mTab so that the page is not also rendered. If the suspended tab is already showing, this
+     * will update its fqdn to the given one.
      */
-    public void show() {
-        if (mTab.getWebContents() == null) return;
-
+    public void show(String fqdn) {
+        mFqdn = fqdn;
+        mTab.addObserver(this);
         mTab.stopLoading();
-        attachView();
+        if (isShowing()) {
+            updateFqdnText();
+        } else {
+            attachView();
+        }
+    }
+
+    /** Remove the suspended tab UI if it's currently being shown. */
+    public void removeIfPresent() {
+        removeViewIfPresent();
+
+        mTab.removeObserver(this);
+        mView = null;
+        mFqdn = null;
+    }
+
+    /** @return the fqdn this SuspendedTab was last shown for. */
+    public String getFqdn() {
+        return mFqdn;
     }
 
     private View createView() {
         Context context = mTab.getContext();
         LayoutInflater inflater = LayoutInflater.from(context);
 
-        String fqdn = Uri.parse(mTab.getUrl()).getHost();
         View suspendedTabView = inflater.inflate(R.layout.suspended_tab, null);
         TextView explanationText =
                 (TextView) suspendedTabView.findViewById(R.id.suspended_tab_explanation);
         explanationText.setText(
-                context.getString(R.string.usage_stats_site_paused_explanation, fqdn));
+                context.getString(R.string.usage_stats_site_paused_explanation, mFqdn));
 
         View settingsLink = suspendedTabView.findViewById(R.id.suspended_tab_settings_button);
         settingsLink.setOnClickListener(new OnClickListener() {
@@ -79,17 +107,20 @@
         assert mView == null;
 
         ViewGroup parent = mTab.getContentView();
+        // getContentView() will return null if the tab doesn't have a WebContents, which is
+        // possible in some situations, e.g. if the renderer crashes.
+        if (parent == null) return;
         mView = createView();
         parent.addView(mView,
                 new LinearLayout.LayoutParams(
                         LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
     }
 
-    private void removeIfPresent() {
-        removeViewIfPresent();
-
-        mTab.removeObserver(this);
-        mView = null;
+    private void updateFqdnText() {
+        Context context = mTab.getContext();
+        TextView explanationText = (TextView) mView.findViewById(R.id.suspended_tab_explanation);
+        explanationText.setText(
+                context.getString(R.string.usage_stats_site_paused_explanation, mFqdn));
     }
 
     private void removeViewIfPresent() {
@@ -102,15 +133,22 @@
         return mView != null && mView.getParent() == mTab.getContentView();
     }
 
+    private void removeSelfIfFqdnChanged(String url) {
+        String newFqdn = Uri.parse(url).getHost();
+        if (newFqdn == null || !newFqdn.equals(mFqdn)) {
+            removeIfPresent();
+        }
+    }
+
     // TabObserver implementation.
     @Override
     public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
-        removeIfPresent();
+        removeSelfIfFqdnChanged(params.getUrl());
     }
 
     @Override
     public void onPageLoadStarted(Tab tab, String url) {
-        removeIfPresent();
+        removeSelfIfFqdnChanged(url);
     }
 
     @Override
@@ -127,4 +165,10 @@
             attachView();
         }
     }
+
+    // UserData implementation.
+    @Override
+    public void destroy() {
+        mTab.removeObserver(this);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
index 0be5e80..8e98f70 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
@@ -17,6 +17,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -33,6 +34,10 @@
     private SuspensionTracker mSuspensionTracker;
     private TokenTracker mTokenTracker;
     private UsageStatsBridge mBridge;
+    // PageViewObservers are scoped to a given ChromeTabbedActivity, but UsageStatsService isn't. To
+    // allow for GC of the observer to happen when the activity goes away, we only hold weak
+    // references here.
+    private List<WeakReference<PageViewObserver>> mPageViewObservers;
 
     private DigitalWellbeingClient mClient;
     private boolean mOptInState;
@@ -53,6 +58,7 @@
         mEventTracker = new EventTracker(mBridge);
         mSuspensionTracker = new SuspensionTracker(mBridge);
         mTokenTracker = new TokenTracker(mBridge);
+        mPageViewObservers = new ArrayList<>();
 
         mOptInState = getOptInState();
         mClient = AppHooks.get().createDigitalWellbeingClient();
@@ -67,8 +73,10 @@
     public PageViewObserver createPageViewObserver(
             TabModelSelector tabModelSelector, Activity activity) {
         ThreadUtils.assertOnUiThread();
-        return new PageViewObserver(
+        PageViewObserver observer = new PageViewObserver(
                 activity, tabModelSelector, mEventTracker, mTokenTracker, mSuspensionTracker);
+        mPageViewObservers.add(new WeakReference<>(observer));
+        return observer;
     }
 
     /** @return Whether the user has authorized DW to access usage stats data. */
@@ -134,10 +142,19 @@
     }
 
     /**
-     * Suspend or unsuspend every site in FQDNs, depending on the truthiness of <c>suspended</c>.
+     * Suspend or unsuspend every site in FQDNs, depending on the value of {@code suspended}.
      */
     public Promise<Void> setWebsitesSuspendedAsync(List<String> fqdns, boolean suspended) {
         ThreadUtils.assertOnUiThread();
+        for (WeakReference<PageViewObserver> observerRef : mPageViewObservers) {
+            PageViewObserver observer = observerRef.get();
+            if (observer != null) {
+                for (String fqdn : fqdns) {
+                    observer.notifySiteSuspensionChanged(fqdn, suspended);
+                }
+            }
+        }
+
         return mSuspensionTracker.setWebsitesSuspended(fqdns, suspended);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
index aa9a566..7d34575b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
@@ -21,6 +21,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.base.test.util.UrlUtils;
@@ -51,6 +52,7 @@
 import org.chromium.net.NetworkChangeNotifier;
 import org.chromium.net.NetworkChangeNotifierAutoDetect;
 import org.chromium.net.test.util.WebServer;
+import org.chromium.ui.test.util.UiDisableIf;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -381,6 +383,7 @@
     @Test
     @MediumTest
     @Feature({"OfflinePrefetchFeed"})
+    @DisableIf.Device(type = {UiDisableIf.TABLET}) // https://crbug.com/950749
     public void testPrefetchForbiddenByServer() throws Throwable {
         mOPS.setForbidGeneratePageBundle(true);
 
@@ -399,6 +402,7 @@
     @Test
     @MediumTest
     @Feature({"OfflinePrefetchFeed"})
+    @DisableIf.Device(type = {UiDisableIf.TABLET}) // https://crbug.com/950749
     public void testPrefetchBecomesEnabledByServer() throws Throwable {
         OfflineTestUtil.setPrefetchingEnabledByServer(false);
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
index 3861f0e..8060470 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.usage_stats;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Matchers.any;
@@ -26,6 +27,7 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.Promise;
+import org.chromium.base.UserDataHost;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.Tab.TabHidingType;
@@ -34,6 +36,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabSelectionType;
+import org.chromium.content_public.browser.WebContents;
 
 import java.util.Arrays;
 
@@ -62,19 +65,28 @@
     private TokenTracker mTokenTracker;
     @Mock
     private SuspensionTracker mSuspensionTracker;
+    @Mock
+    private WebContents mWebContents;
     @Captor
     private ArgumentCaptor<TabObserver> mTabObserverCaptor;
     @Captor
     private ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor;
 
+    private TabObserver mTabObserver;
+    private UserDataHost mUserDataHost;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        mUserDataHost = new UserDataHost();
+
         doReturn(false).when(mTab).isIncognito();
         doReturn(null).when(mTab).getUrl();
+        doReturn(mWebContents).when(mTab).getWebContents();
         doReturn(Arrays.asList(mTabModel)).when(mTabModelSelector).getModels();
         doReturn(mTab).when(mTabModelSelector).getCurrentTab();
+        doReturn(mUserDataHost).when(mTab).getUserDataHost();
         doReturn(Promise.fulfilled("1")).when(mTokenTracker).getTokenForFqdn(anyString());
     }
 
@@ -205,6 +217,7 @@
         PageViewObserver observer = createPageViewObserver();
         onUpdateUrl(mTab, STARTING_URL);
 
+        doReturn(DIFFERENT_URL).when(mTab).getUrl();
         doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(DIFFERENT_FQDN);
         onUpdateUrl(mTab, DIFFERENT_URL);
 
@@ -217,6 +230,7 @@
         PageViewObserver observer = createPageViewObserver();
         onUpdateUrl(mTab, STARTING_URL);
 
+        doReturn(DIFFERENT_URL).when(mTab).getUrl();
         doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(DIFFERENT_FQDN);
         onUpdateUrl(mTab, DIFFERENT_URL);
 
@@ -227,6 +241,82 @@
         verify(mTab, times(1)).removeObserver(suspendedTab);
     }
 
+    @Test
+    public void eagerSuspension() {
+        PageViewObserver observer = createPageViewObserver();
+        onUpdateUrl(mTab, STARTING_URL);
+
+        doReturn(STARTING_URL).when(mTab).getUrl();
+        observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
+
+        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
+        assertTrue(mTabObserverCaptor.getValue() instanceof SuspendedTab);
+    }
+
+    @Test
+    public void eagerSuspension_navigateToDifferentSuspended() {
+        PageViewObserver observer = createPageViewObserver();
+        onUpdateUrl(mTab, STARTING_URL);
+
+        doReturn(STARTING_URL).when(mTab).getUrl();
+        observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
+
+        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
+        SuspendedTab suspendedTab = (SuspendedTab) mTabObserverCaptor.getValue();
+        assertEquals(STARTING_FQDN, suspendedTab.getFqdn());
+
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(DIFFERENT_FQDN);
+        onUpdateUrl(mTab, DIFFERENT_URL);
+
+        verify(mTab, times(3)).addObserver(any());
+        assertEquals(DIFFERENT_FQDN, suspendedTab.getFqdn());
+    }
+
+    @Test
+    public void eagerUnsuspension() {
+        PageViewObserver observer = createPageViewObserver();
+        onUpdateUrl(mTab, STARTING_URL);
+
+        doReturn(STARTING_URL).when(mTab).getUrl();
+        observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
+
+        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
+        assertTrue(mTabObserverCaptor.getValue() instanceof SuspendedTab);
+        SuspendedTab suspendedTab = (SuspendedTab) mTabObserverCaptor.getValue();
+
+        observer.notifySiteSuspensionChanged(STARTING_FQDN, false);
+        verify(mTab, times(1)).removeObserver(suspendedTab);
+    }
+
+    @Test
+    public void eagerUnsuspension_otherDomainActiveAndSuspended() {
+        PageViewObserver observer = createPageViewObserver();
+        onUpdateUrl(mTab, STARTING_URL);
+
+        doReturn(STARTING_URL).when(mTab).getUrl();
+        observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
+        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
+        SuspendedTab suspendedTab = (SuspendedTab) mTabObserverCaptor.getValue();
+
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(DIFFERENT_FQDN);
+        onUpdateUrl(mTab, DIFFERENT_URL);
+
+        // Notifying that STARTING_FQDN is no longer suspended shouldn't remove the active
+        // SuspendedTab for DIFFERENT_FQDN.
+        observer.notifySiteSuspensionChanged(STARTING_FQDN, false);
+        verify(mTab, times(0)).removeObserver(suspendedTab);
+    }
+
+    @Test
+    public void eagerUnsuspension_notAlreadySuspended() {
+        PageViewObserver observer = createPageViewObserver();
+        onUpdateUrl(mTab, STARTING_URL);
+
+        observer.notifySiteSuspensionChanged(STARTING_FQDN, false);
+        verify(mTab, times(1)).addObserver(any());
+        verify(mTab, times(0)).removeObserver(any());
+    }
+
     private PageViewObserver createPageViewObserver() {
         PageViewObserver observer = new PageViewObserver(
                 mActivity, mTabModelSelector, mEventTracker, mTokenTracker, mSuspensionTracker);
@@ -255,7 +345,11 @@
     }
 
     private TabObserver getTabObserver() {
-        return mTabObserverCaptor.getValue();
+        if (mTabObserver == null) {
+            mTabObserver = mTabObserverCaptor.getValue();
+        }
+
+        return mTabObserver;
     }
 
     private TabModelObserver getTabModelObserver() {
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 87b2a02..ddb3816f 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -953,7 +953,7 @@
           If an image doesn’t have a useful description, Chromium will try to provide one for you. To create descriptions, images are sent to Google.
         </message>
         <message name="IDS_CONTENT_CONTEXT_SPELLING_BUBBLE_TEXT" desc="The text of a bubble that confirms users allows integrating the spelling service of Google to Chrome.">
-          Chromium can provide smarter spell-checking by sending what you type in the browser to Google servers, allowing you to use the same spell-checking technology used by Google search.
+          This uses the same spellchecker that's used in Google search. Text you type in the browser is sent to Google. You can always change this behavior in settings.
         </message>
         <if expr="not use_titlecase">
           <message name="IDS_CONTENT_CONTEXT_OPENLINKNEWTAB_INAPP" desc="The name of the command to open a link in a newly created browser tab when the user is in an app window">
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 4e1f4f0..940e2e48 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -549,14 +549,17 @@
           <message name="IDS_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_BUBBLE_DISABLE" desc="The button text that disallows integrating the accessibility labels service of Google.">
             No thanks
           </message>
-          <message name="IDS_CONTENT_CONTEXT_SPELLING_ASK_GOOGLE" desc="The context-menu item that asks whether to integrate the spelling service of Google to Chrome. This text is also used as the title of a bubble which confirms it.">
+          <message name="IDS_CONTENT_CONTEXT_SPELLING_ASK_GOOGLE" desc="The context-menu item that asks whether to integrate the spelling service of Google to Chrome.">
             Use enhanced spell check
           </message>
+          <message name="IDS_CONTENT_CONTEXT_SPELLING_BUBBLE_TITLE" desc="The title of the confirmation modal that pops up when the user turns on 'Use enhanced spell check'">
+            Turn on enhanced spell check
+          </message>
           <message name="IDS_CONTENT_CONTEXT_SPELLING_BUBBLE_ENABLE" desc="The button text that allows integrating the spelling service of Google.">
-            Enable
+            Turn on
           </message>
           <message name="IDS_CONTENT_CONTEXT_SPELLING_BUBBLE_DISABLE" desc="The button text that disallows integrating the spelling service of Google.">
-            No thanks
+            Cancel
           </message>
           <message name="IDS_CONTENT_CONTEXT_SPELLING_CHECKING" desc="The place-holder message shown while the Spelling service is checking text">
             Loading suggestion
@@ -782,9 +785,12 @@
           <message name="IDS_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_BUBBLE_DISABLE" desc="The button text that disallows integrating the accessibility labels service of Google.">
             No Thanks
           </message>
-          <message name="IDS_CONTENT_CONTEXT_SPELLING_ASK_GOOGLE" desc="In Title Case: The context-menu item that asks whether to integrate the spelling service of Google to Chrome. This text is also used as the title of a bubble which confirms it.">
+          <message name="IDS_CONTENT_CONTEXT_SPELLING_ASK_GOOGLE" desc="In Title Case: The context-menu item that asks whether to integrate the spelling service of Google to Chrome.">
             Use Enhanced Spell Check
           </message>
+          <message name="IDS_CONTENT_CONTEXT_SPELLING_BUBBLE_TITLE" desc="The title of the confirmation modal that pops up when the user turns on 'Use enhanced spell check'">
+            Turn On Enhanced Spell Check
+          </message>
           <message name="IDS_CONTENT_CONTEXT_SPELLING_BUBBLE_ENABLE" desc="In Title Case: The button text that allows integrating the spelling service of Google.">
             Enable
           </message>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 813421d..53f7513 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -972,7 +972,7 @@
           If an image doesn’t have a useful description, Chrome will try to provide one for you. To create descriptions, images are sent to Google.
         </message>
         <message name="IDS_CONTENT_CONTEXT_SPELLING_BUBBLE_TEXT" desc="The text of a bubble that confirms users allows integrating the spelling service of Google to Chrome.">
-          Google Chrome can provide smarter spell-checking by sending what you type in the browser to Google servers, allowing you to use the same spell-checking technology used by Google search.
+          This uses the same spellchecker that's used in Google search. Text you type in the browser is sent to Google. You can always change this behavior in settings.
         </message>
         <if expr="not use_titlecase">
           <message name="IDS_CONTENT_CONTEXT_OPENLINKNEWTAB_INAPP" desc="The name of the command to open a link in a newly created browser tab when the user is in an app window">
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 6dbccd6..18bd480 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -4435,7 +4435,7 @@
     <message name="IDS_SETTINGS_MULTIDEVICE_SETUP_BUTTON" desc="Label of the button that opens a menu to the user that allows them to set up a connection between the user's phone and their Chromebook to give them access to special features.">
       Set up
     </message>
-    <message name="IDS_SETTINGS_MULTIDEVICE_VERIFY_BUTTON" desc="Label for the button to get the Chromebook to verify that it can connect with their phone." translateable="false">
+    <message name="IDS_SETTINGS_MULTIDEVICE_VERIFY_BUTTON" desc="Label for the button to get the Chromebook to verify that it can connect with their phone.">
       Verify
     </message>
     <message name="IDS_SETTINGS_MULTIDEVICE_ENABLED" desc="Text to tell user multidevice features are turned on">
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 7a27050..b44d5f6 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4039,6 +4039,11 @@
     {"enable-portals", flag_descriptions::kEnablePortalsName,
      flag_descriptions::kEnablePortalsDescription, kOsAll,
      FEATURE_VALUE_TYPE(blink::features::kPortals)},
+    {"enable-autofill-credit-card-authentication",
+     flag_descriptions::kEnableAutofillCreditCardAuthenticationName,
+     flag_descriptions::kEnableAutofillCreditCardAuthenticationDescription,
+     kOsAll,
+     FEATURE_VALUE_TYPE(autofill::features::kAutofillCreditCardAuthentication)},
 
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc
index 66af5dc..0c71a4dd 100644
--- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc
+++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/apps/intent_helper/apps_navigation_throttle.h"
 
-#include <algorithm>
 #include <utility>
 
 #include "base/bind.h"
@@ -350,9 +349,11 @@
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
   if (!browser)
     return;
-  const PickerShowState picker_show_state = GetPickerShowState();
+  const PickerShowState picker_show_state =
+      GetPickerShowState(apps, web_contents, url);
   switch (picker_show_state) {
     case PickerShowState::kOmnibox:
+      ui_displayed_ = false;
       browser->window()->SetIntentPickerViewVisibility(true);
       break;
     case PickerShowState::kPopOut:
@@ -365,7 +366,10 @@
 }
 
 AppsNavigationThrottle::PickerShowState
-AppsNavigationThrottle::GetPickerShowState() {
+AppsNavigationThrottle::GetPickerShowState(
+    const std::vector<IntentPickerAppInfo>& apps_for_picker,
+    content::WebContents* web_contents,
+    const GURL& url) {
   return PickerShowState::kOmnibox;
 }
 
@@ -377,26 +381,6 @@
                         ui_auto_display_service, url);
 }
 
-bool AppsNavigationThrottle::ShouldAutoDisplayUi(
-    const std::vector<IntentPickerAppInfo>& apps_for_picker,
-    content::WebContents* web_contents,
-    const GURL& url) {
-  if (apps_for_picker.empty())
-    return false;
-
-  // Check if all the app candidates are PWAs.
-  bool only_pwa_apps =
-      std::all_of(apps_for_picker.begin(), apps_for_picker.end(),
-                  [](const IntentPickerAppInfo& app_info) {
-                    return app_info.type == apps::mojom::AppType::kWeb;
-                  });
-  if (only_pwa_apps)
-    return false;
-
-  DCHECK(ui_auto_display_service_);
-  return ui_auto_display_service_->ShouldAutoDisplayUi(url);
-}
-
 // static
 AppsNavigationThrottle::PickerAction AppsNavigationThrottle::GetPickerAction(
     apps::mojom::AppType app_type,
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.h b/chrome/browser/apps/intent_helper/apps_navigation_throttle.h
index 042ab58..4550246 100644
--- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.h
+++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.h
@@ -177,20 +177,16 @@
       std::vector<IntentPickerAppInfo> apps,
       IntentPickerResponse callback);
 
-  virtual PickerShowState GetPickerShowState();
+  virtual PickerShowState GetPickerShowState(
+      const std::vector<IntentPickerAppInfo>& apps_for_picker,
+      content::WebContents* web_contents,
+      const GURL& url);
 
   virtual IntentPickerResponse GetOnPickerClosedCallback(
       content::WebContents* web_contents,
       IntentPickerAutoDisplayService* ui_auto_display_service,
       const GURL& url);
 
-  // Whether or not the intent picker UI should be displayed without the user
-  // clicking in the omnibox's icon.
-  bool ShouldAutoDisplayUi(
-      const std::vector<IntentPickerAppInfo>& apps_for_picker,
-      content::WebContents* web_contents,
-      const GURL& url);
-
   // Keeps track of whether we already shown the UI or preferred app. Since
   // AppsNavigationThrottle cannot wait for the user (due to the non-blocking
   // nature of the feature) the best we can do is check if we launched a
diff --git a/chrome/browser/autocomplete/autocomplete_browsertest.cc b/chrome/browser/autocomplete/autocomplete_browsertest.cc
index d0e4dd1a..1485d03 100644
--- a/chrome/browser/autocomplete/autocomplete_browsertest.cc
+++ b/chrome/browser/autocomplete/autocomplete_browsertest.cc
@@ -98,7 +98,7 @@
   // TODO(phajdan.jr): check state of IsSelectAll when it's consistent across
   // platforms.
 
-  location_bar->FocusLocation();
+  location_bar->FocusLocation(true);
 
   EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
   EXPECT_EQ(base::UTF8ToUTF16(url::kAboutBlankURL), omnibox_view->GetText());
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index 15ce9af..f752cd58 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -383,10 +383,8 @@
 
   void Refresh() override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-    certificate_provider_service_->GetCertificates(
-        base::AdaptCallbackForRepeating(
-            base::BindOnce(&CertsSourceExtensions::DidGetCerts,
-                           weak_ptr_factory_.GetWeakPtr())));
+    certificate_provider_service_->GetCertificates(base::BindOnce(
+        &CertsSourceExtensions::DidGetCerts, weak_ptr_factory_.GetWeakPtr()));
   }
 
   bool SetCertTrust(CERTCertificate* cert,
diff --git a/chrome/browser/certificate_manager_model_unittest.cc b/chrome/browser/certificate_manager_model_unittest.cc
index 3f26fa5..272a1f7 100644
--- a/chrome/browser/certificate_manager_model_unittest.cc
+++ b/chrome/browser/certificate_manager_model_unittest.cc
@@ -259,12 +259,11 @@
         extensions_hang_(extensions_hang) {}
 
   void GetCertificates(
-      const base::RepeatingCallback<void(net::ClientCertIdentityList)>&
-          callback) override {
+      base::OnceCallback<void(net::ClientCertIdentityList)> callback) override {
     if (*extensions_hang_)
       return;
 
-    callback.Run(FakeClientCertIdentityListFromCertificateList(
+    std::move(callback).Run(FakeClientCertIdentityListFromCertificateList(
         *extension_client_certificates_));
   }
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 4fd55c0..b947523 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2895,8 +2895,9 @@
         auto_selected_identity->certificate();
     net::ClientCertIdentity::SelfOwningAcquirePrivateKey(
         std::move(auto_selected_identity),
-        base::Bind(&content::ClientCertificateDelegate::ContinueWithCertificate,
-                   base::Passed(&delegate), std::move(cert)));
+        base::BindOnce(
+            &content::ClientCertificateDelegate::ContinueWithCertificate,
+            std::move(delegate), std::move(cert)));
     LogClientAuthResult(ClientCertSelectionResult::kAutoSelect);
     return;
   }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 9506b93..ce9768d 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2150,8 +2150,6 @@
     "login/screens/mock_update_screen.h",
     "login/screens/mock_welcome_screen.cc",
     "login/screens/mock_welcome_screen.h",
-    "login/test/help_app_test_helper.cc",
-    "login/test/help_app_test_helper.h",
     "login/test/test_condition_waiter.h",
     "login/test/test_predicate_waiter.cc",
     "login/test/test_predicate_waiter.h",
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc
index 2d6010b0c..4111094 100644
--- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc
+++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/bind.h"
@@ -231,31 +232,22 @@
   std::vector<apps::IntentPickerAppInfo> apps_for_picker =
       FindPwaForUrl(web_contents, url, std::move(apps));
 
-  // If we only have PWAs in the app list, do not show the intent picker.
-  // Instead just show the omnibox icon. This is to reduce annoyance to users
-  // until "Remember my choice" is available for desktop PWAs.
-  // TODO(crbug.com/826982): show the intent picker when the app registry is
-  // available to persist "Remember my choice" for PWAs.
-  if (ShouldAutoDisplayUi(apps_for_picker, web_contents, url)) {
-    ShowIntentPickerForApps(
-        web_contents, ui_auto_display_service_, url, std::move(apps_for_picker),
-        GetOnPickerClosedCallback(web_contents, ui_auto_display_service_, url));
-  } else {
-    ui_displayed_ = false;
-    Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
-    // If there were any candidates, show the intent picker icon in the omnibox
-    // so the user can manually pick if they wish.
-    if (browser && !apps_for_picker.empty())
-      browser->window()->SetIntentPickerViewVisibility(/*visible=*/true);
-  }
+  ShowIntentPickerForApps(
+      web_contents, ui_auto_display_service_, url, std::move(apps_for_picker),
+      GetOnPickerClosedCallback(web_contents, ui_auto_display_service_, url));
 
   // We are about to resume the navigation, which may destroy this object.
   Resume();
 }
 
 apps::AppsNavigationThrottle::PickerShowState
-ChromeOsAppsNavigationThrottle::GetPickerShowState() {
-  return PickerShowState::kPopOut;
+ChromeOsAppsNavigationThrottle::GetPickerShowState(
+    const std::vector<apps::IntentPickerAppInfo>& apps_for_picker,
+    content::WebContents* web_contents,
+    const GURL& url) {
+  return ShouldAutoDisplayUi(apps_for_picker, web_contents, url)
+             ? PickerShowState::kPopOut
+             : PickerShowState::kOmnibox;
 }
 
 IntentPickerResponse ChromeOsAppsNavigationThrottle::GetOnPickerClosedCallback(
@@ -272,4 +264,28 @@
   if (web_contents)
     web_contents->ClosePage();
 }
+
+bool ChromeOsAppsNavigationThrottle::ShouldAutoDisplayUi(
+    const std::vector<apps::IntentPickerAppInfo>& apps_for_picker,
+    content::WebContents* web_contents,
+    const GURL& url) {
+  if (apps_for_picker.empty())
+    return false;
+
+  // If we only have PWAs in the app list, do not show the intent picker.
+  // Instead just show the omnibox icon. This is to reduce annoyance to users
+  // until "Remember my choice" is available for desktop PWAs.
+  // TODO(crbug.com/826982): show the intent picker when the app registry is
+  // available to persist "Remember my choice" for PWAs.
+  bool only_pwa_apps =
+      std::all_of(apps_for_picker.begin(), apps_for_picker.end(),
+                  [](const apps::IntentPickerAppInfo& app_info) {
+                    return app_info.type == apps::mojom::AppType::kWeb;
+                  });
+  if (only_pwa_apps)
+    return false;
+
+  DCHECK(ui_auto_display_service_);
+  return ui_auto_display_service_->ShouldAutoDisplayUi(url);
+}
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h
index 74a9840f..00d51b4d 100644
--- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h
+++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h
@@ -102,7 +102,10 @@
       apps::AppsNavigationAction action,
       std::vector<apps::IntentPickerAppInfo> apps) override;
 
-  PickerShowState GetPickerShowState() override;
+  PickerShowState GetPickerShowState(
+      const std::vector<apps::IntentPickerAppInfo>& apps_for_picker,
+      content::WebContents* web_contents,
+      const GURL& url) override;
 
   IntentPickerResponse GetOnPickerClosedCallback(
       content::WebContents* web_contents,
@@ -111,6 +114,13 @@
 
   void CloseTab();
 
+  // Whether or not the intent picker UI should be displayed without the user
+  // clicking in the omnibox's icon.
+  bool ShouldAutoDisplayUi(
+      const std::vector<apps::IntentPickerAppInfo>& apps_for_picker,
+      content::WebContents* web_contents,
+      const GURL& url);
+
   // True if ARC is enabled, false otherwise.
   const bool arc_enabled_;
 
diff --git a/chrome/browser/chromeos/assistant/assistant_util.cc b/chrome/browser/chromeos/assistant/assistant_util.cc
index 3146049..dda3c07 100644
--- a/chrome/browser/chromeos/assistant/assistant_util.cc
+++ b/chrome/browser/chromeos/assistant/assistant_util.cc
@@ -60,7 +60,9 @@
   // Also accept runtime locale which maybe an approximation of user's pref
   // locale.
   const std::string kRuntimeLocale = icu::Locale::getDefault().getName();
-  if (!pref_locale.empty()) {
+  // Bypass locale check when using fake gaia login. There is no need to enforce
+  // in these test environments.
+  if (!chromeos::switches::IsGaiaServicesDisabled() && !pref_locale.empty()) {
     base::ReplaceChars(pref_locale, "-", "_", &pref_locale);
     bool disallowed = !base::ContainsValue(kAllowedLocales, pref_locale) &&
                       !base::ContainsValue(kAllowedLocales, kRuntimeLocale);
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider.h b/chrome/browser/chromeos/certificate_provider/certificate_provider.h
index 8cb3214..2c8e00d8 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider.h
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider.h
@@ -18,7 +18,7 @@
   virtual ~CertificateProvider() {}
 
   virtual void GetCertificates(
-      const base::Callback<void(net::ClientCertIdentityList)>& callback) = 0;
+      base::OnceCallback<void(net::ClientCertIdentityList)> callback) = 0;
 
   virtual std::unique_ptr<CertificateProvider> Copy() = 0;
 
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc
index 03c2d0f..98d5ecf6 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc
@@ -40,10 +40,10 @@
 
 void PostIdentitiesToTaskRunner(
     const scoped_refptr<base::TaskRunner>& target_task_runner,
-    const base::Callback<void(net::ClientCertIdentityList)>& callback,
+    base::OnceCallback<void(net::ClientCertIdentityList)> callback,
     net::ClientCertIdentityList certs) {
-  target_task_runner->PostTask(FROM_HERE,
-                               base::BindOnce(callback, std::move(certs)));
+  target_task_runner->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(certs)));
 }
 
 }  // namespace
@@ -59,15 +59,15 @@
       const base::WeakPtr<CertificateProviderService>& service);
   ~CertificateProviderImpl() override;
 
-  void GetCertificates(const base::Callback<void(net::ClientCertIdentityList)>&
-                           callback) override;
+  void GetCertificates(
+      base::OnceCallback<void(net::ClientCertIdentityList)> callback) override;
 
   std::unique_ptr<CertificateProvider> Copy() override;
 
  private:
   static void GetCertificatesOnServiceThread(
       const base::WeakPtr<CertificateProviderService>& service,
-      const base::Callback<void(net::ClientCertIdentityList)>& callback);
+      base::OnceCallback<void(net::ClientCertIdentityList)> callback);
 
   const scoped_refptr<base::SequencedTaskRunner> service_task_runner_;
   // Must be dereferenced on |service_task_runner_| only.
@@ -134,7 +134,7 @@
         service_(service) {}
 
   void AcquirePrivateKey(
-      const base::Callback<void(scoped_refptr<net::SSLPrivateKey>)>&
+      base::OnceCallback<void(scoped_refptr<net::SSLPrivateKey>)>
           private_key_callback) override;
 
  private:
@@ -149,19 +149,15 @@
 };
 
 void CertificateProviderService::ClientCertIdentity::AcquirePrivateKey(
-    const base::Callback<void(scoped_refptr<net::SSLPrivateKey>)>&
+    base::OnceCallback<void(scoped_refptr<net::SSLPrivateKey>)>
         private_key_callback) {
   // The caller is responsible for keeping the ClientCertIdentity alive until
   // |private_key_callback| is run, so it's safe to use Unretained here.
-  if (base::PostTaskAndReplyWithResult(
-          service_task_runner_.get(), FROM_HERE,
-          base::Bind(&ClientCertIdentity::AcquirePrivateKeyOnServiceThread,
+  base::PostTaskAndReplyWithResult(
+      service_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&ClientCertIdentity::AcquirePrivateKeyOnServiceThread,
                      base::Unretained(this), base::Unretained(certificate())),
-          private_key_callback)) {
-    return;
-  }
-  // If the task could not be posted, behave as if there was no key.
-  private_key_callback.Run(nullptr);
+      std::move(private_key_callback));
 }
 
 scoped_refptr<net::SSLPrivateKey> CertificateProviderService::
@@ -193,16 +189,16 @@
     ~CertificateProviderImpl() {}
 
 void CertificateProviderService::CertificateProviderImpl::GetCertificates(
-    const base::Callback<void(net::ClientCertIdentityList)>& callback) {
+    base::OnceCallback<void(net::ClientCertIdentityList)> callback) {
   const scoped_refptr<base::TaskRunner> source_task_runner =
       base::ThreadTaskRunnerHandle::Get();
-  const base::Callback<void(net::ClientCertIdentityList)>
-      callback_from_service_thread =
-          base::Bind(&PostIdentitiesToTaskRunner, source_task_runner, callback);
+  base::OnceCallback<void(net::ClientCertIdentityList)>
+      callback_from_service_thread = base::BindOnce(
+          &PostIdentitiesToTaskRunner, source_task_runner, std::move(callback));
 
   service_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&GetCertificatesOnServiceThread, service_,
-                                callback_from_service_thread));
+                                std::move(callback_from_service_thread)));
 }
 
 std::unique_ptr<CertificateProvider>
@@ -215,12 +211,12 @@
 void CertificateProviderService::CertificateProviderImpl::
     GetCertificatesOnServiceThread(
         const base::WeakPtr<CertificateProviderService>& service,
-        const base::Callback<void(net::ClientCertIdentityList)>& callback) {
+        base::OnceCallback<void(net::ClientCertIdentityList)> callback) {
   if (!service) {
-    callback.Run(net::ClientCertIdentityList());
+    std::move(callback).Run(net::ClientCertIdentityList());
     return;
   }
-  service->GetCertificatesFromExtensions(callback);
+  service->GetCertificatesFromExtensions(std::move(callback));
 }
 
 CertificateProviderService::SSLPrivateKey::SSLPrivateKey(
@@ -348,10 +344,10 @@
   }
   if (completed) {
     std::map<std::string, CertificateInfoList> certificates;
-    base::Callback<void(net::ClientCertIdentityList)> callback;
+    base::OnceCallback<void(net::ClientCertIdentityList)> callback;
     certificate_requests_.RemoveRequest(cert_request_id, &certificates,
                                         &callback);
-    UpdateCertificatesAndRun(certificates, callback);
+    UpdateCertificatesAndRun(certificates, std::move(callback));
   }
   return true;
 }
@@ -399,10 +395,10 @@
   for (const int cert_request_id :
        certificate_requests_.DropExtension(extension_id)) {
     std::map<std::string, CertificateInfoList> certificates;
-    base::Callback<void(net::ClientCertIdentityList)> callback;
+    base::OnceCallback<void(net::ClientCertIdentityList)> callback;
     certificate_requests_.RemoveRequest(cert_request_id, &certificates,
                                         &callback);
-    UpdateCertificatesAndRun(certificates, callback);
+    UpdateCertificatesAndRun(certificates, std::move(callback));
   }
 
   certificate_map_.RemoveExtension(extension_id);
@@ -414,7 +410,7 @@
 }
 
 void CertificateProviderService::GetCertificatesFromExtensions(
-    const base::Callback<void(net::ClientCertIdentityList)>& callback) {
+    base::OnceCallback<void(net::ClientCertIdentityList)> callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   const std::vector<std::string> provider_extensions(
@@ -423,14 +419,14 @@
   if (provider_extensions.empty()) {
     DVLOG(2) << "No provider extensions left, clear all certificates.";
     UpdateCertificatesAndRun(std::map<std::string, CertificateInfoList>(),
-                             callback);
+                             std::move(callback));
     return;
   }
 
   const int cert_request_id = certificate_requests_.AddRequest(
-      provider_extensions, callback,
-      base::Bind(&CertificateProviderService::TerminateCertificateRequest,
-                 base::Unretained(this)));
+      provider_extensions, std::move(callback),
+      base::BindOnce(&CertificateProviderService::TerminateCertificateRequest,
+                     base::Unretained(this)));
 
   DVLOG(2) << "Start certificate request " << cert_request_id;
   delegate_->BroadcastCertificateRequest(cert_request_id);
@@ -438,7 +434,7 @@
 
 void CertificateProviderService::UpdateCertificatesAndRun(
     const std::map<std::string, CertificateInfoList>& extension_to_certificates,
-    const base::Callback<void(net::ClientCertIdentityList)>& callback) {
+    base::OnceCallback<void(net::ClientCertIdentityList)> callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // Extensions are removed from the service's state when they're unloaded.
@@ -453,7 +449,7 @@
           weak_factory_.GetWeakPtr()));
   }
 
-  callback.Run(std::move(all_certs));
+  std::move(callback).Run(std::move(all_certs));
 }
 
 void CertificateProviderService::TerminateCertificateRequest(
@@ -461,7 +457,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   std::map<std::string, CertificateInfoList> certificates;
-  base::Callback<void(net::ClientCertIdentityList)> callback;
+  base::OnceCallback<void(net::ClientCertIdentityList)> callback;
   if (!certificate_requests_.RemoveRequest(cert_request_id, &certificates,
                                            &callback)) {
     DLOG(WARNING) << "Request id " << cert_request_id << " unknown.";
@@ -469,7 +465,7 @@
   }
 
   DVLOG(1) << "Time out certificate request " << cert_request_id;
-  UpdateCertificatesAndRun(certificates, callback);
+  UpdateCertificatesAndRun(certificates, std::move(callback));
 }
 
 void CertificateProviderService::RequestSignatureFromExtension(
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h
index 7a94a61..ed5bcf7 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h
@@ -166,7 +166,7 @@
   // |extension_to_certificates_| is updated and |callback| is run with the
   // retrieved list of certificates.
   void GetCertificatesFromExtensions(
-      const base::Callback<void(net::ClientCertIdentityList)>& callback);
+      base::OnceCallback<void(net::ClientCertIdentityList)> callback);
 
   // Copies the given certificates into the internal
   // |extension_to_certificates_|. Any previously stored certificates are
@@ -174,7 +174,7 @@
   void UpdateCertificatesAndRun(
       const std::map<std::string, CertificateInfoList>&
           extension_to_certificates,
-      const base::Callback<void(net::ClientCertIdentityList)>& callback);
+      base::OnceCallback<void(net::ClientCertIdentityList)> callback);
 
   // Terminates the certificate request with id |cert_request_id| by ignoring
   // pending replies from extensions. Certificates that were already reported
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service_unittest.cc b/chrome/browser/chromeos/certificate_provider/certificate_provider_service_unittest.cc
index 0055c874..ac750bc 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service_unittest.cc
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service_unittest.cc
@@ -157,7 +157,7 @@
         TestDelegate::RequestType::GET_CERTIFICATES);
 
     certificate_provider_->GetCertificates(
-        base::Bind(&StoreCertificates, certs));
+        base::BindOnce(&StoreCertificates, certs));
 
     task_runner_->RunUntilIdle();
     EXPECT_EQ(TestDelegate::RequestType::NONE,
@@ -168,7 +168,8 @@
   scoped_refptr<net::SSLPrivateKey> FetchIdentityPrivateKey(
       net::ClientCertIdentity* identity) {
     scoped_refptr<net::SSLPrivateKey> ssl_private_key;
-    identity->AcquirePrivateKey(base::Bind(StorePrivateKey, &ssl_private_key));
+    identity->AcquirePrivateKey(
+        base::BindOnce(StorePrivateKey, &ssl_private_key));
     task_runner_->RunUntilIdle();
     return ssl_private_key;
   }
@@ -267,7 +268,7 @@
   test_delegate_->ClearAndExpectRequest(TestDelegate::RequestType::NONE);
 
   certificate_provider_->GetCertificates(
-      base::Bind(&StoreCertificates, &certs));
+      base::BindOnce(&StoreCertificates, &certs));
 
   task_runner_->RunUntilIdle();
   // As |certs| was not empty before, this ensures that StoreCertificates() was
@@ -475,7 +476,7 @@
   private_key->Sign(
       SSL_SIGN_RSA_PKCS1_SHA256,
       std::vector<uint8_t>(input.begin(), input.end()),
-      base::Bind(&ExpectOKAndStoreSignature, &received_signature));
+      base::BindOnce(&ExpectOKAndStoreSignature, &received_signature));
 
   task_runner_->RunUntilIdle();
 
@@ -512,7 +513,7 @@
   net::Error error = net::OK;
   private_key->Sign(SSL_SIGN_RSA_PKCS1_SHA256,
                     std::vector<uint8_t>(input.begin(), input.end()),
-                    base::Bind(&ExpectEmptySignatureAndStoreError, &error));
+                    base::BindOnce(&ExpectEmptySignatureAndStoreError, &error));
 
   task_runner_->RunUntilIdle();
 
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_requests.cc b/chrome/browser/chromeos/certificate_provider/certificate_requests.cc
index 830e840..56c61e29 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_requests.cc
+++ b/chrome/browser/chromeos/certificate_provider/certificate_requests.cc
@@ -39,7 +39,7 @@
   std::map<std::string, CertificateInfoList> extension_to_certificates;
 
   // The callback that must be run with the final list of certificates.
-  base::Callback<void(net::ClientCertIdentityList)> callback;
+  base::OnceCallback<void(net::ClientCertIdentityList)> callback;
 };
 
 CertificateRequests::CertificateRequests() {}
@@ -48,16 +48,16 @@
 
 int CertificateRequests::AddRequest(
     const std::vector<std::string>& extension_ids,
-    const base::Callback<void(net::ClientCertIdentityList)>& callback,
-    const base::Callback<void(int)>& timeout_callback) {
-  std::unique_ptr<CertificateRequestState> state(new CertificateRequestState);
-  state->callback = callback;
+    base::OnceCallback<void(net::ClientCertIdentityList)> callback,
+    base::OnceCallback<void(int)> timeout_callback) {
+  auto state = std::make_unique<CertificateRequestState>();
+  state->callback = std::move(callback);
   state->pending_extensions.insert(extension_ids.begin(), extension_ids.end());
 
   const int request_id = next_free_request_id_++;
   state->timeout.Start(
       FROM_HERE, base::TimeDelta::FromMinutes(kGetCertificatesTimeoutInMinutes),
-      base::Bind(timeout_callback, request_id));
+      base::BindOnce(std::move(timeout_callback), request_id));
 
   const auto insert_result =
       requests_.insert(std::make_pair(request_id, std::move(state)));
@@ -87,14 +87,14 @@
 bool CertificateRequests::RemoveRequest(
     int request_id,
     std::map<std::string, CertificateInfoList>* certificates,
-    base::Callback<void(net::ClientCertIdentityList)>* callback) {
+    base::OnceCallback<void(net::ClientCertIdentityList)>* callback) {
   const auto it = requests_.find(request_id);
   if (it == requests_.end())
     return false;
 
   CertificateRequestState& state = *it->second;
   *certificates = state.extension_to_certificates;
-  *callback = state.callback;
+  *callback = std::move(state.callback);
   requests_.erase(it);
   DVLOG(2) << "Completed certificate request " << request_id;
   return true;
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_requests.h b/chrome/browser/chromeos/certificate_provider/certificate_requests.h
index 1bf44ed..926e7010 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_requests.h
+++ b/chrome/browser/chromeos/certificate_provider/certificate_requests.h
@@ -27,10 +27,9 @@
   // request and be returned by RemoveRequest(). |timeout_callback| will be
   // called with the request id if this request times out before
   // SetCertificates() was called for all extensions in |extension_ids|.
-  int AddRequest(
-      const std::vector<std::string>& extension_ids,
-      const base::Callback<void(net::ClientCertIdentityList)>& callback,
-      const base::Callback<void(int)>& timeout_callback);
+  int AddRequest(const std::vector<std::string>& extension_ids,
+                 base::OnceCallback<void(net::ClientCertIdentityList)> callback,
+                 base::OnceCallback<void(int)> timeout_callback);
 
   // Returns whether this reply was expected, i.e. the request with |request_id|
   // was waiting for a reply from this extension. If it was expected, the
@@ -47,7 +46,7 @@
   bool RemoveRequest(
       int request_id,
       std::map<std::string, CertificateInfoList>* certificates,
-      base::Callback<void(net::ClientCertIdentityList)>* callback);
+      base::OnceCallback<void(net::ClientCertIdentityList)>* callback);
 
   // Removes this extension from all pending requests and returns the ids of
   // all completed requests.
diff --git a/chrome/browser/chromeos/dbus/dbus_helper.cc b/chrome/browser/chromeos/dbus/dbus_helper.cc
index 01b1ce6..c21988bd 100644
--- a/chrome/browser/chromeos/dbus/dbus_helper.cc
+++ b/chrome/browser/chromeos/dbus/dbus_helper.cc
@@ -10,9 +10,9 @@
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 #include "chromeos/dbus/auth_policy/auth_policy_client.h"
 #include "chromeos/dbus/biod/biod_client.h"
-#include "chromeos/dbus/cras_audio_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/hammerd/hammerd_client.h"
 #include "chromeos/dbus/kerberos/kerberos_client.h"
diff --git a/chrome/browser/chromeos/login/eula_browsertest.cc b/chrome/browser/chromeos/login/eula_browsertest.cc
index 4f4fef1..8092a60 100644
--- a/chrome/browser/chromeos/login/eula_browsertest.cc
+++ b/chrome/browser/chromeos/login/eula_browsertest.cc
@@ -8,29 +8,17 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/callback.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/task/post_task.h"
-#include "base/test/bind_test_util.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/login/test/help_app_test_helper.h"
 #include "chrome/browser/chromeos/login/test/js_checker.h"
 #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
-#include "chrome/browser/chromeos/settings/stats_reporting_controller.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
-#include "chrome/installer/util/google_update_settings.h"
-#include "chromeos/dbus/cryptohome/fake_cryptohome_client.h"
 #include "components/guest_view/browser/guest_view_manager.h"
-#include "components/metrics/metrics_pref_names.h"
-#include "components/prefs/pref_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui.h"
@@ -50,6 +38,7 @@
 
 constexpr char kFakeOnlineEulaPath[] = "/intl/en-US/chrome/eula_text.html";
 constexpr char kFakeOnlineEula[] = "No obligations at all";
+
 #if defined(GOOGLE_CHROME_BUILD)
 // See IDS_ABOUT_TERMS_OF_SERVICE for the complete text.
 constexpr char kOfflineEULAWarning[] = "Chrome OS Terms";
@@ -164,46 +153,6 @@
     return *frame_set.begin();
   }
 
-  // Returns an Oobe JSChecker that sends 'click' events instead of 'tap'
-  // events when interacting with UI elements.
-  test::JSChecker NonPolymerOobeJS() {
-    test::JSChecker js = test::OobeJS();
-    js.set_polymer_ui(false);
-    return js;
-  }
-
-  base::OnceClosure SetCollectStatsConsentClosure(bool consented) {
-    return base::BindOnce(
-        base::IgnoreResult(&GoogleUpdateSettings::SetCollectStatsConsent),
-        consented);
-  }
-
-  // Waits until |blocking_closure| finishes executing.
-  void WaitForBlockingCall(base::OnceClosure blocking_closure) {
-    base::RunLoop runloop;
-    base::PostTaskWithTraitsAndReply(FROM_HERE, {base::MayBlock()},
-                                     std::move(blocking_closure),
-                                     runloop.QuitClosure());
-    runloop.Run();
-  }
-
-  // Waits and returns the result of evaluating |blocking_closure|.
-  bool EvaluateBlocking(base::OnceCallback<bool()> blocking_closure) {
-    bool result = false;
-    base::RunLoop runloop;
-    base::PostTaskWithTraitsAndReplyWithResult(
-        FROM_HERE, {base::MayBlock()}, std::move(blocking_closure),
-        base::BindOnce(
-            [](base::RepeatingClosure quit_closure, bool* result_out,
-               bool evaluation_result) {
-              *result_out = evaluation_result;
-              quit_closure.Run();
-            },
-            runloop.QuitClosure(), &result));
-    runloop.Run();
-    return result;
-  }
-
  private:
   std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
     GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
@@ -262,113 +211,5 @@
               std::string::npos);
 }
 
-// Tests that clicking on "System security settings" button opens a dialog
-// showing the TPM password.
-IN_PROC_BROWSER_TEST_F(EulaTest, DisplaysTpmPassword) {
-  ShowEulaScreen();
-
-  NonPolymerOobeJS().TapOnPath({"oobe-eula-md", "installationSettings"});
-  test::OobeJS().ExpectVisiblePath(
-      {"oobe-eula-md", "installationSettingsDialog"});
-
-  test::OobeJS().CreateWaiter(
-      "$('oobe-eula-md').$$('#eula-password').textContent.trim() !== ''");
-  test::OobeJS().ExpectEQ(
-      "$('oobe-eula-md').$$('#eula-password').textContent.trim()",
-      std::string(FakeCryptohomeClient::kStubTpmPassword));
-}
-
-// Verifies statistic collection accepted flow.
-// Advaces to the next screen and verifies stats collection is enabled.
-IN_PROC_BROWSER_TEST_F(EulaTest, EnableUsageStats) {
-  ShowEulaScreen();
-
-  // Verify that toggle is enabled by default.
-  test::OobeJS().ExpectTrue("$('oobe-eula-md').$$('#usageStats').checked");
-
-  ASSERT_TRUE(StatsReportingController::IsInitialized());
-
-  // Explicitly set as false to make sure test modifies these values.
-  StatsReportingController::Get()->SetEnabled(
-      ProfileManager::GetActiveUserProfile(), false);
-  g_browser_process->local_state()->SetBoolean(
-      metrics::prefs::kMetricsReportingEnabled, false);
-
-  WaitForBlockingCall(SetCollectStatsConsentClosure(false));
-
-  // Start Listening for StatsReportingController updates.
-  base::RunLoop runloop;
-  auto subscription =
-      StatsReportingController::Get()->AddObserver(runloop.QuitClosure());
-
-  // Advance to the next screen for changes to take effect.
-  test::OobeJS().TapOnPath({"oobe-eula-md", "acceptButton"});
-
-  // Wait for StartReporting update.
-  runloop.Run();
-
-  // Verify stats collection is enabled.
-  EXPECT_TRUE(StatsReportingController::Get()->IsEnabled());
-  EXPECT_TRUE(g_browser_process->local_state()->GetBoolean(
-      metrics::prefs::kMetricsReportingEnabled));
-  EXPECT_TRUE(EvaluateBlocking(
-      base::BindOnce(&GoogleUpdateSettings::GetCollectStatsConsent)));
-}
-
-// Verify statistic collection denied flow. Clicks on usage stats toggle,
-// advaces to the next screen and verifies stats collection is disabled.
-IN_PROC_BROWSER_TEST_F(EulaTest, DisableUsageStats) {
-  ShowEulaScreen();
-
-  // Verify that toggle is enabled by default.
-  test::OobeJS().ExpectTrue("$('oobe-eula-md').$$('#usageStats').checked");
-
-  ASSERT_TRUE(StatsReportingController::IsInitialized());
-
-  // Explicitly set as true to make sure test modifies these values.
-  StatsReportingController::Get()->SetEnabled(
-      ProfileManager::GetActiveUserProfile(), true);
-  g_browser_process->local_state()->SetBoolean(
-      metrics::prefs::kMetricsReportingEnabled, true);
-
-  WaitForBlockingCall(SetCollectStatsConsentClosure(true));
-
-  // Start Listening for StatsReportingController updates.
-  base::RunLoop runloop;
-  auto subscription =
-      StatsReportingController::Get()->AddObserver(runloop.QuitClosure());
-
-  // Click on the toggle to disable stats collection and advance to the next
-  // screen for changes to take effect.
-  NonPolymerOobeJS().TapOnPath({"oobe-eula-md", "usageStats"});
-  test::OobeJS().TapOnPath({"oobe-eula-md", "acceptButton"});
-
-  // Wait for StartReportingController update.
-  runloop.Run();
-
-  // Verify stats collection is disabled.
-  EXPECT_FALSE(StatsReportingController::Get()->IsEnabled());
-  EXPECT_FALSE(g_browser_process->local_state()->GetBoolean(
-      metrics::prefs::kMetricsReportingEnabled));
-  EXPECT_FALSE(EvaluateBlocking(
-      base::BindOnce(&GoogleUpdateSettings::GetCollectStatsConsent)));
-}
-
-// Tests that clicking on "Learn more" button opens a help dialog.
-IN_PROC_BROWSER_TEST_F(EulaTest, LearnMore) {
-  ShowEulaScreen();
-
-  // Load HelperApp extension.
-  HelpAppTestHelper scoped_helper;
-
-  // Start listening for help dialog creation.
-  HelpAppTestHelper::Waiter waiter;
-
-  NonPolymerOobeJS().TapOnPath({"oobe-eula-md", "learn-more"});
-
-  // Wait until help dialog is displayed.
-  waiter.Wait();
-}
-
 }  // namespace
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/help_app_launcher.cc b/chrome/browser/chromeos/login/help_app_launcher.cc
index e8dd6863..7ad126e 100644
--- a/chrome/browser/chromeos/login/help_app_launcher.cc
+++ b/chrome/browser/chromeos/login/help_app_launcher.cc
@@ -24,12 +24,8 @@
 
 namespace {
 
-// Official HelpApp extension id.
-const char kExtensionId[] = "honijodknafkokifofgiaalefdiedpko";
-
-const char kHelpAppFormat[] = "chrome-extension://%s/oobe.html?id=%d";
-
-const char* g_extension_id_for_test = nullptr;
+const char kHelpAppFormat[] =
+    "chrome-extension://honijodknafkokifofgiaalefdiedpko/oobe.html?id=%d";
 
 }  // namespace
 
@@ -49,24 +45,13 @@
   if (!registry)
     return;
 
-  const char* extension_id = kExtensionId;
-  if (g_extension_id_for_test && *g_extension_id_for_test != '\0') {
-    extension_id = g_extension_id_for_test;
-  }
-
-  GURL url(base::StringPrintf(kHelpAppFormat, extension_id,
-                              static_cast<int>(help_topic_id)));
+  GURL url(base::StringPrintf(kHelpAppFormat, static_cast<int>(help_topic_id)));
   // HelpApp component extension presents only in official builds so we can
   // show help only when the extensions is installed.
   if (registry->enabled_extensions().GetByID(url.host()))
     ShowHelpTopicDialog(profile, GURL(url));
 }
 
-// static
-void HelpAppLauncher::SetExtensionIdForTest(const char* extension_id) {
-  g_extension_id_for_test = extension_id;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // HelpApp, protected:
 
diff --git a/chrome/browser/chromeos/login/help_app_launcher.h b/chrome/browser/chromeos/login/help_app_launcher.h
index 77309678..1a5b2bd 100644
--- a/chrome/browser/chromeos/login/help_app_launcher.h
+++ b/chrome/browser/chromeos/login/help_app_launcher.h
@@ -47,9 +47,6 @@
   // Shows specified help topic.
   void ShowHelpTopic(HelpTopic help_topic_id);
 
-  // Allows tests to specify a different extension id to connect to.
-  static void SetExtensionIdForTest(const char* extension_id);
-
  protected:
   virtual ~HelpAppLauncher();
 
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_unittest.cc b/chrome/browser/chromeos/login/lock/screen_locker_unittest.cc
index ac2f643a..095c766 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker_unittest.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker_unittest.cc
@@ -22,8 +22,8 @@
 #include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/audio/cras_audio_handler.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 #include "chromeos/dbus/biod/biod_client.h"
-#include "chromeos/dbus/cras_audio_client.h"
 #include "chromeos/dbus/cryptohome/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/login/login_state/login_state.h"
diff --git a/chrome/browser/chromeos/login/screens/base_screen.h b/chrome/browser/chromeos/login/screens/base_screen.h
index d9e2901..76970b82d 100644
--- a/chrome/browser/chromeos/login/screens/base_screen.h
+++ b/chrome/browser/chromeos/login/screens/base_screen.h
@@ -55,12 +55,6 @@
   virtual void OnConfigurationChanged();
 
  private:
-  friend class BaseWebUIHandler;
-  friend class EnrollmentScreenTest;
-  friend class NetworkScreenTest;
-  friend class ScreenManager;
-  friend class UpdateScreenTest;
-
   // Configuration itself is owned by WizardController and is accessible
   // to screen only between OnShow / OnHide calls.
   base::Value* configuration_ = nullptr;
diff --git a/chrome/browser/chromeos/login/screens/eula_screen.cc b/chrome/browser/chromeos/login/screens/eula_screen.cc
index 3e48399..0acc4fd 100644
--- a/chrome/browser/chromeos/login/screens/eula_screen.cc
+++ b/chrome/browser/chromeos/login/screens/eula_screen.cc
@@ -44,6 +44,24 @@
     view_->Unbind();
 }
 
+GURL EulaScreen::GetOemEulaUrl() const {
+  const StartupCustomizationDocument* customization =
+      StartupCustomizationDocument::GetInstance();
+  if (customization->IsReady()) {
+    // Previously we're using "initial locale" that device initially
+    // booted with out-of-box. http://crbug.com/145142
+    std::string locale = g_browser_process->GetApplicationLocale();
+    std::string eula_page = customization->GetEULAPage(locale);
+    if (!eula_page.empty())
+      return GURL(eula_page);
+
+    VLOG(1) << "No eula found for locale: " << locale;
+  } else {
+    LOG(ERROR) << "No manifest found.";
+  }
+  return GURL();
+}
+
 void EulaScreen::InitiatePasswordFetch() {
   if (tpm_password_.empty()) {
     password_fetcher_.Fetch();
diff --git a/chrome/browser/chromeos/login/test/help_app_test_helper.cc b/chrome/browser/chromeos/login/test/help_app_test_helper.cc
deleted file mode 100644
index e095e0e3..0000000
--- a/chrome/browser/chromeos/login/test/help_app_test_helper.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/login/test/help_app_test_helper.h"
-
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "chrome/browser/chromeos/extensions/signin_screen_policy_provider.h"
-#include "chrome/browser/chromeos/login/help_app_launcher.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/extensions/chrome_test_extension_loader.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/grit/generated_resources.h"
-#include "ui/aura/env.h"
-#include "ui/aura/window.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace chromeos {
-
-///////////////////////////////////////////////////////////////////////////////
-// HelpAppTestHelper::Waiter
-///////////////////////////////////////////////////////////////////////////////
-
-HelpAppTestHelper::Waiter::Waiter() {
-  aura::Env::GetInstance()->AddObserver(this);
-}
-
-HelpAppTestHelper::Waiter::~Waiter() {
-  aura::Env::GetInstance()->RemoveObserver(this);
-}
-
-void HelpAppTestHelper::Waiter::Wait() {
-  if (!dialog_visible_)
-    run_loop_.Run();
-}
-
-void HelpAppTestHelper::Waiter::OnWindowInitialized(aura::Window* window) {
-  window_observer_.Add(window);
-}
-
-void HelpAppTestHelper::Waiter::OnWindowVisibilityChanged(aura::Window* window,
-                                                          bool visible) {
-  if (IsHelpAppDialog(window) && visible && !dialog_visible_) {
-    dialog_visible_ = true;
-    run_loop_.QuitClosure().Run();
-  }
-}
-
-bool HelpAppTestHelper::Waiter::IsHelpAppDialog(aura::Window* window) {
-  return window->GetTitle() ==
-         l10n_util::GetStringUTF16(IDS_LOGIN_OOBE_HELP_DIALOG_TITLE);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// HelpAppTestHelper
-///////////////////////////////////////////////////////////////////////////////
-
-HelpAppTestHelper::HelpAppTestHelper() {
-  auto reset = GetScopedSigninScreenPolicyProviderDisablerForTesting();
-
-  base::FilePath test_data_dir;
-  base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
-  extensions::ChromeTestExtensionLoader loader(
-      ProfileHelper::GetSigninProfile());
-  loader.set_allow_incognito_access(true);
-
-  scoped_refptr<const extensions::Extension> extension =
-      loader.LoadExtension(test_data_dir.AppendASCII("extensions")
-                               .AppendASCII("api_test")
-                               .AppendASCII("help_app"));
-
-  DCHECK(extension && !extension->id().empty());
-
-  HelpAppLauncher::SetExtensionIdForTest(extension->id().c_str());
-}
-
-HelpAppTestHelper::~HelpAppTestHelper() {
-  HelpAppLauncher::SetExtensionIdForTest(nullptr);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/help_app_test_helper.h b/chrome/browser/chromeos/login/test/help_app_test_helper.h
deleted file mode 100644
index e752448..0000000
--- a/chrome/browser/chromeos/login/test/help_app_test_helper.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_TEST_HELP_APP_TEST_HELPER_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_TEST_HELP_APP_TEST_HELPER_H_
-
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/scoped_observer.h"
-#include "ui/aura/env_observer.h"
-#include "ui/aura/window_observer.h"
-
-namespace chromeos {
-
-// Provides utilies for launching and interacting with HelpApp dialogs in tests.
-class HelpAppTestHelper {
- public:
-  // Waits for a HelpApp dialog to open and become visible.
-  class Waiter : public aura::EnvObserver, public aura::WindowObserver {
-   public:
-    Waiter();
-    ~Waiter() override;
-
-    // Blocks until a HelpApp dialog becomes visible.
-    void Wait();
-
-    // aura::EnvObserver
-    void OnWindowInitialized(aura::Window* window) override;
-
-    // aura::WindowObserver
-    void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
-
-   private:
-    bool IsHelpAppDialog(aura::Window* window);
-
-    base::RunLoop run_loop_;
-    bool dialog_visible_ = false;
-    ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this};
-    DISALLOW_COPY_AND_ASSIGN(Waiter);
-  };
-
-  HelpAppTestHelper();
-  virtual ~HelpAppTestHelper();
-
-  // Performs setup to allow HelpApp dialogs to open in tests.
-  void SetUpHelpAppForTest();
-
-  // TODO(tonydeluna): Add utilities for interacting with the contents of the
-  // help dialogs.
-
-  DISALLOW_COPY_AND_ASSIGN(HelpAppTestHelper);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_TEST_HELP_APP_TEST_HELPER_H_
diff --git a/chrome/browser/chromeos/login/test/js_checker.cc b/chrome/browser/chromeos/login/test/js_checker.cc
index b4f8a5c..de4b3763 100644
--- a/chrome/browser/chromeos/login/test/js_checker.cc
+++ b/chrome/browser/chromeos/login/test/js_checker.cc
@@ -237,11 +237,11 @@
 void JSChecker::TapOnPath(
     std::initializer_list<base::StringPiece> element_ids) {
   ExpectVisiblePath(element_ids);
-  // TODO(crbug.com/949377): Switch to always firing 'click' events when
-  // missing OOBE UI components are migrated to handle 'click' events.
+  // All OOBE UI should be mobile-friendly, so use "tap" instead of "click".
   if (polymer_ui_) {
     Evaluate(GetOobeElementPath(element_ids) + ".fire('tap')");
   } else {
+    // Old test-only UI (fake GAIA, fake SAML) only support "click".
     Evaluate(GetOobeElementPath(element_ids) + ".click()");
   }
 }
diff --git a/chrome/browser/chromeos/net/client_cert_store_chromeos.cc b/chrome/browser/chromeos/net/client_cert_store_chromeos.cc
index 025434e..18d0265 100644
--- a/chrome/browser/chromeos/net/client_cert_store_chromeos.cc
+++ b/chrome/browser/chromeos/net/client_cert_store_chromeos.cc
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/location.h"
 #include "base/task/post_task.h"
 #include "base/threading/scoped_blocking_call.h"
@@ -33,32 +34,35 @@
 
 void ClientCertStoreChromeOS::GetClientCerts(
     const net::SSLCertRequestInfo& cert_request_info,
-    const ClientCertListCallback& callback) {
+    ClientCertListCallback callback) {
   // Caller is responsible for keeping the ClientCertStore alive until the
   // callback is run.
-  base::Callback<void(net::ClientCertIdentityList)>
-      get_platform_certs_and_filter = base::Bind(
+  base::OnceCallback<void(net::ClientCertIdentityList)>
+      get_platform_certs_and_filter = base::BindOnce(
           &ClientCertStoreChromeOS::GotAdditionalCerts, base::Unretained(this),
-          base::Unretained(&cert_request_info), callback);
+          base::Unretained(&cert_request_info), std::move(callback));
 
-  base::Closure get_additional_certs_and_continue;
+  base::OnceClosure get_additional_certs_and_continue;
   if (cert_provider_) {
-    get_additional_certs_and_continue = base::Bind(
-        &CertificateProvider::GetCertificates,
-        base::Unretained(cert_provider_.get()), get_platform_certs_and_filter);
+    get_additional_certs_and_continue =
+        base::BindOnce(&CertificateProvider::GetCertificates,
+                       base::Unretained(cert_provider_.get()),
+                       std::move(get_platform_certs_and_filter));
   } else {
     get_additional_certs_and_continue =
-        base::Bind(get_platform_certs_and_filter,
-                   base::Passed(net::ClientCertIdentityList()));
+        base::BindOnce(std::move(get_platform_certs_and_filter),
+                       net::ClientCertIdentityList());
   }
 
-  if (cert_filter_->Init(get_additional_certs_and_continue))
-    get_additional_certs_and_continue.Run();
+  auto repeating_callback = base::AdaptCallbackForRepeating(
+      std::move(get_additional_certs_and_continue));
+  if (cert_filter_->Init(repeating_callback))
+    repeating_callback.Run();
 }
 
 void ClientCertStoreChromeOS::GotAdditionalCerts(
     const net::SSLCertRequestInfo* request,
-    const ClientCertListCallback& callback,
+    ClientCertListCallback callback,
     net::ClientCertIdentityList additional_certs) {
   scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate;
   if (!password_delegate_factory_.is_null())
@@ -66,10 +70,10 @@
   base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE,
       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::Bind(&ClientCertStoreChromeOS::GetAndFilterCertsOnWorkerThread,
-                 base::Unretained(this), password_delegate,
-                 base::Unretained(request), base::Passed(&additional_certs)),
-      callback);
+      base::BindOnce(&ClientCertStoreChromeOS::GetAndFilterCertsOnWorkerThread,
+                     base::Unretained(this), password_delegate,
+                     base::Unretained(request), std::move(additional_certs)),
+      std::move(callback));
 }
 
 net::ClientCertIdentityList
diff --git a/chrome/browser/chromeos/net/client_cert_store_chromeos.h b/chrome/browser/chromeos/net/client_cert_store_chromeos.h
index f857469..9a5dfdd 100644
--- a/chrome/browser/chromeos/net/client_cert_store_chromeos.h
+++ b/chrome/browser/chromeos/net/client_cert_store_chromeos.h
@@ -49,11 +49,11 @@
 
   // net::ClientCertStore:
   void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
-                      const ClientCertListCallback& callback) override;
+                      ClientCertListCallback callback) override;
 
  private:
   void GotAdditionalCerts(const net::SSLCertRequestInfo* request,
-                          const ClientCertListCallback& callback,
+                          ClientCertListCallback callback,
                           net::ClientCertIdentityList additional_certs);
 
   net::ClientCertIdentityList GetAndFilterCertsOnWorkerThread(
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
index 2e85258a..75ad099b 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
@@ -605,7 +605,7 @@
   SelectCertificatesState* state_ptr = state.get();
   state_ptr->cert_store_->GetClientCerts(
       *state_ptr->cert_request_info_,
-      base::Bind(&DidSelectCertificatesOnIOThread, base::Passed(&state)));
+      base::BindOnce(&DidSelectCertificatesOnIOThread, std::move(state)));
 }
 
 // Filters the obtained certificates on a worker thread. Used by
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.cc b/chrome/browser/chromeos/printing/cups_printers_manager.cc
index 294e52f..9bd5d3d 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.cc
@@ -33,43 +33,6 @@
 namespace chromeos {
 namespace {
 
-class CupsPrintersManagerImpl;
-
-// Since CupsPrintersManager listens to multiple PrinterDetectors, we need to
-// disambiguate incoming observer calls based on their source, and so can't
-// implement PrinterDetector::Observer directly in CupsPrintersManagerImpl.
-//
-// Note that at the time the Proxy is constructed, CupsPrintersManagerImpl's
-// construction may not be complete, so any callbacks into the parent need
-// to be deferred.
-class PrinterDetectorObserverProxy : public PrinterDetector::Observer {
- public:
-  PrinterDetectorObserverProxy(CupsPrintersManagerImpl* parent,
-                               int id,
-                               PrinterDetector* detector)
-      : parent_(parent), id_(id), observer_(this) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
-    // It's ok to Add() before construction is complete because callbacks are on
-    // the same sequence, therefore we will complete construction before any
-    // detection callback will be processed.
-    observer_.Add(detector);
-  }
-  ~PrinterDetectorObserverProxy() override {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
-  }
-
-  // Defined out of line because we need the CupsPrintersManagerImpl
-  // definition first.
-  void OnPrintersFound(
-      const std::vector<PrinterDetector::DetectedPrinter>& printers) override;
-
- private:
-  CupsPrintersManagerImpl* const parent_;
-  const int id_;
-  SEQUENCE_CHECKER(sequence_);
-  ScopedObserver<PrinterDetector, PrinterDetector::Observer> observer_;
-};
-
 // This is akin to python's filter() builtin, but with reverse polarity on the
 // test function -- *remove* all entries in printers for which test_fn returns
 // true, discard the rest.
@@ -118,14 +81,14 @@
 
     // Callbacks may ensue immediately when the observer proxies are set up, so
     // these instantiations must come after everything else is initialized.
-    usb_detector_observer_proxy_ =
-        std::make_unique<PrinterDetectorObserverProxy>(this, kUsbDetector,
-                                                       usb_detector_.get());
+    usb_detector_->RegisterPrintersFoundCallback(
+        base::BindRepeating(&CupsPrintersManagerImpl::OnPrintersFound,
+                            weak_ptr_factory_.GetWeakPtr(), kUsbDetector));
     OnPrintersFound(kUsbDetector, usb_detector_->GetPrinters());
 
-    zeroconf_detector_observer_proxy_ =
-        std::make_unique<PrinterDetectorObserverProxy>(
-            this, kZeroconfDetector, zeroconf_detector_.get());
+    zeroconf_detector_->RegisterPrintersFoundCallback(
+        base::BindRepeating(&CupsPrintersManagerImpl::OnPrintersFound,
+                            weak_ptr_factory_.GetWeakPtr(), kZeroconfDetector));
     OnPrintersFound(kZeroconfDetector, zeroconf_detector_->GetPrinters());
 
     native_printers_allowed_.Init(prefs::kUserNativePrintersAllowed,
@@ -274,8 +237,7 @@
     NotifyObservers({kEnterprise});
   }
 
-  // Callback entry point for PrinterDetectorObserverProxys owned by this
-  // object.
+  // Callback for PrinterDetectors.
   void OnPrintersFound(
       int detector_id,
       const std::vector<PrinterDetector::DetectedPrinter>& printers) {
@@ -513,11 +475,8 @@
       synced_printers_manager_observer_;
 
   std::unique_ptr<PrinterDetector> usb_detector_;
-  std::unique_ptr<PrinterDetectorObserverProxy> usb_detector_observer_proxy_;
 
   std::unique_ptr<PrinterDetector> zeroconf_detector_;
-  std::unique_ptr<PrinterDetectorObserverProxy>
-      zeroconf_detector_observer_proxy_;
 
   scoped_refptr<PpdProvider> ppd_provider_;
 
@@ -562,12 +521,6 @@
   base::WeakPtrFactory<CupsPrintersManagerImpl> weak_ptr_factory_;
 };
 
-void PrinterDetectorObserverProxy::OnPrintersFound(
-    const std::vector<PrinterDetector::DetectedPrinter>& printers) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
-  parent_->OnPrintersFound(id_, printers);
-}
-
 }  // namespace
 
 // static
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
index 7f4b1f5f..04ce83d 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
@@ -164,11 +164,8 @@
   FakePrinterDetector() {}
   ~FakePrinterDetector() override = default;
 
-  void AddObserver(Observer* observer) override {
-    observers_.AddObserver(observer);
-  }
-  void RemoveObserver(Observer* observer) override {
-    observers_.RemoveObserver(observer);
+  void RegisterPrintersFoundCallback(OnPrintersFoundCallback cb) override {
+    on_printers_found_callback_ = std::move(cb);
   }
 
   std::vector<DetectedPrinter> GetPrinters() override { return detections_; }
@@ -177,9 +174,7 @@
       const std::vector<PrinterDetector::DetectedPrinter>& new_detections) {
     detections_.insert(detections_.end(), new_detections.begin(),
                        new_detections.end());
-    for (Observer& observer : observers_) {
-      observer.OnPrintersFound(detections_);
-    }
+    on_printers_found_callback_.Run(detections_);
   }
 
   // Remove printers that have ids in ids.
@@ -195,7 +190,7 @@
 
  private:
   std::vector<DetectedPrinter> detections_;
-  base::ObserverList<PrinterDetector::Observer>::Unchecked observers_;
+  OnPrintersFoundCallback on_printers_found_callback_;
 };
 
 // Fake PpdProvider backend.  This fake generates PpdReferences based on
diff --git a/chrome/browser/chromeos/printing/printer_detector.h b/chrome/browser/chromeos/printing/printer_detector.h
index da8c231..a31853e 100644
--- a/chrome/browser/chromeos/printing/printer_detector.h
+++ b/chrome/browser/chromeos/printing/printer_detector.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/callback.h"
 #include "chromeos/printing/ppd_provider.h"
 #include "chromeos/printing/printer_configuration.h"
 
@@ -23,7 +24,7 @@
 // an up-to-date list of the printers detected is this:
 //
 // auto detector_ = PrinterDetectorImplementation::Create();
-// detector_->AddObserver(this);
+// detector_->RegisterPrintersFoundCallback(cb);
 // printers_ = detector_->GetPrinters();
 //
 class CHROMEOS_EXPORT PrinterDetector {
@@ -37,28 +38,12 @@
     PrinterSearchData ppd_search_data;
   };
 
-  class Observer {
-   public:
-    virtual ~Observer() = default;
-
-    // Called with a collection of printers as they are discovered.  On each
-    // call |printers| is the full set of known printers; it is not
-    // incremental; printers may be added or removed.
-    //
-    // To avoid race conditions of printer state changes, you should register
-    // your Observer and call PrinterDetector::GetPrinters() to populate the
-    // initial state in the same sequenced atom.
-    virtual void OnPrintersFound(
-        const std::vector<DetectedPrinter>& printers) = 0;
-  };
+  using OnPrintersFoundCallback = base::RepeatingCallback<void(
+      const std::vector<DetectedPrinter>& printers)>;
 
   virtual ~PrinterDetector() = default;
 
-  // Observer management.  Observer callbacks will be performed on the calling
-  // sequence, but observers do not need to be on the same sequence as each
-  // other or the detector.
-  virtual void AddObserver(Observer* observer) = 0;
-  virtual void RemoveObserver(Observer* observer) = 0;
+  virtual void RegisterPrintersFoundCallback(OnPrintersFoundCallback cb) = 0;
 
   // Get the current list of known printers.
   virtual std::vector<DetectedPrinter> GetPrinters() = 0;
diff --git a/chrome/browser/chromeos/printing/usb_printer_detector.cc b/chrome/browser/chromeos/printing/usb_printer_detector.cc
index d6142ae..dcbe4e01 100644
--- a/chrome/browser/chromeos/printing/usb_printer_detector.cc
+++ b/chrome/browser/chromeos/printing/usb_printer_detector.cc
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/observer_list_threadsafe.h"
 #include "base/scoped_observer.h"
+#include "base/sequence_checker.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/sequenced_task_runner_handle.h"
@@ -56,8 +57,6 @@
  public:
   explicit UsbPrinterDetectorImpl(device::UsbService* usb_service)
       : usb_observer_(this),
-        observer_list_(
-            new base::ObserverListThreadSafe<UsbPrinterDetector::Observer>),
         weak_ptr_factory_(this) {
     if (usb_service) {
       usb_observer_.Add(usb_service);
@@ -65,20 +64,20 @@
                                          weak_ptr_factory_.GetWeakPtr()));
     }
   }
-  ~UsbPrinterDetectorImpl() override = default;
-
-  // PrinterDetector interface function.
-  void AddObserver(UsbPrinterDetector::Observer* observer) override {
-    observer_list_->AddObserver(observer);
+  ~UsbPrinterDetectorImpl() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
   }
 
-  // PrinterDetector interface function.
-  void RemoveObserver(UsbPrinterDetector::Observer* observer) override {
-    observer_list_->RemoveObserver(observer);
+  // PrinterDetector override.
+  void RegisterPrintersFoundCallback(OnPrintersFoundCallback cb) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
+    DCHECK(!on_printers_found_callback_);
+    on_printers_found_callback_ = std::move(cb);
   }
 
-  // PrinterDetector interface function.
+  // PrinterDetector override.
   std::vector<DetectedPrinter> GetPrinters() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
     base::AutoLock auto_lock(printers_lock_);
     return GetPrintersLocked();
   }
@@ -126,9 +125,9 @@
 
     base::AutoLock auto_lock(printers_lock_);
     printers_[device->guid()] = entry;
-    observer_list_->Notify(FROM_HERE,
-                           &PrinterDetector::Observer::OnPrintersFound,
-                           GetPrintersLocked());
+    if (on_printers_found_callback_) {
+      on_printers_found_callback_.Run(GetPrintersLocked());
+    }
   }
 
   // UsbService::observer override.
@@ -139,21 +138,23 @@
     }
     base::AutoLock auto_lock(printers_lock_);
     printers_.erase(device->guid());
-    observer_list_->Notify(FROM_HERE,
-                           &PrinterDetector::Observer::OnPrintersFound,
-                           GetPrintersLocked());
+    if (on_printers_found_callback_) {
+      on_printers_found_callback_.Run(GetPrintersLocked());
+    }
   }
 
+  SEQUENCE_CHECKER(sequence_);
+
   // Map from USB GUID to DetectedPrinter for all detected printers, and
   // associated lock, since we don't require all access to be from the same
   // sequence.
   std::map<std::string, DetectedPrinter> printers_;
   base::Lock printers_lock_;
 
+  OnPrintersFoundCallback on_printers_found_callback_;
+
   ScopedObserver<device::UsbService, device::UsbService::Observer>
       usb_observer_;
-  scoped_refptr<base::ObserverListThreadSafe<UsbPrinterDetector::Observer>>
-      observer_list_;
   base::WeakPtrFactory<UsbPrinterDetectorImpl> weak_ptr_factory_;
 };
 
diff --git a/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc b/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc
index 2246539..efb2322 100644
--- a/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc
+++ b/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/hash/md5.h"
-#include "base/observer_list_threadsafe.h"
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -210,8 +209,7 @@
  public:
   // Normal constructor, connects to service discovery.
   ZeroconfPrinterDetectorImpl()
-      : discovery_client_(ServiceDiscoverySharedClient::GetInstance()),
-        observer_list_(new base::ObserverListThreadSafe<Observer>()) {
+      : discovery_client_(ServiceDiscoverySharedClient::GetInstance()) {
     CreateDeviceLister(kIppServiceName);
     CreateDeviceLister(kIppsServiceName);
     CreateDeviceLister(kIppEverywhereServiceName);
@@ -221,8 +219,7 @@
   // Testing constructor, uses injected backends.
   explicit ZeroconfPrinterDetectorImpl(
       std::map<std::string, std::unique_ptr<ServiceDiscoveryDeviceLister>>*
-          device_listers)
-      : observer_list_(new base::ObserverListThreadSafe<Observer>()) {
+          device_listers) {
     device_listers_.swap(*device_listers);
     for (auto& entry : device_listers_) {
       entry.second->Start();
@@ -232,19 +229,20 @@
 
   ~ZeroconfPrinterDetectorImpl() override {}
 
+  // PrinterDetector override.
+  void RegisterPrintersFoundCallback(OnPrintersFoundCallback cb) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
+    DCHECK(!on_printers_found_callback_);
+    on_printers_found_callback_ = std::move(cb);
+  }
+
+  // PrinterDetector override.
   std::vector<DetectedPrinter> GetPrinters() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
     base::AutoLock auto_lock(printers_lock_);
     return GetPrintersLocked();
   }
 
-  void AddObserver(Observer* observer) override {
-    observer_list_->AddObserver(observer);
-  }
-
-  void RemoveObserver(Observer* observer) override {
-    observer_list_->RemoveObserver(observer);
-  }
-
   // ServiceDiscoveryDeviceLister::Delegate implementation
   void OnDeviceChanged(const std::string& service_type,
                        bool added,
@@ -258,9 +256,9 @@
     }
     base::AutoLock auto_lock(printers_lock_);
     printers_[service_type][service_description.instance_name()] = printer;
-    observer_list_->Notify(FROM_HERE,
-                           &PrinterDetector::Observer::OnPrintersFound,
-                           GetPrintersLocked());
+    if (on_printers_found_callback_) {
+      on_printers_found_callback_.Run(GetPrintersLocked());
+    }
   }
 
   // ServiceDiscoveryDeviceLister::Delegate implementation.  Remove the
@@ -275,9 +273,9 @@
     auto it = service_type_map.find(service_description.instance_name());
     if (it != service_type_map.end()) {
       service_type_map.erase(it);
-      observer_list_->Notify(FROM_HERE,
-                             &PrinterDetector::Observer::OnPrintersFound,
-                             GetPrintersLocked());
+      if (on_printers_found_callback_) {
+        on_printers_found_callback_.Run(GetPrintersLocked());
+      }
     } else {
       LOG(WARNING) << "Device removal requested for unknown '" << service_name
                    << "'";
@@ -290,9 +288,9 @@
     base::AutoLock auto_lock(printers_lock_);
     if (!printers_[service_type].empty()) {
       printers_[service_type].clear();
-      observer_list_->Notify(FROM_HERE,
-                             &PrinterDetector::Observer::OnPrintersFound,
-                             GetPrintersLocked());
+      if (on_printers_found_callback_) {
+        on_printers_found_callback_.Run(GetPrintersLocked());
+      }
     }
 
     // Request a new round of discovery from the lister.
@@ -337,6 +335,8 @@
     return ret;
   }
 
+  SEQUENCE_CHECKER(sequence_);
+
   // Map from service type to map from instance name to associated known
   // printer, and associated lock.
   std::map<std::string, std::map<std::string, DetectedPrinter>> printers_;
@@ -349,8 +349,7 @@
   std::map<std::string, std::unique_ptr<ServiceDiscoveryDeviceLister>>
       device_listers_;
 
-  // Observers of this object.
-  scoped_refptr<base::ObserverListThreadSafe<Observer>> observer_list_;
+  OnPrintersFoundCallback on_printers_found_callback_;
 };
 
 }  // namespace
diff --git a/chrome/browser/chromeos/printing/zeroconf_printer_detector_unittest.cc b/chrome/browser/chromeos/printing/zeroconf_printer_detector_unittest.cc
index de84ca9..fc1b06d7 100644
--- a/chrome/browser/chromeos/printing/zeroconf_printer_detector_unittest.cc
+++ b/chrome/browser/chromeos/printing/zeroconf_printer_detector_unittest.cc
@@ -285,8 +285,7 @@
   DeferringDelegate deferring_delegate_;
 };
 
-class ZeroconfPrinterDetectorTest : public testing::Test,
-                                    public PrinterDetector::Observer {
+class ZeroconfPrinterDetectorTest : public testing::Test {
  public:
   ZeroconfPrinterDetectorTest() {
     auto* runner = scoped_task_environment_.GetMainThreadTaskRunner().get();
@@ -321,7 +320,8 @@
     // keep the lister fakes accessible after ownership is transferred into the
     // detector.
     listers_.clear();
-    detector_->AddObserver(this);
+    detector_->RegisterPrintersFoundCallback(base::BindRepeating(
+        &ZeroconfPrinterDetectorTest::OnPrintersFound, base::Unretained(this)));
     ipp_lister_->SetDelegate(detector_.get());
     ipps_lister_->SetDelegate(detector_.get());
     ippe_lister_->SetDelegate(detector_.get());
@@ -386,9 +386,9 @@
               actual.ppd_search_data.make_and_model);
   }
 
-  // PrinterDetector::Observer callback.
+  // PrinterDetector callback.
   void OnPrintersFound(
-      const std::vector<PrinterDetector::DetectedPrinter>& printers) override {
+      const std::vector<PrinterDetector::DetectedPrinter>& printers) {
     printers_found_callbacks_.push_back(printers);
   }
 
diff --git a/chrome/browser/download/notification/download_item_notification.cc b/chrome/browser/download/notification/download_item_notification.cc
index 46f0d65..13c4a400 100644
--- a/chrome/browser/download/notification/download_item_notification.cc
+++ b/chrome/browser/download/notification/download_item_notification.cc
@@ -274,6 +274,9 @@
 void DownloadItemNotification::Click(
     const base::Optional<int>& button_index,
     const base::Optional<base::string16>& reply) {
+  if (!item_)
+    return;
+
   if (button_index) {
     if (*button_index < 0 ||
         static_cast<size_t>(*button_index) >= button_actions_->size()) {
@@ -355,6 +358,9 @@
 }
 
 void DownloadItemNotification::Update() {
+  if (!item_)
+    return;
+
   auto download_state = item_->GetState();
 
   // When the download is just completed, interrupted or transitions to
diff --git a/chrome/browser/extensions/chrome_url_request_util.cc b/chrome/browser/extensions/chrome_url_request_util.cc
index 51e835b..7e6616ea 100644
--- a/chrome/browser/extensions/chrome_url_request_util.cc
+++ b/chrome/browser/extensions/chrome_url_request_util.cc
@@ -149,13 +149,14 @@
                       std::string* read_mime_type,
                       net::CompletionOnceCallback callback,
                       bool read_result) {
-    response_info_.headers->AddHeader(
-        base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType,
-                           read_mime_type->c_str()));
+    if (read_result) {
+      response_info_.headers->AddHeader(
+          base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType,
+                             read_mime_type->c_str()));
+    }
     *out_mime_type = *read_mime_type;
     DetermineCharset(*read_mime_type, data.get(), charset);
-    int result = read_result ? net::OK : net::ERR_INVALID_URL;
-    std::move(callback).Run(result);
+    std::move(callback).Run(net::OK);
   }
 
   // We need the filename of the resource to determine the mime type.
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index 708c8f0b5..9be2b5d4 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -791,7 +791,9 @@
     const char* file_name;
     const char* expected_mime_type;
   } test_cases[] = {
-      {"json_file.json", "application/json"}, {"js_file.js", "text/javascript"},
+      {"json_file.json", "application/json"},
+      {"js_file.js", "text/javascript"},
+      {"mem_file.mem", ""},
   };
 
   for (const auto& test_case : test_cases) {
diff --git a/chrome/browser/extensions/global_shortcut_listener_win.cc b/chrome/browser/extensions/global_shortcut_listener_win.cc
index f5d0ac4..c5125495 100644
--- a/chrome/browser/extensions/global_shortcut_listener_win.cc
+++ b/chrome/browser/extensions/global_shortcut_listener_win.cc
@@ -72,25 +72,19 @@
     const ui::Accelerator& accelerator) {
   DCHECK(hotkeys_.find(accelerator) == hotkeys_.end());
 
-  // If we want to listen for media keys, we should do that through the
-  // MediaKeysListenerManager, which will tell the manager to send us media keys
-  // and prevent the HardwareKeyMediaController from receiving the keys.
+  // TODO(https://crbug.com/950704): We should be using
+  // |media_keys_listener_manager->StartWatchingMediaKey(...)| here, but that
+  // currently breaks the GlobalCommandsApiTest.GlobalDuplicatedMediaKey test.
+  // Instead, we'll just disable the MediaKeysListenerManager handling here, and
+  // listen using the fallback RegisterHotKey method.
   if (content::MediaKeysListenerManager::IsMediaKeysListenerManagerEnabled() &&
       Command::IsMediaKey(accelerator)) {
     content::MediaKeysListenerManager* media_keys_listener_manager =
         content::MediaKeysListenerManager::GetInstance();
     DCHECK(media_keys_listener_manager);
 
-    bool success = media_keys_listener_manager->StartWatchingMediaKey(
-        accelerator.key_code(), this);
-
-    // Map the hot key to nullptr, since we don't need a
-    // SingletonHwndHotKeyObserver when the MediaKeysListenerManager is taking
-    // care of it.
-    if (success)
-      hotkeys_[accelerator] = nullptr;
-
-    return success;
+    registered_media_keys_++;
+    media_keys_listener_manager->DisableInternalMediaKeyHandling();
   }
 
   // Convert Accelerator modifiers to OS modifiers.
@@ -120,16 +114,19 @@
   HotKeyMap::iterator it = hotkeys_.find(accelerator);
   DCHECK(it != hotkeys_.end());
 
-  // If we're routing media keys through the MediaKeysListenerManager, then
-  // inform the manager that we're no longer listening to the given key.
+  // TODO(https://crbug.com/950704): We should be using
+  // |media_keys_listener_manager->StopWatchingMediaKey(...)| here.
   if (content::MediaKeysListenerManager::IsMediaKeysListenerManagerEnabled() &&
       Command::IsMediaKey(accelerator)) {
-    content::MediaKeysListenerManager* media_keys_listener_manager =
-        content::MediaKeysListenerManager::GetInstance();
-    DCHECK(media_keys_listener_manager);
+    registered_media_keys_--;
+    DCHECK_GE(registered_media_keys_, 0);
+    if (registered_media_keys_ == 0) {
+      content::MediaKeysListenerManager* media_keys_listener_manager =
+          content::MediaKeysListenerManager::GetInstance();
+      DCHECK(media_keys_listener_manager);
 
-    media_keys_listener_manager->StopWatchingMediaKey(accelerator.key_code(),
-                                                      this);
+      media_keys_listener_manager->EnableInternalMediaKeyHandling();
+    }
   }
 
   hotkeys_.erase(it);
diff --git a/chrome/browser/extensions/global_shortcut_listener_win.h b/chrome/browser/extensions/global_shortcut_listener_win.h
index 800c5c9..d7b245a 100644
--- a/chrome/browser/extensions/global_shortcut_listener_win.h
+++ b/chrome/browser/extensions/global_shortcut_listener_win.h
@@ -46,6 +46,9 @@
   // Whether this object is listening for global shortcuts.
   bool is_listening_;
 
+  // The number of media keys currently registered.
+  int registered_media_keys_ = 0;
+
   // A map of registered accelerators and their registration ids. The value is
   // null for media keys if kHardwareMediaKeyHandling is true.
   using HotKeyMap = std::map<ui::Accelerator,
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 739a65d..93975ea8 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -825,6 +825,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "enable-autofill-credit-card-authentication",
+    "owners": [ "jsaul@google.com", "manasverma@google.com" ],
+    "expiry_milestone": 79
+  },
+  {
     "name": "enable-autofill-credit-card-local-card-migration",
     "owners": [ "jiahuiguo@google.com", "siyua@google.com" ],
     "expiry_milestone": 76
@@ -2046,7 +2051,7 @@
   },
   {
     "name": "expensive-background-timer-throttling",
-    // "owners": [ "your-team" ],
+    "owners": [ "altimin" ],
     "expiry_milestone": 76
   },
   {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 13314db7..cc7a8d4 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -402,6 +402,13 @@
 const char kEnableAutofillCreditCardAblationExperimentDescription[] =
     "If enabled, credit card autofill suggestions will not display.";
 
+const char kEnableAutofillCreditCardAuthenticationName[] =
+    "Allow using platform authenticators to retrieve server cards";
+const char kEnableAutofillCreditCardAuthenticationDescription[] =
+    "When enabled, users will be given the option to use a platform "
+    "authenticator (if available) to verify card ownership when retrieving "
+    "credit cards from Google Payments.";
+
 const char kEnableAutofillCreditCardLastUsedDateDisplayName[] =
     "Display the last used date of a credit card in autofill.";
 const char kEnableAutofillCreditCardLastUsedDateDisplayDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 3c4addf3..c1a26f8b 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -270,6 +270,9 @@
 extern const char kEnableAutofillCreditCardAblationExperimentDisplayName[];
 extern const char kEnableAutofillCreditCardAblationExperimentDescription[];
 
+extern const char kEnableAutofillCreditCardAuthenticationName[];
+extern const char kEnableAutofillCreditCardAuthenticationDescription[];
+
 extern const char kEnableAutofillCreditCardLastUsedDateDisplayName[];
 extern const char kEnableAutofillCreditCardLastUsedDateDisplayDescription[];
 
diff --git a/chrome/browser/google/google_brand_code_map_chromeos.cc b/chrome/browser/google/google_brand_code_map_chromeos.cc
index 68cd1ce1..fe54292 100644
--- a/chrome/browser/google/google_brand_code_map_chromeos.cc
+++ b/chrome/browser/google/google_brand_code_map_chromeos.cc
@@ -67,6 +67,7 @@
                      {"IHZG", {"MLLN", "EZTK", "GJEJ"}},
                      {"JBPA", {"VUZL", "XYPI", "XOWE"}},
                      {"JLRH", {"SAMJ", "GLJZ", "SKTN"}},
+                     {"JYXK", {"USZT", "XXPU", "LJHH"}},
                      {"LASN", {"ILWC", "BQYG", "RROZ"}},
                      {"LEAC", {"DMEA", "EXWD", "PBTU"}},
                      {"LEAE", {"QFVM", "GACH", "BMXB"}},
diff --git a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
index 791b3ac..9e0616a 100644
--- a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
+++ b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
@@ -28,6 +28,7 @@
 
 using testing::_;
 using testing::InvokeWithoutArgs;
+using testing::Return;
 
 namespace mirroring {
 
@@ -178,7 +179,8 @@
   void RequestRefreshFrame() {
     base::RunLoop run_loop;
     EXPECT_CALL(*video_frame_receiver_, OnBufferReadyCall(_))
-        .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+        .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit))
+        .WillRepeatedly(Return());
     video_frame_receiver_->RequestRefreshFrame();
     run_loop.Run();
   }
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 96dbd31..f996f3d 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -1648,8 +1648,9 @@
 
   // net::ClientCertStore:
   void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
-                      const ClientCertListCallback& callback) override {
-    callback.Run(FakeClientCertIdentityListFromCertificateList(certs_));
+                      ClientCertListCallback callback) override {
+    std::move(callback).Run(
+        FakeClientCertIdentityListFromCertificateList(certs_));
   }
 
  private:
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc
index a2f6e6af..7c0b15e5 100644
--- a/chrome/browser/printing/print_browsertest.cc
+++ b/chrome/browser/printing/print_browsertest.cc
@@ -87,7 +87,8 @@
 
 class NupPrintingTestDelegate : public PrintingMessageFilter::TestDelegate {
  public:
-  NupPrintingTestDelegate() {
+  explicit NupPrintingTestDelegate(int initial_document_cookie)
+      : initial_document_cookie_(initial_document_cookie) {
     PrintingMessageFilter::SetDelegateForTesting(this);
   }
   ~NupPrintingTestDelegate() override {
@@ -98,17 +99,31 @@
   PrintMsg_Print_Params GetPrintParams() override {
     PrintMsg_Print_Params params;
     params.page_size = gfx::Size(612, 792);
-    params.content_size = gfx::Size(540, 720);
+    params.content_size = has_margin_ ? gfx::Size(540, 720) : params.page_size;
     params.printable_area = gfx::Rect(612, 792);
     params.dpi = gfx::Size(72, 72);
-    params.document_cookie = kDefaultDocumentCookie;
+    params.document_cookie = GetNextDocumentCookie();
     params.pages_per_sheet = 4;
     params.printed_doc_type =
         IsOopifEnabled() ? SkiaDocumentType::MSKP : SkiaDocumentType::PDF;
     return params;
   }
 
+  int get_print_params_count() const { return get_print_params_count_; }
+
+  void set_no_margin() { has_margin_ = false; }
+
  private:
+  int GetNextDocumentCookie() {
+    int document_cookie = initial_document_cookie_ + get_print_params_count_;
+    ++get_print_params_count_;
+    return document_cookie;
+  }
+
+  const int initial_document_cookie_;
+  int get_print_params_count_ = 0;
+  bool has_margin_ = true;
+
   DISALLOW_COPY_AND_ASSIGN(NupPrintingTestDelegate);
 };
 
@@ -603,24 +618,52 @@
 }
 
 // Printing frame content for the main frame of a generic webpage with N-up
-// priting. This is a regression test for https://crbug.com/937247
+// printing. This is a regression test for https://crbug.com/937247
 IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintNup) {
-  NupPrintingTestDelegate test_delegate;
+  NupPrintingTestDelegate test_delegate(kDefaultDocumentCookie);
   ASSERT_TRUE(embedded_test_server()->Started());
   GURL url(embedded_test_server()->GetURL("/printing/test1.html"));
   ui_test_utils::NavigateToURL(browser(), url);
 
   PrintAndWaitUntilPreviewIsReady(/*print_only_selection=*/false);
+  EXPECT_EQ(1, test_delegate.get_print_params_count());
 }
 
 // Site per process version of PrintBrowserTest.PrintNup.
 IN_PROC_BROWSER_TEST_F(SitePerProcessPrintBrowserTest, PrintNup) {
-  NupPrintingTestDelegate test_delegate;
+  NupPrintingTestDelegate test_delegate(kDefaultDocumentCookie);
   ASSERT_TRUE(embedded_test_server()->Started());
   GURL url(embedded_test_server()->GetURL("/printing/test1.html"));
   ui_test_utils::NavigateToURL(browser(), url);
 
   PrintAndWaitUntilPreviewIsReady(/*print_only_selection=*/false);
+  EXPECT_EQ(1, test_delegate.get_print_params_count());
+}
+
+// Printing frame content for the main frame of a generic webpage with N-up
+// printing and no margins. This covers the test scenario described in
+// https://crbug.com/944516
+IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintNupNoMargins) {
+  NupPrintingTestDelegate test_delegate(kDefaultDocumentCookie);
+  test_delegate.set_no_margin();
+  ASSERT_TRUE(embedded_test_server()->Started());
+  GURL url(embedded_test_server()->GetURL("/printing/test1.html"));
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  PrintAndWaitUntilPreviewIsReady(/*print_only_selection=*/false);
+  EXPECT_EQ(2, test_delegate.get_print_params_count());
+}
+
+// Site per process version of PrintBrowserTest.PrintNup.
+IN_PROC_BROWSER_TEST_F(SitePerProcessPrintBrowserTest, PrintNupNoMargins) {
+  NupPrintingTestDelegate test_delegate(kDefaultDocumentCookie);
+  test_delegate.set_no_margin();
+  ASSERT_TRUE(embedded_test_server()->Started());
+  GURL url(embedded_test_server()->GetURL("/printing/test1.html"));
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  PrintAndWaitUntilPreviewIsReady(/*print_only_selection=*/false);
+  EXPECT_EQ(2, test_delegate.get_print_params_count());
 }
 
 }  // namespace printing
diff --git a/chrome/browser/renderer_context_menu/spelling_bubble_model.cc b/chrome/browser/renderer_context_menu/spelling_bubble_model.cc
index 06fcdf7..e20f77d2 100644
--- a/chrome/browser/renderer_context_menu/spelling_bubble_model.cc
+++ b/chrome/browser/renderer_context_menu/spelling_bubble_model.cc
@@ -29,7 +29,7 @@
 }
 
 base::string16 SpellingBubbleModel::GetTitle() const {
-  return l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_ASK_GOOGLE);
+  return l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLING_BUBBLE_TITLE);
 }
 
 base::string16 SpellingBubbleModel::GetMessageText() const {
diff --git a/chrome/browser/resources/chromeos/cellular_setup/OWNERS b/chrome/browser/resources/chromeos/cellular_setup/OWNERS
index 75e2f312..fa033853 100644
--- a/chrome/browser/resources/chromeos/cellular_setup/OWNERS
+++ b/chrome/browser/resources/chromeos/cellular_setup/OWNERS
@@ -1,2 +1 @@
-azeemarshad@chromium.org
-khorimoto@chromium.org
+file://ui/webui/resources/cr_components/chromeos/cellular_setup/OWNERS
diff --git a/chrome/browser/resources/chromeos/cellular_setup/cellular_setup_dialog.html b/chrome/browser/resources/chromeos/cellular_setup/cellular_setup_dialog.html
index 8ec69bc7..babbec3 100644
--- a/chrome/browser/resources/chromeos/cellular_setup/cellular_setup_dialog.html
+++ b/chrome/browser/resources/chromeos/cellular_setup/cellular_setup_dialog.html
@@ -17,7 +17,7 @@
 </head>
 <body>
   <link rel="import" href="i18n_setup.html">
-  <!-- TODO(khorimoto): Replace button with actual content.-->
-  <button>$i18n{cancel}</button>
+  <link rel="import" href="chrome://resources/cr_components/chromeos/cellular_setup/cellular_setup.html">
+  <cellular-setup></cellular-setup>
 </body>
 </html>
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.html b/chrome/browser/resources/chromeos/login/oobe_eula.html
index 9bc2a14..ddff8a8 100644
--- a/chrome/browser/resources/chromeos/login/oobe_eula.html
+++ b/chrome/browser/resources/chromeos/login/oobe_eula.html
@@ -71,7 +71,7 @@
           </cr-toggle>
           <div id="usageStatsLabelContainer">
             <span id="usageStatsLabel" i18n-content="checkboxLogging"></span>
-            <a id="learn-more" href="#" i18n-content="learnMore"
+            <a id="" href="#" i18n-content="learnMore"
                 on-tap="onUsageStatsHelpLinkClicked_">
             </a>
           </div>
@@ -109,7 +109,7 @@
           </div>
           <div class='password-row layout horizontal'>
             <div class="flex"></div>
-            <div id="eula-password">{{password}}</div>
+            <div>{{password}}</div>
             <div class="flex"></div>
           </div>
         </div>
diff --git a/chrome/browser/resources/md_user_manager/user_manager_pages.js b/chrome/browser/resources/md_user_manager/user_manager_pages.js
index 591594d8..04761b5 100644
--- a/chrome/browser/resources/md_user_manager/user_manager_pages.js
+++ b/chrome/browser/resources/md_user_manager/user_manager_pages.js
@@ -56,7 +56,7 @@
    * This is to prevent events from propagating to the document element, which
    * erroneously triggers user-pod selections.
    *
-   * TODO(scottchen): re-examine if its necessary for user_pod_row.js to bind
+   * TODO(tangltom): re-examine if its necessary for user_pod_row.js to bind
    * listeners on the entire document element.
    *
    * @param {!Event} e
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/landing_view.html b/chrome/browser/resources/welcome/onboarding_welcome/landing_view.html
index 35b8622a..648e986f 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/landing_view.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/landing_view.html
@@ -18,8 +18,8 @@
         outline: none;
       }
     </style>
-    <onboarding-background></onboarding-background>
     <div id="container">
+      <onboarding-background></onboarding-background>
       <h2>$i18n{landingDescription}</h2>
       <h1 tabindex="-1">$i18n{landingTitle}</h1>
       <paper-button class="action-button" on-click="onNewUserClick_">
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/shared/splash_pages_shared_css.html b/chrome/browser/resources/welcome/onboarding_welcome/shared/splash_pages_shared_css.html
index a5d332c8..d213efc6 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/shared/splash_pages_shared_css.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/shared/splash_pages_shared_css.html
@@ -10,10 +10,11 @@
         align-items: center;
         display: flex;
         flex-direction: column;
-        height: 100%;
         justify-content: center;
         margin: auto;
+        min-height: 100%;
         min-width: 800px;
+        position: relative;
       }
 
       h1 {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/signin_view.html b/chrome/browser/resources/welcome/onboarding_welcome/signin_view.html
index 5b6f232..101786f 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/signin_view.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/signin_view.html
@@ -20,8 +20,8 @@
         outline: none;
       }
     </style>
-    <onboarding-background></onboarding-background>
     <div id="container">
+      <onboarding-background></onboarding-background>
       <h2>$i18n{signInSubHeader}</h2>
       <h1 tabindex="-1">$i18n{signInHeader}</h1>
       <paper-button class="action-button" on-click="onSignInClick_">
diff --git a/chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc b/chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc
index 51235f4..baea2e5 100644
--- a/chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc
+++ b/chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc
@@ -674,7 +674,7 @@
   ASSERT_TRUE(window);
   LocationBar* location_bar = window->GetLocationBar();
   ASSERT_TRUE(location_bar);
-  location_bar->FocusLocation();
+  location_bar->FocusLocation(true);
 
   focus_input_and_wait_for_selection_bounds_change();
 }
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 4305fae..766cb2e 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -2445,8 +2445,8 @@
 
   // net::ClientCertStore:
   void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
-                      const ClientCertListCallback& callback) override {
-    callback.Run(std::move(list_));
+                      ClientCertListCallback callback) override {
+    std::move(callback).Run(std::move(list_));
   }
 
  private:
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 8f617131..1d4793b 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1776,6 +1776,8 @@
       "webui/signin/inline_login_handler_chromeos.h",
       "webui/signin/inline_login_handler_dialog_chromeos.cc",
       "webui/signin/inline_login_handler_dialog_chromeos.h",
+      "webui/signin/inline_login_handler_modal_delegate.cc",
+      "webui/signin/inline_login_handler_modal_delegate.h",
       "webui/version_handler_chromeos.cc",
       "webui/version_handler_chromeos.h",
       "window_sizer/window_sizer_ash.cc",
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 9814f062..0f2a2e18 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1122,11 +1122,12 @@
   // Two differences between this and FocusLocationBar():
   // (1) This doesn't get recorded in user metrics, since it's called
   //     internally.
-  // (2) This checks whether the location bar can be focused, and if not, clears
-  //     the focus.  FocusLocationBar() is only reached when the location bar is
-  //     focusable, but this may be reached at other times, e.g. while in
-  //     fullscreen mode, where we need to leave focus in a consistent state.
-  window_->SetFocusToLocationBar();
+  // (2) This is called with |select_all| == false, because this is a renderer
+  //     initiated focus (this method is a WebContentsDelegate override).
+  //     We don't select-all for renderer initiated focuses, as the user may
+  //     currently be typing something while the tab finishes loading. We don't
+  //     want to clobber user input by selecting all while the user is typing.
+  window_->SetFocusToLocationBar(false);
 }
 
 content::KeyboardEventProcessingResult Browser::PreHandleKeyboardEvent(
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index bf5a3fa..3e4ebd9 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -1099,7 +1099,7 @@
 
 void FocusLocationBar(Browser* browser) {
   base::RecordAction(UserMetricsAction("FocusLocation"));
-  browser->window()->SetFocusToLocationBar();
+  browser->window()->SetFocusToLocationBar(true);
 }
 
 void FocusSearch(Browser* browser) {
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index b109b526..83eb1a4 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -250,7 +250,7 @@
 
   // Tries to focus the location bar.  Clears the window focus (to avoid
   // inconsistent state) if this fails.
-  virtual void SetFocusToLocationBar() = 0;
+  virtual void SetFocusToLocationBar(bool select_all) = 0;
 
   // Informs the view whether or not a load is in progress for the current tab.
   // The view can use this notification to update the reload/stop button.
diff --git a/chrome/browser/ui/libgtkui/native_theme_gtk.cc b/chrome/browser/ui/libgtkui/native_theme_gtk.cc
index d8d72cad..9cc6c94 100644
--- a/chrome/browser/ui/libgtkui/native_theme_gtk.cc
+++ b/chrome/browser/ui/libgtkui/native_theme_gtk.cc
@@ -77,6 +77,8 @@
     case ui::NativeTheme::kColorId_DialogBackground:
     case ui::NativeTheme::kColorId_BubbleBackground:
       return GetBgColor("");
+    case ui::NativeTheme::kColorId_BubbleFooterBackground:
+      return GetBgColor("#statusbar");
 
     // FocusableBorder
     case ui::NativeTheme::kColorId_FocusedBorderColor:
diff --git a/chrome/browser/ui/location_bar/location_bar.h b/chrome/browser/ui/location_bar/location_bar.h
index 239d3ba..c4a0819 100644
--- a/chrome/browser/ui/location_bar/location_bar.h
+++ b/chrome/browser/ui/location_bar/location_bar.h
@@ -44,8 +44,16 @@
   // latency of page loads starting at user input.
   virtual void AcceptInput(base::TimeTicks match_selection_timestamp) = 0;
 
-  // Focuses the location bar and selects its contents.
-  virtual void FocusLocation() = 0;
+  // Focuses the location bar.  Optionally also selects its contents.
+  //
+  // User-initiated focuses should have |select_all| set to true, as users
+  // are accustomed to being able to use Ctrl+L to select-all in the omnibox.
+  //
+  // Renderer-initiated focuses should have |select_all| set to false, as the
+  // user may be in the middle of typing while the tab finishes loading.
+  // In that case, we don't want to select-all and cause the user to clobber
+  // their already-typed text.
+  virtual void FocusLocation(bool select_all) = 0;
 
   // Puts the user into keyword mode with their default search provider.
   virtual void FocusSearch() = 0;
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index 5e2a74e2..c77f594 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -766,6 +766,24 @@
   EXPECT_EQ(old_selected_line, popup_model->selected_line());
 }
 
+IN_PROC_BROWSER_TEST_F(OmniboxViewTest,
+                       RendererInitiatedFocusPreservesUserText) {
+  OmniboxView* omnibox_view = nullptr;
+  ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view));
+
+  // Type a single character.
+  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_A, 0));
+  EXPECT_EQ(base::ASCIIToUTF16("a"), omnibox_view->GetText());
+
+  // Simulate a renderer-initated focus event.
+  browser()->SetFocusToLocationBar();
+
+  // Type an additional character and verify that we didn't clobber the
+  // character we already typed.
+  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_B, 0));
+  EXPECT_EQ(base::ASCIIToUTF16("ab"), omnibox_view->GetText());
+}
+
 IN_PROC_BROWSER_TEST_F(OmniboxViewTest, BasicTextOperations) {
   ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
   chrome::FocusLocationBar(browser());
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
index 077b9a3..a718fc2 100644
--- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -74,7 +74,7 @@
           ->OmniboxFocusChanged(OMNIBOX_FOCUS_VISIBLE,
                                 OMNIBOX_FOCUS_CHANGE_EXPLICIT);
     } else {
-      instant_browser()->window()->GetLocationBar()->FocusLocation();
+      instant_browser()->window()->GetLocationBar()->FocusLocation(false);
     }
   }
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index f0bb928a..f473255 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -366,6 +366,7 @@
       show_animation_->Show();
     }
 
+    // ui::EF_MIDDLE_MOUSE_BUTTON opens all bookmarked links in separate tabs.
     set_triggerable_event_flags(ui::EF_LEFT_MOUSE_BUTTON |
                                 ui::EF_MIDDLE_MOUSE_BUTTON);
   }
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 70dd35b..a723a48e 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1086,7 +1086,7 @@
   return GetLocationBarView();
 }
 
-void BrowserView::SetFocusToLocationBar() {
+void BrowserView::SetFocusToLocationBar(bool select_all) {
   // On Windows, changing focus to the location bar causes the browser window to
   // become active. This can steal focus if the user has another window open
   // already. On Chrome OS, changing focus makes a view believe it has a focus
@@ -1098,7 +1098,7 @@
 #endif
 
   LocationBarView* location_bar = GetLocationBarView();
-  location_bar->FocusLocation();
+  location_bar->FocusLocation(select_all);
   if (!location_bar->omnibox_view()->HasFocus()) {
     // If none of location bar got focus, then clear focus.
     views::FocusManager* focus_manager = GetFocusManager();
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 4059a9c..2343a31 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -342,7 +342,7 @@
   PageActionIconContainer* GetPageActionIconContainer() override;
   PageActionIconContainer* GetToolbarPageActionIconContainer() override;
   LocationBar* GetLocationBar() const override;
-  void SetFocusToLocationBar() override;
+  void SetFocusToLocationBar(bool select_all) override;
   void UpdateReloadStopState(bool is_loading, bool force) override;
   void UpdateToolbar(content::WebContents* contents) override;
   void UpdateToolbarVisibility(bool visible, bool animate) override;
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc
index 6ff26af..5634d6c 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc
@@ -31,9 +31,8 @@
 };
 
 // Tests that clicking a link from a tabbed browser to within the scope of an
-// installed app shows the intent picker with the installed app details.
-// For chrome OS platform, the intent picker bubble will pop out while for
-// other platforms, only intent picker icon will be show in Omnibox.
+// installed app shows the intent picker icon in Omnibox. The intent picker
+// bubble will only show up for android apps which is too hard to test.
 IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTest,
                        NavigationToInScopeLinkShowsIntentPicker) {
   InstallTestBookmarkApp();
@@ -55,15 +54,7 @@
 
   IntentPickerBubbleView* intent_picker =
       IntentPickerBubbleView::intent_picker_bubble();
-#if defined(OS_CHROMEOS)
-  ASSERT_TRUE(intent_picker);
-  EXPECT_EQ(web_contents, intent_picker->web_contents());
-  EXPECT_EQ(1u, intent_picker->GetAppInfoForTesting().size());
-  EXPECT_EQ(GetAppName(),
-            intent_picker->GetAppInfoForTesting()[0].display_name);
-#else
   EXPECT_FALSE(intent_picker);
-#endif
 }
 
 // Tests that clicking a link from a tabbed browser to outside the scope of an
diff --git a/chrome/browser/ui/views/keyboard_access_browsertest.cc b/chrome/browser/ui/views/keyboard_access_browsertest.cc
index 827844d..33c85150 100644
--- a/chrome/browser/ui/views/keyboard_access_browsertest.cc
+++ b/chrome/browser/ui/views/keyboard_access_browsertest.cc
@@ -209,7 +209,7 @@
       false);
 
   if (focus_omnibox)
-    browser()->window()->GetLocationBar()->FocusLocation();
+    browser()->window()->GetLocationBar()->FocusLocation(false);
 
 #if defined(OS_CHROMEOS)
   // Chrome OS doesn't have a way to just focus the app menu, so we use Alt+F to
@@ -384,7 +384,7 @@
       browser_view->toolbar_button_provider()->GetAppMenuButton(), browser(),
       true);
 
-  browser()->window()->GetLocationBar()->FocusLocation();
+  browser()->window()->GetLocationBar()->FocusLocation(false);
 
   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
       browser(), ui::VKEY_F10, false, false, false, false));
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index b57bbc4..7e3cb62 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -341,13 +341,17 @@
 ////////////////////////////////////////////////////////////////////////////////
 // LocationBarView, public LocationBar implementation:
 
-void LocationBarView::FocusLocation() {
+void LocationBarView::FocusLocation(bool select_all) {
   const bool omnibox_already_focused = omnibox_view_->HasFocus();
 
   omnibox_view_->SetFocus();
+
   if (omnibox_already_focused)
     omnibox_view()->model()->ClearKeyword();
 
+  if (!select_all)
+    return;
+
   omnibox_view_->SelectAll(true);
 
   // Only exit Query in Omnibox mode on focus command if the location bar was
@@ -1205,7 +1209,7 @@
 // LocationBarView, private DropdownBarHostDelegate implementation:
 
 void LocationBarView::FocusAndSelectAll() {
-  FocusLocation();
+  FocusLocation(true);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index d31abf64..cb3cd0e 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -199,7 +199,7 @@
   bool ActivateFirstInactiveBubbleForAccessibility();
 
   // LocationBar:
-  void FocusLocation() override;
+  void FocusLocation(bool select_all) override;
   void Revert() override;
   OmniboxView* GetOmniboxView() override;
 
diff --git a/chrome/browser/ui/views/platform_keys_certificate_selector_chromeos.cc b/chrome/browser/ui/views/platform_keys_certificate_selector_chromeos.cc
index d08e097..6b3a3615 100644
--- a/chrome/browser/ui/views/platform_keys_certificate_selector_chromeos.cc
+++ b/chrome/browser/ui/views/platform_keys_certificate_selector_chromeos.cc
@@ -36,7 +36,7 @@
   ~ClientCertIdentityPlatformKeys() override = default;
 
   void AcquirePrivateKey(
-      const base::Callback<void(scoped_refptr<net::SSLPrivateKey>)>&
+      base::OnceCallback<void(scoped_refptr<net::SSLPrivateKey>)>
           private_key_callback) override {
     NOTREACHED();
   }
diff --git a/chrome/browser/ui/views/ssl_client_certificate_selector.cc b/chrome/browser/ui/views/ssl_client_certificate_selector.cc
index 75aa15a..8c0fbfb 100644
--- a/chrome/browser/ui/views/ssl_client_certificate_selector.cc
+++ b/chrome/browser/ui/views/ssl_client_certificate_selector.cc
@@ -53,8 +53,8 @@
     net::X509Certificate* cert = identity->certificate();
     net::ClientCertIdentity::SelfOwningAcquirePrivateKey(
         std::move(identity),
-        base::Bind(&SSLClientAuthObserverImpl::GotPrivateKey,
-                   base::Passed(&self), base::Unretained(cert)));
+        base::BindOnce(&SSLClientAuthObserverImpl::GotPrivateKey,
+                       std::move(self), base::Unretained(cert)));
   }
 
   void GotPrivateKey(net::X509Certificate* cert,
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index c908bae7..deafa983 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -618,7 +618,7 @@
 bool ToolbarView::SetPaneFocusAndFocusDefault() {
   if (!location_bar_->HasFocus()) {
     SetPaneFocus(location_bar_);
-    location_bar_->FocusLocation();
+    location_bar_->FocusLocation(true);
     return true;
   }
 
diff --git a/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc b/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc
index 0e68320..85c54f1 100644
--- a/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc
@@ -15,8 +15,8 @@
 #include "chrome/browser/chromeos/system/fake_input_device_settings.h"
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.h"
+#include "chromeos/dbus/audio/fake_cras_audio_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_cras_audio_client.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "content/public/browser/web_ui.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
index 0375c27..b8e663f 100644
--- a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
@@ -4,11 +4,43 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h"
 
+#include <memory>
+
+#include "ash/public/cpp/ash_features.h"
+#include "ash/public/cpp/stylus_utils.h"
+#include "chrome/browser/chromeos/android_sms/android_sms_app_manager.h"
+#include "chrome/browser/chromeos/android_sms/android_sms_service_factory.h"
+#include "chrome/browser/chromeos/arc/arc_util.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
+#include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
+#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
+#include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/crostini_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/date_time_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/device_pointer_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/device_power_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/device_storage_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/internet_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h"
+#include "chrome/browser/ui/webui/settings/tts_handler.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/browser_resources.h"
+#include "chromeos/constants/chromeos_features.h"
+#include "chromeos/constants/chromeos_switches.h"
+#include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
+#include "components/arc/arc_util.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/ui_base_features.h"
 
 namespace chromeos {
 namespace settings {
@@ -19,8 +51,7 @@
   content::WebUIDataSource* html_source =
       content::WebUIDataSource::Create(chrome::kChromeUIOSSettingsHost);
 
-  // TODO(jamescook): Factor out page handlers from MdSettingsUI and initialize
-  // them both there and here.
+  InitWebUIHandlers(profile, web_ui, html_source);
 
   html_source->UseGzip();
   html_source->SetDefaultResource(IDR_OS_SETTINGS_HTML);
@@ -30,5 +61,113 @@
 
 OSSettingsUI::~OSSettingsUI() = default;
 
+// static
+void OSSettingsUI::InitWebUIHandlers(Profile* profile,
+                                     content::WebUI* web_ui,
+                                     content::WebUIDataSource* html_source) {
+  web_ui->AddMessageHandler(std::make_unique<AccessibilityHandler>(web_ui));
+  web_ui->AddMessageHandler(std::make_unique<AndroidAppsHandler>(profile));
+  if (crostini::IsCrostiniUIAllowedForProfile(profile,
+                                              false /* check_policy */)) {
+    web_ui->AddMessageHandler(std::make_unique<CrostiniHandler>(profile));
+  }
+  web_ui->AddMessageHandler(CupsPrintersHandler::Create(web_ui));
+  web_ui->AddMessageHandler(
+      base::WrapUnique(DateTimeHandler::Create(html_source)));
+  web_ui->AddMessageHandler(std::make_unique<FingerprintHandler>(profile));
+  if (chromeos::switches::IsAssistantEnabled()) {
+    web_ui->AddMessageHandler(
+        std::make_unique<GoogleAssistantHandler>(profile));
+  }
+  web_ui->AddMessageHandler(std::make_unique<KeyboardHandler>());
+  web_ui->AddMessageHandler(std::make_unique<PointerHandler>());
+  web_ui->AddMessageHandler(std::make_unique<StorageHandler>(profile));
+  web_ui->AddMessageHandler(std::make_unique<StylusHandler>());
+  web_ui->AddMessageHandler(std::make_unique<InternetHandler>(profile));
+  web_ui->AddMessageHandler(std::make_unique<::settings::TtsHandler>());
+  web_ui->AddMessageHandler(
+      std::make_unique<chromeos::smb_dialog::SmbHandler>(profile));
+
+  if (!profile->IsGuestSession()) {
+    chromeos::android_sms::AndroidSmsService* android_sms_service =
+        chromeos::android_sms::AndroidSmsServiceFactory::GetForBrowserContext(
+            profile);
+    web_ui->AddMessageHandler(std::make_unique<MultideviceHandler>(
+        profile->GetPrefs(),
+        chromeos::multidevice_setup::MultiDeviceSetupClientFactory::
+            GetForProfile(profile),
+        android_sms_service
+            ? android_sms_service->android_sms_pairing_state_tracker()
+            : nullptr,
+        android_sms_service ? android_sms_service->android_sms_app_manager()
+                            : nullptr));
+  }
+
+  html_source->AddBoolean(
+      "multideviceAllowedByPolicy",
+      chromeos::multidevice_setup::AreAnyMultiDeviceFeaturesAllowed(
+          profile->GetPrefs()));
+  html_source->AddBoolean(
+      "quickUnlockEnabled",
+      chromeos::quick_unlock::IsPinEnabled(profile->GetPrefs()));
+  html_source->AddBoolean(
+      "quickUnlockDisabledByPolicy",
+      chromeos::quick_unlock::IsPinDisabledByPolicy(profile->GetPrefs()));
+  const bool fingerprint_unlock_enabled =
+      chromeos::quick_unlock::IsFingerprintEnabled(profile);
+  html_source->AddBoolean("fingerprintUnlockEnabled",
+                          fingerprint_unlock_enabled);
+  if (fingerprint_unlock_enabled) {
+    html_source->AddBoolean(
+        "isFingerprintReaderOnKeyboard",
+        chromeos::quick_unlock::IsFingerprintReaderOnKeyboard());
+  }
+  html_source->AddBoolean("lockScreenNotificationsEnabled",
+                          ash::features::IsLockScreenNotificationsEnabled());
+  html_source->AddBoolean(
+      "lockScreenHideSensitiveNotificationsSupported",
+      ash::features::IsLockScreenHideSensitiveNotificationsSupported());
+  html_source->AddBoolean("showTechnologyBadge",
+                          !ash::features::IsSeparateNetworkIconsEnabled());
+  html_source->AddBoolean("hasInternalStylus",
+                          ash::stylus_utils::HasInternalStylus());
+
+  html_source->AddBoolean(
+      "showKioskNextShell",
+      base::FeatureList::IsEnabled(ash::features::kKioskNextShell));
+
+  html_source->AddBoolean("showCrostini",
+                          crostini::IsCrostiniUIAllowedForProfile(
+                              profile, false /* check_policy */));
+
+  html_source->AddBoolean("allowCrostini",
+                          crostini::IsCrostiniUIAllowedForProfile(profile));
+
+  html_source->AddBoolean("isDemoSession",
+                          chromeos::DemoSession::IsDeviceInDemoMode());
+
+  html_source->AddBoolean("assistantEnabled",
+                          chromeos::switches::IsAssistantEnabled());
+
+  // We have 2 variants of Android apps settings. Default case, when the Play
+  // Store app exists we show expandable section that allows as to
+  // enable/disable the Play Store and link to Android settings which is
+  // available once settings app is registered in the system.
+  // For AOSP images we don't have the Play Store app. In last case we Android
+  // apps settings consists only from root link to Android settings and only
+  // visible once settings app is registered.
+  html_source->AddBoolean("androidAppsVisible",
+                          arc::IsArcAllowedForProfile(profile));
+  html_source->AddBoolean("havePlayStoreApp", arc::IsPlayStoreAvailable());
+
+  // TODO(mash): Support Chrome power settings in Mash. https://crbug.com/644348
+  bool enable_power_settings = !::features::IsMultiProcessMash();
+  html_source->AddBoolean("enablePowerSettings", enable_power_settings);
+  if (enable_power_settings) {
+    web_ui->AddMessageHandler(
+        std::make_unique<PowerHandler>(profile->GetPrefs()));
+  }
+}
+
 }  // namespace settings
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h
index 6f5fdbdf..5a71248 100644
--- a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h
+++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h
@@ -8,6 +8,13 @@
 #include "base/macros.h"
 #include "content/public/browser/web_ui_controller.h"
 
+class Profile;
+
+namespace content {
+class WebUI;
+class WebUIDataSource;
+}  // namespace content
+
 namespace chromeos {
 namespace settings {
 
@@ -17,6 +24,11 @@
   explicit OSSettingsUI(content::WebUI* web_ui);
   ~OSSettingsUI() override;
 
+  // Initializes the WebUI message handlers for OS-specific settings.
+  static void InitWebUIHandlers(Profile* profile,
+                                content::WebUI* web_ui,
+                                content::WebUIDataSource* html_source);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(OSSettingsUI);
 };
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index d01eb0f7..aab2166 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -73,49 +73,22 @@
 
 #if defined(OS_WIN) || defined(OS_CHROMEOS)
 #include "chrome/browser/ui/webui/settings/languages_handler.h"
-#include "chrome/browser/ui/webui/settings/tts_handler.h"
 #endif  // defined(OS_WIN) || defined(OS_CHROMEOS)
 
 #if defined(OS_CHROMEOS)
 #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
-#include "ash/public/cpp/stylus_utils.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/account_manager/account_manager_util.h"
-#include "chrome/browser/chromeos/android_sms/android_sms_app_manager.h"
-#include "chrome/browser/chromeos/android_sms/android_sms_service_factory.h"
-#include "chrome/browser/chromeos/arc/arc_util.h"
-#include "chrome/browser/chromeos/crostini/crostini_util.h"
-#include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
-#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
-#include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
-#include "chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/crostini_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/date_time_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/device_pointer_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/device_power_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/device_storage_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/internet_handler.h"
-#include "chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/grit/browser_resources.h"
 #include "chromeos/components/account_manager/account_manager.h"
 #include "chromeos/components/account_manager/account_manager_factory.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
-#include "chromeos/constants/chromeos_switches.h"
-#include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
-#include "components/arc/arc_util.h"
-#include "ui/base/ui_base_features.h"
+#include "components/prefs/pref_service.h"
 #include "ui/chromeos/resources/grit/ui_chromeos_resources.h"
 #else  // !defined(OS_CHROMEOS)
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
@@ -181,6 +154,8 @@
   AddSettingsPageUIHandler(std::make_unique<ImportDataHandler>());
 
 #if defined(OS_WIN) || defined(OS_CHROMEOS)
+  // TODO(jamescook): Sort out how language is split between Chrome OS and
+  // and browser settings.
   AddSettingsPageUIHandler(std::make_unique<LanguagesHandler>(web_ui));
 #endif  // defined(OS_WIN) || defined(OS_CHROMEOS)
 
@@ -199,11 +174,13 @@
   AddSettingsPageUIHandler(std::make_unique<SecurityKeysHandler>());
 
 #if defined(OS_CHROMEOS)
-  AddSettingsPageUIHandler(
-      std::make_unique<chromeos::settings::AccessibilityHandler>(web_ui));
-  AddSettingsPageUIHandler(
-      std::make_unique<chromeos::settings::AndroidAppsHandler>(profile));
+  // TODO: Remove this when SplitSettings is the default and there are no
+  // Chrome OS settings in the browser settings page.
+  chromeos::settings::OSSettingsUI::InitWebUIHandlers(profile, web_ui,
+                                                      html_source);
 
+  // TODO(jamescook): Sort out how account management is split between Chrome OS
+  // and browser settings.
   if (chromeos::IsAccountManagerAvailable(profile)) {
     chromeos::AccountManagerFactory* factory =
         g_browser_process->platform_part()->GetAccountManagerFactory();
@@ -222,32 +199,6 @@
   }
   AddSettingsPageUIHandler(
       std::make_unique<chromeos::settings::ChangePictureHandler>());
-  if (crostini::IsCrostiniUIAllowedForProfile(profile,
-                                              false /* check_policy */)) {
-    AddSettingsPageUIHandler(
-        std::make_unique<chromeos::settings::CrostiniHandler>(profile));
-  }
-  AddSettingsPageUIHandler(
-      chromeos::settings::CupsPrintersHandler::Create(web_ui));
-  AddSettingsPageUIHandler(
-      std::make_unique<chromeos::settings::FingerprintHandler>(profile));
-  if (chromeos::switches::IsAssistantEnabled()) {
-    AddSettingsPageUIHandler(
-        std::make_unique<chromeos::settings::GoogleAssistantHandler>(profile));
-  }
-  AddSettingsPageUIHandler(
-      std::make_unique<chromeos::settings::KeyboardHandler>());
-  AddSettingsPageUIHandler(
-      std::make_unique<chromeos::settings::PointerHandler>());
-  AddSettingsPageUIHandler(
-      std::make_unique<chromeos::settings::StorageHandler>(profile));
-  AddSettingsPageUIHandler(
-      std::make_unique<chromeos::settings::StylusHandler>());
-  AddSettingsPageUIHandler(
-      std::make_unique<chromeos::settings::InternetHandler>(profile));
-  AddSettingsPageUIHandler(std::make_unique<TtsHandler>());
-  AddSettingsPageUIHandler(
-      std::make_unique<chromeos::smb_dialog::SmbHandler>(profile));
 #else
   AddSettingsPageUIHandler(std::make_unique<DefaultBrowserHandler>());
   AddSettingsPageUIHandler(std::make_unique<ManageProfileHandler>(profile));
@@ -288,93 +239,7 @@
   html_source->AddBoolean("passwordProtectionAvailable",
                           password_protection_available);
 
-#if defined(OS_CHROMEOS)
-  if (!profile->IsGuestSession()) {
-    chromeos::android_sms::AndroidSmsService* android_sms_service =
-        chromeos::android_sms::AndroidSmsServiceFactory::GetForBrowserContext(
-            profile);
-    AddSettingsPageUIHandler(
-        std::make_unique<chromeos::settings::MultideviceHandler>(
-            profile->GetPrefs(),
-            chromeos::multidevice_setup::MultiDeviceSetupClientFactory::
-                GetForProfile(profile),
-            android_sms_service
-                ? android_sms_service->android_sms_pairing_state_tracker()
-                : nullptr,
-            android_sms_service ? android_sms_service->android_sms_app_manager()
-                                : nullptr));
-  }
-  html_source->AddBoolean(
-      "multideviceAllowedByPolicy",
-      chromeos::multidevice_setup::AreAnyMultiDeviceFeaturesAllowed(
-          profile->GetPrefs()));
-
-  AddSettingsPageUIHandler(base::WrapUnique(
-      chromeos::settings::DateTimeHandler::Create(html_source)));
-
-  AddSettingsPageUIHandler(
-      std::make_unique<chromeos::settings::StylusHandler>());
-  html_source->AddBoolean(
-      "quickUnlockEnabled",
-      chromeos::quick_unlock::IsPinEnabled(profile->GetPrefs()));
-  html_source->AddBoolean(
-      "quickUnlockDisabledByPolicy",
-      chromeos::quick_unlock::IsPinDisabledByPolicy(profile->GetPrefs()));
-  const bool fingerprint_unlock_enabled =
-      chromeos::quick_unlock::IsFingerprintEnabled(profile);
-  html_source->AddBoolean("fingerprintUnlockEnabled",
-                          fingerprint_unlock_enabled);
-  if (fingerprint_unlock_enabled) {
-    html_source->AddBoolean(
-        "isFingerprintReaderOnKeyboard",
-        chromeos::quick_unlock::IsFingerprintReaderOnKeyboard());
-  }
-  html_source->AddBoolean("lockScreenNotificationsEnabled",
-                          ash::features::IsLockScreenNotificationsEnabled());
-  html_source->AddBoolean(
-      "lockScreenHideSensitiveNotificationsSupported",
-      ash::features::IsLockScreenHideSensitiveNotificationsSupported());
-  html_source->AddBoolean("showTechnologyBadge",
-                          !ash::features::IsSeparateNetworkIconsEnabled());
-  html_source->AddBoolean("hasInternalStylus",
-                          ash::stylus_utils::HasInternalStylus());
-
-  html_source->AddBoolean(
-      "showKioskNextShell",
-      base::FeatureList::IsEnabled(ash::features::kKioskNextShell));
-
-  html_source->AddBoolean("showCrostini",
-                          crostini::IsCrostiniUIAllowedForProfile(
-                              profile, false /* check_policy */));
-
-  html_source->AddBoolean("allowCrostini",
-                          crostini::IsCrostiniUIAllowedForProfile(profile));
-
-  html_source->AddBoolean("isDemoSession",
-                          chromeos::DemoSession::IsDeviceInDemoMode());
-
-  html_source->AddBoolean("assistantEnabled",
-                          chromeos::switches::IsAssistantEnabled());
-
-  // We have 2 variants of Android apps settings. Default case, when the Play
-  // Store app exists we show expandable section that allows as to
-  // enable/disable the Play Store and link to Android settings which is
-  // available once settings app is registered in the system.
-  // For AOSP images we don't have the Play Store app. In last case we Android
-  // apps settings consists only from root link to Android settings and only
-  // visible once settings app is registered.
-  html_source->AddBoolean("androidAppsVisible",
-                          arc::IsArcAllowedForProfile(profile));
-  html_source->AddBoolean("havePlayStoreApp", arc::IsPlayStoreAvailable());
-
-  // TODO(mash): Support Chrome power settings in Mash. https://crbug.com/644348
-  bool enable_power_settings = !features::IsMultiProcessMash();
-  html_source->AddBoolean("enablePowerSettings", enable_power_settings);
-  if (enable_power_settings) {
-    AddSettingsPageUIHandler(std::make_unique<chromeos::settings::PowerHandler>(
-        profile->GetPrefs()));
-  }
-#else   // !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS)
   html_source->AddBoolean(
       "diceEnabled",
       AccountConsistencyModeManager::IsDiceEnabledForProfile(profile));
@@ -401,6 +266,7 @@
 
 #if defined(OS_CHROMEOS)
   // Add the System Web App resources for Settings.
+  // TODO(jamescook|calamity): Migrate to chromeos::settings::OSSettingsUI.
   if (web_app::SystemWebAppManager::IsEnabled()) {
     html_source->AddResourcePath("icon-192.png", IDR_SETTINGS_LOGO_192);
     html_source->AddResourcePath("pwa.html", IDR_PWA_HTML);
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
index 7465d51..aaab6f0 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
 #include "chrome/common/webui_url_constants.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "net/base/url_util.h"
 #include "ui/aura/window.h"
 #include "ui/display/display.h"
@@ -45,9 +46,34 @@
   dialog->ShowSystemDialog();
 }
 
+gfx::Size InlineLoginHandlerDialogChromeOS::GetMaximumDialogSize() {
+  gfx::Size size;
+  GetDialogSize(&size);
+  return size;
+}
+
+gfx::NativeView InlineLoginHandlerDialogChromeOS::GetHostView() const {
+  return dialog_window();
+}
+
+gfx::Point InlineLoginHandlerDialogChromeOS::GetDialogPosition(
+    const gfx::Size& size) {
+  gfx::Size host_size = GetHostView()->bounds().size();
+
+  // Show all sub-dialogs at center-top.
+  return gfx::Point(std::max(0, (host_size.width() - size.width()) / 2), 0);
+}
+
+void InlineLoginHandlerDialogChromeOS::AddObserver(
+    web_modal::ModalDialogHostObserver* observer) {}
+
+void InlineLoginHandlerDialogChromeOS::RemoveObserver(
+    web_modal::ModalDialogHostObserver* observer) {}
+
 InlineLoginHandlerDialogChromeOS::InlineLoginHandlerDialogChromeOS(
     const GURL& url)
-    : SystemWebDialogDelegate(url, base::string16() /* title */) {}
+    : SystemWebDialogDelegate(url, base::string16() /* title */),
+      delegate_(this) {}
 
 InlineLoginHandlerDialogChromeOS::~InlineLoginHandlerDialogChromeOS() {
   DCHECK_EQ(this, dialog);
@@ -69,4 +95,15 @@
   return false;
 }
 
+void InlineLoginHandlerDialogChromeOS::OnDialogShown(
+    content::WebUI* webui,
+    content::RenderViewHost* render_view_host) {
+  SystemWebDialogDelegate::OnDialogShown(webui, render_view_host);
+  web_modal::WebContentsModalDialogManager::CreateForWebContents(
+      webui->GetWebContents());
+  web_modal::WebContentsModalDialogManager::FromWebContents(
+      webui->GetWebContents())
+      ->SetDelegate(&delegate_);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h
index 192f1be..703e4a2 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h
@@ -9,6 +9,8 @@
 
 #include "base/macros.h"
 #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
+#include "chrome/browser/ui/webui/signin/inline_login_handler_modal_delegate.h"
+#include "components/web_modal/web_contents_modal_dialog_host.h"
 
 class GURL;
 
@@ -17,13 +19,22 @@
 // Extends from |SystemWebDialogDelegate| to create an always-on-top but movable
 // dialog. It is intentionally made movable so that users can copy-paste account
 // passwords from password managers.
-class InlineLoginHandlerDialogChromeOS : public SystemWebDialogDelegate {
+class InlineLoginHandlerDialogChromeOS
+    : public SystemWebDialogDelegate,
+      public web_modal::WebContentsModalDialogHost {
  public:
   // Displays the dialog. |email| is an optional parameter that if provided,
   // pre-fills the account email field in the sign-in dialog - useful for
   // account re-authentication.
   static void Show(const std::string& email = std::string());
 
+  // web_modal::WebContentsModalDialogHost overrides.
+  gfx::Size GetMaximumDialogSize() override;
+  gfx::NativeView GetHostView() const override;
+  gfx::Point GetDialogPosition(const gfx::Size& size) override;
+  void AddObserver(web_modal::ModalDialogHostObserver* observer) override;
+  void RemoveObserver(web_modal::ModalDialogHostObserver* observer) override;
+
  protected:
   explicit InlineLoginHandlerDialogChromeOS(const GURL& url);
   ~InlineLoginHandlerDialogChromeOS() override;
@@ -32,8 +43,12 @@
   void GetDialogSize(gfx::Size* size) const override;
   std::string GetDialogArgs() const override;
   bool ShouldShowDialogTitle() const override;
+  void OnDialogShown(content::WebUI* webui,
+                     content::RenderViewHost* render_view_host) override;
 
  private:
+  InlineLoginHandlerModalDelegate delegate_;
+
   DISALLOW_COPY_AND_ASSIGN(InlineLoginHandlerDialogChromeOS);
 };
 
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_modal_delegate.cc b/chrome/browser/ui/webui/signin/inline_login_handler_modal_delegate.cc
new file mode 100644
index 0000000..c231c7b4
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_modal_delegate.cc
@@ -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.
+
+#include "chrome/browser/ui/webui/signin/inline_login_handler_modal_delegate.h"
+
+#include "base/logging.h"
+#include "content/public/browser/web_contents.h"
+
+namespace chromeos {
+
+InlineLoginHandlerModalDelegate::InlineLoginHandlerModalDelegate(
+    web_modal::WebContentsModalDialogHost* host)
+    : host_(host) {}
+
+InlineLoginHandlerModalDelegate::~InlineLoginHandlerModalDelegate() = default;
+
+web_modal::WebContentsModalDialogHost*
+InlineLoginHandlerModalDelegate::GetWebContentsModalDialogHost() {
+  return host_;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_modal_delegate.h b/chrome/browser/ui/webui/signin/inline_login_handler_modal_delegate.h
new file mode 100644
index 0000000..8ca37afa
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_modal_delegate.h
@@ -0,0 +1,38 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SIGNIN_INLINE_LOGIN_HANDLER_MODAL_DELEGATE_H_
+#define CHROME_BROWSER_UI_WEBUI_SIGNIN_INLINE_LOGIN_HANDLER_MODAL_DELEGATE_H_
+
+#include "base/macros.h"
+#include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
+
+namespace chromeos {
+
+// Used to display sub-modals inside |InlineLoginHandlerDialogChromeOS| modal
+// dialog, e.g. displaying a dialog for accounts using 2FA with WebAuthn,
+// where users can select alternate 2FAs.
+class InlineLoginHandlerModalDelegate
+    : public ChromeWebModalDialogManagerDelegate {
+ public:
+  // |host| is a non owning pointer to the host dialog of this delegate
+  // (|InlineLoginHandlerDialogChromeOS|).
+  explicit InlineLoginHandlerModalDelegate(
+      web_modal::WebContentsModalDialogHost* host);
+  ~InlineLoginHandlerModalDelegate() override;
+
+  // web_modal::WebContentsModalDialogManagerDelegate overrides.
+  web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost()
+      override;
+
+ private:
+  // Non-owning pointer.
+  web_modal::WebContentsModalDialogHost* host_;
+
+  DISALLOW_COPY_AND_ASSIGN(InlineLoginHandlerModalDelegate);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_INLINE_LOGIN_HANDLER_MODAL_DELEGATE_H_
diff --git a/chrome/browser/vr/elements/viewport_aware_root.cc b/chrome/browser/vr/elements/viewport_aware_root.cc
index eaa062a..aea3236 100644
--- a/chrome/browser/vr/elements/viewport_aware_root.cc
+++ b/chrome/browser/vr/elements/viewport_aware_root.cc
@@ -42,8 +42,36 @@
 ViewportAwareRoot::~ViewportAwareRoot() = default;
 
 bool ViewportAwareRoot::OnBeginFrame(const gfx::Transform& head_pose) {
+  // head_pose is head_from_world.  Invert to get world_from_head.
   gfx::Vector3dF look_at = vr::GetForwardVector(head_pose);
-  return AdjustRotationForHeadPose(look_at);
+  bool changed = AdjustRotationForHeadPose(look_at);
+  if (recenter_on_rotate_) {
+    gfx::Transform world_from_head;
+    bool invertable = head_pose.GetInverse(&world_from_head);
+    DCHECK(invertable);  // Pose data has been validated already.
+    gfx::Point3F head_pos_in_world_space{0.f, 0.f, 0.f};
+    world_from_head.TransformPoint(&head_pos_in_world_space);
+    changed = AdjustTranslation(head_pos_in_world_space.x(),
+                                head_pos_in_world_space.z(), changed);
+  }
+  return changed;
+}
+
+bool ViewportAwareRoot::AdjustTranslation(float head_in_world_x,
+                                          float head_in_world_z,
+                                          bool did_rotate) {
+  gfx::Point3F center_point_in_world{0.f, 0.f, 0.f};
+  LocalTransform().TransformPoint(&center_point_in_world);
+  gfx::Vector2dF offset = {head_in_world_x - center_point_in_world.x(),
+                           head_in_world_z - center_point_in_world.z()};
+
+  const float kMinTranslationLength =
+      1.2f;  // If you move 1.2m, we'll recenter.
+  if (did_rotate || offset.Length() > kMinTranslationLength) {
+    SetTranslate(head_in_world_x, center_point_in_world.y(), head_in_world_z);
+    return true;
+  }
+  return false;
 }
 
 bool ViewportAwareRoot::AdjustRotationForHeadPose(
@@ -83,6 +111,8 @@
 
 void ViewportAwareRoot::Reset() {
   viewport_aware_total_rotation_ = 0.f;
+  x_center = 0;
+  z_center = 0;
   SetRotate(0.f, 1.f, 0.f, gfx::DegToRad(viewport_aware_total_rotation_));
 }
 
diff --git a/chrome/browser/vr/elements/viewport_aware_root.h b/chrome/browser/vr/elements/viewport_aware_root.h
index 70427a4..110c28e2 100644
--- a/chrome/browser/vr/elements/viewport_aware_root.h
+++ b/chrome/browser/vr/elements/viewport_aware_root.h
@@ -24,17 +24,24 @@
 
   void Reset();
   bool HasVisibleChildren();
+  void SetRecenterOnRotate(bool recenter_on_rotate) {
+    recenter_on_rotate_ = true;
+  }
 
  protected:
   // Returns true if the rotation was adjusted.
   // Virtual for tests.
   virtual bool AdjustRotationForHeadPose(const gfx::Vector3dF& look_at);
+  virtual bool AdjustTranslation(float head_x, float head_z, bool did_rotate);
 
  private:
   bool OnBeginFrame(const gfx::Transform& head_pose) override;
 
   float viewport_aware_total_rotation_ = 0.f;
+  float x_center = 0;
+  float z_center = 0;
   bool children_visible_ = false;
+  bool recenter_on_rotate_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(ViewportAwareRoot);
 };
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index 755818c..287ab69 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -1873,11 +1873,21 @@
 void UiSceneCreator::CreateViewportAwareRoot() {
   auto element = std::make_unique<ViewportAwareRoot>();
   element->SetName(kWebVrViewportAwareRoot);
+
+  // On Windows, allow the viewport-aware UI to translate as well as rotate, so
+  // it remains centered appropriately if the user moves.  Only enabled for
+  // OS_WIN, since it conflicts with browser UI that isn't shown on Windows.
+#if defined(OS_WIN)
+  element->SetRecenterOnRotate(true);
+#endif
   scene_->AddUiElement(kWebVrRoot, std::move(element));
 
   element = std::make_unique<ViewportAwareRoot>();
   element->SetName(k2dBrowsingViewportAwareRoot);
   element->set_contributes_to_parent_bounds(false);
+#if defined(OS_WIN)
+  element->SetRecenterOnRotate(true);
+#endif
   scene_->AddUiElement(k2dBrowsingRepositioner, std::move(element));
 }
 
diff --git a/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc b/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc
index fcd22738..c7c9e264 100644
--- a/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc
+++ b/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc
@@ -87,6 +87,7 @@
 }
 
 void VRBrowserRendererThreadWin::StartWebXrTimeout() {
+  waiting_for_first_frame_ = true;
   overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(),
                                          draw_state_.ShouldDrawWebXR());
 
@@ -115,6 +116,7 @@
   if (!webxr_frame_timeout_closure_.IsCancelled())
     webxr_frame_timeout_closure_.Cancel();
   OnSpinnerVisibilityChanged(false);
+  waiting_for_first_frame_ = false;
 }
 
 int VRBrowserRendererThreadWin::GetNextRequestId() {
@@ -455,7 +457,7 @@
   if (!success && graphics_) {
     graphics_->ResetMemoryBuffer();
   }
-  if (scheduler_ui_ && success)
+  if (scheduler_ui_ && success && !waiting_for_first_frame_)
     scheduler_ui_->OnWebXrFrameAvailable();
   if (draw_state_.ShouldDrawUI() && started_) {
     overlay_->RequestNextOverlayPose(
@@ -471,9 +473,9 @@
 }
 
 bool VRBrowserRendererThreadWin::DrawState::ShouldDrawWebXR() {
-  return (prompt_ == ExternalPromptNotificationType::kPromptNone &&
-          !spinner_visible_) ||
-         indicators_visible_;
+  return ((prompt_ == ExternalPromptNotificationType::kPromptNone ||
+           indicators_visible_) &&
+          !spinner_visible_);
 }
 
 bool VRBrowserRendererThreadWin::DrawState::SetPrompt(
diff --git a/chrome/browser/vr/win/vr_browser_renderer_thread_win.h b/chrome/browser/vr/win/vr_browser_renderer_thread_win.h
index a8675ee..ccf7465 100644
--- a/chrome/browser/vr/win/vr_browser_renderer_thread_win.h
+++ b/chrome/browser/vr/win/vr_browser_renderer_thread_win.h
@@ -102,6 +102,7 @@
   DrawState draw_state_;
   bool started_ = false;
   bool webxr_presenting_ = false;
+  bool waiting_for_first_frame_ = true;
   int current_request_id_ = 0;
 
   device::mojom::ImmersiveOverlayPtr overlay_;
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 66f188d1..7ef87da 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -230,7 +230,13 @@
 
 // Enables or disables the ability to install PWAs from the omnibox.
 const base::Feature kDesktopPWAsOmniboxInstall{
-    "DesktopPWAsOmniboxInstall", base::FEATURE_ENABLED_BY_DEFAULT};
+  "DesktopPWAsOmniboxInstall",
+#if defined(OS_CHROMEOS)
+      base::FEATURE_DISABLED_BY_DEFAULT
+#else
+      base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+};
 
 // Disables downloads of unsafe file types over HTTP.
 const base::Feature kDisallowUnsafeHttpDownloads{
diff --git a/chrome/common/extensions/docs/templates/articles/webstore.html b/chrome/common/extensions/docs/templates/articles/webstore.html
new file mode 100644
index 0000000..3a46f0a
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/articles/webstore.html
@@ -0,0 +1,8 @@
+<h1>chrome.webstore</h1>
+
+<p>
+  As of 06/12/2018, inline installation is deprecated. For more information,
+  read our
+  <a href="https://blog.chromium.org/2018/06/improving-extension-transparency-for.html">Chromium Blog post</a>
+  and <a href="/extensions/inline_faq">Migration FAQ</a>.
+</p>
diff --git a/chrome/common/extensions/docs/templates/intros/webstore.html b/chrome/common/extensions/docs/templates/intros/webstore.html
deleted file mode 100644
index e9d5374..0000000
--- a/chrome/common/extensions/docs/templates/intros/webstore.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<p class="caution">
-  <b>Important:</b>
-  As of 06/12/2018, inline installation is deprecated.
-  For more information, read our
-  <a href="https://blog.chromium.org/2018/06/improving-extension-transparency-for.html">Chromium Blog post</a>
-  and <a href="/extensions/inline_faq">Migration FAQ</a>.
-</p>
diff --git a/chrome/common/extensions/docs/templates/public/extensions/webstore.html b/chrome/common/extensions/docs/templates/public/extensions/webstore.html
index a21f5bd2..19a17f1 100644
--- a/chrome/common/extensions/docs/templates/public/extensions/webstore.html
+++ b/chrome/common/extensions/docs/templates/public/extensions/webstore.html
@@ -1 +1 @@
-{{+partials.standard_extensions_api api:apis.extensions.webstore intro:intros.webstore/}}
+{{+partials.standard_extensions_article article:articles.webstore/}}
diff --git a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
index dd2433edb..8a019d0d 100644
--- a/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
+++ b/chrome/renderer/extensions/automation_ax_tree_wrapper.cc
@@ -189,6 +189,7 @@
       return api::automation::EVENT_TYPE_ARIAATTRIBUTECHANGED;
 
     case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED:
+    case ui::AXEventGenerator::Event::CONTROLS_CHANGED:
     case ui::AXEventGenerator::Event::CLASS_NAME_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index f339ac8..7bc7be9 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -90,7 +90,7 @@
   LocationBar* GetLocationBar() const override;
   PageActionIconContainer* GetPageActionIconContainer() override;
   PageActionIconContainer* GetToolbarPageActionIconContainer() override;
-  void SetFocusToLocationBar() override {}
+  void SetFocusToLocationBar(bool select_all) override {}
   void UpdateReloadStopState(bool is_loading, bool force) override {}
   void UpdateToolbar(content::WebContents* contents) override {}
   void UpdateToolbarVisibility(bool visible, bool animate) override {}
@@ -195,7 +195,7 @@
     base::TimeTicks GetMatchSelectionTimestamp() const override;
     void AcceptInput() override {}
     void AcceptInput(base::TimeTicks match_selection_timestamp) override {}
-    void FocusLocation() override {}
+    void FocusLocation(bool select_all) override {}
     void FocusSearch() override {}
     void UpdateContentSettingsIcons() override {}
     void UpdateSaveCreditCardIcon() override {}
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py
index 94ee53a..b3747b0 100644
--- a/chrome/test/chromedriver/client/chromedriver.py
+++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -147,7 +147,7 @@
       debugger_address=None, logging_prefs=None,
       mobile_emulation=None, experimental_options=None,
       download_dir=None, network_connection=None,
-      send_w3c_capability=None, send_w3c_request=None,
+      send_w3c_capability=True, send_w3c_request=True,
       page_load_strategy=None, unexpected_alert_behaviour=None,
       devtools_events_to_log=None, accept_insecure_certs=None,
       timeouts=None, test_name=None):
@@ -226,7 +226,7 @@
         options['prefs']['download'] = {}
       options['prefs']['download']['default_directory'] = download_dir
 
-    if send_w3c_capability:
+    if send_w3c_capability is not None:
       options['w3c'] = send_w3c_capability
 
     params = {
@@ -314,10 +314,10 @@
   def _ExecuteCommand(self, command, params={}):
     params = self._WrapValue(params)
     response = self._executor.Execute(command, params)
-    if (not self.w3c_compliant and 'status' in response
+    if ('status' in response
         and response['status'] != 0):
       raise _ExceptionForLegacyResponse(response)
-    elif (self.w3c_compliant and type(response['value']) is dict
+    elif (type(response['value']) is dict
           and 'error' in response['value']):
       raise _ExceptionForStandardResponse(response)
     return response
@@ -331,7 +331,10 @@
     return self.ExecuteCommand(Command.GET_WINDOW_HANDLES)
 
   def SwitchToWindow(self, handle_or_name):
-    self.ExecuteCommand(Command.SWITCH_TO_WINDOW, {'name': handle_or_name})
+    if self.w3c_compliant:
+      self.ExecuteCommand(Command.SWITCH_TO_WINDOW, {'handle': handle_or_name})
+    else:
+      self.ExecuteCommand(Command.SWITCH_TO_WINDOW, {'name': handle_or_name})
 
   def GetCurrentWindowHandle(self):
     return self.ExecuteCommand(Command.GET_CURRENT_WINDOW_HANDLE)
@@ -357,6 +360,16 @@
         {'script': script, 'args': converted_args})
 
   def SwitchToFrame(self, id_or_name):
+    if isinstance(id_or_name, basestring) and self.w3c_compliant:
+        try:
+          id_or_name = self.FindElement('css selector',
+                                        '[id="%s"]' % id_or_name)
+        except NoSuchElement:
+          try:
+            id_or_name = self.FindElement('css selector',
+                                          '[name="%s"]' % id_or_name)
+          except NoSuchElement:
+            raise NoSuchFrame(id_or_name)
     self.ExecuteCommand(Command.SWITCH_TO_FRAME, {'id': id_or_name})
 
   def SwitchToFrameByIndex(self, index):
diff --git a/chrome/test/chromedriver/client/webelement.py b/chrome/test/chromedriver/client/webelement.py
index 9eda862..e8bf6a6 100644
--- a/chrome/test/chromedriver/client/webelement.py
+++ b/chrome/test/chromedriver/client/webelement.py
@@ -53,16 +53,16 @@
     self._Execute(Command.CLEAR_ELEMENT)
 
   def SendKeys(self, *values):
-    typing = []
-    for value in values:
-      if isinstance(value, int):
-        value = str(value)
-      for i in range(len(value)):
-        typing.append(value[i])
-    self._Execute(Command.SEND_KEYS_TO_ELEMENT, {'value': typing})
-
-  def SendKeysW3c(self, text):
-    self._Execute(Command.SEND_KEYS_TO_ELEMENT, {'text': text})
+    if self._chromedriver.w3c_compliant:
+      self._Execute(Command.SEND_KEYS_TO_ELEMENT, {'text': str(*values)})
+    else:
+      typing = []
+      for value in values:
+        if isinstance(value, int):
+          value = str(value)
+        for i in range(len(value)):
+          typing.append(value[i])
+        self._Execute(Command.SEND_KEYS_TO_ELEMENT, {'value': typing})
 
   def GetLocation(self):
     return self._Execute(Command.GET_ELEMENT_LOCATION)
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index bbbf66f..3c4bcd30 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -704,11 +704,10 @@
                                                        kSessionStorage),
                                    false /*w3c_standard_command*/)),
 
-      // No W3C equivalent.
+      // Non-standard command but supported in the foreseeable future.
       CommandMapping(
           kPost, "session/:sessionId/log",
-          WrapToCommand("GetLog", base::BindRepeating(&ExecuteGetLog),
-                        false /*w3c_standard_command*/)),
+          WrapToCommand("GetLog", base::BindRepeating(&ExecuteGetLog))),
 
       // No W3C equivalent.
       CommandMapping(
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 0a369bce..f7b56da 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -169,8 +169,6 @@
 _ANDROID_NEGATIVE_FILTER = {}
 _ANDROID_NEGATIVE_FILTER['chrome'] = (
     _NEGATIVE_FILTER + [
-        # TODO(chrisgao): fix hang of tab crash test on android.
-        'ChromeDriverTest.testTabCrash',
         # Android doesn't support switches and extensions.
         'ChromeSwitchesCapabilityTest.*',
         'ChromeExtensionsCapabilityTest.*',
@@ -404,21 +402,6 @@
   def testGetCurrentWindowHandle(self):
     self._driver.GetCurrentWindowHandle()
 
-  def testDragAndDropWithSVGImage(self):
-    self._driver.Load(
-                    self.GetHttpUrlForFile('/chromedriver/drag_and_drop.svg'))
-    drag = self._driver.FindElement("css selector", "#GreenRectangle")
-    drop = self._driver.FindElement("css selector", "#FolderRectangle")
-    self._driver.MouseMoveTo(drag)
-    self._driver.MouseButtonDown()
-    self._driver.MouseMoveTo(drop)
-    self._driver.MouseButtonUp()
-    self.assertTrue(self._driver.IsAlertOpen())
-    self.assertEquals('GreenRectangle has been dropped into a folder.',
-                      self._driver.GetAlertMessage())
-    self._driver.HandleAlert(True)
-    self.assertEquals('translate(300,55)', drag.GetAttribute("transform"))
-
   def testCloseWindow(self):
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html'))
     old_handles = self._driver.GetWindowHandles()
@@ -554,19 +537,16 @@
     self._driver.Load(self.GetHttpUrlForFile(
         '/chromedriver/nested_frameset.html'))
     self._driver.SwitchToFrameByIndex(0)
-    self.assertTrue(self._driver.FindElement("css selector", "#link")
-                    .IsDisplayed())
+    self._driver.FindElement("css selector", "#link")
     self._driver.SwitchToMainFrame()
     self._driver.SwitchToFrame('2Frame')
-    self.assertTrue(self._driver.FindElement("css selector", "#l1")
-                    .IsDisplayed())
+    self._driver.FindElement("css selector", "#l1")
     self._driver.SwitchToMainFrame()
     self._driver.SwitchToFrame('fourth_frame')
     self.assertTrue('One' in self._driver.GetPageSource())
     self._driver.SwitchToMainFrame()
     self._driver.SwitchToFrameByIndex(4)
-    self.assertTrue(self._driver.FindElement("css selector", "#aa1")
-                    .IsDisplayed())
+    self._driver.FindElement("css selector", "#aa1")
 
   def testExecuteInRemovedFrame(self):
     self._driver.ExecuteScript(
@@ -622,13 +602,6 @@
                             self._driver.FindElement,
                             'tag name', 'divine')
 
-  def testUnexpectedAlertOpenExceptionMessage(self):
-    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
-    self._driver.ExecuteScript('window.alert("Hi");')
-    self.assertRaisesRegexp(chromedriver.UnexpectedAlertOpen,
-                            'unexpected alert open: {Alert text : Hi}',
-                            self._driver.FindElement, 'tag name', 'divine')
-
   def testFindElements(self):
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
     self._driver.ExecuteScript(
@@ -931,38 +904,11 @@
     value = self._driver.ExecuteScript('return arguments[0].value;', text)
     self.assertEquals('', value)
 
-  def testSendKeysToElement(self):
-    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
-    text = self._driver.ExecuteScript(
-        'document.body.innerHTML = \'<input type="text">\';'
-        'var input = document.getElementsByTagName("input")[0];'
-        'input.addEventListener("change", function() {'
-        '  document.body.appendChild(document.createElement("br"));'
-        '});'
-        'return input;')
-    text.SendKeys('0123456789+-*/ Hi')
-    text.SendKeys(', there!')
-    value = self._driver.ExecuteScript('return arguments[0].value;', text)
-    self.assertEquals('0123456789+-*/ Hi, there!', value)
-
-  def testSendingTabKeyMovesToNextInputElement(self):
-    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/two_inputs.html'))
-    first = self._driver.FindElement('css selector', '#first')
-    second = self._driver.FindElement('css selector', '#second')
-    first.Click()
-    self._driver.SendKeys('snoopy')
-    self._driver.SendKeys(u'\uE004')
-    self._driver.SendKeys('prickly pete')
-    self.assertEquals('snoopy', self._driver.ExecuteScript(
-        'return arguments[0].value;', first))
-    self.assertEquals('prickly pete', self._driver.ExecuteScript(
-        'return arguments[0].value;', second))
-
   def testSendKeysToInputFileElement(self):
     file_name = os.path.join(_TEST_DATA_DIR, 'anchor_download_test.png')
     self._driver.Load(ChromeDriverTest.GetHttpUrlForFile(
         '/chromedriver/file_input.html'))
-    elem = self._driver.FindElement('id', 'id_file')
+    elem = self._driver.FindElement('css selector', '#id_file')
     elem.SendKeys(file_name)
     text = self._driver.ExecuteScript(
         'var input = document.getElementById("id_file").value;'
@@ -1038,101 +984,6 @@
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
     self._driver.Refresh()
 
-  def testMouseMoveTo(self):
-    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
-    div = self._driver.ExecuteScript(
-        'document.body.innerHTML = "<div>old</div>";'
-        'var div = document.getElementsByTagName("div")[0];'
-        'div.style["width"] = "100px";'
-        'div.style["height"] = "100px";'
-        'div.addEventListener("mouseover", function() {'
-        '  var div = document.getElementsByTagName("div")[0];'
-        '  div.innerHTML="new<br>";'
-        '});'
-        'return div;')
-    self._driver.MouseMoveTo(div, 10, 10)
-    self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
-
-  def testMoveToElementAndClick(self):
-    # This page gets rendered differently depending on which platform the test
-    # is running on, and what window size is being used. So we need to do some
-    # sanity checks to make sure that the <a> element is split across two lines
-    # of text.
-    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/multiline.html'))
-
-    # Check that link element spans two lines and that the first ClientRect is
-    # above the second.
-    link = self._driver.FindElements('tag name', 'a')[0]
-    client_rects = self._driver.ExecuteScript(
-        'return arguments[0].getClientRects();', link)
-    self.assertEquals(2, len(client_rects))
-    self.assertTrue(client_rects[0]['bottom'] <= client_rects[1]['top'])
-
-    # Check that the center of the link's bounding ClientRect is outside the
-    # element.
-    bounding_client_rect = self._driver.ExecuteScript(
-        'return arguments[0].getBoundingClientRect();', link)
-    center = bounding_client_rect['left'] + bounding_client_rect['width'] / 2
-    self.assertTrue(client_rects[1]['right'] < center)
-    self.assertTrue(center < client_rects[0]['left'])
-
-    self._driver.MouseMoveTo(link)
-    self._driver.MouseClick()
-    self.assertTrue(self._driver.GetCurrentUrl().endswith('#top'))
-
-  def testMouseClick(self):
-    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
-    div = self._driver.ExecuteScript(
-        'document.body.innerHTML = "<div>old</div>";'
-        'var div = document.getElementsByTagName("div")[0];'
-        'div.style["width"] = "100px";'
-        'div.style["height"] = "100px";'
-        'div.addEventListener("click", function() {'
-        '  var div = document.getElementsByTagName("div")[0];'
-        '  div.innerHTML="new<br>";'
-        '});'
-        'return div;')
-    self._driver.MouseMoveTo(div)
-    self._driver.MouseClick()
-    self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
-
-  def testMouseButtonDownAndUp(self):
-    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
-    self._driver.ExecuteScript(
-        'document.body.innerHTML = "<div>old</div>";'
-        'var div = document.getElementsByTagName("div")[0];'
-        'div.style["width"] = "100px";'
-        'div.style["height"] = "100px";'
-        'div.addEventListener("mousedown", function() {'
-        '  var div = document.getElementsByTagName("div")[0];'
-        '  div.innerHTML="new1<br>";'
-        '});'
-        'div.addEventListener("mouseup", function() {'
-        '  var div = document.getElementsByTagName("div")[0];'
-        '  div.innerHTML="new2<a></a>";'
-        '});')
-    self._driver.MouseMoveTo(None, 50, 50)
-    self._driver.MouseButtonDown()
-    self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
-    self._driver.MouseButtonUp()
-    self.assertEquals(1, len(self._driver.FindElements('tag name', 'a')))
-
-  def testMouseDoubleClick(self):
-    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
-    div = self._driver.ExecuteScript(
-        'document.body.innerHTML = "<div>old</div>";'
-        'var div = document.getElementsByTagName("div")[0];'
-        'div.style["width"] = "100px";'
-        'div.style["height"] = "100px";'
-        'div.addEventListener("dblclick", function() {'
-        '  var div = document.getElementsByTagName("div")[0];'
-        '  div.innerHTML="new<br>";'
-        '});'
-        'return div;')
-    self._driver.MouseMoveTo(div, 1, 1)
-    self._driver.MouseDoubleClick()
-    self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
-
   def testAlert(self):
     self.assertFalse(self._driver.IsAlertOpen())
     self._driver.ExecuteScript('window.confirmed = confirm(\'HI\');')
@@ -1326,7 +1177,8 @@
 
     self.WaitForCondition(lambda: len(GetPendingLogs(self._driver)) > 0 , 6)
     self.assertEqual('console-api', new_logs[0][0]['source'])
-    self.assertTrue('"RepeatedError" "Second" "Third"' in new_logs[0][0]['message'])
+    self.assertTrue('"RepeatedError" "Second" "Third"' in
+                    new_logs[0][0]['message'])
 
   def testGetLogOnClosedWindow(self):
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html'))
@@ -1357,28 +1209,10 @@
         ".*Uncaught TypeError: Cannot read property 'y' of undefined.*",
         self._driver.Load, url)
 
-  def testContextMenuEventFired(self):
-    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/context_menu.html'))
-    self._driver.MouseMoveTo(self._driver.FindElement('tag name', 'div'))
-    self._driver.MouseClick(2)
-    self.assertTrue(self._driver.ExecuteScript('return success'))
-
-  def testTabCrash(self):
-    # If a tab is crashed, the session will be deleted.
-    # When 31 is released, will reload the tab instead.
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=547
-    self.assertRaises(chromedriver.UnknownError,
-                      self._driver.Load, 'chrome://crash')
-    self.assertRaises(chromedriver.InvalidSessionId,
-                      self._driver.GetCurrentUrl)
-
   def testDoesntHangOnDebugger(self):
     self._driver.Load('about:blank')
     self._driver.ExecuteScript('debugger;')
 
-  def testMobileEmulationDisabledByDefault(self):
-    self.assertFalse(self._driver.capabilities['mobileEmulationEnabled'])
-
   def testChromeDriverSendLargeData(self):
     script = 'var s = ""; for (var i = 0; i < 10e6; i++) s += "0"; return s;'
     lots_of_data = self._driver.ExecuteScript(script)
@@ -1604,20 +1438,6 @@
     with self.assertRaises(chromedriver.StaleElementReference):
       elem.Click()
 
-  def testShadowDomDisplayed(self):
-    """Checks that trying to manipulate shadow DOM elements that are detached
-    from the document raises a StaleElementReference exception"""
-    self._driver.Load(self.GetHttpUrlForFile(
-        '/chromedriver/shadow_dom_test.html'))
-    elem = self._FindElementInShadowDom(
-        ["#innerDiv", "#parentDiv", "#button"])
-    self.assertTrue(elem.IsDisplayed())
-    elem2 = self._driver.FindElement("css selector", "#hostContent")
-    self.assertTrue(elem2.IsDisplayed())
-    self._driver.ExecuteScript(
-        'document.querySelector("#outerDiv").style.display="None";')
-    self.assertFalse(elem.IsDisplayed())
-
   def testTouchSingleTapElement(self):
     self._driver.Load(self.GetHttpUrlForFile(
         '/chromedriver/touch_action_tests.html'))
@@ -1720,13 +1540,6 @@
     width_after_pinch = self._driver.ExecuteScript('return window.innerWidth;')
     self.assertAlmostEqual(2.0, float(width_before_pinch) / width_after_pinch)
 
-  def testHasTouchScreen(self):
-    self.assertIn('hasTouchScreen', self._driver.capabilities)
-    if _ANDROID_PACKAGE_KEY:
-      self.assertTrue(self._driver.capabilities['hasTouchScreen'])
-    else:
-      self.assertFalse(self._driver.capabilities['hasTouchScreen'])
-
   def testSwitchesToTopFrameAfterNavigation(self):
     self._driver.Load('about:blank')
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/outer.html'))
@@ -2062,8 +1875,8 @@
         '  document.body.appendChild(document.createElement("br"));'
         '});'
         'return input;')
-    text.SendKeysW3c('0123456789+-*/ Hi')
-    text.SendKeysW3c(', there!')
+    text.SendKeys('0123456789+-*/ Hi')
+    text.SendKeys(', there!')
     value = self._driver.ExecuteScript('return arguments[0].value;', text)
     self.assertEquals('0123456789+-*/ Hi, there!', value)
 
@@ -2076,6 +1889,201 @@
     # In W3C mode, the alert is dismissed by default.
     self.assertFalse(self._driver.IsAlertOpen())
 
+
+class ChromeDriverTestLegacy(ChromeDriverBaseTestWithWebServer):
+  """End to end tests for ChromeDriver in Legacy mode."""
+
+  def setUp(self):
+    self._driver = self.CreateDriver(send_w3c_capability=False,
+                                     send_w3c_request=False)
+
+  def testContextMenuEventFired(self):
+    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/context_menu.html'))
+    self._driver.MouseMoveTo(self._driver.FindElement('tag name', 'div'))
+    self._driver.MouseClick(2)
+    self.assertTrue(self._driver.ExecuteScript('return success'))
+
+  def testDragAndDropWithSVGImage(self):
+    self._driver.Load(
+        self.GetHttpUrlForFile('/chromedriver/drag_and_drop.svg'))
+    drag = self._driver.FindElement("css selector", "#GreenRectangle")
+    drop = self._driver.FindElement("css selector", "#FolderRectangle")
+    self._driver.MouseMoveTo(drag)
+    self._driver.MouseButtonDown()
+    self._driver.MouseMoveTo(drop)
+    self._driver.MouseButtonUp()
+    self.assertTrue(self._driver.IsAlertOpen())
+    self.assertEquals('GreenRectangle has been dropped into a folder.',
+                      self._driver.GetAlertMessage())
+    self._driver.HandleAlert(True)
+    self.assertEquals('translate(300,55)', drag.GetAttribute("transform"))
+
+  def testMouseButtonDownAndUp(self):
+    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
+    self._driver.ExecuteScript(
+        'document.body.innerHTML = "<div>old</div>";'
+        'var div = document.getElementsByTagName("div")[0];'
+        'div.style["width"] = "100px";'
+        'div.style["height"] = "100px";'
+        'div.addEventListener("mousedown", function() {'
+        '  var div = document.getElementsByTagName("div")[0];'
+        '  div.innerHTML="new1<br>";'
+        '});'
+        'div.addEventListener("mouseup", function() {'
+        '  var div = document.getElementsByTagName("div")[0];'
+        '  div.innerHTML="new2<a></a>";'
+        '});')
+    self._driver.MouseMoveTo(None, 50, 50)
+    self._driver.MouseButtonDown()
+    self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
+    self._driver.MouseButtonUp()
+    self.assertEquals(1, len(self._driver.FindElements('tag name', 'a')))
+
+  def testMouseClick(self):
+    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
+    div = self._driver.ExecuteScript(
+        'document.body.innerHTML = "<div>old</div>";'
+        'var div = document.getElementsByTagName("div")[0];'
+        'div.style["width"] = "100px";'
+        'div.style["height"] = "100px";'
+        'div.addEventListener("click", function() {'
+        '  var div = document.getElementsByTagName("div")[0];'
+        '  div.innerHTML="new<br>";'
+        '});'
+        'return div;')
+    self._driver.MouseMoveTo(div)
+    self._driver.MouseClick()
+    self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
+
+  def testMouseDoubleClick(self):
+    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
+    div = self._driver.ExecuteScript(
+        'document.body.innerHTML = "<div>old</div>";'
+        'var div = document.getElementsByTagName("div")[0];'
+        'div.style["width"] = "100px";'
+        'div.style["height"] = "100px";'
+        'div.addEventListener("dblclick", function() {'
+        '  var div = document.getElementsByTagName("div")[0];'
+        '  div.innerHTML="new<br>";'
+        '});'
+        'return div;')
+    self._driver.MouseMoveTo(div, 1, 1)
+    self._driver.MouseDoubleClick()
+    self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
+
+  def testMouseMoveTo(self):
+    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
+    div = self._driver.ExecuteScript(
+        'document.body.innerHTML = "<div>old</div>";'
+        'var div = document.getElementsByTagName("div")[0];'
+        'div.style["width"] = "100px";'
+        'div.style["height"] = "100px";'
+        'div.addEventListener("mouseover", function() {'
+        '  var div = document.getElementsByTagName("div")[0];'
+        '  div.innerHTML="new<br>";'
+        '});'
+        'return div;')
+    self._driver.MouseMoveTo(div, 10, 10)
+    self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
+
+  def testMoveToElementAndClick(self):
+    # This page gets rendered differently depending on which platform the test
+    # is running on, and what window size is being used. So we need to do some
+    # sanity checks to make sure that the <a> element is split across two lines
+    # of text.
+    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/multiline.html'))
+
+    # Check that link element spans two lines and that the first ClientRect is
+    # above the second.
+    link = self._driver.FindElements('tag name', 'a')[0]
+    client_rects = self._driver.ExecuteScript(
+        'return arguments[0].getClientRects();', link)
+    self.assertEquals(2, len(client_rects))
+    self.assertTrue(client_rects[0]['bottom'] <= client_rects[1]['top'])
+
+    # Check that the center of the link's bounding ClientRect is outside the
+    # element.
+    bounding_client_rect = self._driver.ExecuteScript(
+        'return arguments[0].getBoundingClientRect();', link)
+    center = bounding_client_rect['left'] + bounding_client_rect['width'] / 2
+    self.assertTrue(client_rects[1]['right'] < center)
+    self.assertTrue(center < client_rects[0]['left'])
+
+    self._driver.MouseMoveTo(link)
+    self._driver.MouseClick()
+    self.assertTrue(self._driver.GetCurrentUrl().endswith('#top'))
+
+
+  def _FindElementInShadowDom(self, css_selectors):
+    """Find an element inside shadow DOM using CSS selectors.
+    The last item in css_selectors identify the element to find. All preceding
+    selectors identify the hierarchy of shadow hosts to traverse in order to
+    reach the target shadow DOM."""
+    current = None
+    for selector in css_selectors:
+      if current is None:
+        # First CSS selector, start from root DOM.
+        current = self._driver
+      else:
+        # current is a shadow host selected previously.
+        # Enter the corresponding shadow root.
+        current = self._driver.ExecuteScript(
+            'return arguments[0].shadowRoot', current)
+      current = current.FindElement('css selector', selector)
+    return current
+
+  def testShadowDomDisplayed(self):
+    """Checks that trying to manipulate shadow DOM elements that are detached
+    from the document raises a StaleElementReference exception"""
+    self._driver.Load(self.GetHttpUrlForFile(
+        '/chromedriver/shadow_dom_test.html'))
+    elem = self._FindElementInShadowDom(
+        ["#innerDiv", "#parentDiv", "#button"])
+    self.assertTrue(elem.IsDisplayed())
+    elem2 = self._driver.FindElement("css selector", "#hostContent")
+    self.assertTrue(elem2.IsDisplayed())
+    self._driver.ExecuteScript(
+        'document.querySelector("#outerDiv").style.display="None";')
+    self.assertFalse(elem.IsDisplayed())
+
+  def testSendingTabKeyMovesToNextInputElement(self):
+    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/two_inputs.html'))
+    first = self._driver.FindElement('css selector', '#first')
+    second = self._driver.FindElement('css selector', '#second')
+    first.Click()
+    self._driver.SendKeys('snoopy')
+    self._driver.SendKeys(u'\uE004')
+    self._driver.SendKeys('prickly pete')
+    self.assertEquals('snoopy', self._driver.ExecuteScript(
+        'return arguments[0].value;', first))
+    self.assertEquals('prickly pete', self._driver.ExecuteScript(
+        'return arguments[0].value;', second))
+
+  def testMobileEmulationDisabledByDefault(self):
+    self.assertFalse(self._driver.capabilities['mobileEmulationEnabled'])
+
+  def testSendKeysToElement(self):
+    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
+    text = self._driver.ExecuteScript(
+        'document.body.innerHTML = \'<input type="text">\';'
+        'var input = document.getElementsByTagName("input")[0];'
+        'input.addEventListener("change", function() {'
+        '  document.body.appendChild(document.createElement("br"));'
+        '});'
+        'return input;')
+    text.SendKeys('0123456789+-*/ Hi')
+    text.SendKeys(', there!')
+    value = self._driver.ExecuteScript('return arguments[0].value;', text)
+    self.assertEquals('0123456789+-*/ Hi, there!', value)
+
+  def testUnexpectedAlertOpenExceptionMessage(self):
+    self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
+    self._driver.ExecuteScript('window.alert("Hi");')
+    self.assertRaisesRegexp(chromedriver.UnexpectedAlertOpen,
+                            'unexpected alert open: {Alert text : Hi}',
+                            self._driver.FindElement, 'tag name', 'divine')
+
+
 class ChromeDriverSiteIsolation(ChromeDriverBaseTestWithWebServer):
   """Tests for ChromeDriver with the new Site Isolation Chrome feature.
 
@@ -2504,8 +2512,11 @@
     self.assertEquals(timeouts['pageLoad'], 456)
     self.assertEquals(timeouts['script'], 789)
 
-  def testUnexpectedAlertBehaviour(self):
-    driver = self.CreateDriver(unexpected_alert_behaviour="accept")
+  # Run in Legacy mode
+  def testUnexpectedAlertBehaviourLegacy(self):
+    driver = self.CreateDriver(unexpected_alert_behaviour="accept",
+                               send_w3c_capability=False,
+                               send_w3c_request=False)
     self.assertEquals("accept",
                       driver.capabilities['unexpectedAlertBehaviour'])
     driver.ExecuteScript('alert("HI");')
@@ -2681,8 +2692,10 @@
   def GlobalTearDown():
     MobileEmulationCapabilityTest._http_server.Shutdown()
 
+  # Run in Legacy mode
   def testDeviceMetricsWithStandardWidth(self):
     driver = self.CreateDriver(
+        send_w3c_capability=False, send_w3c_request=False,
         mobile_emulation = {
             'deviceMetrics': {'width': 360, 'height': 640, 'pixelRatio': 3},
             'userAgent': 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Bui'
@@ -2695,8 +2708,10 @@
     self.assertEqual(360, driver.ExecuteScript('return window.screen.width'))
     self.assertEqual(640, driver.ExecuteScript('return window.screen.height'))
 
+  # Run in Legacy mode
   def testDeviceMetricsWithDeviceWidth(self):
     driver = self.CreateDriver(
+        send_w3c_capability=False, send_w3c_request=False,
         mobile_emulation = {
             'deviceMetrics': {'width': 360, 'height': 640, 'pixelRatio': 3},
             'userAgent': 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Bui'
@@ -2759,8 +2774,10 @@
     div.Click()
     self.assertEquals(1, len(driver.FindElements('tag name', 'br')))
 
+  # Run in Legacy mode
   def testTapElement(self):
     driver = self.CreateDriver(
+        send_w3c_capability=False, send_w3c_request=False,
         mobile_emulation = {'deviceName': 'Nexus 5'})
     driver.Load('about:blank')
     div = driver.ExecuteScript(
@@ -2773,12 +2790,6 @@
     div.SingleTap()
     self.assertEquals(1, len(driver.FindElements('tag name', 'br')))
 
-  def testHasTouchScreen(self):
-    driver = self.CreateDriver(
-        mobile_emulation = {'deviceName': 'Nexus 5'})
-    self.assertIn('hasTouchScreen', driver.capabilities)
-    self.assertTrue(driver.capabilities['hasTouchScreen'])
-
   def testDoesntWaitWhenPageLoadStrategyIsNone(self):
     class HandleRequest(object):
       def __init__(self):
@@ -2822,11 +2833,13 @@
     self.assertRaises(chromedriver.UnknownError,
                       driver.SetNetworkConnection, 0x1)
 
+  # Run in Legacy mode
   def testNetworkConnectionEnabled(self):
     # mobileEmulation must be enabled for networkConnection to be enabled
     driver = self.CreateDriver(
         mobile_emulation={'deviceName': 'Nexus 5'},
-        network_connection=True)
+        network_connection=True,
+        send_w3c_capability=False, send_w3c_request=False)
     self.assertTrue(driver.capabilities['mobileEmulationEnabled'])
     self.assertTrue(driver.capabilities['networkConnectionEnabled'])
 
@@ -2944,17 +2957,28 @@
     network = driver.GetNetworkConnection()
     self.assertEquals(network, connection_type)
 
-  def testW3cCompliantResponses(self):
-    # It's an error to send W3C format request without W3C capability flag.
-    with self.assertRaises(chromedriver.SessionNotCreated):
-      self.CreateDriver(send_w3c_request=True)
-
-    # Can disable W3C capability in a legacy format request.
-    driver = self.CreateDriver(send_w3c_capability=False)
+  def testDefaultComplianceMode(self):
+    driver = self.CreateDriver(send_w3c_capability=None,
+                               send_w3c_request=False)
     self.assertFalse(driver.w3c_compliant)
 
-    # Can set W3C capability flag in a W3C format request.
-    driver = self.CreateDriver(send_w3c_capability=True, send_w3c_request=True)
+  def testW3cCompliantResponses(self):
+    # It's an error to send Legacy format request
+    # without Legacy capability flag.
+    with self.assertRaises(chromedriver.InvalidArgument):
+      self.CreateDriver(send_w3c_request=False)
+
+    # It's an error to send Legacy format capability
+    # without Legacy request flag.
+    with self.assertRaises(chromedriver.SessionNotCreated):
+      self.CreateDriver(send_w3c_capability=False)
+
+    # Can enable W3C capability in a W3C format request.
+    driver = self.CreateDriver(send_w3c_capability=True)
+    self.assertTrue(driver.w3c_compliant)
+
+    # Can enable W3C request in a legacy format request.
+    driver = self.CreateDriver(send_w3c_request=True)
     self.assertTrue(driver.w3c_compliant)
 
     # Asserts that errors are being raised correctly in the test client
@@ -2962,8 +2986,9 @@
     self.assertRaises(chromedriver.UnknownError,
                       driver.GetNetworkConnection)
 
-  def testNonCompliantByDefault(self):
-    driver = self.CreateDriver();
+    # Can set Legacy capability flag in a Legacy format request.
+    driver = self.CreateDriver(send_w3c_capability=False,
+                               send_w3c_request=False)
     self.assertFalse(driver.w3c_compliant)
 
 
@@ -3248,8 +3273,10 @@
     HeadlessInvalidCertificateTest._https_server = webserver.WebServer(
         chrome_paths.GetTestData(), cert_path)
     if _ANDROID_PACKAGE_KEY:
-      HeadlessInvalidCertificateTest._device = device_utils.DeviceUtils.HealthyDevices()[0]
-      https_host_port = HeadlessInvalidCertificateTest._https_server._server.server_port
+      HeadlessInvalidCertificateTest._device = device_utils.DeviceUtils\
+                                                           .HealthyDevices()[0]
+      https_host_port = HeadlessInvalidCertificateTest._https_server._server\
+                                                      .server_port
       forwarder.Forwarder.Map([(https_host_port, https_host_port)],
                               ChromeDriverTest._device)
 
diff --git a/chrome/test/data/extensions/api_test/help_app/manifest.json b/chrome/test/data/extensions/api_test/help_app/manifest.json
deleted file mode 100644
index 5b9d0ef..0000000
--- a/chrome/test/data/extensions/api_test/help_app/manifest.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuCAA3/rQ/X5xUBc2DhjXGB7U0Fn6memyWN5u3XYc1QzNdKodI5hmqVRi6yVePzmQuSdsA2M7wG0enGkg7qfQKNydcHPM7z/J0GEmSqzadrtz5QzWN2JemkIB3ilB7gO1RcyEluuHDhepCbVCwIr3VbguaaoatW4zYndqgC9mNOF5M73G44s6GkCunNcHtUaleaRiwt12y+WZsKIfRW90ijyESlSOEmGVhWwMld9SnAJv/P7apNr2HfQR4Bemriu02ypAPuJQ6zpvK+DRFdXu1bb7gOuN10+zPCjrt8SLs79rZ974bA56gAqUjDf3kLtJiHXMavCPUf3Fs1mvpzKTJwIDAQAB",
-  "name": "Help",
-  "version": "4.0",
-  "description" : "Test Chrome OS Help",
-  "manifest_version": 2,
-  "incognito" : "split"
-}
diff --git a/chrome/test/data/extensions/api_test/help_app/oobe.html b/chrome/test/data/extensions/api_test/help_app/oobe.html
deleted file mode 100644
index 058b00e..0000000
--- a/chrome/test/data/extensions/api_test/help_app/oobe.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Fake Help App</title>
-</head>
-<body>
-  In official builds this shows help pages.
-</body>
-</html>
diff --git a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
index e5b5a6d..8a5fb38 100644
--- a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
@@ -347,7 +347,7 @@
     menu.close();
   });
 
-  // TODO(scottchen): fix flakiness and re-enable this test.
+  // TODO(dpapad): fix flakiness and re-enable this test.
   test.skip(
       '[auto-reposition] enables repositioning if content changes',
       function(done) {
diff --git a/chrome/test/data/webui/settings/crostini_page_test.js b/chrome/test/data/webui/settings/crostini_page_test.js
index bdbe01a..a24cea3 100644
--- a/chrome/test/data/webui/settings/crostini_page_test.js
+++ b/chrome/test/data/webui/settings/crostini_page_test.js
@@ -106,7 +106,7 @@
 
     test('Sanity', function() {
       assertTrue(!!subpage.$$('#crostini-shared-paths'));
-      assertTrue(!subpage.$$('#crostini-shared-usb-devices'));
+      assertTrue(!!subpage.$$('#crostini-shared-usb-devices'));
       assertTrue(!!subpage.$$('#crostini-export-import'));
       assertTrue(!!subpage.$$('#remove'));
     });
diff --git a/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc b/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc
index 427cb99..55a85b5 100644
--- a/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc
+++ b/chromecast/renderer/extensions/automation_ax_tree_wrapper.cc
@@ -196,6 +196,7 @@
 
     case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED:
     case ui::AXEventGenerator::Event::CLASS_NAME_CHANGED:
+    case ui::AXEventGenerator::Event::CONTROLS_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
     case ui::AXEventGenerator::Event::ENABLED_CHANGED:
diff --git a/chromeos/audio/audio_device.h b/chromeos/audio/audio_device.h
index c26e2de..647ff06 100644
--- a/chromeos/audio/audio_device.h
+++ b/chromeos/audio/audio_device.h
@@ -12,7 +12,7 @@
 #include <vector>
 
 #include "base/component_export.h"
-#include "chromeos/dbus/audio_node.h"
+#include "chromeos/dbus/audio/audio_node.h"
 
 namespace chromeos {
 
diff --git a/chromeos/audio/audio_devices_pref_handler_impl_unittest.cc b/chromeos/audio/audio_devices_pref_handler_impl_unittest.cc
index b72eca7..5c35499 100644
--- a/chromeos/audio/audio_devices_pref_handler_impl_unittest.cc
+++ b/chromeos/audio/audio_devices_pref_handler_impl_unittest.cc
@@ -11,7 +11,7 @@
 #include "chromeos/audio/audio_device.h"
 #include "chromeos/audio/audio_devices_pref_handler.h"
 #include "chromeos/constants/chromeos_pref_names.h"
-#include "chromeos/dbus/audio_node.h"
+#include "chromeos/dbus/audio/audio_node.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromeos/audio/cras_audio_handler.h b/chromeos/audio/cras_audio_handler.h
index 4cd58f5e..1603d6d 100644
--- a/chromeos/audio/cras_audio_handler.h
+++ b/chromeos/audio/cras_audio_handler.h
@@ -22,9 +22,9 @@
 #include "chromeos/audio/audio_device.h"
 #include "chromeos/audio/audio_devices_pref_handler.h"
 #include "chromeos/audio/audio_pref_observer.h"
-#include "chromeos/dbus/audio_node.h"
-#include "chromeos/dbus/cras_audio_client.h"
-#include "chromeos/dbus/volume_state.h"
+#include "chromeos/dbus/audio/audio_node.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
+#include "chromeos/dbus/audio/volume_state.h"
 #include "media/base/video_facing.h"
 
 namespace base {
diff --git a/chromeos/audio/cras_audio_handler_unittest.cc b/chromeos/audio/cras_audio_handler_unittest.cc
index 3cda8e30..5b5405d 100644
--- a/chromeos/audio/cras_audio_handler_unittest.cc
+++ b/chromeos/audio/cras_audio_handler_unittest.cc
@@ -20,8 +20,8 @@
 #include "base/values.h"
 #include "chromeos/audio/audio_devices_pref_handler.h"
 #include "chromeos/audio/audio_devices_pref_handler_stub.h"
-#include "chromeos/dbus/audio_node.h"
-#include "chromeos/dbus/fake_cras_audio_client.h"
+#include "chromeos/dbus/audio/audio_node.h"
+#include "chromeos/dbus/audio/fake_cras_audio_client.h"
 #include "media/base/video_facing.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index 6d87db7..5e931e01 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -24,7 +24,7 @@
 
 // Enables or disables Crostini support for usb mounting.
 const base::Feature kCrostiniUsbSupport{"CrostiniUsbSupport",
-                                        base::FEATURE_DISABLED_BY_DEFAULT};
+                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables or disables Crostini usb mounting for unsupported devices.
 // To enable, CrostiniUsbSupport must also be enabled.
diff --git a/chromeos/dbus/BUILD.gn b/chromeos/dbus/BUILD.gn
index 931208b..28145cb 100644
--- a/chromeos/dbus/BUILD.gn
+++ b/chromeos/dbus/BUILD.gn
@@ -42,16 +42,20 @@
     "arc_obb_mounter_client.h",
     "arc_oemcrypto_client.cc",
     "arc_oemcrypto_client.h",
-    "audio_node.cc",
-    "audio_node.h",
+    "audio/audio_node.cc",
+    "audio/audio_node.h",
+    "audio/cras_audio_client.cc",
+    "audio/cras_audio_client.h",
+    "audio/fake_cras_audio_client.cc",
+    "audio/fake_cras_audio_client.h",
+    "audio/volume_state.cc",
+    "audio/volume_state.h",
     "cec_service_client.cc",
     "cec_service_client.h",
     "cicerone_client.cc",
     "cicerone_client.h",
     "concierge_client.cc",
     "concierge_client.h",
-    "cras_audio_client.cc",
-    "cras_audio_client.h",
     "cros_disks_client.cc",
     "cros_disks_client.h",
     "dbus_client.h",
@@ -80,8 +84,6 @@
     "fake_cicerone_client.h",
     "fake_concierge_client.cc",
     "fake_concierge_client.h",
-    "fake_cras_audio_client.cc",
-    "fake_cras_audio_client.h",
     "fake_cros_disks_client.cc",
     "fake_cros_disks_client.h",
     "fake_debug_daemon_client.cc",
@@ -132,8 +134,6 @@
     "util/version_loader.h",
     "virtual_file_provider_client.cc",
     "virtual_file_provider_client.h",
-    "volume_state.cc",
-    "volume_state.h",
   ]
 }
 
@@ -202,12 +202,12 @@
     "//third_party/icu",
   ]
   sources = [
+    "audio/cras_audio_client_unittest.cc",
     "auth_policy/fake_auth_policy_client_unittest.cc",
     "biod/biod_client_unittest.cc",
     "biod/fake_biod_client_unittest.cc",
     "blocking_method_caller_unittest.cc",
     "cec_service_client_unittest.cc",
-    "cras_audio_client_unittest.cc",
     "cros_disks_client_unittest.cc",
     "cryptohome/fake_cryptohome_client_unittest.cc",
     "dbus_thread_manager_unittest.cc",
diff --git a/chromeos/dbus/audio_node.cc b/chromeos/dbus/audio/audio_node.cc
similarity index 77%
rename from chromeos/dbus/audio_node.cc
rename to chromeos/dbus/audio/audio_node.cc
index f8f0baef3..7d459fc 100644
--- a/chromeos/dbus/audio_node.cc
+++ b/chromeos/dbus/audio/audio_node.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/dbus/audio_node.h"
+#include "chromeos/dbus/audio/audio_node.h"
 
 #include <stdint.h>
 
@@ -41,12 +41,8 @@
 
 std::string AudioNode::ToString() const {
   std::string result;
-  base::StringAppendF(&result,
-                      "is_input = %s ",
-                      is_input ? "true" : "false");
-  base::StringAppendF(&result,
-                      "id = 0x%" PRIx64 " ",
-                      id);
+  base::StringAppendF(&result, "is_input = %s ", is_input ? "true" : "false");
+  base::StringAppendF(&result, "id = 0x%" PRIx64 " ", id);
   base::StringAppendF(&result, "stable_device_id_version = %d",
                       StableDeviceIdVersion());
   base::StringAppendF(&result, "stable_device_id_v1 = 0x%" PRIx64 " ",
@@ -54,15 +50,9 @@
   base::StringAppendF(&result, "stable_device_id_v2 = 0x%" PRIx64 " ",
                       stable_device_id_v2);
   base::StringAppendF(&result, "device_name = %s ", device_name.c_str());
-  base::StringAppendF(&result,
-                      "type = %s ",
-                      type.c_str());
-  base::StringAppendF(&result,
-                      "name = %s ",
-                      name.c_str());
-  base::StringAppendF(&result,
-                      "active = %s ",
-                      active ? "true" : "false");
+  base::StringAppendF(&result, "type = %s ", type.c_str());
+  base::StringAppendF(&result, "name = %s ", name.c_str());
+  base::StringAppendF(&result, "active = %s ", active ? "true" : "false");
   base::StringAppendF(&result, "plugged_time= %s ",
                       base::NumberToString(plugged_time).c_str());
 
diff --git a/chromeos/dbus/audio_node.h b/chromeos/dbus/audio/audio_node.h
similarity index 90%
rename from chromeos/dbus/audio_node.h
rename to chromeos/dbus/audio/audio_node.h
index a19f984..30af6ae3 100644
--- a/chromeos/dbus/audio_node.h
+++ b/chromeos/dbus/audio/audio_node.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_DBUS_AUDIO_NODE_H_
-#define CHROMEOS_DBUS_AUDIO_NODE_H_
+#ifndef CHROMEOS_DBUS_AUDIO_AUDIO_NODE_H_
+#define CHROMEOS_DBUS_AUDIO_AUDIO_NODE_H_
 
 #include <stdint.h>
 
@@ -52,4 +52,4 @@
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_DBUS_AUDIO_NODE_H_
+#endif  // CHROMEOS_DBUS_AUDIO_AUDIO_NODE_H_
diff --git a/chromeos/dbus/cras_audio_client.cc b/chromeos/dbus/audio/cras_audio_client.cc
similarity index 97%
rename from chromeos/dbus/cras_audio_client.cc
rename to chromeos/dbus/audio/cras_audio_client.cc
index 04eb8c87..5566ff7 100644
--- a/chromeos/dbus/cras_audio_client.cc
+++ b/chromeos/dbus/audio/cras_audio_client.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/dbus/cras_audio_client.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 
 #include <stdint.h>
 
@@ -13,7 +13,7 @@
 #include "base/format_macros.h"
 #include "base/macros.h"
 #include "base/strings/stringprintf.h"
-#include "chromeos/dbus/fake_cras_audio_client.h"
+#include "chromeos/dbus/audio/fake_cras_audio_client.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
 #include "dbus/object_path.h"
@@ -160,8 +160,7 @@
   }
 
   void GetNodes(DBusMethodCallback<AudioNodeList> callback) override {
-    dbus::MethodCall method_call(cras::kCrasControlInterface,
-                                 cras::kGetNodes);
+    dbus::MethodCall method_call(cras::kCrasControlInterface, cras::kGetNodes);
     cras_proxy_->CallMethod(
         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
         base::BindOnce(&CrasAudioClientImpl::OnGetNodes,
@@ -330,8 +329,7 @@
     dbus::MessageReader reader(signal);
     bool system_mute, user_mute;
     if (!reader.PopBool(&system_mute) || !reader.PopBool(&user_mute)) {
-      LOG(ERROR) << "Error reading signal from cras:"
-                 << signal->ToString();
+      LOG(ERROR) << "Error reading signal from cras:" << signal->ToString();
     }
     for (auto& observer : observers_)
       observer.OutputMuteChanged(user_mute);
@@ -342,8 +340,7 @@
     dbus::MessageReader reader(signal);
     bool mute;
     if (!reader.PopBool(&mute)) {
-      LOG(ERROR) << "Error reading signal from cras:"
-                 << signal->ToString();
+      LOG(ERROR) << "Error reading signal from cras:" << signal->ToString();
     }
     for (auto& observer : observers_)
       observer.InputMuteChanged(mute);
@@ -358,8 +355,7 @@
     dbus::MessageReader reader(signal);
     uint64_t node_id;
     if (!reader.PopUint64(&node_id)) {
-      LOG(ERROR) << "Error reading signal from cras:"
-                 << signal->ToString();
+      LOG(ERROR) << "Error reading signal from cras:" << signal->ToString();
     }
     for (auto& observer : observers_)
       observer.ActiveOutputNodeChanged(node_id);
@@ -369,8 +365,7 @@
     dbus::MessageReader reader(signal);
     uint64_t node_id;
     if (!reader.PopUint64(&node_id)) {
-      LOG(ERROR) << "Error reading signal from cras:"
-                 << signal->ToString();
+      LOG(ERROR) << "Error reading signal from cras:" << signal->ToString();
     }
     for (auto& observer : observers_)
       observer.ActiveInputNodeChanged(node_id);
@@ -559,7 +554,7 @@
       if (!array_reader->PopDictEntry(&dict_entry_reader) ||
           !dict_entry_reader.PopString(&key) ||
           !dict_entry_reader.PopVariant(&value_reader)) {
-         return false;
+        return false;
       }
 
       if (key == cras::kIsInputProperty) {
diff --git a/chromeos/dbus/cras_audio_client.h b/chromeos/dbus/audio/cras_audio_client.h
similarity index 94%
rename from chromeos/dbus/cras_audio_client.h
rename to chromeos/dbus/audio/cras_audio_client.h
index 3ef45d09..037dc7b 100644
--- a/chromeos/dbus/cras_audio_client.h
+++ b/chromeos/dbus/audio/cras_audio_client.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_DBUS_CRAS_AUDIO_CLIENT_H_
-#define CHROMEOS_DBUS_CRAS_AUDIO_CLIENT_H_
+#ifndef CHROMEOS_DBUS_AUDIO_CRAS_AUDIO_CLIENT_H_
+#define CHROMEOS_DBUS_AUDIO_CRAS_AUDIO_CLIENT_H_
 
 #include <stdint.h>
 
@@ -14,10 +14,13 @@
 #include "base/component_export.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
-#include "chromeos/dbus/audio_node.h"
-#include "chromeos/dbus/dbus_client.h"
+#include "chromeos/dbus/audio/audio_node.h"
+#include "chromeos/dbus/audio/volume_state.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
-#include "chromeos/dbus/volume_state.h"
+
+namespace dbus {
+class Bus;
+}
 
 namespace chromeos {
 
@@ -144,7 +147,8 @@
   virtual void SwapLeftRight(uint64_t node_id, bool swap) = 0;
 
   virtual void SetGlobalOutputChannelRemix(
-      int32_t channels, const std::vector<double>& mixer) = 0;
+      int32_t channels,
+      const std::vector<double>& mixer) = 0;
 
   // Runs the callback as soon as the service becomes available.
   virtual void WaitForServiceToBeAvailable(
@@ -162,4 +166,4 @@
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_DBUS_CRAS_AUDIO_CLIENT_H_
+#endif  // CHROMEOS_DBUS_AUDIO_CRAS_AUDIO_CLIENT_H_
diff --git a/chromeos/dbus/cras_audio_client_unittest.cc b/chromeos/dbus/audio/cras_audio_client_unittest.cc
similarity index 95%
rename from chromeos/dbus/cras_audio_client_unittest.cc
rename to chromeos/dbus/audio/cras_audio_client_unittest.cc
index 23b00b5..6e6495b 100644
--- a/chromeos/dbus/cras_audio_client_unittest.cc
+++ b/chromeos/dbus/audio/cras_audio_client_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/dbus/cras_audio_client.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 
 #include <memory>
 #include <string>
@@ -254,8 +254,8 @@
 
 class CrasAudioClientTest : public testing::Test {
  public:
-  CrasAudioClientTest() : interface_name_(cras::kCrasControlInterface),
-                          response_(nullptr) {}
+  CrasAudioClientTest()
+      : interface_name_(cras::kCrasControlInterface), response_(nullptr) {}
 
   void SetUp() override {
     // Create a mock bus.
@@ -264,10 +264,9 @@
     mock_bus_ = new dbus::MockBus(options);
 
     // Create a mock cras proxy.
-    mock_cras_proxy_ = new dbus::MockObjectProxy(
-        mock_bus_.get(),
-        cras::kCrasServiceName,
-        dbus::ObjectPath(cras::kCrasServicePath));
+    mock_cras_proxy_ =
+        new dbus::MockObjectProxy(mock_bus_.get(), cras::kCrasServiceName,
+                                  dbus::ObjectPath(cras::kCrasServicePath));
 
     // Set an expectation so mock_cras_proxy's CallMethod() will use
     // OnCallMethod() to return responses.
@@ -370,8 +369,8 @@
 
  protected:
   // A callback to intercept and check the method call arguments.
-  typedef base::Callback<void(
-      dbus::MessageReader* reader)> ArgumentCheckCallback;
+  typedef base::Callback<void(dbus::MessageReader* reader)>
+      ArgumentCheckCallback;
 
   // Sets expectations for called method name and arguments, and sets response.
   void PrepareForMethodCall(const std::string& method_name,
@@ -413,7 +412,7 @@
   }
 
   // Send output node volume changed signal to the tested client.
-  void SendOutputNodeVolumeChangedSignal(dbus::Signal *signal) {
+  void SendOutputNodeVolumeChangedSignal(dbus::Signal* signal) {
     ASSERT_FALSE(output_node_volume_changed_handler_.is_null());
     output_node_volume_changed_handler_.Run(signal);
   }
@@ -605,8 +604,7 @@
   const bool kSystemMuteOn = false;
   const bool kUserMuteOn = true;
   // Create a signal.
-  dbus::Signal signal(cras::kCrasControlInterface,
-                      cras::kOutputMuteChanged);
+  dbus::Signal signal(cras::kCrasControlInterface, cras::kOutputMuteChanged);
   dbus::MessageWriter writer(&signal);
   writer.AppendBool(kSystemMuteOn);
   writer.AppendBool(kUserMuteOn);
@@ -635,8 +633,7 @@
 TEST_F(CrasAudioClientTest, InputMuteChanged) {
   const bool kInputMuteOn = true;
   // Create a signal.
-  dbus::Signal signal(cras::kCrasControlInterface,
-                      cras::kInputMuteChanged);
+  dbus::Signal signal(cras::kCrasControlInterface, cras::kInputMuteChanged);
   dbus::MessageWriter writer(&signal);
   writer.AppendBool(kInputMuteOn);
 
@@ -711,8 +708,7 @@
 
 TEST_F(CrasAudioClientTest, NodesChanged) {
   // Create a signal.
-  dbus::Signal signal(cras::kCrasControlInterface,
-                      cras::kNodesChanged);
+  dbus::Signal signal(cras::kCrasControlInterface, cras::kNodesChanged);
   // Set expectations.
   MockObserver observer;
   EXPECT_CALL(observer, NodesChanged()).Times(1);
@@ -830,8 +826,7 @@
   WriteNodesToResponse(expected_node_list, &writer);
 
   // Set expectations.
-  PrepareForMethodCall(cras::kGetNodes,
-                       base::Bind(&ExpectNoArgument),
+  PrepareForMethodCall(cras::kGetNodes, base::Bind(&ExpectNoArgument),
                        response.get());
   // Call method.
   bool called = false;
@@ -871,11 +866,10 @@
   std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
 
   // Set expectations.
-  PrepareForMethodCall(cras::kSetOutputNodeVolume,
-                       base::Bind(&ExpectUint64AndInt32Arguments,
-                                  kNodeId,
-                                  kVolume),
-                       response.get());
+  PrepareForMethodCall(
+      cras::kSetOutputNodeVolume,
+      base::Bind(&ExpectUint64AndInt32Arguments, kNodeId, kVolume),
+      response.get());
   // Call method.
   client()->SetOutputNodeVolume(kNodeId, kVolume);
   // Run the message loop.
@@ -904,11 +898,10 @@
   std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
 
   // Set expectations.
-  PrepareForMethodCall(cras::kSetInputNodeGain,
-                       base::Bind(&ExpectUint64AndInt32Arguments,
-                                  kNodeId,
-                                  kInputGain),
-                       response.get());
+  PrepareForMethodCall(
+      cras::kSetInputNodeGain,
+      base::Bind(&ExpectUint64AndInt32Arguments, kNodeId, kInputGain),
+      response.get());
   // Call method.
   client()->SetInputNodeGain(kNodeId, kInputGain);
   // Run the message loop.
@@ -1027,11 +1020,10 @@
   std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
 
   // Set expectations.
-  PrepareForMethodCall(cras::kSwapLeftRight,
-                       base::Bind(&ExpectUint64AndBoolArguments,
-                                  kNodeId,
-                                  kSwap),
-                       response.get());
+  PrepareForMethodCall(
+      cras::kSwapLeftRight,
+      base::Bind(&ExpectUint64AndBoolArguments, kNodeId, kSwap),
+      response.get());
   // Call method.
   client()->SwapLeftRight(kNodeId, kSwap);
   // Run the message loop.
@@ -1045,11 +1037,10 @@
   std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
 
   // Set expectations.
-  PrepareForMethodCall(cras::kSetGlobalOutputChannelRemix,
-                       base::Bind(&ExpectInt32AndArrayOfDoublesArguments,
-                                  kChannels,
-                                  kMixer),
-                       response.get());
+  PrepareForMethodCall(
+      cras::kSetGlobalOutputChannelRemix,
+      base::Bind(&ExpectInt32AndArrayOfDoublesArguments, kChannels, kMixer),
+      response.get());
 
   // Call method.
   client()->SetGlobalOutputChannelRemix(kChannels, kMixer);
diff --git a/chromeos/dbus/fake_cras_audio_client.cc b/chromeos/dbus/audio/fake_cras_audio_client.cc
similarity index 98%
rename from chromeos/dbus/fake_cras_audio_client.cc
rename to chromeos/dbus/audio/fake_cras_audio_client.cc
index 7e51b5da..778f5d64 100644
--- a/chromeos/dbus/fake_cras_audio_client.cc
+++ b/chromeos/dbus/audio/fake_cras_audio_client.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/dbus/fake_cras_audio_client.h"
+#include "chromeos/dbus/audio/fake_cras_audio_client.h"
 
 #include <utility>
 
@@ -205,7 +205,8 @@
 void FakeCrasAudioClient::SwapLeftRight(uint64_t node_id, bool swap) {}
 
 void FakeCrasAudioClient::SetGlobalOutputChannelRemix(
-    int32_t channels, const std::vector<double>& mixer) {}
+    int32_t channels,
+    const std::vector<double>& mixer) {}
 
 void FakeCrasAudioClient::AddActiveOutputNode(uint64_t node_id) {
   for (size_t i = 0; i < node_list_.size(); ++i) {
diff --git a/chromeos/dbus/fake_cras_audio_client.h b/chromeos/dbus/audio/fake_cras_audio_client.h
similarity index 94%
rename from chromeos/dbus/fake_cras_audio_client.h
rename to chromeos/dbus/audio/fake_cras_audio_client.h
index e26ff85..0915ae2 100644
--- a/chromeos/dbus/fake_cras_audio_client.h
+++ b/chromeos/dbus/audio/fake_cras_audio_client.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_DBUS_FAKE_CRAS_AUDIO_CLIENT_H_
-#define CHROMEOS_DBUS_FAKE_CRAS_AUDIO_CLIENT_H_
+#ifndef CHROMEOS_DBUS_AUDIO_FAKE_CRAS_AUDIO_CLIENT_H_
+#define CHROMEOS_DBUS_AUDIO_FAKE_CRAS_AUDIO_CLIENT_H_
 
 #include <stdint.h>
 
@@ -11,7 +11,7 @@
 
 #include "base/component_export.h"
 #include "base/macros.h"
-#include "chromeos/dbus/cras_audio_client.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 
 namespace chromeos {
 
@@ -99,4 +99,4 @@
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_DBUS_FAKE_CRAS_AUDIO_CLIENT_H_
+#endif  // CHROMEOS_DBUS_AUDIO_FAKE_CRAS_AUDIO_CLIENT_H_
diff --git a/chromeos/dbus/audio/volume_state.cc b/chromeos/dbus/audio/volume_state.cc
new file mode 100644
index 0000000..78a2211
--- /dev/null
+++ b/chromeos/dbus/audio/volume_state.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/audio/volume_state.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+
+namespace chromeos {
+
+VolumeState::VolumeState()
+    : output_volume(0),
+      output_system_mute(false),
+      input_gain(0),
+      input_mute(false),
+      output_user_mute(false) {}
+
+std::string VolumeState::ToString() const {
+  std::string result;
+  base::StringAppendF(&result, "output_volume = %d ", output_volume);
+  base::StringAppendF(&result, "output_system_mute = %s ",
+                      output_system_mute ? "true" : "false");
+  base::StringAppendF(&result, "input_gain = %d ", input_gain);
+  base::StringAppendF(&result, "input_mute = %s ",
+                      input_mute ? "true" : "false");
+  base::StringAppendF(&result, "output_user_mute = %s ",
+                      output_user_mute ? "true" : "false");
+  return result;
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/volume_state.h b/chromeos/dbus/audio/volume_state.h
similarity index 79%
rename from chromeos/dbus/volume_state.h
rename to chromeos/dbus/audio/volume_state.h
index 80e00ac..41dde91 100644
--- a/chromeos/dbus/volume_state.h
+++ b/chromeos/dbus/audio/volume_state.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_DBUS_VOLUME_STATE_H_
-#define CHROMEOS_DBUS_VOLUME_STATE_H_
+#ifndef CHROMEOS_DBUS_AUDIO_VOLUME_STATE_H_
+#define CHROMEOS_DBUS_AUDIO_VOLUME_STATE_H_
 
 #include <stdint.h>
 
@@ -26,4 +26,4 @@
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_DBUS_VOLUME_STATE_H_
+#endif  // CHROMEOS_DBUS_AUDIO_VOLUME_STATE_H_
diff --git a/chromeos/dbus/cryptohome/fake_cryptohome_client.cc b/chromeos/dbus/cryptohome/fake_cryptohome_client.cc
index 2e108ca1..587fcafb 100644
--- a/chromeos/dbus/cryptohome/fake_cryptohome_client.cc
+++ b/chromeos/dbus/cryptohome/fake_cryptohome_client.cc
@@ -47,9 +47,6 @@
 
 }  // namespace
 
-// static
-constexpr char FakeCryptohomeClient::kStubTpmPassword[] = "Stub-TPM-password";
-
 FakeCryptohomeClient::FakeCryptohomeClient()
     : service_is_available_(true),
       remove_firmware_management_parameters_from_tpm_call_count_(0),
@@ -187,6 +184,7 @@
 
 void FakeCryptohomeClient::TpmGetPassword(
     DBusMethodCallback<std::string> callback) {
+  constexpr char kStubTpmPassword[] = "Stub-TPM-password";
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback), std::string(kStubTpmPassword)));
diff --git a/chromeos/dbus/cryptohome/fake_cryptohome_client.h b/chromeos/dbus/cryptohome/fake_cryptohome_client.h
index e28d25d8..982127e 100644
--- a/chromeos/dbus/cryptohome/fake_cryptohome_client.h
+++ b/chromeos/dbus/cryptohome/fake_cryptohome_client.h
@@ -36,9 +36,6 @@
   // Checks that a FakeCryptohome instance was initialized and returns it.
   static FakeCryptohomeClient* Get();
 
-  // Expose stub password for tests.
-  static const char kStubTpmPassword[];
-
   // CryptohomeClient overrides
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
diff --git a/chromeos/dbus/volume_state.cc b/chromeos/dbus/volume_state.cc
deleted file mode 100644
index 9f105c4f..0000000
--- a/chromeos/dbus/volume_state.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/dbus/volume_state.h"
-
-#include "base/format_macros.h"
-#include "base/strings/stringprintf.h"
-
-namespace chromeos {
-
-VolumeState::VolumeState()
-    : output_volume(0),
-      output_system_mute(false),
-      input_gain(0),
-      input_mute(false),
-      output_user_mute(false) {
-}
-
-std::string VolumeState::ToString() const {
-  std::string result;
-  base::StringAppendF(&result,
-                      "output_volume = %d ",
-                      output_volume);
-  base::StringAppendF(&result,
-                      "output_system_mute = %s ",
-                      output_system_mute ? "true" : "false");
-  base::StringAppendF(&result,
-                      "input_gain = %d ",
-                      input_gain);
-  base::StringAppendF(&result,
-                      "input_mute = %s ",
-                      input_mute ? "true" : "false");
-  base::StringAppendF(&result,
-                      "output_user_mute = %s ",
-                      output_user_mute ? "true" : "false");
-  return result;
-}
-
-}  // namespace chromeos
diff --git a/components/autofill/core/common/autofill_payments_features.cc b/components/autofill/core/common/autofill_payments_features.cc
index 7563255..7f1fb17 100644
--- a/components/autofill/core/common/autofill_payments_features.cc
+++ b/components/autofill/core/common/autofill_payments_features.cc
@@ -23,6 +23,11 @@
 const base::Feature kAutofillCreditCardAblationExperiment{
     "AutofillCreditCardAblationExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables the use of platform authenticators through WebAuthn to retrieve
+// credit cards from Google payments.
+const base::Feature kAutofillCreditCardAuthentication{
+    "AutofillCreditCardAuthentication", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kAutofillCreditCardLocalCardMigration{
     "AutofillCreditCardLocalCardMigration", base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/components/autofill/core/common/autofill_payments_features.h b/components/autofill/core/common/autofill_payments_features.h
index 869a3bc3..b0062c96 100644
--- a/components/autofill/core/common/autofill_payments_features.h
+++ b/components/autofill/core/common/autofill_payments_features.h
@@ -20,6 +20,7 @@
 
 // All features in alphabetical order.
 extern const base::Feature kAutofillCreditCardAblationExperiment;
+extern const base::Feature kAutofillCreditCardAuthentication;
 extern const base::Feature kAutofillCreditCardLocalCardMigration;
 extern const base::Feature kAutofillDoNotUploadSaveUnsupportedCards;
 extern const base::Feature kAutofillDownstreamUseGooglePayBrandingOniOS;
diff --git a/components/content_capture/browser/content_capture_receiver.cc b/components/content_capture/browser/content_capture_receiver.cc
index 394869b..10b1f4c 100644
--- a/components/content_capture/browser/content_capture_receiver.cc
+++ b/components/content_capture/browser/content_capture_receiver.cc
@@ -46,6 +46,10 @@
   // We can't avoid copy the data here, because id need to be overriden.
   ContentCaptureData content(data);
   content.id = id_;
+  // Always have frame URL attached, since the ContentCaptureConsumer will
+  // be reset once activity is resumed, URL is needed to rebuild session.
+  if (!first_data)
+    content.value = frame_content_capture_data_.value;
   manager->DidCaptureContent(this, content);
 }
 
diff --git a/components/content_capture/browser/content_capture_receiver_test.cc b/components/content_capture/browser/content_capture_receiver_test.cc
index 9ada1eb1..c5476e53 100644
--- a/components/content_capture/browser/content_capture_receiver_test.cc
+++ b/components/content_capture/browser/content_capture_receiver_test.cc
@@ -121,6 +121,15 @@
     test_data2_.value = base::ASCIIToUTF16("http://foo.org/bar");
     test_data2_.bounds = gfx::Rect(10, 10);
     test_data2_.children.push_back(child);
+    // Update to test_data_.
+    ContentCaptureData child2;
+    // Have the unique id for text content.
+    child2.id = 3;
+    child2.value = base::ASCIIToUTF16("World");
+    child2.bounds = gfx::Rect(5, 10, 5, 5);
+    test_data_update_.value = base::ASCIIToUTF16("http://foo.com/bar");
+    test_data_update_.bounds = gfx::Rect(10, 10);
+    test_data_update_.children.push_back(child2);
   }
 
   void SetupChildFrame() {
@@ -143,6 +152,9 @@
 
   const ContentCaptureData& test_data() const { return test_data_; }
   const ContentCaptureData& test_data2() const { return test_data2_; }
+  const ContentCaptureData& test_data_update() const {
+    return test_data_update_;
+  }
   const std::vector<int64_t>& expected_removed_ids() const {
     return expected_removed_ids_;
   }
@@ -163,6 +175,14 @@
     return expected;
   }
 
+  ContentCaptureData GetExpectedTestDataUpdate(bool main_frame) const {
+    ContentCaptureData expected(test_data_update_);
+    // Replaces the id with expected id.
+    expected.id = ContentCaptureReceiver::GetIdFrom(main_frame ? main_frame_
+                                                               : child_frame_);
+    return expected;
+  }
+
   ContentCaptureReceiverManagerHelper* content_capture_receiver_manager_helper()
       const {
     return content_capture_receiver_manager_helper_;
@@ -213,6 +233,7 @@
   content::RenderFrameHost* child_frame_ = nullptr;
   ContentCaptureData test_data_;
   ContentCaptureData test_data2_;
+  ContentCaptureData test_data_update_;
   // Expected removed Ids.
   std::vector<int64_t> expected_removed_ids_{2};
 };
@@ -237,14 +258,14 @@
   EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
             content_capture_receiver_manager_helper()->captured_data());
   // Simulates to update the content within the same document.
-  DidCaptureContent(test_data2(), false /* first_data */);
+  DidCaptureContent(test_data_update(), false /* first_data */);
   // Verifies to get test_data2() with correct frame content id.
   EXPECT_TRUE(
       content_capture_receiver_manager_helper()->parent_session().empty());
   // Verifies that the sesssion isn't removed.
   EXPECT_TRUE(
       content_capture_receiver_manager_helper()->removed_session().empty());
-  EXPECT_EQ(GetExpectedTestData2(true /* main_frame */),
+  EXPECT_EQ(GetExpectedTestDataUpdate(true /* main_frame */),
             content_capture_receiver_manager_helper()->captured_data());
 }
 
diff --git a/components/cronet/native/sample/sample_executor.h b/components/cronet/native/sample/sample_executor.h
index df32032..f7108d7 100644
--- a/components/cronet/native/sample/sample_executor.h
+++ b/components/cronet/native/sample/sample_executor.h
@@ -24,7 +24,7 @@
   // Gets Cronet_ExecutorPtr implemented by |this|.
   Cronet_ExecutorPtr GetExecutor();
 
-  // Shuts down the executor, so all pendning tasks are destroyed without
+  // Shuts down the executor, so all pending tasks are destroyed without
   // getting executed.
   void ShutdownExecutor();
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
index 3279d3cf..ab0a87e 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
@@ -4,6 +4,7 @@
 
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
 
+#include <algorithm>
 #include <cmath>
 #include <utility>
 #include <vector>
@@ -325,7 +326,8 @@
 
   int64_t GetListPrefValue(size_t index) {
     MaybeInitialize();
-    return GetInt64PrefValue(*update_, index);
+    return std::max(GetInt64PrefValue(*update_, index),
+                    static_cast<int64_t>(0));
   }
 
  private:
diff --git a/components/flags_ui/resources/flags.css b/components/flags_ui/resources/flags.css
index 4e0d048..32d6f4d 100644
--- a/components/flags_ui/resources/flags.css
+++ b/components/flags_ui/resources/flags.css
@@ -41,8 +41,10 @@
   --link-color: var(--google-blue-700);
   --separator-color: rgba(0, 0, 0, .06);
   --toolbar-color: white;
+  --toolbar-height: 57px;
 
   background: white;
+  overflow-y: scroll;
 }
 
 html[dark] {
@@ -99,7 +101,7 @@
   display: flex;
   flex: 1;
   flex-direction: column;
-  margin: 0 auto;
+  margin: var(--toolbar-height) auto 0;
   max-width: calc(700px + 2 * var(--side-padding));
   width: 100%;
 }
@@ -132,6 +134,7 @@
   box-shadow: 0 2px 2px 0 var(--shadow-color);
   box-sizing: border-box;
   flex: none;
+  height: var(--toolbar-height);
   left: 0;
   position: fixed;
   top: 0;
@@ -408,9 +411,7 @@
   top: 0;
 }
 
-.tab:active,
-.tab:focus {
-  background: var(--toolbar-color);
+html:not(.focus-outline-visible) .tab:focus {
   outline: 0;
 }
 
diff --git a/components/omnibox/browser/vector_icons/answer_dictionary.icon b/components/omnibox/browser/vector_icons/answer_dictionary.icon
index 2d7ec5f..57b02f1 100644
--- a/components/omnibox/browser/vector_icons/answer_dictionary.icon
+++ b/components/omnibox/browser/vector_icons/answer_dictionary.icon
@@ -3,30 +3,27 @@
 // found in the LICENSE file.
 
 // Source: definition_16px.svg --> SVGOMG --> Skiafy
+// Appearance Description: A book with large bookmark.
 
-CANVAS_DIMENSIONS, 16,
-MOVE_TO, 1, 13,
-R_H_LINE_TO, 14,
-R_V_LINE_TO, 2,
-H_LINE_TO, 1,
-CLOSE,
-MOVE_TO, 13, 1,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 10,
-R_H_LINE_TO, -1,
-CLOSE,
-MOVE_TO, 5.81f, 1,
-LINE_TO, 2, 11,
-R_H_LINE_TO, 1.56f,
-R_LINE_TO, 0.78f, -2.14f,
-R_H_LINE_TO, 4.33f,
-LINE_TO, 9.44f, 11,
-H_LINE_TO, 11,
-LINE_TO, 7.2f, 1,
-H_LINE_TO, 5.81f,
-CLOSE,
-R_MOVE_TO, -0.95f, 6.43f,
-R_LINE_TO, 1.65f, -4.52f,
-R_LINE_TO, 1.65f, 4.52f,
-H_LINE_TO, 4.85f,
+CANVAS_DIMENSIONS, 16,

+MOVE_TO, 13, 1,

+H_LINE_TO, 3,

+R_CUBIC_TO, -0.6f, 0, -1, 0.4f, -1, 1,

+R_V_LINE_TO, 12,

+R_CUBIC_TO, 0, 0.6f, 0.4f, 1, 1, 1,

+R_H_LINE_TO, 10,

+R_CUBIC_TO, 0.6f, 0, 1, -0.4f, 1, -1,

+V_LINE_TO, 2,

+R_CUBIC_TO, 0, -0.6f, -0.4f, -1, -1, -1,

+CLOSE,

+R_MOVE_TO, -1, 12,

+H_LINE_TO, 4,

+V_LINE_TO, 3,

+R_H_LINE_TO, 1,

+R_V_LINE_TO, 6,

+R_LINE_TO, 2, -1.1f,

+LINE_TO, 9, 9,

+V_LINE_TO, 3,

+R_H_LINE_TO, 3,

+R_V_LINE_TO, 10,

 CLOSE
diff --git a/components/omnibox/browser/vector_icons/answer_when_is.icon b/components/omnibox/browser/vector_icons/answer_when_is.icon
index afc2d935..ea8a42bf 100644
--- a/components/omnibox/browser/vector_icons/answer_when_is.icon
+++ b/components/omnibox/browser/vector_icons/answer_when_is.icon
@@ -1,25 +1,33 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Source: time_16px.svg --> SVGOMG --> Skiafy
-
-CANVAS_DIMENSIONS, 16,
-MOVE_TO, 8, 0,
-ARC_TO, 7.99f, 7.99f, 0, 0, 0, 0, 8,
-R_CUBIC_TO, 0, 4.42f, 3.58f, 8, 8, 8,
-R_ARC_TO, 8, 8, 0, 1, 0, 0, -16,
-CLOSE,
-MOVE_TO, 8, 14,
-R_CUBIC_TO, -3.31f, 0, -6, -2.68f, -6, -6,
-R_CUBIC_TO, 0, -3.32f, 2.69f, -6, 6, -6,
-R_CUBIC_TO, 3.31f, 0, 6, 2.69f, 6, 6,
-R_CUBIC_TO, 0, 3.31f, -2.68f, 6, -6, 6,
-CLOSE,
-MOVE_TO, 8, 5,
-H_LINE_TO, 7,
-R_V_LINE_TO, 3.93f,
-LINE_TO, 10.5f, 11,
-R_LINE_TO, 0.5f, -0.81f,
-R_LINE_TO, -3, -1.75f,
-CLOSE
+// Copyright 2018 The Chromium Authors. All rights reserved.

+// Use of this source code is governed by a BSD-style license that can be

+// found in the LICENSE file.

+

+// Source: calendar_16px.svg --> SVGOMG --> Skiafy

+// Appearance Description: A calendar marking one day with a circle.

+

+CANVAS_DIMENSIONS, 16,

+CIRCLE, 10, 10, 2,

+MOVE_TO, 13.7f, 2,

+H_LINE_TO, 13,

+V_LINE_TO, 1,

+R_H_LINE_TO, -2,

+R_V_LINE_TO, 1,

+H_LINE_TO, 5,

+V_LINE_TO, 1,

+H_LINE_TO, 3,

+R_V_LINE_TO, 1,

+R_H_LINE_TO, -0.7f,

+CUBIC_TO, 1.6f, 2, 1, 2.6f, 1, 3.3f,

+R_V_LINE_TO, 10.3f,

+R_CUBIC_TO, 0, 0.8f, 0.6f, 1.4f, 1.3f, 1.4f,

+R_H_LINE_TO, 11.3f,

+R_CUBIC_TO, 0.7f, 0, 1.3f, -0.6f, 1.3f, -1.3f,

+V_LINE_TO, 3.3f,

+R_CUBIC_TO, 0.1f, -0.7f, -0.5f, -1.3f, -1.2f, -1.3f,

+CLOSE,

+MOVE_TO, 13, 13,

+H_LINE_TO, 3,

+V_LINE_TO, 5,

+R_H_LINE_TO, 10,

+R_V_LINE_TO, 8,

+CLOSE

diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index bc9134a..b6fa8404 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2097,10 +2097,15 @@
       # with the windows 8 sdk it does the wrong thing.
       "__ATLHOST_H__",
     ]
+    sources += [
+      "media/system_media_controls_notifier.cc",
+      "media/system_media_controls_notifier.h",
+    ]
     deps += [
       "//third_party/blink/public/common:font_unique_name_table_proto",
       "//third_party/iaccessible2",
       "//third_party/isimpledom",
+      "//ui/base/win/system_media_controls",
     ]
     libs += [
       "comctl32.lib",
diff --git a/content/browser/accessibility/accessibility_action_browsertest.cc b/content/browser/accessibility/accessibility_action_browsertest.cc
index d7fcd7f..925da66 100644
--- a/content/browser/accessibility/accessibility_action_browsertest.cc
+++ b/content/browser/accessibility/accessibility_action_browsertest.cc
@@ -591,4 +591,99 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(AccessibilityActionBrowserTest,
+                       AriaControlsChangedEvent) {
+  NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+
+  AccessibilityNotificationWaiter waiter(shell()->web_contents(),
+                                         ui::kAXModeComplete,
+                                         ax::mojom::Event::kLoadComplete);
+  GURL url(
+      "data:text/html,"
+      "<body>"
+      "<script>"
+      "function setcontrols(ele, event) {"
+      "  ele.setAttribute('aria-controls', 'radio1 radio2');"
+      "}"
+      "</script>"
+      "<div id='radiogroup' role='radiogroup' aria-label='group'"
+      "     onclick='setcontrols(this, event)'>"
+      "<div id='radio1' role='radio'>radio1</div>"
+      "<div id='radio2' role='radio'>radio2</div>"
+      "</div>"
+      "</body>");
+  NavigateToURL(shell(), url);
+  waiter.WaitForNotification();
+
+  BrowserAccessibility* target =
+      FindNode(ax::mojom::Role::kRadioGroup, "group");
+  ASSERT_NE(nullptr, target);
+  BrowserAccessibility* radio1 =
+      FindNode(ax::mojom::Role::kRadioButton, "radio1");
+  ASSERT_NE(nullptr, radio1);
+  BrowserAccessibility* radio2 =
+      FindNode(ax::mojom::Role::kRadioButton, "radio2");
+  ASSERT_NE(nullptr, radio2);
+
+  AccessibilityNotificationWaiter waiter2(
+      shell()->web_contents(), ui::kAXModeComplete,
+      ui::AXEventGenerator::Event::CONTROLS_CHANGED);
+  GetManager()->DoDefaultAction(*target);
+  waiter2.WaitForNotification();
+
+  auto&& control_list = target->GetData().GetIntListAttribute(
+      ax::mojom::IntListAttribute::kControlsIds);
+  EXPECT_EQ(2u, control_list.size());
+
+  auto find_radio1 =
+      std::find(control_list.cbegin(), control_list.cend(), radio1->GetId());
+  auto find_radio2 =
+      std::find(control_list.cbegin(), control_list.cend(), radio2->GetId());
+  EXPECT_NE(find_radio1, control_list.cend());
+  EXPECT_NE(find_radio2, control_list.cend());
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityActionBrowserTest, FocusLostOnDeletedNode) {
+  NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+
+  GURL url(
+      "data:text/html,"
+      "<button id='1'>1</button>"
+      "<iframe id='iframe' srcdoc=\""
+      "<button id='2'>2</button>"
+      "\"></iframe>");
+
+  NavigateToURL(shell(), url);
+  EnableAccessibilityForWebContents(shell()->web_contents());
+
+  auto FocusNodeAndReload = [this, &url](const std::string& node_name,
+                                         const std::string& focus_node_script) {
+    WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
+                                                  node_name);
+    BrowserAccessibility* node = FindNode(ax::mojom::Role::kButton, node_name);
+    ASSERT_NE(nullptr, node);
+
+    EXPECT_TRUE(ExecuteScript(shell(), focus_node_script));
+    WaitForAccessibilityFocusChange();
+
+    EXPECT_EQ(node->GetId(),
+              GetFocusedAccessibilityNodeInfo(shell()->web_contents()).id);
+
+    // Reloading the frames will achieve two things:
+    //   1. Force the deletion of the node being tested.
+    //   2. Lose focus on the node by focusing a new frame.
+    AccessibilityNotificationWaiter load_waiter(
+        shell()->web_contents(), ui::kAXModeComplete,
+        ax::mojom::Event::kLoadComplete);
+    NavigateToURL(shell(), url);
+    load_waiter.WaitForNotification();
+  };
+
+  FocusNodeAndReload("1", "document.getElementById('1').focus();");
+  FocusNodeAndReload("2",
+                     "var iframe = document.getElementById('iframe');"
+                     "var inner_doc = iframe.contentWindow.document;"
+                     "inner_doc.getElementById('2').focus();");
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/accessibility_tree_formatter_blink.cc b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
index 9905afa0..ecbc5a0 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_blink.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
@@ -223,8 +223,8 @@
   dict->SetInteger("boundsWidth", bounds.width());
   dict->SetInteger("boundsHeight", bounds.height());
 
-  bool offscreen = false;
-  gfx::Rect page_bounds = node.GetPageBoundsRect(&offscreen);
+  ui::AXOffscreenResult offscreen_result = ui::AXOffscreenResult::kOnscreen;
+  gfx::Rect page_bounds = node.GetClippedRootFrameBoundsRect(&offscreen_result);
   dict->SetInteger("pageBoundsX", page_bounds.x());
   dict->SetInteger("pageBoundsY", page_bounds.y());
   dict->SetInteger("pageBoundsWidth", page_bounds.width());
@@ -234,7 +234,8 @@
                    node.GetData().relative_bounds.transform &&
                        !node.GetData().relative_bounds.transform->IsIdentity());
 
-  gfx::Rect unclipped_bounds = node.GetPageBoundsRect(&offscreen, false);
+  gfx::Rect unclipped_bounds =
+      node.GetUnclippedRootFrameBoundsRect(&offscreen_result);
   dict->SetInteger("unclippedBoundsX", unclipped_bounds.x());
   dict->SetInteger("unclippedBoundsY", unclipped_bounds.y());
   dict->SetInteger("unclippedBoundsWidth", unclipped_bounds.width());
@@ -248,7 +249,7 @@
       dict->SetBoolean(ui::ToString(state), true);
   }
 
-  if (offscreen)
+  if (offscreen_result == ui::AXOffscreenResult::kOffscreen)
     dict->SetBoolean(STATE_OFFSCREEN, true);
 
   for (int32_t attr_index =
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index cd47876..baf9f95 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -351,56 +351,117 @@
   return GetData().html_attributes;
 }
 
-gfx::Rect BrowserAccessibility::GetFrameBoundsRect() const {
-  return RelativeToAbsoluteBounds(gfx::RectF(), true);
+gfx::Rect BrowserAccessibility::GetClippedScreenBoundsRect(
+    ui::AXOffscreenResult* offscreen_result) const {
+  return GetBoundsRect(ui::AXCoordinateSystem::kScreen,
+                       ui::AXClippingBehavior::kClipped, offscreen_result);
 }
 
-gfx::Rect BrowserAccessibility::GetPageBoundsRect(bool* offscreen,
-                                                  bool clip_bounds) const {
-  return RelativeToAbsoluteBounds(gfx::RectF(), false, offscreen, clip_bounds);
+gfx::Rect BrowserAccessibility::GetUnclippedScreenBoundsRect(
+    ui::AXOffscreenResult* offscreen_result) const {
+  return GetBoundsRect(ui::AXCoordinateSystem::kScreen,
+                       ui::AXClippingBehavior::kUnclipped, offscreen_result);
 }
 
-gfx::Rect BrowserAccessibility::GetTextRangeBoundsRect(
-    int start_offset,
-    int end_offset,
-    ui::AXPlatformNodeDelegate::TextRangeBoundsCoordinateSystem
-        coordinate_system) const {
+gfx::Rect BrowserAccessibility::GetClippedRootFrameBoundsRect(
+    ui::AXOffscreenResult* offscreen_result) const {
+  return GetBoundsRect(ui::AXCoordinateSystem::kRootFrame,
+                       ui::AXClippingBehavior::kClipped, offscreen_result);
+}
+
+gfx::Rect BrowserAccessibility::GetUnclippedRootFrameBoundsRect(
+    ui::AXOffscreenResult* offscreen_result) const {
+  return GetBoundsRect(ui::AXCoordinateSystem::kRootFrame,
+                       ui::AXClippingBehavior::kUnclipped, offscreen_result);
+}
+
+gfx::Rect BrowserAccessibility::GetClippedFrameBoundsRect(
+    ui::AXOffscreenResult* offscreen_result) const {
+  return GetBoundsRect(ui::AXCoordinateSystem::kFrame,
+                       ui::AXClippingBehavior::kUnclipped, offscreen_result);
+}
+
+gfx::Rect BrowserAccessibility::GetUnclippedScreenRangeBoundsRect(
+    const int start_offset,
+    const int end_offset,
+    ui::AXOffscreenResult* offscreen_result) const {
+  return GetRangeBoundsRect(
+      start_offset, end_offset, ui::AXCoordinateSystem::kScreen,
+      ui::AXClippingBehavior::kUnclipped, offscreen_result);
+}
+
+gfx::Rect BrowserAccessibility::GetUnclippedRootFrameRangeBoundsRect(
+    const int start_offset,
+    const int end_offset,
+    ui::AXOffscreenResult* offscreen_result) const {
+  return GetRangeBoundsRect(
+      start_offset, end_offset, ui::AXCoordinateSystem::kRootFrame,
+      ui::AXClippingBehavior::kUnclipped, offscreen_result);
+}
+
+gfx::Rect BrowserAccessibility::GetBoundsRect(
+    const ui::AXCoordinateSystem coordinate_system,
+    const ui::AXClippingBehavior clipping_behavior,
+    ui::AXOffscreenResult* offscreen_result) const {
+  return RelativeToAbsoluteBounds(gfx::RectF(), coordinate_system,
+                                  clipping_behavior, offscreen_result);
+}
+
+gfx::Rect BrowserAccessibility::GetRangeBoundsRect(
+    const int start_offset,
+    const int end_offset,
+    const ui::AXCoordinateSystem coordinate_system,
+    const ui::AXClippingBehavior clipping_behavior,
+    ui::AXOffscreenResult* offscreen_result) const {
+  int effective_start_offset = start_offset;
+  int effective_end_offset = end_offset;
+
+  if (effective_start_offset == effective_end_offset)
+    return gfx::Rect();
+  if (effective_start_offset > effective_end_offset)
+    std::swap(effective_start_offset, effective_end_offset);
+
   const base::string16& text_str = GetText();
-  if (start_offset == end_offset)
+  if (effective_start_offset < 0 ||
+      effective_start_offset >= static_cast<int>(text_str.size()))
     return gfx::Rect();
-
-  if (start_offset > end_offset)
-    std::swap(start_offset, end_offset);
-
-  if (start_offset < 0 || start_offset >= static_cast<int>(text_str.size()))
-    return gfx::Rect();
-  if (end_offset < 0 || end_offset > static_cast<int>(text_str.size()))
+  if (effective_end_offset < 0 ||
+      effective_end_offset > static_cast<int>(text_str.size()))
     return gfx::Rect();
 
   switch (coordinate_system) {
-    case ui::AXPlatformNodeDelegate::TextRangeBoundsCoordinateSystem::Screen:
-      return GetScreenBoundsForRange(start_offset, end_offset - start_offset);
-    case ui::AXPlatformNodeDelegate::Window:
-      return GetPageBoundsForRange(start_offset, end_offset - start_offset);
-    case ui::AXPlatformNodeDelegate::Parent:
-      if (!PlatformGetParent())
-        return gfx::Rect();
-      return GetPageBoundsForRange(start_offset, end_offset - start_offset) -
-             PlatformGetParent()->GetPageBoundsRect().OffsetFromOrigin();
+    case ui::AXCoordinateSystem::kScreen: {
+      gfx::Rect bounds = GetRootFrameRangeBoundsRect(
+          effective_start_offset, effective_end_offset - effective_start_offset,
+          clipping_behavior, offscreen_result);
+      bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin());
+      return bounds;
+    }
+    case ui::AXCoordinateSystem::kRootFrame:
+      return GetRootFrameRangeBoundsRect(
+          effective_start_offset, effective_end_offset - effective_start_offset,
+          clipping_behavior, offscreen_result);
+    case ui::AXCoordinateSystem::kFrame:
+      NOTIMPLEMENTED();
+      return gfx::Rect();
   }
 }
 
-gfx::Rect BrowserAccessibility::GetPageBoundsForRange(int start,
-                                                      int len,
-                                                      bool clipped) const {
+gfx::Rect BrowserAccessibility::GetRootFrameRangeBoundsRect(
+    int start,
+    int len,
+    const ui::AXClippingBehavior clipping_behavior,
+    ui::AXOffscreenResult* offscreen_result) const {
   DCHECK_GE(start, 0);
   DCHECK_GE(len, 0);
 
   // Standard text fields such as textarea have an embedded div inside them that
   // holds all the text.
   // TODO(nektar): This is fragile! Replace with code that flattens tree.
-  if (IsPlainTextField() && InternalChildCount() == 1)
-    return InternalGetChild(0)->GetPageBoundsForRange(start, len);
+  if (IsPlainTextField() && InternalChildCount() == 1) {
+    return InternalGetChild(0)->GetRootFrameRangeBoundsRect(
+        start, len, clipping_behavior, offscreen_result);
+  }
 
   if (GetRole() != ax::mojom::Role::kStaticText) {
     gfx::Rect bounds;
@@ -414,10 +475,12 @@
       if (start < child_length_in_parent) {
         gfx::Rect child_rect;
         if (child->IsTextOnlyObject()) {
-          child_rect = child->GetPageBoundsForRange(start, len);
+          child_rect = child->GetRootFrameRangeBoundsRect(
+              start, len, clipping_behavior, offscreen_result);
         } else {
-          child_rect = child->GetPageBoundsForRange(
-              0, static_cast<int>(child->GetText().size()));
+          child_rect = child->GetRootFrameRangeBoundsRect(
+              0, static_cast<int>(child->GetText().size()), clipping_behavior,
+              offscreen_result);
         }
         bounds.Union(child_rect);
         len -= (child_length_in_parent - start);
@@ -429,7 +492,9 @@
     }
     // When past the end of text, the area will be 0.
     // In this case, use bounds provided for the caret.
-    return bounds.IsEmpty() ? GetPageBoundsPastEndOfText() : bounds;
+    return bounds.IsEmpty() ? GetRootFrameBoundsPastEndOfText(clipping_behavior,
+                                                              offscreen_result)
+                            : bounds;
   }
 
   int end = start + len;
@@ -516,8 +581,8 @@
     // Don't clip bounds. Some screen magnifiers (e.g. ZoomText) prefer to
     // get unclipped bounds so that they can make smooth scrolling calculations.
     gfx::Rect absolute_child_rect = child->RelativeToAbsoluteBounds(
-        child_overlap_rect, false /* frame_only */, nullptr /* offscreen */,
-        clipped /* clip_bounds */);
+        child_overlap_rect, ui::AXCoordinateSystem::kRootFrame,
+        clipping_behavior, offscreen_result);
     if (bounds.width() == 0 && bounds.height() == 0) {
       bounds = absolute_child_rect;
     } else {
@@ -528,10 +593,13 @@
   return bounds;
 }
 
-gfx::Rect BrowserAccessibility::GetScreenBoundsForRange(int start,
-                                                        int len,
-                                                        bool clipped) const {
-  gfx::Rect bounds = GetPageBoundsForRange(start, len, clipped);
+gfx::Rect BrowserAccessibility::GetScreenRangeBoundsRect(
+    int start,
+    int len,
+    const ui::AXClippingBehavior clipping_behavior,
+    ui::AXOffscreenResult* offscreen_result) const {
+  gfx::Rect bounds = GetRootFrameRangeBoundsRect(start, len, clipping_behavior,
+                                                 offscreen_result);
 
   // Adjust the bounds by the top left corner of the containing view's bounds
   // in screen coordinates.
@@ -540,10 +608,9 @@
   return bounds;
 }
 
-// Get a rect for a 1-width character past the end of text. This is what ATs
-// expect when getting the character extents past the last character in a line,
-// and equals what the caret bounds would be when past the end of the text.
-gfx::Rect BrowserAccessibility::GetPageBoundsPastEndOfText() const {
+gfx::Rect BrowserAccessibility::GetRootFrameBoundsPastEndOfText(
+    const ui::AXClippingBehavior clipping_behavior,
+    ui::AXOffscreenResult* offscreen_result) const {
   // Step 1: get approximate caret bounds. The thickness may not yet be correct.
   gfx::Rect bounds;
   if (InternalChildCount() > 0) {
@@ -551,12 +618,14 @@
     // available, and then correct for thickness of caret.
     BrowserAccessibility* child = InternalGetChild(InternalChildCount() - 1);
     int child_text_len = child->GetText().size();
-    bounds = child->GetPageBoundsForRange(child_text_len, child_text_len);
+    bounds = child->GetRootFrameRangeBoundsRect(
+        child_text_len, child_text_len, clipping_behavior, offscreen_result);
     if (bounds.width() == 0 && bounds.height() == 0)
       return bounds;  // Inline text boxes info not yet available.
   } else {
     // Compute bounds of where caret would be, based on bounds of object.
-    bounds = GetPageBoundsRect();
+    bounds = GetBoundsRect(ui::AXCoordinateSystem::kRootFrame,
+                           clipping_behavior, offscreen_result);
   }
 
   // Step 2: correct for the thickness of the caret.
@@ -928,13 +997,16 @@
 
 gfx::Rect BrowserAccessibility::RelativeToAbsoluteBounds(
     gfx::RectF bounds,
-    bool frame_only,
-    bool* offscreen,
-    bool clip_bounds) const {
+    const ui::AXCoordinateSystem coordinate_system,
+    const ui::AXClippingBehavior clipping_behavior,
+    ui::AXOffscreenResult* offscreen_result) const {
+  const bool clip_bounds =
+      clipping_behavior == ui::AXClippingBehavior::kClipped;
+  bool offscreen = false;
   const BrowserAccessibility* node = this;
   while (node) {
     bounds = node->manager()->ax_tree()->RelativeToTreeBounds(
-        node->node(), bounds, offscreen, clip_bounds);
+        node->node(), bounds, &offscreen, clip_bounds);
 
     // On some platforms we need to unapply root scroll offsets.
     const BrowserAccessibility* root = node->manager()->GetRoot();
@@ -948,19 +1020,28 @@
       }
     }
 
-    if (frame_only)
+    if (coordinate_system == ui::AXCoordinateSystem::kFrame)
       break;
 
     node = root->PlatformGetParent();
   }
 
+  if (coordinate_system == ui::AXCoordinateSystem::kScreen)
+    bounds.Offset(manager()->GetViewBounds().OffsetFromOrigin());
+
+  if (offscreen_result) {
+    *offscreen_result = offscreen ? ui::AXOffscreenResult::kOffscreen
+                                  : ui::AXOffscreenResult::kOnscreen;
+  }
+
   return gfx::ToEnclosingRect(bounds);
 }
 
 bool BrowserAccessibility::IsOffscreen() const {
-  bool offscreen = false;
-  RelativeToAbsoluteBounds(gfx::RectF(), false, &offscreen);
-  return offscreen;
+  ui::AXOffscreenResult offscreen_result = ui::AXOffscreenResult::kOnscreen;
+  RelativeToAbsoluteBounds(gfx::RectF(), ui::AXCoordinateSystem::kRootFrame,
+                           ui::AXClippingBehavior::kClipped, &offscreen_result);
+  return offscreen_result == ui::AXOffscreenResult::kOffscreen;
 }
 
 bool BrowserAccessibility::IsWebContent() const {
@@ -1154,26 +1235,6 @@
   return child->GetNativeViewAccessible();
 }
 
-gfx::Rect BrowserAccessibility::GetClippedScreenBoundsRect() const {
-  gfx::Rect bounds = GetPageBoundsRect(nullptr, true);
-
-  // Adjust the bounds by the top left corner of the containing view's bounds
-  // in screen coordinates.
-  bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin());
-
-  return bounds;
-}
-
-gfx::Rect BrowserAccessibility::GetUnclippedScreenBoundsRect() const {
-  gfx::Rect bounds = GetPageBoundsRect(nullptr, false);
-
-  // Adjust the bounds by the top left corner of the containing view's bounds
-  // in screen coordinates.
-  bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin());
-
-  return bounds;
-}
-
 gfx::NativeViewAccessible BrowserAccessibility::HitTestSync(int x, int y) {
   auto* accessible = manager_->CachingAsyncHitTest(gfx::Point(x, y));
   if (!accessible)
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 2d07fcf..b4b9189e 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -159,33 +159,46 @@
   // Returns nullptr if there are no children.
   BrowserAccessibility* InternalDeepestLastChild() const;
 
-  // Returns the bounds of this object in coordinates relative to this frame.
-  gfx::Rect GetFrameBoundsRect() const;
+  // Derivative utils for AXPlatformNodeDelegate::GetBoundsRect
+  gfx::Rect GetClippedScreenBoundsRect(
+      ui::AXOffscreenResult* offscreen_result = nullptr) const;
+  gfx::Rect GetUnclippedScreenBoundsRect(
+      ui::AXOffscreenResult* offscreen_result = nullptr) const;
+  gfx::Rect GetClippedRootFrameBoundsRect(
+      ui::AXOffscreenResult* offscreen_result = nullptr) const;
+  gfx::Rect GetUnclippedRootFrameBoundsRect(
+      ui::AXOffscreenResult* offscreen_result = nullptr) const;
+  gfx::Rect GetClippedFrameBoundsRect(
+      ui::AXOffscreenResult* offscreen_result = nullptr) const;
 
-  // Returns the bounds of this object in coordinates relative to the
-  // page (specifically, the top-left corner of the topmost web contents).
-  // Optionally updates |offscreen| to be true if the element is offscreen
-  // within its page. Clips bounds by default unless |clip_bounds| is false.
-  gfx::Rect GetPageBoundsRect(bool* offscreen = nullptr,
-                              bool clip_bounds = true) const;
+  // Derivative utils for AXPlatformNodeDelegate::GetRangeBoundsRect
+  gfx::Rect GetUnclippedScreenRangeBoundsRect(
+      const int start_offset,
+      const int end_offset,
+      ui::AXOffscreenResult* offscreen_result = nullptr) const;
+  gfx::Rect GetUnclippedRootFrameRangeBoundsRect(
+      const int start_offset,
+      const int end_offset,
+      ui::AXOffscreenResult* offscreen_result = nullptr) const;
+
+  // DEPRECATED: Prefer using the interfaces provided by AXPlatformNodeDelegate
+  // when writing new code.
+  gfx::Rect GetScreenRangeBoundsRect(
+      int start,
+      int len,
+      const ui::AXClippingBehavior clipping_behavior,
+      ui::AXOffscreenResult* offscreen_result = nullptr) const;
 
   // Returns the bounds of the given range in coordinates relative to the
-  // top-left corner of the overall web area. Only valid when the
-  // role is WebAXRoleStaticText.
-  gfx::Rect GetPageBoundsForRange(int start,
-                                  int len,
-                                  bool clipped = false) const;
-
-  // Convert a bounding rectangle from this node's coordinate system
-  // (which is relative to its nearest scrollable ancestor) to
-  // absolute bounds, either in page coordinates (when |frameOnly| is
-  // false), or in frame coordinates (when |frameOnly| is true).
-  // Updates optional |offscreen| to be true if the node is offscreen.
-  // If |clip_bounds| is set to false, will return unclipped bounds.
-  virtual gfx::Rect RelativeToAbsoluteBounds(gfx::RectF bounds,
-                                             bool frame_only,
-                                             bool* offscreen = nullptr,
-                                             bool clip_bounds = true) const;
+  // top-left corner of the overall web area. Only valid when the role is
+  // WebAXRoleStaticText.
+  // DEPRECATED (for public use): Prefer using the interfaces provided by
+  // AXPlatformNodeDelegate when writing new non-private code.
+  gfx::Rect GetRootFrameRangeBoundsRect(
+      int start,
+      int len,
+      const ui::AXClippingBehavior clipping_behavior,
+      ui::AXOffscreenResult* offscreen_result = nullptr) const;
 
   // This is to handle the cases such as ARIA textbox, where the value should
   // be calculated from the object's inner text.
@@ -355,16 +368,16 @@
   gfx::NativeViewAccessible GetParent() override;
   int GetChildCount() override;
   gfx::NativeViewAccessible ChildAtIndex(int index) override;
-  gfx::Rect GetClippedScreenBoundsRect() const override;
-  gfx::Rect GetUnclippedScreenBoundsRect() const override;
-  gfx::Rect GetScreenBoundsForRange(int start,
-                                    int len,
-                                    bool clipped = false) const override;
-  gfx::Rect GetTextRangeBoundsRect(
-      int start_offset,
-      int end_offset,
-      ui::AXPlatformNodeDelegate::TextRangeBoundsCoordinateSystem
-          coordinate_system) const override;
+  gfx::Rect GetBoundsRect(
+      const ui::AXCoordinateSystem coordinate_system,
+      const ui::AXClippingBehavior clipping_behavior,
+      ui::AXOffscreenResult* offscreen_result = nullptr) const override;
+  gfx::Rect GetRangeBoundsRect(
+      const int start_offset,
+      const int end_offset,
+      const ui::AXCoordinateSystem coordinate_system,
+      const ui::AXClippingBehavior clipping_behavior,
+      ui::AXOffscreenResult* offscreen_result = nullptr) const override;
   gfx::NativeViewAccessible HitTestSync(int x, int y) override;
   gfx::NativeViewAccessible GetFocus() override;
   ui::AXPlatformNode* GetFromNodeID(int32_t id) override;
@@ -457,7 +470,27 @@
   // text, depending on the platform.
   base::string16 GetInnerText() const;
 
-  gfx::Rect GetPageBoundsPastEndOfText() const;
+  // Return the bounds after converting from this node's coordinate system
+  // (which is relative to its nearest scrollable ancestor) to the coordinate
+  // system specified. If the clipping behavior is set to clipped, clipping is
+  // applied to all bounding boxes so that the resulting rect is within the
+  // window. If the clipping behavior is unclipped, the resulting rect may be
+  // outside of the window or offscreen. If an offscreen result address is
+  // provided, it will be populated depending on whether the returned bounding
+  // box is onscreen or offscreen.
+  gfx::Rect RelativeToAbsoluteBounds(
+      gfx::RectF bounds,
+      const ui::AXCoordinateSystem coordinate_system,
+      const ui::AXClippingBehavior clipping_behavior,
+      ui::AXOffscreenResult* offscreen_result) const;
+
+  // Return a rect for a 1-width character past the end of text. This is what
+  // ATs expect when getting the character extents past the last character in a
+  // line, and equals what the caret bounds would be when past the end of the
+  // text.
+  gfx::Rect GetRootFrameBoundsPastEndOfText(
+      const ui::AXClippingBehavior clipping_behavior,
+      ui::AXOffscreenResult* offscreen_result = nullptr) const;
 
   // Given a set of node ids, return the nodes in this delegate's tree to
   // which they correspond.
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index 761b7832..1e076ad 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -1215,18 +1215,18 @@
     // If this is a web area inside of an iframe, try to use the bounds of
     // the containing element.
     BrowserAccessibility* parent = PlatformGetParent();
-    while (parent && (parent->GetPageBoundsRect().width() == 0 ||
-                      parent->GetPageBoundsRect().height() == 0)) {
+    while (parent && (parent->GetClippedRootFrameBoundsRect().width() == 0 ||
+                      parent->GetClippedRootFrameBoundsRect().height() == 0)) {
       parent = parent->PlatformGetParent();
     }
     if (parent)
-      bounds = parent->GetPageBoundsRect();
+      bounds = parent->GetClippedRootFrameBoundsRect();
     else
-      bounds = GetPageBoundsRect();
+      bounds = GetClippedRootFrameBoundsRect();
   } else {
     // Otherwise this is something like a scrollable div, just use the
     // bounds of this object itself.
-    bounds = GetPageBoundsRect();
+    bounds = GetClippedRootFrameBoundsRect();
   }
 
   // Scroll by 80% of one page.
@@ -1526,7 +1526,7 @@
       CHECK_EQ(ax::mojom::Role::kInlineTextBox, child->GetRole());
       // TODO(dmazzoni): replace this with a proper API to determine
       // if two inline text boxes are on the same line. http://crbug.com/421771
-      int y = child->GetPageBoundsRect().y();
+      int y = child->GetClippedRootFrameBoundsRect().y();
       if (i == 0) {
         line_starts->push_back(offset);
       } else if (y != last_y) {
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 864129f..5759578 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -1517,7 +1517,7 @@
 - (NSPoint)origin {
   if (![self instanceActive])
     return NSMakePoint(0, 0);
-  gfx::Rect bounds = owner_->GetPageBoundsRect();
+  gfx::Rect bounds = owner_->GetClippedRootFrameBoundsRect();
   return NSMakePoint(bounds.x(), bounds.y());
 }
 
@@ -2063,7 +2063,7 @@
 - (NSValue*)size {
   if (![self instanceActive])
     return nil;
-  gfx::Rect bounds = owner_->GetPageBoundsRect();
+  gfx::Rect bounds = owner_->GetClippedRootFrameBoundsRect();
   return [NSValue valueWithSize:NSMakeSize(bounds.width(), bounds.height())];
 }
 
@@ -2675,7 +2675,7 @@
       return nil;
     NSRange range = [(NSValue*)parameter rangeValue];
     gfx::Rect rect =
-        owner_->GetScreenBoundsForRange(range.location, range.length);
+        owner_->GetUnclippedScreenRangeBoundsRect(range.location, range.length);
     NSRect nsrect = [self rectInScreen:rect];
     return [NSValue valueWithRect:nsrect];
   }
@@ -2734,7 +2734,7 @@
     DCHECK_GE(startOffset, 0);
     DCHECK_GE(endOffset, 0);
 
-    gfx::Rect rect = BrowserAccessibilityManager::GetPageBoundsForRange(
+    gfx::Rect rect = BrowserAccessibilityManager::GetRootFrameRangeBoundsRect(
         *startObject, startOffset, *endObject, endOffset);
     NSRect nsrect = [self rectInScreen:rect];
     return [NSValue valueWithRect:nsrect];
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc
index 42141e7..b9f2412 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -186,10 +186,10 @@
     *x = bounds.x();
     *y = bounds.y();
   } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
-    gfx::Rect bounds = owner()->GetPageBoundsRect();
+    gfx::Rect bounds = owner()->GetClippedRootFrameBoundsRect();
     gfx::Rect parent_bounds =
         owner()->PlatformGetParent()
-            ? owner()->PlatformGetParent()->GetPageBoundsRect()
+            ? owner()->PlatformGetParent()->GetClippedRootFrameBoundsRect()
             : gfx::Rect();
     *x = bounds.x() - parent_bounds.x();
     *y = bounds.y() - parent_bounds.y();
@@ -209,8 +209,8 @@
   if (!height || !width)
     return E_INVALIDARG;
 
-  *height = owner()->GetPageBoundsRect().height();
-  *width = owner()->GetPageBoundsRect().width();
+  *height = owner()->GetClippedRootFrameBoundsRect().height();
+  *width = owner()->GetClippedRootFrameBoundsRect().width();
   return S_OK;
 }
 
@@ -249,13 +249,15 @@
 
   gfx::Rect character_bounds;
   if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
-    character_bounds = owner()->GetScreenBoundsForRange(offset, 1);
+    character_bounds = owner()->GetScreenRangeBoundsRect(
+        offset, 1, ui::AXClippingBehavior::kUnclipped);
   } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
-    character_bounds = owner()->GetPageBoundsForRange(offset, 1);
+    character_bounds = owner()->GetRootFrameRangeBoundsRect(
+        offset, 1, ui::AXClippingBehavior::kUnclipped);
     if (owner()->PlatformGetParent()) {
       character_bounds -= owner()
                               ->PlatformGetParent()
-                              ->GetPageBoundsRect(nullptr, false)
+                              ->GetUnclippedRootFrameBoundsRect()
                               .OffsetFromOrigin();
     }
   } else {
@@ -532,10 +534,10 @@
   LONG length = end_index - start_index + 1;
   DCHECK_GE(length, 0);
 
-  gfx::Rect string_bounds = owner()->GetPageBoundsForRange(start_index, length);
-
+  gfx::Rect string_bounds = owner()->GetRootFrameRangeBoundsRect(
+      start_index, length, ui::AXClippingBehavior::kUnclipped);
   string_bounds -=
-      owner()->GetPageBoundsRect(nullptr, false).OffsetFromOrigin();
+      owner()->GetUnclippedRootFrameBoundsRect().OffsetFromOrigin();
   x -= string_bounds.x();
   y -= string_bounds.y();
 
@@ -1476,8 +1478,8 @@
     return E_INVALIDARG;
   }
 
-  gfx::Rect bounds =
-      owner()->GetScreenBoundsForRange(start_index, end_index - start_index);
+  gfx::Rect bounds = owner()->GetScreenRangeBoundsRect(
+      start_index, end_index - start_index, ui::AXClippingBehavior::kUnclipped);
   *out_x = bounds.x();
   *out_y = bounds.y();
   *out_width = bounds.width();
@@ -1506,7 +1508,8 @@
 
   manager->ScrollToMakeVisible(
       *owner(),
-      owner()->GetPageBoundsForRange(start_index, end_index - start_index));
+      owner()->GetRootFrameRangeBoundsRect(start_index, end_index - start_index,
+                                           ui::AXClippingBehavior::kUnclipped));
 
   return S_OK;
 }
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index d785b61..5d26862 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -156,8 +156,6 @@
       factory_(factory),
       tree_(new ui::AXSerializableTree()),
       user_is_navigating_away_(false),
-      last_focused_node_(nullptr),
-      last_focused_manager_(nullptr),
       connected_to_parent_tree_node_(false),
       ax_tree_id_(ui::AXTreeIDUnknown()),
       device_scale_factor_(1.0f),
@@ -174,8 +172,6 @@
       factory_(factory),
       tree_(new ui::AXSerializableTree()),
       user_is_navigating_away_(false),
-      last_focused_node_(nullptr),
-      last_focused_manager_(nullptr),
       ax_tree_id_(ui::AXTreeIDUnknown()),
       device_scale_factor_(1.0f),
       use_custom_device_scale_factor_for_testing_(false),
@@ -214,6 +210,13 @@
     false;
 
 // static
+base::Optional<int32_t> BrowserAccessibilityManager::last_focused_node_id_ = {};
+
+// static
+base::Optional<ui::AXTreeID>
+    BrowserAccessibilityManager::last_focused_node_tree_id_ = {};
+
+// static
 ui::AXTreeUpdate BrowserAccessibilityManager::GetEmptyDocument() {
   ui::AXNodeData empty_document;
   empty_document.id = 0;
@@ -247,15 +250,14 @@
     focus = nullptr;
   }
 
-  if (focus != last_focused_node_) {
-    if (last_focused_node_)
-      OnFocusLost(last_focused_node_);
+  BrowserAccessibility* last_focused_node = GetLastFocusedNode();
+  if (focus != last_focused_node) {
+    if (last_focused_node)
+      OnFocusLost(last_focused_node);
     if (focus)
       FireFocusEvent(focus);
   }
-
-  last_focused_node_ = focus;
-  last_focused_manager_ = focus ? focus->manager() : nullptr;
+  SetLastFocusedNode(focus);
 }
 
 bool BrowserAccessibilityManager::CanFireEvents() {
@@ -343,10 +345,8 @@
 }
 
 void BrowserAccessibilityManager::OnWindowBlurred() {
-  if (IsRootTree()) {
-    last_focused_node_ = nullptr;
-    last_focused_manager_ = nullptr;
-  }
+  if (IsRootTree())
+    SetLastFocusedNode(nullptr);
 }
 
 void BrowserAccessibilityManager::UserIsNavigatingAway() {
@@ -402,7 +402,8 @@
   }
 
   // If this page is hidden by an interstitial, suppress all events.
-  if (GetRootManager()->hidden_by_interstitial_page()) {
+  BrowserAccessibilityManager* root_manager = GetRootManager();
+  if (root_manager->hidden_by_interstitial_page()) {
     event_generator_.ClearEvents();
     return;
   }
@@ -425,7 +426,7 @@
   // Screen readers might not do the right thing if they're not aware of what
   // has focus, so always try that first. Nothing will be fired if the window
   // itself isn't focused or if focus hasn't changed.
-  GetRootManager()->FireFocusEventsIfNeeded();
+  root_manager->FireFocusEventsIfNeeded();
 
   // Fire any events related to changes to the tree.
   for (auto targeted_event : event_generator_) {
@@ -457,7 +458,7 @@
       continue;
 
     if (event.event_type == ax::mojom::Event::kHover)
-      GetRootManager()->CacheHitTestResult(event_target);
+      root_manager->CacheHitTestResult(event_target);
 
     FireBlinkEvent(event.event_type, event_target);
   }
@@ -1090,7 +1091,7 @@
 }
 
 // static
-gfx::Rect BrowserAccessibilityManager::GetPageBoundsForRange(
+gfx::Rect BrowserAccessibilityManager::GetRootFrameRangeBoundsRect(
     const BrowserAccessibility& start_object,
     int start_offset,
     const BrowserAccessibility& end_object,
@@ -1107,8 +1108,9 @@
       return gfx::Rect();
     }
 
-    return start_object.GetPageBoundsForRange(start_offset,
-                                              end_offset - start_offset);
+    return start_object.GetRootFrameRangeBoundsRect(
+        start_offset, end_offset - start_offset,
+        ui::AXClippingBehavior::kUnclipped);
   }
 
   gfx::Rect result;
@@ -1137,10 +1139,11 @@
         start_char_index = start_offset;
       if (current == last)
         end_char_index = end_offset;
-      result.Union(current->GetPageBoundsForRange(
-          start_char_index, end_char_index - start_char_index));
+      result.Union(current->GetRootFrameRangeBoundsRect(
+          start_char_index, end_char_index - start_char_index,
+          ui::AXClippingBehavior::kUnclipped));
     } else {
-      result.Union(current->GetPageBoundsRect());
+      result.Union(current->GetClippedRootFrameBoundsRect());
     }
 
     if (current == last)
@@ -1156,12 +1159,10 @@
                                                       ui::AXNode* node) {
   DCHECK(node);
   if (BrowserAccessibility* wrapper = GetFromAXNode(node)) {
-    if (wrapper == last_focused_node_) {
-      last_focused_node_ = nullptr;
-      last_focused_manager_ = nullptr;
-    }
-    wrapper->Destroy();
+    if (wrapper == GetLastFocusedNode())
+      SetLastFocusedNode(nullptr);
     id_wrapper_map_.erase(node->id());
+    wrapper->Destroy();
   }
 }
 
@@ -1204,6 +1205,12 @@
     ui::AXTree* tree,
     bool root_changed,
     const std::vector<ui::AXTreeObserver::Change>& changes) {
+  // When the root changes and this is the root manager, we may need to
+  // fire a new focus event.
+  if (root_changed && last_focused_node_tree_id_ &&
+      ax_tree_id_ == last_focused_node_tree_id_.value())
+    SetLastFocusedNode(nullptr);
+
   bool ax_tree_id_changed = false;
   if (GetTreeData().tree_id != ui::AXTreeIDUnknown() &&
       GetTreeData().tree_id != ax_tree_id_) {
@@ -1218,13 +1225,6 @@
   // we're properly connected.
   if (ax_tree_id_changed || root_changed)
     connected_to_parent_tree_node_ = false;
-
-  // When the root changes and this is the root manager, we may need to
-  // fire a new focus event.
-  if (root_changed && last_focused_manager_ == this) {
-    last_focused_node_ = nullptr;
-    last_focused_manager_ = nullptr;
-  }
 }
 
 ui::AXNode* BrowserAccessibilityManager::GetNodeFromTree(ui::AXTreeID tree_id,
@@ -1274,6 +1274,30 @@
   return delegate()->AccessibilityIsMainFrame();
 }
 
+// static
+void BrowserAccessibilityManager::SetLastFocusedNode(
+    BrowserAccessibility* node) {
+  if (node) {
+    DCHECK(node->manager());
+    last_focused_node_id_ = node->GetId();
+    last_focused_node_tree_id_ = node->manager()->ax_tree_id();
+  } else {
+    last_focused_node_id_.reset();
+    last_focused_node_tree_id_.reset();
+  }
+}
+
+// static
+BrowserAccessibility* BrowserAccessibilityManager::GetLastFocusedNode() {
+  if (last_focused_node_id_) {
+    DCHECK(last_focused_node_tree_id_);
+    if (BrowserAccessibilityManager* last_focused_manager =
+            FromID(last_focused_node_tree_id_.value()))
+      return last_focused_manager->GetFromID(last_focused_node_id_.value());
+  }
+  return nullptr;
+}
+
 ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
   std::unique_ptr<
       ui::AXTreeSource<const ui::AXNode*, ui::AXNodeData, ui::AXTreeData>>
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 3bc89525..b1e8eaf 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -361,7 +361,7 @@
       const BrowserAccessibility& end_object,
       int end_offset);
 
-  static gfx::Rect GetPageBoundsForRange(
+  static gfx::Rect GetRootFrameRangeBoundsRect(
       const BrowserAccessibility& start_object,
       int start_offset,
       const BrowserAccessibility& end_object,
@@ -431,6 +431,9 @@
   virtual void SendLocationChangeEvents(
       const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
 
+  static void SetLastFocusedNode(BrowserAccessibility* node);
+  static BrowserAccessibility* GetLastFocusedNode();
+
  protected:
   // The object that can perform actions on our behalf.
   BrowserAccessibilityDelegate* delegate_;
@@ -453,16 +456,6 @@
 
   BrowserAccessibilityFindInPageInfo find_in_page_info_;
 
-  // These are only used by the root BrowserAccessibilityManager of a
-  // frame tree. Stores the last focused node and last focused manager so
-  // that when focus might have changed we can figure out whether we need
-  // to fire a focus event.
-  //
-  // NOTE: these pointers are not cleared, so they should never be
-  // dereferenced, only used for comparison.
-  BrowserAccessibility* last_focused_node_;
-  BrowserAccessibilityManager* last_focused_manager_;
-
   // These cache the AX tree ID, node ID, and global screen bounds of the
   // last object found by an asynchronous hit test. Subsequent hit test
   // requests that remain within this object's bounds will return the same
@@ -496,6 +489,15 @@
   // flakiness. See NeverSuppressOrDelayEventsForTesting() for details.
   static bool never_suppress_or_delay_events_for_testing_;
 
+  // Stores the id of the last focused node across all frames, as well as the id
+  // of the tree that contains it, so that when focus might have changed we can
+  // figure out whether we need to fire a focus event.
+  //
+  // NOTE: Don't use or modify these properties directly, use the
+  // SetLastFocusedNode and GetLastFocusedNode methods instead.
+  static base::Optional<int32_t> last_focused_node_id_;
+  static base::Optional<ui::AXTreeID> last_focused_node_tree_id_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManager);
 };
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index 3b0d41b..3d6729e7 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -202,6 +202,7 @@
     case ui::AXEventGenerator::Event::CHILDREN_CHANGED:
     case ui::AXEventGenerator::Event::CLASS_NAME_CHANGED:
     case ui::AXEventGenerator::Event::COLLAPSED:
+    case ui::AXEventGenerator::Event::CONTROLS_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
     case ui::AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED:
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
index a66ff87..21de0d4 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -374,6 +374,7 @@
     case ui::AXEventGenerator::Event::ACCESS_KEY_CHANGED:
     case ui::AXEventGenerator::Event::AUTO_COMPLETE_CHANGED:
     case ui::AXEventGenerator::Event::CHILDREN_CHANGED:
+    case ui::AXEventGenerator::Event::CONTROLS_CHANGED:
     case ui::AXEventGenerator::Event::CLASS_NAME_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
     case ui::AXEventGenerator::Event::DESCRIPTION_CHANGED:
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index 4ac2bbc..0d2fddd 100644
--- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -634,28 +634,49 @@
   ASSERT_NE(nullptr, static_text_accessible);
 
   EXPECT_EQ(gfx::Rect(100, 100, 6, 9).ToString(),
-            static_text_accessible->GetPageBoundsForRange(0, 1).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 1, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(100, 100, 26, 9).ToString(),
-            static_text_accessible->GetPageBoundsForRange(0, 5).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 5, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(100, 109, 5, 9).ToString(),
-            static_text_accessible->GetPageBoundsForRange(7, 1).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    7, 1, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(100, 109, 25, 9).ToString(),
-            static_text_accessible->GetPageBoundsForRange(7, 5).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    7, 5, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(),
-            static_text_accessible->GetPageBoundsForRange(5, 3).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    5, 3, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(),
-            static_text_accessible->GetPageBoundsForRange(0, 13).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 13, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   // Note that each child in the parent element is represented by a single
   // embedded object character and not by its text.
   // TODO(nektar): Investigate failure on Linux.
   EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(),
-            root_accessible->GetPageBoundsForRange(0, 13).ToString());
+            root_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 13, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 }
 
 TEST_F(BrowserAccessibilityManagerTest, BoundsForRangeMultiElement) {
@@ -718,50 +739,50 @@
   // The first line.
   EXPECT_EQ(gfx::Rect(0, 20, 33, 9).ToString(),
             manager
-                ->GetPageBoundsForRange(*static_text_accessible, 0,
-                                        *static_text_accessible, 3)
+                ->GetRootFrameRangeBoundsRect(*static_text_accessible, 0,
+                                              *static_text_accessible, 3)
                 .ToString());
 
   // Part of the first line.
   EXPECT_EQ(gfx::Rect(0, 20, 21, 9).ToString(),
             manager
-                ->GetPageBoundsForRange(*static_text_accessible, 0,
-                                        *static_text_accessible, 2)
+                ->GetRootFrameRangeBoundsRect(*static_text_accessible, 0,
+                                              *static_text_accessible, 2)
                 .ToString());
 
   // Part of the first line.
   EXPECT_EQ(gfx::Rect(10, 20, 23, 9).ToString(),
             manager
-                ->GetPageBoundsForRange(*static_text_accessible, 1,
-                                        *static_text_accessible, 3)
+                ->GetRootFrameRangeBoundsRect(*static_text_accessible, 1,
+                                              *static_text_accessible, 3)
                 .ToString());
 
   // The second line.
   EXPECT_EQ(gfx::Rect(10, 40, 33, 9).ToString(),
             manager
-                ->GetPageBoundsForRange(*static_text_accessible2, 0,
-                                        *static_text_accessible2, 3)
+                ->GetRootFrameRangeBoundsRect(*static_text_accessible2, 0,
+                                              *static_text_accessible2, 3)
                 .ToString());
 
   // All of both lines.
   EXPECT_EQ(gfx::Rect(0, 20, 43, 29).ToString(),
             manager
-                ->GetPageBoundsForRange(*static_text_accessible, 0,
-                                        *static_text_accessible2, 3)
+                ->GetRootFrameRangeBoundsRect(*static_text_accessible, 0,
+                                              *static_text_accessible2, 3)
                 .ToString());
 
   // Part of both lines.
   EXPECT_EQ(gfx::Rect(10, 20, 23, 29).ToString(),
             manager
-                ->GetPageBoundsForRange(*static_text_accessible, 2,
-                                        *static_text_accessible2, 1)
+                ->GetRootFrameRangeBoundsRect(*static_text_accessible, 2,
+                                              *static_text_accessible2, 1)
                 .ToString());
 
   // Part of both lines in reverse order.
   EXPECT_EQ(gfx::Rect(10, 20, 23, 29).ToString(),
             manager
-                ->GetPageBoundsForRange(*static_text_accessible2, 1,
-                                        *static_text_accessible, 2)
+                ->GetRootFrameRangeBoundsRect(*static_text_accessible2, 1,
+                                              *static_text_accessible, 2)
                 .ToString());
 }
 
@@ -771,8 +792,9 @@
   // words, on-screen it would look like "123cba". This is possible to
   // achieve if the source string had unicode control characters
   // to switch directions. This test doesn't worry about how, though - it just
-  // tests that if something like that were to occur, GetPageBoundsForRange
-  // returns the correct bounds for different ranges.
+  // tests that if something like that were to occur,
+  // GetRootFrameRangeBoundsRect returns the correct bounds for different
+  // ranges.
 
   ui::AXNodeData root;
   root.id = 1;
@@ -827,24 +849,42 @@
   ASSERT_NE(nullptr, static_text_accessible);
 
   EXPECT_EQ(gfx::Rect(100, 100, 60, 20).ToString(),
-            static_text_accessible->GetPageBoundsForRange(0, 6).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 6, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(100, 100, 10, 20).ToString(),
-            static_text_accessible->GetPageBoundsForRange(0, 1).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 1, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(100, 100, 30, 20).ToString(),
-            static_text_accessible->GetPageBoundsForRange(0, 3).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 3, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(150, 100, 10, 20).ToString(),
-            static_text_accessible->GetPageBoundsForRange(3, 1).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    3, 1, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(130, 100, 30, 20).ToString(),
-            static_text_accessible->GetPageBoundsForRange(3, 3).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    3, 3, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   // This range is only two characters, but because of the direction switch
   // the bounds are as wide as four characters.
   EXPECT_EQ(gfx::Rect(120, 100, 40, 20).ToString(),
-            static_text_accessible->GetPageBoundsForRange(2, 2).ToString());
+            static_text_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    2, 2, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 }
 
 TEST_F(BrowserAccessibilityManagerTest, BoundsForRangeScrolledWindow) {
@@ -890,10 +930,16 @@
 
   if (manager->UseRootScrollOffsetsWhenComputingBounds()) {
     EXPECT_EQ(gfx::Rect(75, 50, 16, 9).ToString(),
-              static_text_accessible->GetPageBoundsForRange(0, 3).ToString());
+              static_text_accessible
+                  ->GetRootFrameRangeBoundsRect(
+                      0, 3, ui::AXClippingBehavior::kUnclipped)
+                  .ToString());
   } else {
     EXPECT_EQ(gfx::Rect(100, 100, 16, 9).ToString(),
-              static_text_accessible->GetPageBoundsForRange(0, 3).ToString());
+              static_text_accessible
+                  ->GetRootFrameRangeBoundsRect(
+                      0, 3, ui::AXClippingBehavior::kUnclipped)
+                  .ToString());
   }
 }
 
@@ -968,22 +1014,40 @@
   ASSERT_NE(nullptr, div_accessible);
 
   EXPECT_EQ(gfx::Rect(100, 100, 20, 20).ToString(),
-            div_accessible->GetPageBoundsForRange(0, 1).ToString());
+            div_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 1, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(100, 100, 40, 20).ToString(),
-            div_accessible->GetPageBoundsForRange(0, 2).ToString());
+            div_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 2, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(100, 100, 80, 20).ToString(),
-            div_accessible->GetPageBoundsForRange(0, 4).ToString());
+            div_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 4, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(120, 100, 60, 20).ToString(),
-            div_accessible->GetPageBoundsForRange(1, 3).ToString());
+            div_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    1, 3, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(120, 100, 80, 20).ToString(),
-            div_accessible->GetPageBoundsForRange(1, 4).ToString());
+            div_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    1, 4, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 
   EXPECT_EQ(gfx::Rect(100, 100, 100, 20).ToString(),
-            div_accessible->GetPageBoundsForRange(0, 5).ToString());
+            div_accessible
+                ->GetRootFrameRangeBoundsRect(
+                    0, 5, ui::AXClippingBehavior::kUnclipped)
+                .ToString());
 }
 
 TEST_F(BrowserAccessibilityManagerTest, TestNextPreviousInTreeOrder) {
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index bd5ae4f..994bcae6 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -127,6 +127,12 @@
     case ax::mojom::Event::kScrolledToAnchor:
       FireWinAccessibilityEvent(EVENT_SYSTEM_SCROLLINGSTART, node);
       break;
+    case ax::mojom::Event::kTextChanged:
+      FireUiaTextContainerEvent(UIA_Text_TextChangedEventId, node);
+      break;
+    case ax::mojom::Event::kTextSelectionChanged:
+      FireUiaTextContainerEvent(UIA_Text_TextSelectionChangedEventId, node);
+      break;
     default:
       break;
   }
@@ -178,6 +184,9 @@
       FireUiaPropertyChangedEvent(
           UIA_ExpandCollapseExpandCollapseStatePropertyId, node);
       break;
+    case ui::AXEventGenerator::Event::CONTROLS_CHANGED:
+      FireUiaPropertyChangedEvent(UIA_ControllerForPropertyId, node);
+      break;
     case ui::AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
       FireUiaPropertyChangedEvent(UIA_DescribedByPropertyId, node);
       break;
@@ -381,6 +390,21 @@
   }
 }
 
+void BrowserAccessibilityManagerWin::FireUiaTextContainerEvent(
+    LONG uia_event,
+    BrowserAccessibility* node) {
+  // If the node supports text pattern, fire the event from itself, otherwise,
+  // fire the event from the closest ancestor that supports text pattern.
+  while (node) {
+    if (ToBrowserAccessibilityWin(node)->GetCOM()->IsPatternProviderSupported(
+            UIA_TextPatternId)) {
+      FireUiaAccessibilityEvent(uia_event, node);
+      return;
+    }
+    node = node->PlatformGetParent();
+  }
+}
+
 bool BrowserAccessibilityManagerWin::CanFireEvents() {
   if (!BrowserAccessibilityManager::CanFireEvents())
     return false;
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.h b/content/browser/accessibility/browser_accessibility_manager_win.h
index 3d337f6..ed3b9c9 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.h
+++ b/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -58,6 +58,7 @@
   void FireUiaAccessibilityEvent(LONG uia_event, BrowserAccessibility* node);
   void FireUiaPropertyChangedEvent(LONG uia_property,
                                    BrowserAccessibility* node);
+  void FireUiaTextContainerEvent(LONG uia_event, BrowserAccessibility* node);
 
   // Track this object and post a VISIBLE_DATA_CHANGED notification when
   // its container scrolls.
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index f4ce89ed..cebad7e 100644
--- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_widget_host_view.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
@@ -70,6 +71,26 @@
   void TearDownOnMainThread() override;
 
  protected:
+  void LoadInitialAccessibilityTreeFromUrl(
+      const GURL& url,
+      ui::AXMode accessibility_mode = ui::kAXModeComplete) {
+    AccessibilityNotificationWaiter waiter(shell()->web_contents(),
+                                           accessibility_mode,
+                                           ax::mojom::Event::kLoadComplete);
+    NavigateToURL(shell(), url);
+    waiter.WaitForNotification();
+  }
+
+  void LoadInitialAccessibilityTreeFromHtmlFilePath(
+      const std::string& html_file_path,
+      ui::AXMode accessibility_mode = ui::kAXModeComplete) {
+    if (!embedded_test_server()->Started())
+      ASSERT_TRUE(embedded_test_server()->Start());
+    ASSERT_TRUE(embedded_test_server()->Started());
+    LoadInitialAccessibilityTreeFromUrl(
+        embedded_test_server()->GetURL(html_file_path), accessibility_mode);
+  }
+
   BrowserAccessibilityManager* GetManager() {
     WebContentsImpl* web_contents =
         static_cast<WebContentsImpl*>(shell()->web_contents());
@@ -604,4 +625,109 @@
                GetAttr(input2, StringAttribute::kPlaceholder).c_str());
 }
 
+// On Android root scroll offset is handled by the Java layer. The final rect
+// bounds is device specific.
+#ifndef OS_ANDROID
+IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
+                       GetBoundsRectUnclippedRootFrameFromIFrame) {
+  // Start by loading a document with iframes.
+  LoadInitialAccessibilityTreeFromHtmlFilePath(
+      "/accessibility/html/iframe-padding.html");
+  WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
+                                                "Second Button");
+
+  // Get the delegate for the iframe leaf of the top-level accessibility tree
+  // for the second iframe.
+  BrowserAccessibilityManager* browser_accessibility_manager = GetManager();
+  ASSERT_NE(nullptr, browser_accessibility_manager);
+  BrowserAccessibility* root_browser_accessibility =
+      browser_accessibility_manager->GetRoot();
+  ASSERT_NE(nullptr, root_browser_accessibility);
+  BrowserAccessibility* leaf_iframe_browser_accessibility =
+      root_browser_accessibility->InternalDeepestLastChild();
+  ASSERT_NE(nullptr, leaf_iframe_browser_accessibility);
+  ASSERT_EQ(ax::mojom::Role::kIframe,
+            leaf_iframe_browser_accessibility->GetRole());
+
+  // The frame coordinates of the iframe node within the top-level tree is
+  // relative to the top level frame. That is why the top-level default padding
+  // is included.
+  ASSERT_EQ(gfx::Rect(30, 230, 300, 100).ToString(),
+            leaf_iframe_browser_accessibility
+                ->GetBoundsRect(ui::AXCoordinateSystem::kRootFrame,
+                                ui::AXClippingBehavior::kUnclipped)
+                .ToString());
+
+  // Now get the root delegate of the iframe's accessibility tree.
+  AXTreeID iframe_tree_id = AXTreeID::FromString(
+      leaf_iframe_browser_accessibility->GetStringAttribute(
+          ax::mojom::StringAttribute::kChildTreeId));
+  BrowserAccessibilityManager* iframe_browser_accessibility_manager =
+      BrowserAccessibilityManager::FromID(iframe_tree_id);
+  ASSERT_NE(nullptr, iframe_browser_accessibility_manager);
+  BrowserAccessibility* root_iframe_browser_accessibility =
+      iframe_browser_accessibility_manager->GetRoot();
+  ASSERT_NE(nullptr, root_iframe_browser_accessibility);
+  ASSERT_EQ(ax::mojom::Role::kRootWebArea,
+            root_iframe_browser_accessibility->GetRole());
+
+  // The root frame bounds of the iframe are still relative to the top-level
+  // frame.
+  ASSERT_EQ(gfx::Rect(30, 230, 300, 100).ToString(),
+            root_iframe_browser_accessibility
+                ->GetBoundsRect(ui::AXCoordinateSystem::kRootFrame,
+                                ui::AXClippingBehavior::kUnclipped)
+                .ToString());
+}
+
+IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
+                       GetBoundsRectUnclippedFrameFromIFrame) {
+  // Start by loading a document with iframes.
+  LoadInitialAccessibilityTreeFromHtmlFilePath(
+      "/accessibility/html/iframe-padding.html");
+  WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
+                                                "Second Button");
+
+  // Get the delegate for the iframe leaf of the top-level accessibility tree
+  // for the second iframe.
+  BrowserAccessibilityManager* browser_accessibility_manager = GetManager();
+  ASSERT_NE(nullptr, browser_accessibility_manager);
+  BrowserAccessibility* root_browser_accessibility =
+      browser_accessibility_manager->GetRoot();
+  ASSERT_NE(nullptr, root_browser_accessibility);
+  BrowserAccessibility* leaf_iframe_browser_accessibility =
+      root_browser_accessibility->InternalDeepestLastChild();
+  ASSERT_NE(nullptr, leaf_iframe_browser_accessibility);
+  ASSERT_EQ(ax::mojom::Role::kIframe,
+            leaf_iframe_browser_accessibility->GetRole());
+
+  // The frame coordinates of the iframe node within the top-level tree is
+  // relative to the top level frame.
+  ASSERT_EQ(gfx::Rect(30, 230, 300, 100).ToString(),
+            leaf_iframe_browser_accessibility
+                ->GetBoundsRect(ui::AXCoordinateSystem::kFrame,
+                                ui::AXClippingBehavior::kUnclipped)
+                .ToString());
+
+  // Now get the root delegate of the iframe's accessibility tree.
+  AXTreeID iframe_tree_id = AXTreeID::FromString(
+      leaf_iframe_browser_accessibility->GetStringAttribute(
+          ax::mojom::StringAttribute::kChildTreeId));
+  BrowserAccessibilityManager* iframe_browser_accessibility_manager =
+      BrowserAccessibilityManager::FromID(iframe_tree_id);
+  ASSERT_NE(nullptr, iframe_browser_accessibility_manager);
+  BrowserAccessibility* root_iframe_browser_accessibility =
+      iframe_browser_accessibility_manager->GetRoot();
+  ASSERT_NE(nullptr, root_iframe_browser_accessibility);
+  ASSERT_EQ(ax::mojom::Role::kRootWebArea,
+            root_iframe_browser_accessibility->GetRole());
+
+  // The frame bounds of the iframe are now relative to itself.
+  ASSERT_EQ(gfx::Rect(0, 0, 300, 100).ToString(),
+            root_iframe_browser_accessibility
+                ->GetBoundsRect(ui::AXCoordinateSystem::kFrame,
+                                ui::AXClippingBehavior::kUnclipped)
+                .ToString());
+}
+#endif
 }  // namespace content
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index 8531dfe..3827cbf 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -241,6 +241,11 @@
 }
 
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
+                       AccessibilityEventsAriaControlsChanged) {
+  RunEventTest(FILE_PATH_LITERAL("aria-controls-changed.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
                        AccessibilityEventsAriaTreeCollapse) {
   RunEventTest(FILE_PATH_LITERAL("aria-tree-collapse.html"));
 }
@@ -579,6 +584,11 @@
 }
 
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
+                       AccessibilityEventsTextSelectionChanged) {
+  RunEventTest(FILE_PATH_LITERAL("text-selection-changed.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
                        AccessibilityEventsAriaCheckedChanged) {
   RunEventTest(FILE_PATH_LITERAL("aria-checked-changed.html"));
 }
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 991047b..d0c4466 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -248,6 +248,10 @@
   RunCSSTest(FILE_PATH_LITERAL("pseudo-element-alternative-text.html"));
 }
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityCSSDOMElements) {
+  RunCSSTest(FILE_PATH_LITERAL("dom-element-css-alternative-text.html"));
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
                        AccessibilityCSSTableIncomplete) {
   RunCSSTest(FILE_PATH_LITERAL("table-incomplete.html"));
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc
index af4cc7c..6dede06 100644
--- a/content/browser/accessibility/web_contents_accessibility_android.cc
+++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -698,12 +698,13 @@
   float dip_scale = use_zoom_for_dsf_enabled_
                         ? 1 / root_manager_->device_scale_factor()
                         : 1.0;
-  gfx::Rect absolute_rect = gfx::ScaleToEnclosingRect(node->GetPageBoundsRect(),
-                                                      dip_scale, dip_scale);
+  gfx::Rect absolute_rect = gfx::ScaleToEnclosingRect(
+      node->GetUnclippedRootFrameBoundsRect(), dip_scale, dip_scale);
   gfx::Rect parent_relative_rect = absolute_rect;
   if (node->PlatformGetParent()) {
     gfx::Rect parent_rect = gfx::ScaleToEnclosingRect(
-        node->PlatformGetParent()->GetPageBoundsRect(), dip_scale, dip_scale);
+        node->PlatformGetParent()->GetUnclippedRootFrameBoundsRect(), dip_scale,
+        dip_scale);
     parent_relative_rect.Offset(-parent_rect.OffsetFromOrigin());
   }
   bool is_root = node->PlatformGetParent() == NULL;
@@ -850,9 +851,10 @@
     const JavaParamRef<jobject>& obj,
     jint unique_id) {
   BrowserAccessibilityAndroid* node = GetAXFromUniqueID(unique_id);
-  if (node)
+  if (node) {
     node->manager()->ScrollToMakeVisible(
-        *node, gfx::Rect(node->GetFrameBoundsRect().size()));
+        *node, gfx::Rect(node->GetClippedFrameBoundsRect().size()));
+  }
 }
 
 void WebContentsAccessibilityAndroid::SetTextFieldValue(
@@ -1196,10 +1198,11 @@
     return nullptr;
   }
 
-  gfx::Rect object_bounds = node->GetPageBoundsRect();
+  gfx::Rect object_bounds = node->GetUnclippedRootFrameBoundsRect();
   int coords[4 * len];
   for (int i = 0; i < len; i++) {
-    gfx::Rect char_bounds = node->GetPageBoundsForRange(start + i, 1, false);
+    gfx::Rect char_bounds = node->GetRootFrameRangeBoundsRect(
+        start + i, 1, ui::AXClippingBehavior::kUnclipped);
     if (char_bounds.IsEmpty())
       char_bounds = object_bounds;
     coords[4 * i + 0] = char_bounds.x();
diff --git a/content/browser/image_capture/OWNERS b/content/browser/image_capture/OWNERS
index cc7f7bb..c261502 100644
--- a/content/browser/image_capture/OWNERS
+++ b/content/browser/image_capture/OWNERS
@@ -1,7 +1,5 @@
+mcasas@chromium.org
 miu@chromium.org
 
-# Original (legacy) owner.
-mcasas@chromium.org
-
 # COMPONENT: Blink>ImageCapture
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-dev@chromium.org
diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc
index f21530f..0f774df 100644
--- a/content/browser/loader/resource_loader_unittest.cc
+++ b/content/browser/loader/resource_loader_unittest.cc
@@ -96,11 +96,12 @@
 
   // net::ClientCertStore:
   void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
-                      const ClientCertListCallback& callback) override {
+                      ClientCertListCallback callback) override {
     *requested_authorities_ = cert_request_info.cert_authorities;
     ++(*request_count_);
 
-    callback.Run(net::FakeClientCertIdentityListFromCertificateList(response_));
+    std::move(callback).Run(
+        net::FakeClientCertIdentityListFromCertificateList(response_));
   }
 
  private:
@@ -122,15 +123,14 @@
         on_loader_deleted_callback_(on_loader_deleted_callback) {}
 
   // net::ClientCertStore:
-  void GetClientCerts(
-      const net::SSLCertRequestInfo& cert_request_info,
-      const ClientCertListCallback& cert_selected_callback) override {
+  void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
+                      ClientCertListCallback cert_selected_callback) override {
     // Don't destroy |loader_| while it's on the stack.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(&LoaderDestroyingCertStore::DoCallback,
-                       base::Unretained(loader_), cert_selected_callback,
-                       on_loader_deleted_callback_));
+        FROM_HERE, base::BindOnce(&LoaderDestroyingCertStore::DoCallback,
+                                  base::Unretained(loader_),
+                                  std::move(cert_selected_callback),
+                                  on_loader_deleted_callback_));
   }
 
  private:
@@ -138,10 +138,10 @@
   // LoaderDestroyingCertStore (ClientCertStores are actually handles, and not
   // global cert stores).
   static void DoCallback(std::unique_ptr<ResourceLoader>* loader,
-                         const ClientCertListCallback& cert_selected_callback,
+                         ClientCertListCallback cert_selected_callback,
                          const base::Closure& on_loader_deleted_callback) {
     loader->reset();
-    cert_selected_callback.Run(net::ClientCertIdentityList());
+    std::move(cert_selected_callback).Run(net::ClientCertIdentityList());
     on_loader_deleted_callback.Run();
   }
 
diff --git a/content/browser/media/media_keys_listener_manager_impl.cc b/content/browser/media/media_keys_listener_manager_impl.cc
index 6e0472dc..9cfc9a2 100644
--- a/content/browser/media/media_keys_listener_manager_impl.cc
+++ b/content/browser/media/media_keys_listener_manager_impl.cc
@@ -22,6 +22,10 @@
 #include "ui/base/now_playing/now_playing_info_center_delegate.h"
 #endif
 
+#if defined(OS_WIN)
+#include "content/browser/media/system_media_controls_notifier.h"
+#endif
+
 namespace content {
 
 MediaKeysListenerManagerImpl::ListeningData::ListeningData()
@@ -159,6 +163,12 @@
   }
 #endif
 
+#if defined(OS_WIN)
+  system_media_controls_notifier_ =
+      std::make_unique<SystemMediaControlsNotifier>(connector_);
+  system_media_controls_notifier_->Initialize();
+#endif  // defined(OS_WIN)
+
   auxiliary_services_started_ = true;
 }
 
diff --git a/content/browser/media/media_keys_listener_manager_impl.h b/content/browser/media/media_keys_listener_manager_impl.h
index be19904..f37dd5f5 100644
--- a/content/browser/media/media_keys_listener_manager_impl.h
+++ b/content/browser/media/media_keys_listener_manager_impl.h
@@ -28,6 +28,10 @@
 class NowPlayingInfoCenterNotifier;
 #endif
 
+#if defined(OS_WIN)
+class SystemMediaControlsNotifier;
+#endif  // defined(OS_WIN)
+
 // Listens for media keys and decides which listeners receive which events. In
 // particular, it owns one of its delegates (HardwareKeyMediaController), and
 // only propagates to the HardwareKeyMediaController if no other delegates are
@@ -114,6 +118,10 @@
       now_playing_info_center_notifier_;
 #endif
 
+#if defined(OS_WIN)
+  std::unique_ptr<SystemMediaControlsNotifier> system_media_controls_notifier_;
+#endif  // defined(OS_WIN)
+
   DISALLOW_COPY_AND_ASSIGN(MediaKeysListenerManagerImpl);
 };
 
diff --git a/content/browser/media/system_media_controls_notifier.cc b/content/browser/media/system_media_controls_notifier.cc
new file mode 100644
index 0000000..2d701e2
--- /dev/null
+++ b/content/browser/media/system_media_controls_notifier.cc
@@ -0,0 +1,75 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/system_media_controls_notifier.h"
+
+#include <memory>
+#include <utility>
+
+#include "services/media_session/public/mojom/constants.mojom.h"
+#include "services/media_session/public/mojom/media_session.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service.h"
+
+namespace content {
+
+using ABI::Windows::Media::MediaPlaybackStatus;
+
+SystemMediaControlsNotifier::SystemMediaControlsNotifier(
+    service_manager::Connector* connector)
+    : connector_(connector) {}
+
+SystemMediaControlsNotifier::~SystemMediaControlsNotifier() = default;
+
+void SystemMediaControlsNotifier::Initialize() {
+  // |service_| can be set in tests.
+  if (!service_)
+    service_ = system_media_controls::SystemMediaControlsService::GetInstance();
+
+  // |service_| can still be null if the current system does not support System
+  // Media Transport Controls.
+  if (!service_)
+    return;
+
+  // |connector_| can be null in tests.
+  if (!connector_)
+    return;
+
+  // Connect to the MediaControllerManager and create a MediaController that
+  // controls the active session so we can observe it.
+  media_session::mojom::MediaControllerManagerPtr controller_manager_ptr;
+  connector_->BindInterface(media_session::mojom::kServiceName,
+                            mojo::MakeRequest(&controller_manager_ptr));
+  controller_manager_ptr->CreateActiveMediaController(
+      mojo::MakeRequest(&media_controller_ptr_));
+
+  // Observe the active media controller for changes to playback state and
+  // supported actions.
+  media_session::mojom::MediaControllerObserverPtr media_controller_observer;
+  media_controller_observer_binding_.Bind(
+      mojo::MakeRequest(&media_controller_observer));
+  media_controller_ptr_->AddObserver(std::move(media_controller_observer));
+}
+
+void SystemMediaControlsNotifier::MediaSessionInfoChanged(
+    media_session::mojom::MediaSessionInfoPtr session_info) {
+  DCHECK(service_);
+
+  session_info_ = std::move(session_info);
+  if (session_info_) {
+    if (session_info_->playback_state ==
+        media_session::mojom::MediaPlaybackState::kPlaying) {
+      service_->SetPlaybackStatus(
+          MediaPlaybackStatus::MediaPlaybackStatus_Playing);
+    } else {
+      service_->SetPlaybackStatus(
+          MediaPlaybackStatus::MediaPlaybackStatus_Paused);
+    }
+  } else {
+    service_->SetPlaybackStatus(
+        MediaPlaybackStatus::MediaPlaybackStatus_Stopped);
+  }
+}
+
+}  // namespace content
diff --git a/content/browser/media/system_media_controls_notifier.h b/content/browser/media/system_media_controls_notifier.h
new file mode 100644
index 0000000..ed7bc8e
--- /dev/null
+++ b/content/browser/media/system_media_controls_notifier.h
@@ -0,0 +1,73 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_SYSTEM_MEDIA_CONTROLS_NOTIFIER_H_
+#define CONTENT_BROWSER_MEDIA_SYSTEM_MEDIA_CONTROLS_NOTIFIER_H_
+
+#include <memory>
+#include <vector>
+
+#include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/media_session/public/mojom/media_controller.mojom.h"
+
+namespace system_media_controls {
+class SystemMediaControlsService;
+}  // namespace system_media_controls
+
+namespace service_manager {
+class Connector;
+}  // namespace service_manager
+
+namespace content {
+
+// The SystemMediaControlsNotifier connects to Window's "System Media Transport
+// Controls" and keeps the OS informed of the current media playstate and
+// metadata. It observes changes to the active Media Session and updates the
+// SMTC accordingly.
+class CONTENT_EXPORT SystemMediaControlsNotifier
+    : public media_session::mojom::MediaControllerObserver {
+ public:
+  explicit SystemMediaControlsNotifier(service_manager::Connector* connector);
+  ~SystemMediaControlsNotifier() override;
+
+  void Initialize();
+
+  // media_session::mojom::MediaControllerObserver implementation.
+  void MediaSessionInfoChanged(
+      media_session::mojom::MediaSessionInfoPtr session_info) override;
+  void MediaSessionMetadataChanged(
+      const base::Optional<media_session::MediaMetadata>& metadata) override {}
+  void MediaSessionActionsChanged(
+      const std::vector<media_session::mojom::MediaSessionAction>& actions)
+      override {}
+  void MediaSessionChanged(
+      const base::Optional<base::UnguessableToken>& request_id) override {}
+
+  void SetSystemMediaControlsServiceForTesting(
+      system_media_controls::SystemMediaControlsService* service) {
+    service_ = service;
+  }
+
+ private:
+  // Our connection to Window's System Media Transport Controls.
+  system_media_controls::SystemMediaControlsService* service_ = nullptr;
+
+  // used to connect to the Media Session service.
+  service_manager::Connector* connector_;
+
+  // Tracks current media session state/metadata.
+  media_session::mojom::MediaControllerPtr media_controller_ptr_;
+  media_session::mojom::MediaSessionInfoPtr session_info_;
+
+  // Used to receive updates to the active media controller.
+  mojo::Binding<media_session::mojom::MediaControllerObserver>
+      media_controller_observer_binding_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsNotifier);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MEDIA_SYSTEM_MEDIA_CONTROLS_NOTIFIER_H_
diff --git a/content/browser/media/system_media_controls_notifier_unittest.cc b/content/browser/media/system_media_controls_notifier_unittest.cc
new file mode 100644
index 0000000..ab90552
--- /dev/null
+++ b/content/browser/media/system_media_controls_notifier_unittest.cc
@@ -0,0 +1,84 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/system_media_controls_notifier.h"
+
+#include <memory>
+#include <utility>
+
+#include "services/media_session/public/mojom/media_session.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/win/system_media_controls/mock_system_media_controls_service.h"
+
+namespace content {
+
+using ABI::Windows::Media::MediaPlaybackStatus;
+using media_session::mojom::MediaPlaybackState;
+using media_session::mojom::MediaSessionInfo;
+using media_session::mojom::MediaSessionInfoPtr;
+using testing::Expectation;
+
+class SystemMediaControlsNotifierTest : public testing::Test {
+ public:
+  SystemMediaControlsNotifierTest() = default;
+  ~SystemMediaControlsNotifierTest() override = default;
+
+  void SetUp() override {
+    notifier_ =
+        std::make_unique<SystemMediaControlsNotifier>(/*connector=*/nullptr);
+    notifier_->SetSystemMediaControlsServiceForTesting(
+        &mock_system_media_controls_service_);
+    notifier_->Initialize();
+  }
+
+ protected:
+  void SimulatePlaying() {
+    MediaSessionInfoPtr session_info(MediaSessionInfo::New());
+    session_info->playback_state = MediaPlaybackState::kPlaying;
+    notifier_->MediaSessionInfoChanged(std::move(session_info));
+  }
+
+  void SimulatePaused() {
+    MediaSessionInfoPtr session_info(MediaSessionInfo::New());
+    session_info->playback_state = MediaPlaybackState::kPaused;
+    notifier_->MediaSessionInfoChanged(std::move(session_info));
+  }
+
+  void SimulateStopped() { notifier_->MediaSessionInfoChanged(nullptr); }
+
+  SystemMediaControlsNotifier& notifier() { return *notifier_; }
+  system_media_controls::testing::MockSystemMediaControlsService&
+  mock_system_media_controls_service() {
+    return mock_system_media_controls_service_;
+  }
+
+ private:
+  std::unique_ptr<SystemMediaControlsNotifier> notifier_;
+  system_media_controls::testing::MockSystemMediaControlsService
+      mock_system_media_controls_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsNotifierTest);
+};
+
+TEST_F(SystemMediaControlsNotifierTest, ProperlyUpdatesPlaybackState) {
+  Expectation playing = EXPECT_CALL(
+      mock_system_media_controls_service(),
+      SetPlaybackStatus(MediaPlaybackStatus::MediaPlaybackStatus_Playing));
+  Expectation paused =
+      EXPECT_CALL(
+          mock_system_media_controls_service(),
+          SetPlaybackStatus(MediaPlaybackStatus::MediaPlaybackStatus_Paused))
+          .After(playing);
+  EXPECT_CALL(
+      mock_system_media_controls_service(),
+      SetPlaybackStatus(MediaPlaybackStatus::MediaPlaybackStatus_Stopped))
+      .After(paused);
+
+  SimulatePlaying();
+  SimulatePaused();
+  SimulateStopped();
+}
+
+}  // namespace content
diff --git a/content/browser/portal/portal.cc b/content/browser/portal/portal.cc
index 8e5c70e..55dcb5cf 100644
--- a/content/browser/portal/portal.cc
+++ b/content/browser/portal/portal.cc
@@ -101,12 +101,13 @@
   if (!portal_contents_) {
     // Create the Portal WebContents.
     WebContents::CreateParams params(outer_contents_impl->GetBrowserContext());
-    portal_contents_ = WebContents::Create(params);
+    SetPortalContents(WebContents::Create(params));
     web_contents_created = true;
   }
-  portal_contents_impl_ = static_cast<WebContentsImpl*>(portal_contents_.get());
-  portal_contents_impl_->set_portal(this);
-  portal_contents_impl_->SetDelegate(this);
+
+  DCHECK_EQ(portal_contents_.get(), portal_contents_impl_);
+  DCHECK_EQ(portal_contents_impl_->portal(), this);
+  DCHECK_EQ(portal_contents_impl_->GetDelegate(), this);
 
   outer_contents_impl->AttachInnerWebContents(std::move(portal_contents_),
                                               outer_node->current_frame_host());
@@ -136,6 +137,7 @@
 
   if (outer_contents->portal()) {
     mojo::ReportBadMessage("Portal::Activate called on nested portal");
+    binding_->Close();  // Also deletes |this|.
     return;
   }
 
@@ -144,19 +146,24 @@
   std::unique_ptr<WebContents> portal_contents =
       portal_contents_impl_->DetachFromOuterWebContents();
 
-  static_cast<RenderWidgetHostViewBase*>(
-      outer_contents->GetMainFrame()->GetView())
-      ->Destroy();
-  std::unique_ptr<WebContents> contents = delegate->SwapWebContents(
-      outer_contents, std::move(portal_contents), true, is_loading);
-  CHECK_EQ(contents.get(), outer_contents);
+  auto* outer_contents_main_frame_view = static_cast<RenderWidgetHostViewBase*>(
+      outer_contents->GetMainFrame()->GetView());
+  if (outer_contents_main_frame_view)
+    outer_contents_main_frame_view->Destroy();
+  std::unique_ptr<WebContents> predecessor_web_contents =
+      delegate->SwapWebContents(outer_contents, std::move(portal_contents),
+                                true, is_loading);
+  CHECK_EQ(predecessor_web_contents.get(), outer_contents);
+
   portal_contents_impl_->set_portal(nullptr);
+
   blink::mojom::PortalAssociatedPtr portal_ptr;
   Portal* portal = Create(portal_contents_impl_->GetMainFrame(),
                           mojo::MakeRequest(&portal_ptr));
+  portal->SetPortalContents(std::move(predecessor_web_contents));
+
   portal_contents_impl_->GetMainFrame()->OnPortalActivated(
       portal->portal_token_, portal_ptr.PassInterface(), std::move(data));
-  portal->portal_contents_ = std::move(contents);
   std::move(callback).Run();
 }
 
@@ -192,4 +199,11 @@
   binding_ = binding;
 }
 
+void Portal::SetPortalContents(std::unique_ptr<WebContents> web_contents) {
+  portal_contents_ = std::move(web_contents);
+  portal_contents_impl_ = static_cast<WebContentsImpl*>(portal_contents_.get());
+  portal_contents_impl_->SetDelegate(this);
+  portal_contents_impl_->set_portal(this);
+}
+
 }  // namespace content
diff --git a/content/browser/portal/portal.h b/content/browser/portal/portal.h
index 96025cb3..5829af8 100644
--- a/content/browser/portal/portal.h
+++ b/content/browser/portal/portal.h
@@ -88,6 +88,8 @@
  private:
   explicit Portal(RenderFrameHostImpl* owner_render_frame_host);
 
+  void SetPortalContents(std::unique_ptr<WebContents> web_contents);
+
   RenderFrameHostImpl* owner_render_frame_host_;
 
   // Uniquely identifies the portal, this token is used by the browser process
diff --git a/content/browser/renderer_host/media/OWNERS b/content/browser/renderer_host/media/OWNERS
index 107a4d64..68a9bdc 100644
--- a/content/browser/renderer_host/media/OWNERS
+++ b/content/browser/renderer_host/media/OWNERS
@@ -7,10 +7,8 @@
 olka@chromium.org
 maxmorin@chromium.org
 
+per-file *video*=mcasas@chromium.org
 per-file *video*=chfremer@chromium.org
 
-# Original (legacy) owner.
-per-file *video*=mcasas@chromium.org
-
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia
-# TEAM: webrtc-dev@chromium.org
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index 4648ff8..b0ada0c 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -42,7 +42,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/cras_audio_client.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 #endif
 
 using ::testing::_;
diff --git a/content/browser/ssl/ssl_client_auth_handler.cc b/content/browser/ssl/ssl_client_auth_handler.cc
index 29bafea..e2a1dbd 100644
--- a/content/browser/ssl/ssl_client_auth_handler.cc
+++ b/content/browser/ssl/ssl_client_auth_handler.cc
@@ -98,7 +98,7 @@
       // callback.
       client_cert_store_->GetClientCerts(
           *cert_request_info_,
-          base::Bind(&SSLClientAuthHandler::Core::DidGetClientCerts, this));
+          base::BindOnce(&SSLClientAuthHandler::Core::DidGetClientCerts, this));
     } else {
       DidGetClientCerts(net::ClientCertIdentityList());
     }
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index 2b0e315..4eeaaeb3 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -40,6 +40,7 @@
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/tracing/public/cpp/trace_event_agent.h"
 #include "services/tracing/public/cpp/traced_process_impl.h"
+#include "services/tracing/public/cpp/tracing_features.h"
 #include "services/tracing/public/mojom/constants.mojom.h"
 #include "v8/include/v8-version-string.h"
 
@@ -220,7 +221,7 @@
   // this does not happen; however, if the service manager is teared down during
   // tracing, e.g. at Chrome shutdown, tracing controller may finish flushing
   // traces without waiting for tracing agents.
-  if (trace_config_) {
+  if (trace_config_ && !tracing::TracingUsesPerfettoBackend()) {
     DCHECK(IsTracing());
     metadata_dict->SetString("trace-config", trace_config_->ToString());
   }
diff --git a/content/browser/webrtc/OWNERS b/content/browser/webrtc/OWNERS
index 106f113a..4002051 100644
--- a/content/browser/webrtc/OWNERS
+++ b/content/browser/webrtc/OWNERS
@@ -1,12 +1,9 @@
 chfremer@chromium.org
 emircan@chromium.org
 guidou@chromium.org
+mcasas@chromium.org
 tommi@chromium.org
 
 per-file *test*=phoglund@chromium.org
 
-# Original (legacy) owner.
-mcasas@chromium.org
-
 # COMPONENT: Blink>WebRTC
-# TEAM: webrtc-dev@chromium.org
diff --git a/content/browser/webrtc/webrtc_content_browsertest_base.cc b/content/browser/webrtc/webrtc_content_browsertest_base.cc
index a29cd1f..d13dc9b 100644
--- a/content/browser/webrtc/webrtc_content_browsertest_base.cc
+++ b/content/browser/webrtc/webrtc_content_browsertest_base.cc
@@ -24,7 +24,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/cras_audio_client.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 #endif
 
 namespace content {
diff --git a/content/renderer/image_capture/OWNERS b/content/renderer/image_capture/OWNERS
index ab8e7ba..57aa41f 100644
--- a/content/renderer/image_capture/OWNERS
+++ b/content/renderer/image_capture/OWNERS
@@ -1,7 +1,5 @@
+mcasas@chromium.org
 reillyg@chromium.org
 
-# Original (legacy) owner.
-mcasas@chromium.org
-
 # COMPONENT: Blink>ImageCapture
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-dev@chromium.org
diff --git a/content/renderer/media/stream/OWNERS b/content/renderer/media/stream/OWNERS
index 32889cc..c205d4f9 100644
--- a/content/renderer/media/stream/OWNERS
+++ b/content/renderer/media/stream/OWNERS
@@ -2,5 +2,5 @@
 
 per-file media_stream_audio_processor*=aluebs@chromium.org
 
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia
diff --git a/content/renderer/media_capture_from_element/OWNERS b/content/renderer/media_capture_from_element/OWNERS
index d176cccc..446f8fb0 100644
--- a/content/renderer/media_capture_from_element/OWNERS
+++ b/content/renderer/media_capture_from_element/OWNERS
@@ -1,7 +1,4 @@
 emircan@chromium.org
-
-# Original (legacy) owner.
 mcasas@chromium.org
 
 # COMPONENT: Blink>MediaStream>CaptureFromElement
-# TEAM: webrtc-dev@chromium.org
diff --git a/content/renderer/media_recorder/OWNERS b/content/renderer/media_recorder/OWNERS
index c6eb0c4..6675929 100644
--- a/content/renderer/media_recorder/OWNERS
+++ b/content/renderer/media_recorder/OWNERS
@@ -1,7 +1,5 @@
 emircan@chromium.org
-
-# Original (legacy) owner.
 mcasas@chromium.org
 
 # COMPONENT: Blink>MediaRecording
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-dev@chromium.org
diff --git a/content/shell/test_runner/accessibility_controller.cc b/content/shell/test_runner/accessibility_controller.cc
index 3957b4a..97a8d9d 100644
--- a/content/shell/test_runner/accessibility_controller.cc
+++ b/content/shell/test_runner/accessibility_controller.cc
@@ -260,7 +260,6 @@
   blink::WebNode node = obj.GetNode();
   if (!node.IsNull() && node.IsElementNode()) {
     blink::WebElement element = node.To<blink::WebElement>();
-    element.GetAttribute("id");
     if (element.GetAttribute("id") == id)
       return elements_.GetOrCreate(obj);
   }
@@ -269,7 +268,7 @@
   for (unsigned i = 0; i < childCount; i++) {
     v8::Local<v8::Object> result =
         FindAccessibleElementByIdRecursive(obj.ChildAt(i), id);
-    if (*result)
+    if (!result.IsEmpty())
       return result;
   }
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 5052d6a..18455585 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1250,7 +1250,7 @@
     deps += [
       "//chromeos/audio",
 
-      # TODO(stevenjb): Replace with //chromeos/dbus/cras once extracted.
+      # TODO(stevenjb): Replace with //chromeos/dbus/audio once extracted.
       # https://crbug.com/940810.
       "//chromeos/dbus",
     ]
@@ -2129,10 +2129,12 @@
     }
   }
   if (is_win) {
+    sources += [ "../browser/media/system_media_controls_notifier_unittest.cc" ]
     deps += [
       "//third_party/blink/public/common",
       "//third_party/blink/public/common:font_unique_name_table_proto",
       "//third_party/iaccessible2",
+      "//ui/base/win/system_media_controls:test_support",
     ]
     libs = [
       "dwrite.lib",
@@ -2156,7 +2158,7 @@
     deps += [
       "//chromeos/audio",
 
-      # TODO(stevenjb): Replace with //chromeos/dbus/cras once extracted.
+      # TODO(stevenjb): Replace with //chromeos/dbus/audio once extracted.
       # https://crbug.com/940810.
       "//chromeos/dbus",
     ]
diff --git a/content/test/DEPS b/content/test/DEPS
index c4e0990..e743fb947 100644
--- a/content/test/DEPS
+++ b/content/test/DEPS
@@ -13,7 +13,7 @@
 
   # For WebRTC tests.
   "+chromeos/audio",
-  "+chromeos/dbus/cras_audio_client.h",
+  "+chromeos/dbus/audio",
   # Testing utilities can access anything in content/
   "+content",
   "+device/bluetooth", # For WebBluetooth tests
diff --git a/content/test/data/accessibility/aria/aria-owns-expected-blink.txt b/content/test/data/accessibility/aria/aria-owns-expected-blink.txt
index faf94dc..580d01f 100644
--- a/content/test/data/accessibility/aria/aria-owns-expected-blink.txt
+++ b/content/test/data/accessibility/aria/aria-owns-expected-blink.txt
@@ -1,8 +1,8 @@
 rootWebArea
 ++list
 ++++listItem
+++++++listMarker name='• '
 ++++++genericContainer
-++++++++listMarker name='• '
 ++++++++staticText name='One'
 ++++++++++inlineTextBox name='One'
 ++++listItem
diff --git a/content/test/data/accessibility/aria/aria-owns-expected-mac.txt b/content/test/data/accessibility/aria/aria-owns-expected-mac.txt
index c2b9c52..4481ffe 100644
--- a/content/test/data/accessibility/aria/aria-owns-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-owns-expected-mac.txt
@@ -1,8 +1,8 @@
 AXWebArea
 ++AXList
 ++++AXGroup
+++++++AXListMarker AXValue='• '
 ++++++AXGroup
-++++++++AXListMarker AXValue='• '
 ++++++++AXStaticText AXValue='One'
 ++++AXGroup
 ++++++AXListMarker AXValue='• '
diff --git a/content/test/data/accessibility/css/dom-element-css-alternative-text-expected-auralinux.txt b/content/test/data/accessibility/css/dom-element-css-alternative-text-expected-auralinux.txt
new file mode 100644
index 0000000..1747a89
--- /dev/null
+++ b/content/test/data/accessibility/css/dom-element-css-alternative-text-expected-auralinux.txt
@@ -0,0 +1,3 @@
+[document web]
+++[section]
+++++[image] name='alternative text'
diff --git a/content/test/data/accessibility/css/dom-element-css-alternative-text-expected-blink.txt b/content/test/data/accessibility/css/dom-element-css-alternative-text-expected-blink.txt
new file mode 100644
index 0000000..ff1a61a
--- /dev/null
+++ b/content/test/data/accessibility/css/dom-element-css-alternative-text-expected-blink.txt
@@ -0,0 +1,3 @@
+rootWebArea
+++genericContainer
+++++image name='alternative text'
diff --git a/content/test/data/accessibility/css/dom-element-css-alternative-text.html b/content/test/data/accessibility/css/dom-element-css-alternative-text.html
new file mode 100644
index 0000000..a0e2774
--- /dev/null
+++ b/content/test/data/accessibility/css/dom-element-css-alternative-text.html
@@ -0,0 +1,14 @@
+
+<!DOCTYPE html>
+<html>
+<head>
+  <style>
+    #element {
+      content: url(bullet.png) / "alternative text";
+    }
+  </style>
+</head>
+<body>
+  <span id="element">DOM text</span>
+</body>
+</html>
diff --git a/content/test/data/accessibility/event/add-hidden-attribute-expected-win.txt b/content/test/data/accessibility/event/add-hidden-attribute-expected-win.txt
index 2e7b947..4b87b52 100644
--- a/content/test/data/accessibility/event/add-hidden-attribute-expected-win.txt
+++ b/content/test/data/accessibility/event/add-hidden-attribute-expected-win.txt
@@ -1,3 +1,3 @@
 EVENT_OBJECT_HIDE on <div#item3> role=ROLE_SYSTEM_LISTITEM name="Item 3" PosInSet=3 SetSize=3
 EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_LIST SetSize=2
-IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_LIST SetSize=3 old_text={'<obj>' start=2 end=3}
+IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_LIST SetSize=2 old_text={'<obj>' start=2 end=3}
diff --git a/content/test/data/accessibility/event/add-hidden-attribute-subtree-expected-win.txt b/content/test/data/accessibility/event/add-hidden-attribute-subtree-expected-win.txt
index e556781..c7a7def 100644
--- a/content/test/data/accessibility/event/add-hidden-attribute-subtree-expected-win.txt
+++ b/content/test/data/accessibility/event/add-hidden-attribute-subtree-expected-win.txt
@@ -1,3 +1,3 @@
 EVENT_OBJECT_HIDE on <li#item3> role=ROLE_SYSTEM_LISTITEM PosInSet=3 SetSize=3
 EVENT_OBJECT_REORDER on <ul> role=ROLE_SYSTEM_LIST SetSize=2
-IA2_EVENT_TEXT_REMOVED on <ul> role=ROLE_SYSTEM_LIST SetSize=3 old_text={'<obj>' start=2 end=3}
+IA2_EVENT_TEXT_REMOVED on <ul> role=ROLE_SYSTEM_LIST SetSize=2 old_text={'<obj>' start=2 end=3}
diff --git a/content/test/data/accessibility/event/add-subtree-expected-win.txt b/content/test/data/accessibility/event/add-subtree-expected-win.txt
index de590142..57b78be 100644
--- a/content/test/data/accessibility/event/add-subtree-expected-win.txt
+++ b/content/test/data/accessibility/event/add-subtree-expected-win.txt
@@ -1,3 +1,3 @@
 EVENT_OBJECT_REORDER on <ul> role=ROLE_SYSTEM_LIST SetSize=3
 EVENT_OBJECT_SHOW on <li> role=ROLE_SYSTEM_LISTITEM PosInSet=3 SetSize=3
-IA2_EVENT_TEXT_INSERTED on <ul> role=ROLE_SYSTEM_LIST SetSize=2 new_text={'<obj>' start=2 end=3}
+IA2_EVENT_TEXT_INSERTED on <ul> role=ROLE_SYSTEM_LIST SetSize=3 new_text={'<obj>' start=2 end=3}
diff --git a/content/test/data/accessibility/event/aria-combo-box-focus.html b/content/test/data/accessibility/event/aria-combo-box-focus.html
index 7f95c02..8453827 100644
--- a/content/test/data/accessibility/event/aria-combo-box-focus.html
+++ b/content/test/data/accessibility/event/aria-combo-box-focus.html
@@ -2,6 +2,7 @@
 This line is to unflake the test, but may not be necessary (crbug.com/c/791268):
 @WIN-DENY:EVENT_OBJECT_LOCATIONCHANGE*
 @WIN-DENY:EVENT_OBJECT_SHOW*
+@UIA-WIN-DENY:Text_TextSelectionChanged*
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/data/accessibility/event/aria-controls-changed-expected-uia-win.txt b/content/test/data/accessibility/event/aria-controls-changed-expected-uia-win.txt
new file mode 100644
index 0000000..d4270214
--- /dev/null
+++ b/content/test/data/accessibility/event/aria-controls-changed-expected-uia-win.txt
@@ -0,0 +1,3 @@
+ControllerFor changed on role=radiogroup
+=== Start Continuation ===
+ControllerFor changed on role=button
diff --git a/content/test/data/accessibility/event/aria-controls-changed.html b/content/test/data/accessibility/event/aria-controls-changed.html
new file mode 100644
index 0000000..22ed288
--- /dev/null
+++ b/content/test/data/accessibility/event/aria-controls-changed.html
@@ -0,0 +1,29 @@
+<!--
+@UIA-WIN-DENY:*
+@UIA-WIN-ALLOW:ControllerFor*
+-->
+<!DOCTYPE html>
+<div id="radiogroup" role="radiogroup">
+  <div id="radio1" role="radio">radio1</div>
+  <div id="radio2" role="radio">radio2</div>
+  <div id="radio3" role="radio">radio3</div>
+</div>
+
+<input id="input1" type="text">
+<input id="input2" type="text">
+<button role="button" aria-controls="input1"></button>
+
+<script>
+  var go_passes = [
+    () => document.querySelector('div[role=radiogroup]').setAttribute(
+                                 'aria-controls', 'radio1 radio2 radio3'),
+    () => document.querySelector('button[role=button]').setAttribute(
+                                 'aria-controls', 'input2'),
+  ];
+
+  var current_pass = 0;
+  function go() {
+    go_passes[current_pass++].call();
+    return current_pass < go_passes.length;
+  }
+</script>
diff --git a/content/test/data/accessibility/event/description-change-indirect.html b/content/test/data/accessibility/event/description-change-indirect.html
index f5888b5..6cc0c53 100644
--- a/content/test/data/accessibility/event/description-change-indirect.html
+++ b/content/test/data/accessibility/event/description-change-indirect.html
@@ -1,6 +1,7 @@
 <!--
 @BLINK-ALLOW:description=*
 @WIN-ALLOW:description=*
+@UIA-WIN-DENY:Text_TextChanged*
 @MAC-ALLOW:AXDescription*
 @MAC-ALLOW:AXDescription*
 -->
diff --git a/content/test/data/accessibility/event/description-change.html b/content/test/data/accessibility/event/description-change.html
index c080dc39..0a9e6c1 100644
--- a/content/test/data/accessibility/event/description-change.html
+++ b/content/test/data/accessibility/event/description-change.html
@@ -1,3 +1,6 @@
+<!--
+@UIA-WIN-DENY:Text_TextChanged*
+-->
 <!DOCTYPE html>
 <html>
 <body>
diff --git a/content/test/data/accessibility/event/live-region-change.html b/content/test/data/accessibility/event/live-region-change.html
index caf272b..0624e55 100644
--- a/content/test/data/accessibility/event/live-region-change.html
+++ b/content/test/data/accessibility/event/live-region-change.html
@@ -1,3 +1,6 @@
+<!--
+@UIA-WIN-DENY:Text_TextChanged*
+-->
 <!DOCTYPE html>
 <html>
 <body>
diff --git a/content/test/data/accessibility/event/live-region-create.html b/content/test/data/accessibility/event/live-region-create.html
index a887b2a..5f09c9e 100644
--- a/content/test/data/accessibility/event/live-region-create.html
+++ b/content/test/data/accessibility/event/live-region-create.html
@@ -1,3 +1,6 @@
+<!--
+@UIA-WIN-DENY:Text_TextChanged*
+-->
 <!DOCTYPE html>
 <html>
 <body>
diff --git a/content/test/data/accessibility/event/menulist-collapse-next.html b/content/test/data/accessibility/event/menulist-collapse-next.html
index 0d985ed..d1b01f5 100644
--- a/content/test/data/accessibility/event/menulist-collapse-next.html
+++ b/content/test/data/accessibility/event/menulist-collapse-next.html
@@ -1,3 +1,6 @@
+<!--
+@UIA-WIN-DENY:Text_TextChanged*
+-->
 <!DOCTYPE html>
 <html>
 <body>
diff --git a/content/test/data/accessibility/event/menulist-collapse.html b/content/test/data/accessibility/event/menulist-collapse.html
index ad7f1855..ac1dacb4a 100644
--- a/content/test/data/accessibility/event/menulist-collapse.html
+++ b/content/test/data/accessibility/event/menulist-collapse.html
@@ -1,3 +1,6 @@
+<!--
+@UIA-WIN-DENY:Text_TextChanged*
+-->
 <!DOCTYPE html>
 <html>
 <body>
diff --git a/content/test/data/accessibility/event/menulist-focus.html b/content/test/data/accessibility/event/menulist-focus.html
index 73ba0b0..bc5b9b0 100644
--- a/content/test/data/accessibility/event/menulist-focus.html
+++ b/content/test/data/accessibility/event/menulist-focus.html
@@ -1,3 +1,6 @@
+<!--
+@UIA-WIN-DENY:Text_TextChanged*
+-->
 <!DOCTYPE html>
 <html>
 <body>
diff --git a/content/test/data/accessibility/event/name-change-indirect.html b/content/test/data/accessibility/event/name-change-indirect.html
index 7064872..6f8a356 100644
--- a/content/test/data/accessibility/event/name-change-indirect.html
+++ b/content/test/data/accessibility/event/name-change-indirect.html
@@ -1,3 +1,6 @@
+<!--
+@UIA-WIN-DENY:Text_TextChanged*
+-->
 <!DOCTYPE html>
 <html>
 <body>
diff --git a/content/test/data/accessibility/event/name-change.html b/content/test/data/accessibility/event/name-change.html
index c2646d3..23f9899a 100644
--- a/content/test/data/accessibility/event/name-change.html
+++ b/content/test/data/accessibility/event/name-change.html
@@ -1,3 +1,6 @@
+<!--
+@UIA-WIN-DENY:Text_TextChanged*
+-->
 <!DOCTYPE html>
 <html>
 <body>
diff --git a/content/test/data/accessibility/event/remove-child-expected-win.txt b/content/test/data/accessibility/event/remove-child-expected-win.txt
index 2e7b947..4b87b52 100644
--- a/content/test/data/accessibility/event/remove-child-expected-win.txt
+++ b/content/test/data/accessibility/event/remove-child-expected-win.txt
@@ -1,3 +1,3 @@
 EVENT_OBJECT_HIDE on <div#item3> role=ROLE_SYSTEM_LISTITEM name="Item 3" PosInSet=3 SetSize=3
 EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_LIST SetSize=2
-IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_LIST SetSize=3 old_text={'<obj>' start=2 end=3}
+IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_LIST SetSize=2 old_text={'<obj>' start=2 end=3}
diff --git a/content/test/data/accessibility/event/text-changed-contenteditable-expected-auralinux.txt b/content/test/data/accessibility/event/text-changed-contenteditable-expected-auralinux.txt
index 1d49e7e7..4419f72 100644
--- a/content/test/data/accessibility/event/text-changed-contenteditable-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/text-changed-contenteditable-expected-auralinux.txt
@@ -14,11 +14,11 @@
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
-TEXT-INSERT (start=0 length=16 'Before Div After') role=ROLE_SECTION name='(null)' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
-TEXT-INSERT (start=0 length=22 'Before Paragraph After') role=ROLE_PARAGRAPH name='(null)' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
-TEXT-INSERT (start=0 length=9 'Modified ') role=ROLE_PARAGRAPH name='(null)' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
-TEXT-INSERT (start=0 length=9 'Modified ') role=ROLE_SECTION name='(null)' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
-TEXT-REMOVE (start=0 length=3 'Div') role=ROLE_SECTION name='(null)' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
-TEXT-REMOVE (start=0 length=3 'Div') role=ROLE_SECTION name='(null)' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
-TEXT-REMOVE (start=0 length=9 'Paragraph') role=ROLE_PARAGRAPH name='(null)' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
-TEXT-REMOVE (start=0 length=9 'Paragraph') role=ROLE_PARAGRAPH name='(null)' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
+TEXT-INSERT (start=0 length=16 'Before Div After') role=ROLE_SECTION name='d3' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
+TEXT-INSERT (start=0 length=22 'Before Paragraph After') role=ROLE_PARAGRAPH name='p3' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
+TEXT-INSERT (start=0 length=9 'Modified ') role=ROLE_PARAGRAPH name='p1' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
+TEXT-INSERT (start=0 length=9 'Modified ') role=ROLE_SECTION name='d1' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
+TEXT-REMOVE (start=0 length=3 'Div') role=ROLE_SECTION name='d2' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
+TEXT-REMOVE (start=0 length=3 'Div') role=ROLE_SECTION name='d3' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
+TEXT-REMOVE (start=0 length=9 'Paragraph') role=ROLE_PARAGRAPH name='p2' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
+TEXT-REMOVE (start=0 length=9 'Paragraph') role=ROLE_PARAGRAPH name='p3' EDITABLE,ENABLED,FOCUSABLE,MULTI-LINE,SENSITIVE,SHOWING,VISIBLE,SELECTABLE-TEXT
diff --git a/content/test/data/accessibility/event/text-changed-contenteditable-expected-uia-win.txt b/content/test/data/accessibility/event/text-changed-contenteditable-expected-uia-win.txt
new file mode 100644
index 0000000..c34ee1e
--- /dev/null
+++ b/content/test/data/accessibility/event/text-changed-contenteditable-expected-uia-win.txt
@@ -0,0 +1,4 @@
+Text_TextChanged on role=group, name=d1
+Text_TextChanged on role=group, name=d3
+Text_TextChanged on role=group, name=p1
+Text_TextChanged on role=group, name=p3
diff --git a/content/test/data/accessibility/event/text-changed-contenteditable-expected-win.txt b/content/test/data/accessibility/event/text-changed-contenteditable-expected-win.txt
new file mode 100644
index 0000000..0d46f381
--- /dev/null
+++ b/content/test/data/accessibility/event/text-changed-contenteditable-expected-win.txt
@@ -0,0 +1,24 @@
+EVENT_OBJECT_HIDE on role=ROLE_SYSTEM_STATICTEXT name="Div" IA2_STATE_EDITABLE
+EVENT_OBJECT_HIDE on role=ROLE_SYSTEM_STATICTEXT name="Div" IA2_STATE_EDITABLE
+EVENT_OBJECT_HIDE on role=ROLE_SYSTEM_STATICTEXT name="Div" IA2_STATE_EDITABLE
+EVENT_OBJECT_HIDE on role=ROLE_SYSTEM_STATICTEXT name="Paragraph" IA2_STATE_EDITABLE
+EVENT_OBJECT_HIDE on role=ROLE_SYSTEM_STATICTEXT name="Paragraph" IA2_STATE_EDITABLE
+EVENT_OBJECT_HIDE on role=ROLE_SYSTEM_STATICTEXT name="Paragraph" IA2_STATE_EDITABLE
+EVENT_OBJECT_SHOW on role=ROLE_SYSTEM_STATICTEXT name="Before Div After" IA2_STATE_EDITABLE
+EVENT_OBJECT_SHOW on role=ROLE_SYSTEM_STATICTEXT name="Before Paragraph After" IA2_STATE_EDITABLE
+EVENT_OBJECT_SHOW on role=ROLE_SYSTEM_STATICTEXT name="Modified Div" IA2_STATE_EDITABLE
+EVENT_OBJECT_SHOW on role=ROLE_SYSTEM_STATICTEXT name="Modified Paragraph" IA2_STATE_EDITABLE
+EVENT_OBJECT_VALUECHANGE on <div#d1> role=DIV name="d1" value="Modified Div" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT
+EVENT_OBJECT_VALUECHANGE on <div#d2> role=DIV name="d2" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT
+EVENT_OBJECT_VALUECHANGE on <div#d3> role=DIV name="d3" value="Before Div After" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT
+EVENT_OBJECT_VALUECHANGE on <p#p1> role=P name="p1" value="Modified Paragraph" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT
+EVENT_OBJECT_VALUECHANGE on <p#p2> role=P name="p2" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT
+EVENT_OBJECT_VALUECHANGE on <p#p3> role=P name="p3" value="Before Paragraph After" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT
+IA2_EVENT_TEXT_INSERTED on <div#d1> role=DIV name="d1" value="Modified Div" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT new_text={'Modified ' start=0 end=9}
+IA2_EVENT_TEXT_INSERTED on <div#d3> role=DIV name="d3" value="Before Div After" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT new_text={'Before Div After' start=0 end=16}
+IA2_EVENT_TEXT_INSERTED on <p#p1> role=P name="p1" value="Modified Paragraph" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT new_text={'Modified ' start=0 end=9}
+IA2_EVENT_TEXT_INSERTED on <p#p3> role=P name="p3" value="Before Paragraph After" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT new_text={'Before Paragraph After' start=0 end=22}
+IA2_EVENT_TEXT_REMOVED on <div#d2> role=DIV name="d2" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT old_text={'Div' start=0 end=3}
+IA2_EVENT_TEXT_REMOVED on <div#d3> role=DIV name="d3" value="Before Div After" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT old_text={'Div' start=0 end=3}
+IA2_EVENT_TEXT_REMOVED on <p#p2> role=P name="p2" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT old_text={'Paragraph' start=0 end=9}
+IA2_EVENT_TEXT_REMOVED on <p#p3> role=P name="p3" value="Before Paragraph After" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_MULTI_LINE,IA2_STATE_SELECTABLE_TEXT old_text={'Paragraph' start=0 end=9}
diff --git a/content/test/data/accessibility/event/text-changed-contenteditable.html b/content/test/data/accessibility/event/text-changed-contenteditable.html
index db0f3248..f7b1f57 100644
--- a/content/test/data/accessibility/event/text-changed-contenteditable.html
+++ b/content/test/data/accessibility/event/text-changed-contenteditable.html
@@ -1,12 +1,16 @@
+<!--
+The children changed / reorder event is fired an unpredictable number of times.
+@WIN-DENY:EVENT_OBJECT_REORDER*
+-->
 <!DOCTYPE html>
 <html>
 <body>
-<p id="p1" contenteditable>Paragraph</p>
-<p id="p2" contenteditable>Paragraph</p>
-<p id="p3" contenteditable>Paragraph</p>
-<div id="d1" contenteditable>Div</div>
-<div id="d2" contenteditable>Div</div>
-<div id="d3" contenteditable>Div</div>
+<p id="p1" aria-label="p1" contenteditable>Paragraph</p>
+<p id="p2" aria-label="p2" contenteditable>Paragraph</p>
+<p id="p3" aria-label="p3" contenteditable>Paragraph</p>
+<div id="d1" aria-label="d1" contenteditable>Div</div>
+<div id="d2" aria-label="d2" contenteditable>Div</div>
+<div id="d3" aria-label="d3" contenteditable>Div</div>
 <script>
   function go() {
     document.querySelector('#p1').textContent = 'Modified Paragraph';
diff --git a/content/test/data/accessibility/event/text-changed-expected-auralinux.txt b/content/test/data/accessibility/event/text-changed-expected-auralinux.txt
index 6e87438..8fa35bd 100644
--- a/content/test/data/accessibility/event/text-changed-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/text-changed-expected-auralinux.txt
@@ -1,5 +1,5 @@
+NAME-CHANGED:Modified Div role=ROLE_TEXT name='Modified Div' ENABLED,SENSITIVE,SHOWING,VISIBLE
 NAME-CHANGED:Modified Heading role=ROLE_TEXT name='Modified Heading' ENABLED,SENSITIVE,SHOWING,VISIBLE
-NAME-CHANGED:Text modified role=ROLE_TEXT name='Text modified' ENABLED,SENSITIVE,SHOWING,VISIBLE
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
@@ -7,4 +7,3 @@
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
-
diff --git a/content/test/data/accessibility/event/text-changed-expected-uia-win.txt b/content/test/data/accessibility/event/text-changed-expected-uia-win.txt
index abbec0f..81b32ff 100644
--- a/content/test/data/accessibility/event/text-changed-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/text-changed-expected-uia-win.txt
@@ -1,2 +1,5 @@
-Name changed on role=description, name=Text modified
-Name changed on role=heading, name=Heading
+Name changed on role=description, name=Modified Div
+Name changed on role=heading, name=h
+Text_TextChanged on role=description, name=Modified Div
+Text_TextChanged on role=document
+Text_TextChanged on role=heading, name=h
diff --git a/content/test/data/accessibility/event/text-changed-expected-win.txt b/content/test/data/accessibility/event/text-changed-expected-win.txt
index 7dbfc10..9b465af 100644
--- a/content/test/data/accessibility/event/text-changed-expected-win.txt
+++ b/content/test/data/accessibility/event/text-changed-expected-win.txt
@@ -1,8 +1,8 @@
 EVENT_OBJECT_HIDE on role=ROLE_SYSTEM_STATICTEXT name="Para"
 EVENT_OBJECT_SHOW on role=ROLE_SYSTEM_STATICTEXT name="Modified Para"
-IA2_EVENT_TEXT_INSERTED on <div> role=DIV name="div" new_text={'Text modified' start=0 end=13}
-IA2_EVENT_TEXT_INSERTED on <h2#h> role=H2 name="Heading" level=2 new_text={'Modified Heading' start=0 end=16}
-IA2_EVENT_TEXT_INSERTED on <p#p> role=P new_text={'Modified Para' start=0 end=13}
-IA2_EVENT_TEXT_REMOVED on <div> role=DIV name="div" old_text={'Div' start=0 end=3}
-IA2_EVENT_TEXT_REMOVED on <h2#h> role=H2 name="Heading" level=2 old_text={'Heading' start=0 end=7}
-IA2_EVENT_TEXT_REMOVED on <p#p> role=P old_text={'Para' start=0 end=4}
+IA2_EVENT_TEXT_INSERTED on <div#d> role=DIV name="d" new_text={'Modified Div' start=0 end=12}
+IA2_EVENT_TEXT_INSERTED on <h2#h> role=H2 name="h" level=2 new_text={'Modified Heading' start=0 end=16}
+IA2_EVENT_TEXT_INSERTED on <p#p> role=P name="p" new_text={'Modified Para' start=0 end=13}
+IA2_EVENT_TEXT_REMOVED on <div#d> role=DIV name="d" old_text={'Div' start=0 end=3}
+IA2_EVENT_TEXT_REMOVED on <h2#h> role=H2 name="h" level=2 old_text={'Heading' start=0 end=7}
+IA2_EVENT_TEXT_REMOVED on <p#p> role=P name="p" old_text={'Para' start=0 end=4}
diff --git a/content/test/data/accessibility/event/text-changed.html b/content/test/data/accessibility/event/text-changed.html
index 77f4ebc..cf715e3c 100644
--- a/content/test/data/accessibility/event/text-changed.html
+++ b/content/test/data/accessibility/event/text-changed.html
@@ -5,14 +5,14 @@
 <!DOCTYPE html>
 <html>
 <body>
-<p id="p">Para</p>
-<h2 id="h">Heading</h2>
-<div aria-label="div">Div</div>
+<p id="p" aria-label="p">Para</p>
+<h2 id="h" aria-label="h">Heading</h2>
+<div id="d" aria-label="d">Div</div>
 <script>
   function go() {
     document.querySelector('#p').textContent = 'Modified Para';
     document.querySelector('#h').firstChild.data = 'Modified Heading';
-    document.querySelector('div').firstChild.data = 'Text modified';
+    document.querySelector('#d').firstChild.data = 'Modified Div';
   }
 </script>
 </body>
diff --git a/content/test/data/accessibility/event/text-selection-changed-expected-uia-win.txt b/content/test/data/accessibility/event/text-selection-changed-expected-uia-win.txt
new file mode 100644
index 0000000..9a5505b
--- /dev/null
+++ b/content/test/data/accessibility/event/text-selection-changed-expected-uia-win.txt
@@ -0,0 +1,5 @@
+Text_TextSelectionChanged on role=document
+=== Start Continuation ===
+Text_TextSelectionChanged on role=textbox, name=input
+=== Start Continuation ===
+Text_TextSelectionChanged on role=textbox, name=textarea
diff --git a/content/test/data/accessibility/event/text-selection-changed.html b/content/test/data/accessibility/event/text-selection-changed.html
new file mode 100644
index 0000000..6b9dfa4
--- /dev/null
+++ b/content/test/data/accessibility/event/text-selection-changed.html
@@ -0,0 +1,34 @@
+<!--
+@UIA-WIN-DENY:AutomationFocusChanged*
+-->
+<!DOCTYPE html>
+<div>
+  <h1 id="header" aria-label="title">title</h1>
+  <input id="input" aria-label="input" value="input"/>
+  <textarea id="textarea" aria-label="textarea"></textarea>
+</div>
+<script>
+  var input = document.getElementById("input");
+  var header = document.getElementById("header");
+  var textarea = document.getElementById("textarea");
+
+  const go_passes = [
+    () => {
+      var range = document.createRange();
+      range.selectNodeContents(header);
+      window.getSelection().removeAllRanges();
+      window.getSelection().addRange(range);
+    },
+    () => {
+      input.focus();
+      input.setSelectionRange(2, 3);
+    },
+    () => textarea.select(),
+  ];
+
+  var current_pass = 0;
+  function go() {
+    go_passes[current_pass++].call();
+    return current_pass < go_passes.length;
+  }
+</script>
diff --git a/content/test/data/accessibility/html/modal-dialog-opened-expected-android.txt b/content/test/data/accessibility/html/modal-dialog-opened-expected-android.txt
index badc901b..2b5b6e0 100644
--- a/content/test/data/accessibility/html/modal-dialog-opened-expected-android.txt
+++ b/content/test/data/accessibility/html/modal-dialog-opened-expected-android.txt
@@ -1,5 +1,5 @@
 android.webkit.WebView focusable scrollable
-++android.view.View
 ++android.app.Dialog role_description='dialog'
 ++++android.view.View name='The dialog subtree should be the only text content in the accessibility tree. '
 ++++android.view.View role_description='link' clickable focusable focused link name='Link inside the dialog.'
+++android.view.View
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/modal-dialog-opened-expected-auralinux.txt b/content/test/data/accessibility/html/modal-dialog-opened-expected-auralinux.txt
index 6a184f3..210eb46 100644
--- a/content/test/data/accessibility/html/modal-dialog-opened-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/modal-dialog-opened-expected-auralinux.txt
@@ -1,6 +1,6 @@
 [document web]
-++[section]
 ++[dialog] modal
 ++++[text] name='The dialog subtree should be the only text content in the accessibility tree. '
 ++++[link] name='Link inside the dialog.'
 ++++++[text] name='Link inside the dialog.'
+++[section]
diff --git a/content/test/data/accessibility/html/modal-dialog-opened-expected-blink.txt b/content/test/data/accessibility/html/modal-dialog-opened-expected-blink.txt
index 7bf19fc..1cf7805 100644
--- a/content/test/data/accessibility/html/modal-dialog-opened-expected-blink.txt
+++ b/content/test/data/accessibility/html/modal-dialog-opened-expected-blink.txt
@@ -1,8 +1,8 @@
 rootWebArea
-++genericContainer
 ++dialog
 ++++staticText name='The dialog subtree should be the only text content in the accessibility tree. '
 ++++++inlineTextBox name='The dialog subtree should be the only text content in the accessibility tree. '
 ++++link name='Link inside the dialog.'
 ++++++staticText name='Link inside the dialog.'
 ++++++++inlineTextBox name='Link inside the dialog.'
+++genericContainer
diff --git a/content/test/data/accessibility/html/modal-dialog-opened-expected-mac.txt b/content/test/data/accessibility/html/modal-dialog-opened-expected-mac.txt
index e3e9609b..b2f19e8 100644
--- a/content/test/data/accessibility/html/modal-dialog-opened-expected-mac.txt
+++ b/content/test/data/accessibility/html/modal-dialog-opened-expected-mac.txt
@@ -1,6 +1,6 @@
 AXWebArea
-++AXGroup
 ++AXGroup AXSubrole=AXApplicationDialog
 ++++AXStaticText AXValue='The dialog subtree should be the only text content in the accessibility tree. '
 ++++AXLink AXTitle='Link inside the dialog.'
 ++++++AXStaticText AXValue='Link inside the dialog.'
+++AXGroup
diff --git a/content/test/data/accessibility/html/modal-dialog-opened-expected-win.txt b/content/test/data/accessibility/html/modal-dialog-opened-expected-win.txt
index 09ab3cb..8fd398a 100644
--- a/content/test/data/accessibility/html/modal-dialog-opened-expected-win.txt
+++ b/content/test/data/accessibility/html/modal-dialog-opened-expected-win.txt
@@ -1,6 +1,6 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_DIALOG IA2_STATE_MODAL
 ++++ROLE_SYSTEM_STATICTEXT name='The dialog subtree should be the only text content in the accessibility tree. '
 ++++ROLE_SYSTEM_LINK name='Link inside the dialog.' FOCUSABLE
 ++++++ROLE_SYSTEM_STATICTEXT name='Link inside the dialog.'
+++IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/html/modal-dialog-stack-expected-android.txt b/content/test/data/accessibility/html/modal-dialog-stack-expected-android.txt
index 75cb37a..aaa0943 100644
--- a/content/test/data/accessibility/html/modal-dialog-stack-expected-android.txt
+++ b/content/test/data/accessibility/html/modal-dialog-stack-expected-android.txt
@@ -1,5 +1,5 @@
 android.webkit.WebView focusable focused scrollable
-++android.view.View
 ++android.app.Dialog role_description='dialog'
 ++++android.view.View name='This is the now active dialog. Of course it should be in the tree. '
 ++++android.widget.Button role_description='button' clickable focusable name='This is in the active dialog and should be in the tree.'
+++android.view.View
diff --git a/content/test/data/accessibility/html/modal-dialog-stack-expected-auralinux.txt b/content/test/data/accessibility/html/modal-dialog-stack-expected-auralinux.txt
index 7a0a189..c072723 100644
--- a/content/test/data/accessibility/html/modal-dialog-stack-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/modal-dialog-stack-expected-auralinux.txt
@@ -1,5 +1,5 @@
 [document web]
-++[section]
 ++[dialog] modal
 ++++[text] name='This is the now active dialog. Of course it should be in the tree. '
 ++++[push button] name='This is in the active dialog and should be in the tree.'
+++[section]
diff --git a/content/test/data/accessibility/html/modal-dialog-stack-expected-blink.txt b/content/test/data/accessibility/html/modal-dialog-stack-expected-blink.txt
index 127caf8..98dcc461 100644
--- a/content/test/data/accessibility/html/modal-dialog-stack-expected-blink.txt
+++ b/content/test/data/accessibility/html/modal-dialog-stack-expected-blink.txt
@@ -1,6 +1,6 @@
 rootWebArea
-++genericContainer
 ++dialog
 ++++staticText name='This is the now active dialog. Of course it should be in the tree. '
 ++++++inlineTextBox name='This is the now active dialog. Of course it should be in the tree. '
 ++++button name='This is in the active dialog and should be in the tree.'
+++genericContainer
diff --git a/content/test/data/accessibility/html/modal-dialog-stack-expected-mac.txt b/content/test/data/accessibility/html/modal-dialog-stack-expected-mac.txt
index fd373b1..1561a8b7 100644
--- a/content/test/data/accessibility/html/modal-dialog-stack-expected-mac.txt
+++ b/content/test/data/accessibility/html/modal-dialog-stack-expected-mac.txt
@@ -1,5 +1,5 @@
 AXWebArea
-++AXGroup
 ++AXGroup AXSubrole=AXApplicationDialog
 ++++AXStaticText AXValue='This is the now active dialog. Of course it should be in the tree. '
 ++++AXButton AXTitle='This is in the active dialog and should be in the tree.'
+++AXGroup
diff --git a/content/test/data/accessibility/html/modal-dialog-stack-expected-win.txt b/content/test/data/accessibility/html/modal-dialog-stack-expected-win.txt
index df25937bd..0160c77e 100644
--- a/content/test/data/accessibility/html/modal-dialog-stack-expected-win.txt
+++ b/content/test/data/accessibility/html/modal-dialog-stack-expected-win.txt
@@ -1,5 +1,5 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_DIALOG IA2_STATE_MODAL
 ++++ROLE_SYSTEM_STATICTEXT name='This is the now active dialog. Of course it should be in the tree. '
 ++++ROLE_SYSTEM_PUSHBUTTON name='This is in the active dialog and should be in the tree.' FOCUSABLE
+++IA2_ROLE_SECTION
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 99dae1d..48bc2272 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -312,6 +312,10 @@
     self.Flaky('deqp/functional/gles3/multisample.html',
         ['win', ('amd', 0x6613)], bug=687374)
 
+    # Failing on AMD RX 550
+    self.Skip('deqp/functional/gles3/fborender/shared_colorbuffer_02.html',
+              ['win', ('amd', 0x699f)], bug=3354) # ANGLE bug ID
+
     # Win / Intel
     self.Fail('conformance/rendering/rendering-stencil-large-viewport.html',
         ['win', 'intel', 'd3d11'], bug=782317)
@@ -455,6 +459,8 @@
         ['linux', 'passthrough', 'opengl', 'intel'], bug=2760) # ANGLE bug
     self.Fail('conformance2/textures/misc/tex-mipmap-levels.html',
         ['linux', 'passthrough', 'opengl', 'intel'], bug=2761) # ANGLE bug
+    self.Flaky('conformance/extensions/webgl-compressed-texture-s3tc.html',
+        ['linux', 'passthrough', 'opengl', 'intel'], bug=950787)
 
     # Regressions in 10.12.4.
     self.Fail('conformance2/textures/misc/tex-base-level-bug.html',
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 74ab3d0..f2b5ff1 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -338,10 +338,14 @@
     self.Fail('conformance/rendering/clipping-wide-points.html',
         ['win', 'amd', 'opengl'], bug=1506) # angle bug ID
     # AMD RX 550 Failures
+    self.Skip('conformance/glsl/bugs/gl-fragcoord-multisampling-bug.html',
+        ['win', ('amd', 0x699f), 'opengl'], bug=950123)
     self.Skip('conformance/glsl/misc/fragcolor-fragdata-invariant.html',
         ['win', ('amd', 0x699f), 'opengl'], bug=950123)
     self.Skip('conformance/glsl/samplers/glsl-function-texture2dprojlod.html',
         ['win', ('amd', 0x699f), 'opengl'], bug=950123)
+    self.Skip('conformance/rendering/line-rendering-quality.html',
+        ['win', ('amd', 0x699f), 'opengl'], bug=950123)
 
     # Mark ANGLE's OpenGL as flaky on Windows Amd
     self.Flaky('conformance/*', ['win', 'amd', 'opengl'], bug=582083)
diff --git a/content/test/ppapi/ppapi_test.cc b/content/test/ppapi/ppapi_test.cc
index d3c9b29..b622d12 100644
--- a/content/test/ppapi/ppapi_test.cc
+++ b/content/test/ppapi/ppapi_test.cc
@@ -22,7 +22,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/cras_audio_client.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 #endif
 
 namespace content {
diff --git a/docs/sublime_ide.md b/docs/sublime_ide.md
index 2526e6b3..9706386 100644
--- a/docs/sublime_ide.md
+++ b/docs/sublime_ide.md
@@ -262,7 +262,7 @@
 page](https://github.com/karlinjf/ChromiumXRefs/).
 
 
-## Code Completion, Error Highlighting, Go-to-Definition, and Find References with LSP
+## Code Completion, Error Highlighting, Go-to-Definition, and Find References with LSP (clangd)
 
 Gives Sublime Text 3 rich editing features for languages with Language Server
 Protocol support. It searches the current compilation unit for definitions and
@@ -270,28 +270,15 @@
 
 In this case, we're going to add C/C++ support.
 
-1. Install clangd
+1. Refer to [clangd.md](clangd.md) to install clangd and build a compilation
+   database.
 
-    ```shell 
-    sudo apt-get install clangd
-    ```
+1. Install the [LSP Package](https://github.com/tomv564/LSP) and enable clangd
+   support by following the [link](https://clang.llvm.org/extra/clangd/Installation.html#editor-plugins)
+   and following the instructions for Sublime Text.
 
-1. Build a compilation database (clangd learns how to compile chromium objects
-   with this). You'll need to run this periodically to keep it up to date.
-
-    ```shell 
-    ninja -C out -t compdb cxx > compile_commands.json
-    mv compile_commands.json <path_to_src>
-    ```
-
-1. Install the LSP package in sublime-text
-
-1. Open a source file in your chromium project
-
-1. Ctrl+Shift+P and select "LSP: enable language server in project" and select
-   clangd
-
-To remove sublime text's auto completion and only show LSPs (recommended), set the following LSP preference:
+To remove sublime text's auto completion and only show LSPs (recommended), set
+the following LSP preference:
 
 ```json
 "only_show_lsp_completions": true
diff --git a/extensions/browser/api/audio/audio_apitest_chromeos.cc b/extensions/browser/api/audio/audio_apitest_chromeos.cc
index eb5e76f..5b0d7ba3 100644
--- a/extensions/browser/api/audio/audio_apitest_chromeos.cc
+++ b/extensions/browser/api/audio/audio_apitest_chromeos.cc
@@ -13,7 +13,7 @@
 #include "build/build_config.h"
 #include "chromeos/audio/audio_devices_pref_handler_stub.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/fake_cras_audio_client.h"
+#include "chromeos/dbus/audio/fake_cras_audio_client.h"
 #include "extensions/common/features/feature_session_type.h"
 #include "extensions/common/switches.h"
 #include "extensions/shell/test/shell_apitest.h"
diff --git a/extensions/common/features/simple_feature.cc b/extensions/common/features/simple_feature.cc
index 3746bc1..f8f6318 100644
--- a/extensions/common/features/simple_feature.cc
+++ b/extensions/common/features/simple_feature.cc
@@ -187,10 +187,6 @@
 }
 
 bool IsAllowlistedForTest(const HashedExtensionId& hashed_id) {
-  // TODO(jackhou): Delete the commandline allowlisting mechanism.
-  // Since it is only used it tests, ideally it should not be set via the
-  // commandline. At the moment the commandline is used as a mechanism to pass
-  // the id to the renderer process.
   const std::string& allowlisted_id = g_allowlist_info.Get().hashed_id;
   return !allowlisted_id.empty() && allowlisted_id == hashed_id.value();
 }
@@ -603,8 +599,10 @@
     return CreateAvailability(NOT_FOUND_IN_WHITELIST);
   }
 
-  if (location_ && !MatchesManifestLocation(location))
+  if (location_ && !MatchesManifestLocation(location) &&
+      !IsAllowlistedForTest(hashed_id)) {
     return CreateAvailability(INVALID_LOCATION);
+  }
 
   if (min_manifest_version_ && manifest_version < *min_manifest_version_)
     return CreateAvailability(INVALID_MIN_MANIFEST_VERSION);
diff --git a/extensions/shell/browser/shell_audio_controller_chromeos_unittest.cc b/extensions/shell/browser/shell_audio_controller_chromeos_unittest.cc
index 80a6cb2..f8525f3 100644
--- a/extensions/shell/browser/shell_audio_controller_chromeos_unittest.cc
+++ b/extensions/shell/browser/shell_audio_controller_chromeos_unittest.cc
@@ -13,8 +13,8 @@
 #include "chromeos/audio/audio_device.h"
 #include "chromeos/audio/audio_devices_pref_handler.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/audio_node.h"
-#include "chromeos/dbus/fake_cras_audio_client.h"
+#include "chromeos/dbus/audio/audio_node.h"
+#include "chromeos/dbus/audio/fake_cras_audio_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using chromeos::AudioDevice;
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc
index c97008d..8a7860cc 100644
--- a/extensions/shell/browser/shell_browser_main_parts.cc
+++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -64,7 +64,7 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-#include "chromeos/dbus/cras_audio_client.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #elif defined(OS_LINUX)
diff --git a/fuchsia/engine/BUILD.gn b/fuchsia/engine/BUILD.gn
index 1ee7c32..1112933128 100644
--- a/fuchsia/engine/BUILD.gn
+++ b/fuchsia/engine/BUILD.gn
@@ -71,6 +71,7 @@
     "//content/public/child",
     "//content/public/common",
     "//content/public/renderer",
+    "//fuchsia:web_fidl",
     "//fuchsia/base",
     "//fuchsia/base:modular",
     "//mojo/public/cpp/bindings",
@@ -78,6 +79,7 @@
     "//services/service_manager/sandbox",
     "//skia/public/interfaces",
     "//third_party/blink/public/common",
+    "//third_party/fuchsia-sdk/sdk:web",
     "//ui/aura",
     "//ui/base/ime",
     "//ui/display",
@@ -92,10 +94,6 @@
   data = [
     "$root_out_dir/webrunner.pak",
   ]
-  public_deps = [
-    "//fuchsia:web_fidl",
-    "//third_party/fuchsia-sdk/sdk:web",
-  ]
   configs += [ ":web_engine_implementation" ]
   sources = [
     "browser/context_impl.cc",
@@ -104,8 +102,16 @@
     "browser/discarding_event_filter.h",
     "browser/frame_impl.cc",
     "browser/frame_impl.h",
+    "browser/legacy_context_bridge.cc",
+    "browser/legacy_context_bridge.h",
+    "browser/legacy_frame_bridge.cc",
+    "browser/legacy_frame_bridge.h",
     "browser/legacy_message_port_bridge.cc",
     "browser/legacy_message_port_bridge.h",
+    "browser/legacy_navigation_controller_bridge.cc",
+    "browser/legacy_navigation_controller_bridge.h",
+    "browser/legacy_navigation_event_listener_bridge.cc",
+    "browser/legacy_navigation_event_listener_bridge.h",
     "browser/message_port_impl.cc",
     "browser/message_port_impl.h",
     "browser/web_engine_browser_context.cc",
@@ -227,6 +233,7 @@
     ":web_engine_core",
     "//base/test:run_all_unittests",
     "//base/test:test_support",
+    "//fuchsia:web_fidl",
     "//testing/gmock",
     "//testing/gtest",
   ]
diff --git a/fuchsia/engine/browser/context_impl.cc b/fuchsia/engine/browser/context_impl.cc
index 749177d..ad3fc6e0 100644
--- a/fuchsia/engine/browser/context_impl.cc
+++ b/fuchsia/engine/browser/context_impl.cc
@@ -11,6 +11,7 @@
 #include "base/fuchsia/fuchsia_logging.h"
 #include "content/public/browser/web_contents.h"
 #include "fuchsia/engine/browser/frame_impl.h"
+#include "fuchsia/engine/browser/legacy_frame_bridge.h"
 
 ContextImpl::ContextImpl(content::BrowserContext* browser_context)
     : browser_context_(browser_context) {}
@@ -18,12 +19,13 @@
 ContextImpl::~ContextImpl() = default;
 
 void ContextImpl::CreateFrame(
-    fidl::InterfaceRequest<chromium::web::Frame> frame_request) {
+    fidl::InterfaceRequest<fuchsia::web::Frame> frame) {
   content::WebContents::CreateParams create_params(browser_context_, nullptr);
   create_params.initially_hidden = true;
   auto web_contents = content::WebContents::Create(create_params);
+
   frames_.insert(std::make_unique<FrameImpl>(std::move(web_contents), this,
-                                             std::move(frame_request)));
+                                             std::move(frame)));
 }
 
 void ContextImpl::DestroyFrame(FrameImpl* frame) {
@@ -35,8 +37,7 @@
   return allow_javascript_injection_;
 }
 
-FrameImpl* ContextImpl::GetFrameImplForTest(
-    chromium::web::FramePtr* frame_ptr) {
+FrameImpl* ContextImpl::GetFrameImplForTest(fuchsia::web::FramePtr* frame_ptr) {
   DCHECK(frame_ptr);
 
   // Find the FrameImpl whose channel is connected to |frame_ptr| by inspecting
@@ -60,3 +61,15 @@
 
   return nullptr;
 }
+
+FrameImpl* ContextImpl::GetFrameImplForTest(
+    chromium::web::FramePtr* frame_ptr) {
+  DCHECK(frame_ptr);
+
+  fuchsia::web::FramePtr* fuchsia_frame_ptr =
+      LegacyFrameBridge::GetFramePtrForTest(frame_ptr);
+  if (!fuchsia_frame_ptr)
+    return nullptr;
+
+  return GetFrameImplForTest(fuchsia_frame_ptr);
+}
diff --git a/fuchsia/engine/browser/context_impl.h b/fuchsia/engine/browser/context_impl.h
index 4e68f91..c28f23fe5 100644
--- a/fuchsia/engine/browser/context_impl.h
+++ b/fuchsia/engine/browser/context_impl.h
@@ -5,7 +5,7 @@
 #ifndef FUCHSIA_ENGINE_BROWSER_CONTEXT_IMPL_H_
 #define FUCHSIA_ENGINE_BROWSER_CONTEXT_IMPL_H_
 
-#include <lib/fidl/cpp/binding_set.h>
+#include <fuchsia/web/cpp/fidl.h>
 #include <memory>
 #include <set>
 
@@ -20,10 +20,10 @@
 
 class FrameImpl;
 
-// Implementation of Context from //fuchsia/fidl/context.fidl.
+// Implementation of Context from fuchsia.web.
 // Owns a BrowserContext instance and uses it to create new WebContents/Frames.
 // All created Frames are owned by this object.
-class WEB_ENGINE_EXPORT ContextImpl : public chromium::web::Context {
+class WEB_ENGINE_EXPORT ContextImpl : public fuchsia::web::Context {
  public:
   // |browser_context| must outlive ContextImpl.
   explicit ContextImpl(content::BrowserContext* browser_context);
@@ -41,11 +41,12 @@
   // Returns |true| if JS injection was enabled for this Context.
   bool IsJavaScriptInjectionAllowed();
 
-  // chromium::web::Context implementation.
-  void CreateFrame(fidl::InterfaceRequest<chromium::web::Frame> frame) override;
+  // fuchsia::web::Context implementation.
+  void CreateFrame(fidl::InterfaceRequest<fuchsia::web::Frame> frame) override;
 
   // Gets the underlying FrameImpl service object associated with a connected
   // |frame_ptr| client.
+  FrameImpl* GetFrameImplForTest(fuchsia::web::FramePtr* frame_ptr);
   FrameImpl* GetFrameImplForTest(chromium::web::FramePtr* frame_ptr);
 
  private:
diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc
index ed0b2c0..29ad5c99 100644
--- a/fuchsia/engine/browser/frame_impl.cc
+++ b/fuchsia/engine/browser/frame_impl.cc
@@ -4,14 +4,11 @@
 
 #include "fuchsia/engine/browser/frame_impl.h"
 
-#include <zircon/syscalls.h>
-
-#include <string>
+#include <limits>
 
 #include "base/bind_helpers.h"
 #include "base/fuchsia/fuchsia_logging.h"
-#include "base/logging.h"
-#include "base/run_loop.h"
+#include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/public/browser/browser_thread.h"
@@ -23,7 +20,6 @@
 #include "content/public/common/was_activated_option.h"
 #include "fuchsia/base/mem_buffer_util.h"
 #include "fuchsia/engine/browser/context_impl.h"
-#include "fuchsia/engine/browser/legacy_message_port_bridge.h"
 #include "fuchsia/engine/browser/message_port_impl.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
@@ -37,6 +33,11 @@
 
 namespace {
 
+// logging::LogSeverity does not define a value to disable logging so set a
+// value much lower than logging::LOG_VERBOSE here.
+const logging::LogSeverity kLogSeverityNone =
+    std::numeric_limits<logging::LogSeverity>::min();
+
 // Layout manager that allows only one child window and stretches it to fill the
 // parent.
 class LayoutManagerImpl : public aura::LayoutManager {
@@ -75,40 +76,54 @@
   DISALLOW_COPY_AND_ASSIGN(LayoutManagerImpl);
 };
 
-chromium::web::NavigationEntry ConvertContentNavigationEntry(
+fuchsia::web::NavigationState ConvertContentNavigationEntry(
     content::NavigationEntry* entry) {
   DCHECK(entry);
-  chromium::web::NavigationEntry converted;
-  converted.title = base::UTF16ToUTF8(entry->GetTitleForDisplay());
-  converted.url = entry->GetURL().spec();
-  converted.is_error =
-      entry->GetPageType() == content::PageType::PAGE_TYPE_ERROR;
+
+  fuchsia::web::NavigationState converted;
+  converted.set_title(base::UTF16ToUTF8(entry->GetTitleForDisplay()));
+  converted.set_url(entry->GetURL().spec());
+
+  switch (entry->GetPageType()) {
+    case content::PageType::PAGE_TYPE_NORMAL:
+    case content::PageType::PAGE_TYPE_INTERSTITIAL:
+      converted.set_page_type(fuchsia::web::PageType::NORMAL);
+      break;
+    case content::PageType::PAGE_TYPE_ERROR:
+      converted.set_page_type(fuchsia::web::PageType::ERROR);
+      break;
+  }
   return converted;
 }
 
-// Computes the observable differences between |entry_1| and |entry_2|.
+// Computes the observable differences between |old_entry| and |new_entry|.
 // Returns true if they are different, |false| if their observable fields are
 // identical.
-bool ComputeNavigationEvent(const chromium::web::NavigationEntry& old_entry,
-                            const chromium::web::NavigationEntry& new_entry,
-                            chromium::web::NavigationEvent* computed_event) {
-  DCHECK(computed_event);
+bool DiffNavigationEntries(const fuchsia::web::NavigationState& old_entry,
+                           const fuchsia::web::NavigationState& new_entry,
+                           fuchsia::web::NavigationState* difference) {
+  DCHECK(difference);
 
   bool is_changed = false;
 
-  if (old_entry.title != new_entry.title) {
+  DCHECK(new_entry.has_title());
+  if (!old_entry.has_title() || (new_entry.title() != old_entry.title())) {
     is_changed = true;
-    computed_event->title = new_entry.title;
+    difference->set_title(new_entry.title());
   }
 
-  if (old_entry.url != new_entry.url) {
+  DCHECK(new_entry.has_url());
+  if (!old_entry.has_url() || (new_entry.url() != old_entry.url())) {
     is_changed = true;
-    computed_event->url = new_entry.url;
+    difference->set_url(new_entry.url());
   }
 
-  computed_event->is_error = new_entry.is_error;
-  if (old_entry.is_error != new_entry.is_error)
+  DCHECK(new_entry.has_page_type());
+  if (!old_entry.has_page_type() ||
+      (new_entry.page_type() != old_entry.page_type())) {
     is_changed = true;
+    difference->set_page_type(new_entry.page_type());
+  }
 
   return is_changed;
 }
@@ -180,12 +195,33 @@
   DISALLOW_COPY_AND_ASSIGN(ScenicWindowTreeHost);
 };
 
+logging::LogSeverity ConsoleLogLevelToLoggingSeverity(
+    fuchsia::web::ConsoleLogLevel level) {
+  switch (level) {
+    case fuchsia::web::ConsoleLogLevel::NONE:
+      return kLogSeverityNone;
+    case fuchsia::web::ConsoleLogLevel::DEBUG:
+      return logging::LOG_VERBOSE;
+    case fuchsia::web::ConsoleLogLevel::INFO:
+      return logging::LOG_INFO;
+    case fuchsia::web::ConsoleLogLevel::WARN:
+      return logging::LOG_WARNING;
+    case fuchsia::web::ConsoleLogLevel::ERROR:
+      return logging::LOG_ERROR;
+  }
+  NOTREACHED()
+      << "Unknown log level: "
+      << static_cast<std::underlying_type<fuchsia::web::ConsoleLogLevel>::type>(
+             level);
+}
+
 }  // namespace
 
 FrameImpl::FrameImpl(std::unique_ptr<content::WebContents> web_contents,
                      ContextImpl* context,
-                     fidl::InterfaceRequest<chromium::web::Frame> frame_request)
+                     fidl::InterfaceRequest<fuchsia::web::Frame> frame_request)
     : web_contents_(std::move(web_contents)),
+      log_level_(kLogSeverityNone),
       context_(context),
       binding_(this, std::move(frame_request)),
       weak_factory_(this) {
@@ -209,29 +245,6 @@
   return zx::unowned_channel(binding_.channel());
 }
 
-bool FrameImpl::ShouldCreateWebContents(
-    content::WebContents* web_contents,
-    content::RenderFrameHost* opener,
-    content::SiteInstance* source_site_instance,
-    int32_t route_id,
-    int32_t main_frame_route_id,
-    int32_t main_frame_widget_route_id,
-    content::mojom::WindowContainerType window_container_type,
-    const GURL& opener_url,
-    const std::string& frame_name,
-    const GURL& target_url,
-    const std::string& partition_id,
-    content::SessionStorageNamespace* session_storage_namespace) {
-  DCHECK_EQ(web_contents, web_contents_.get());
-
-  // Prevent any child WebContents (popup windows, tabs, etc.) from spawning.
-  // TODO(crbug.com/888131): Implement support for popup windows.
-  NOTIMPLEMENTED() << "Ignored popup window request for URL: "
-                   << target_url.spec();
-
-  return false;
-}
-
 void FrameImpl::CreateView(fuchsia::ui::views::ViewToken view_token) {
   // If a View to this Frame is already active then disconnect it.
   TearDownView();
@@ -264,85 +277,50 @@
   window_tree_host_->Show();
 }
 
-void FrameImpl::CreateView2(
-    zx::eventpair view_token_value,
-    fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> incoming_services,
-    fidl::InterfaceHandle<fuchsia::sys::ServiceProvider> outgoing_services) {
-  fuchsia::ui::views::ViewToken view_token;
-  view_token.value = std::move(view_token_value);
-  CreateView(std::move(view_token));
-}
-
 void FrameImpl::GetNavigationController(
-    fidl::InterfaceRequest<chromium::web::NavigationController> controller) {
+    fidl::InterfaceRequest<fuchsia::web::NavigationController> controller) {
   controller_bindings_.AddBinding(this, std::move(controller));
 }
 
-void FrameImpl::SetJavaScriptLogLevel(chromium::web::LogLevel level) {
-  log_level_ = level;
-}
-
-void FrameImpl::SetNavigationEventObserver(
-    fidl::InterfaceHandle<chromium::web::NavigationEventObserver> observer) {
-  // Reset the event buffer state.
-  waiting_for_navigation_event_ack_ = false;
-  cached_navigation_state_ = {};
-  pending_navigation_event_ = {};
-  pending_navigation_event_is_dirty_ = false;
-
-  if (observer) {
-    navigation_observer_.Bind(std::move(observer));
-    navigation_observer_.set_error_handler(
-        [this](zx_status_t status) { SetNavigationEventObserver(nullptr); });
-  } else {
-    navigation_observer_.Unbind();
-  }
-}
-
-void FrameImpl::ExecuteJavaScript(std::vector<std::string> origins,
-                                  fuchsia::mem::Buffer script,
-                                  chromium::web::ExecuteMode mode,
-                                  ExecuteJavaScriptCallback callback) {
-  if (mode == chromium::web::ExecuteMode::ON_PAGE_LOAD) {
-    // TODO(https://crbug.com/946235): Remove this.
-    AddJavaScriptBindings(next_transitional_bindings_id_++, std::move(origins),
-                          std::move(script), std::move(callback));
-    return;
-  } else if (mode != chromium::web::ExecuteMode::IMMEDIATE_ONCE) {
-    // Unknown mode, ignored.
-    callback(false);
-    return;
-  }
-
+void FrameImpl::ExecuteJavaScriptNoResult(
+    std::vector<std::string> origins,
+    fuchsia::mem::Buffer script,
+    ExecuteJavaScriptNoResultCallback callback) {
+  fuchsia::web::Frame_ExecuteJavaScriptNoResult_Result result;
   if (!context_->IsJavaScriptInjectionAllowed()) {
-    callback(false);
+    result.set_err(fuchsia::web::FrameError::INTERNAL_ERROR);
+    callback(std::move(result));
     return;
   }
 
   if (!IsOriginWhitelisted(web_contents_->GetLastCommittedURL(), origins)) {
-    callback(false);
+    result.set_err(fuchsia::web::FrameError::INVALID_ORIGIN);
+    callback(std::move(result));
     return;
   }
 
   base::string16 script_utf16;
   if (!cr_fuchsia::ReadUTF8FromVMOAsUTF16(script, &script_utf16)) {
-    LOG(WARNING) << "Script is not valid UTF8.";
-    callback(false);
+    result.set_err(fuchsia::web::FrameError::BUFFER_NOT_UTF8);
+    callback(std::move(result));
     return;
   }
 
   web_contents_->GetMainFrame()->ExecuteJavaScript(script_utf16,
                                                    base::NullCallback());
-
-  callback(true);
+  result.set_response(fuchsia::web::Frame_ExecuteJavaScriptNoResult_Response());
+  callback(std::move(result));
 }
 
-void FrameImpl::AddJavaScriptBindings(uint64_t id,
-                                      std::vector<std::string> origins,
-                                      fuchsia::mem::Buffer script,
-                                      AddJavaScriptBindingsCallback callback) {
+void FrameImpl::AddBeforeLoadJavaScript(
+    uint64_t id,
+    std::vector<std::string> origins,
+    fuchsia::mem::Buffer script,
+    AddBeforeLoadJavaScriptCallback callback) {
+  fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result;
   if (!context_->IsJavaScriptInjectionAllowed()) {
-    callback(false);
+    result.set_err(fuchsia::web::FrameError::INTERNAL_ERROR);
+    callback(std::move(result));
     return;
   }
 
@@ -350,18 +328,14 @@
   // it can be efficiently shared with multiple renderer processes.
   base::string16 script_utf16;
   if (!cr_fuchsia::ReadUTF8FromVMOAsUTF16(script, &script_utf16)) {
-    callback(false);
+    result.set_err(fuchsia::web::FrameError::BUFFER_NOT_UTF8);
+    callback(std::move(result));
     return;
   }
 
   // Create a read-only VMO from |script|.
   fuchsia::mem::Buffer script_buffer =
       cr_fuchsia::MemBufferFromString16(script_utf16);
-  if (!script_buffer.vmo) {
-    LOG(WARNING) << "Couldn't read script contents from VMO.";
-    callback(false);
-    return;
-  }
 
   // Wrap the VMO into a read-only shared-memory container that Mojo can work
   // with.
@@ -382,69 +356,108 @@
   before_load_scripts_[id] =
       OriginScopedScript(origins, std::move(script_region_mojo));
 
-  callback(true);
+  result.set_response(fuchsia::web::Frame_AddBeforeLoadJavaScript_Response());
+  callback(std::move(result));
 }
 
-void FrameImpl::RemoveJavaScriptBindings(
-    uint64_t id,
-    RemoveJavaScriptBindingsCallback callback) {
+void FrameImpl::RemoveBeforeLoadJavaScript(uint64_t id) {
   before_load_scripts_.erase(id);
 
   for (auto script_id_iter = before_load_scripts_order_.begin();
        script_id_iter != before_load_scripts_order_.end(); ++script_id_iter) {
     if (*script_id_iter == id) {
       before_load_scripts_order_.erase(script_id_iter);
-      callback(true);
       return;
     }
   }
-
-  callback(false);
 }
 
-void FrameImpl::PostMessage(chromium::web::WebMessage message,
-                            std::string target_origin,
+void FrameImpl::PostMessage(std::string origin,
+                            fuchsia::web::WebMessage message,
                             PostMessageCallback callback) {
   constexpr char kWildcardOrigin[] = "*";
 
-  if (target_origin.empty()) {
-    callback(false);
+  fuchsia::web::Frame_PostMessage_Result result;
+  if (origin.empty()) {
+    result.set_err(fuchsia::web::FrameError::INVALID_ORIGIN);
+    callback(std::move(result));
     return;
   }
 
-  base::Optional<base::string16> target_origin_utf16;
-  if (target_origin != kWildcardOrigin)
-    target_origin_utf16 = base::UTF8ToUTF16(target_origin);
+  if (!message.has_data()) {
+    result.set_err(fuchsia::web::FrameError::NO_DATA_IN_MESSAGE);
+    callback(std::move(result));
+    return;
+  }
+
+  base::Optional<base::string16> origin_utf16;
+  if (origin != kWildcardOrigin)
+    origin_utf16 = base::UTF8ToUTF16(origin);
 
   base::string16 data_utf16;
-  if (!cr_fuchsia::ReadUTF8FromVMOAsUTF16(message.data, &data_utf16)) {
-    DLOG(WARNING) << "PostMessage() rejected non-UTF8 |message.data|.";
-    callback(false);
+  if (!cr_fuchsia::ReadUTF8FromVMOAsUTF16(message.data(), &data_utf16)) {
+    result.set_err(fuchsia::web::FrameError::BUFFER_NOT_UTF8);
+    callback(std::move(result));
     return;
   }
 
   // Include outgoing MessagePorts in the message.
   std::vector<mojo::ScopedMessagePipeHandle> message_ports;
-  if (message.outgoing_transfer) {
-    if (!message.outgoing_transfer->is_message_port()) {
-      DLOG(WARNING) << "|outgoing_transfer| is not a MessagePort.";
-      callback(false);
-      return;
+  if (message.has_outgoing_transfer()) {
+    // Verify that all the Transferables are valid before we start allocating
+    // resources to them.
+    for (const fuchsia::web::OutgoingTransferable& outgoing :
+         message.outgoing_transfer()) {
+      if (!outgoing.is_message_port()) {
+        result.set_err(fuchsia::web::FrameError::INTERNAL_ERROR);
+        callback(std::move(result));
+        return;
+      }
     }
 
-    mojo::ScopedMessagePipeHandle port = LegacyMessagePortBridge::FromFidl(
-        std::move(message.outgoing_transfer->message_port()));
-    if (!port) {
-      callback(false);
-      return;
+    for (fuchsia::web::OutgoingTransferable& outgoing :
+         *message.mutable_outgoing_transfer()) {
+      mojo::ScopedMessagePipeHandle port =
+          MessagePortImpl::FromFidl(std::move(outgoing.message_port()));
+      if (!port) {
+        result.set_err(fuchsia::web::FrameError::INTERNAL_ERROR);
+        callback(std::move(result));
+        return;
+      }
+      message_ports.push_back(std::move(port));
     }
-    message_ports.push_back(std::move(port));
   }
 
   content::MessagePortProvider::PostMessageToFrame(
-      web_contents_.get(), base::string16(), target_origin_utf16,
+      web_contents_.get(), base::string16(), origin_utf16,
       std::move(data_utf16), std::move(message_ports));
-  callback(true);
+  result.set_response(fuchsia::web::Frame_PostMessage_Response());
+  callback(std::move(result));
+}
+
+void FrameImpl::SetNavigationEventListener(
+    fidl::InterfaceHandle<fuchsia::web::NavigationEventListener> listener) {
+  // Reset the event buffer state.
+  waiting_for_navigation_event_ack_ = false;
+  cached_navigation_state_ = {};
+  pending_navigation_event_ = {};
+  pending_navigation_event_is_dirty_ = false;
+
+  if (listener) {
+    navigation_listener_.Bind(std::move(listener));
+    navigation_listener_.set_error_handler(
+        [this](zx_status_t status) { SetNavigationEventListener(nullptr); });
+  } else {
+    navigation_listener_.Unbind();
+  }
+}
+
+void FrameImpl::SetJavaScriptLogLevel(fuchsia::web::ConsoleLogLevel level) {
+  log_level_ = ConsoleLogLevelToLoggingSeverity(level);
+}
+
+void FrameImpl::SetEnableInput(bool enable_input) {
+  discarding_event_filter_.set_discard_events(!enable_input);
 }
 
 FrameImpl::OriginScopedScript::OriginScopedScript() = default;
@@ -481,9 +494,9 @@
 }
 
 void FrameImpl::OnNavigationEntryChanged(content::NavigationEntry* entry) {
-  chromium::web::NavigationEntry entry_converted =
+  fuchsia::web::NavigationState entry_converted =
       ConvertContentNavigationEntry(entry);
-  pending_navigation_event_is_dirty_ |= ComputeNavigationEvent(
+  pending_navigation_event_is_dirty_ |= DiffNavigationEntries(
       cached_navigation_state_, entry_converted, &pending_navigation_event_);
   cached_navigation_state_ = std::move(entry_converted);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -492,7 +505,7 @@
 }
 
 void FrameImpl::MaybeSendNavigationEvent() {
-  if (!navigation_observer_)
+  if (!navigation_listener_)
     return;
 
   if (!pending_navigation_event_is_dirty_ ||
@@ -505,7 +518,7 @@
 
   // Send the event to the observer and, upon acknowledgement, revisit this
   // function to send another update.
-  navigation_observer_->OnNavigationStateChanged(
+  navigation_listener_->OnNavigationStateChanged(
       std::move(pending_navigation_event_), [this]() {
         waiting_for_navigation_event_ack_ = false;
         MaybeSendNavigationEvent();
@@ -514,21 +527,31 @@
   pending_navigation_event_ = {};
 }
 
-void FrameImpl::LoadUrl(std::string url, chromium::web::LoadUrlParams params) {
+void FrameImpl::LoadUrl(std::string url,
+                        fuchsia::web::LoadUrlParams params,
+                        LoadUrlCallback callback) {
+  fuchsia::web::NavigationController_LoadUrl_Result result;
   GURL validated_url(url);
   if (!validated_url.is_valid()) {
-    // TODO(crbug.com/934539): Add type epitaph.
-    DLOG(WARNING) << "Invalid URL: " << url;
+    result.set_err(fuchsia::web::NavigationControllerError::INVALID_URL);
+    callback(std::move(result));
     return;
   }
 
   content::NavigationController::LoadURLParams params_converted(validated_url);
   if (params.has_headers()) {
-    std::vector<base::StringPiece> extra_headers;
+    std::vector<std::string> extra_headers;
     extra_headers.reserve(params.headers().size());
     for (const auto& header : params.headers()) {
-      extra_headers.push_back(base::StringPiece(
-          reinterpret_cast<const char*>(header.data()), header.size()));
+      // TODO(crbug.com/964732): Check there is no colon in |header_name|.
+      base::StringPiece header_name(
+          reinterpret_cast<const char*>(header.name.data()),
+          header.name.size());
+      base::StringPiece header_value(
+          reinterpret_cast<const char*>(header.value.data()),
+          header.value.size());
+      extra_headers.emplace_back(
+          base::StrCat({header_name, ": ", header_value}));
     }
     params_converted.extra_headers = base::JoinString(extra_headers, "\n");
   }
@@ -543,7 +566,10 @@
   } else {
     params_converted.was_activated = content::WasActivatedOption::kNo;
   }
+
   web_contents_->GetController().LoadURLWithParams(params_converted);
+  result.set_response(fuchsia::web::NavigationController_LoadUrl_Response());
+  callback(std::move(result));
 }
 
 void FrameImpl::GoBack() {
@@ -560,29 +586,88 @@
   web_contents_->Stop();
 }
 
-void FrameImpl::Reload(chromium::web::ReloadType type) {
+void FrameImpl::Reload(fuchsia::web::ReloadType type) {
   content::ReloadType internal_reload_type;
   switch (type) {
-    case chromium::web::ReloadType::PARTIAL_CACHE:
+    case fuchsia::web::ReloadType::PARTIAL_CACHE:
       internal_reload_type = content::ReloadType::NORMAL;
       break;
-    case chromium::web::ReloadType::NO_CACHE:
+    case fuchsia::web::ReloadType::NO_CACHE:
       internal_reload_type = content::ReloadType::BYPASSING_CACHE;
       break;
   }
   web_contents_->GetController().Reload(internal_reload_type, false);
 }
 
-void FrameImpl::GetVisibleEntry(GetVisibleEntryCallback callback) {
+void FrameImpl::GetVisibleEntry(
+    fuchsia::web::NavigationController::GetVisibleEntryCallback callback) {
   content::NavigationEntry* entry =
       web_contents_->GetController().GetVisibleEntry();
   if (!entry) {
-    callback(nullptr);
+    callback({});
     return;
   }
 
-  chromium::web::NavigationEntry output = ConvertContentNavigationEntry(entry);
-  callback(std::make_unique<chromium::web::NavigationEntry>(std::move(output)));
+  callback(ConvertContentNavigationEntry(entry));
+}
+
+bool FrameImpl::ShouldCreateWebContents(
+    content::WebContents* web_contents,
+    content::RenderFrameHost* opener,
+    content::SiteInstance* source_site_instance,
+    int32_t route_id,
+    int32_t main_frame_route_id,
+    int32_t main_frame_widget_route_id,
+    content::mojom::WindowContainerType window_container_type,
+    const GURL& opener_url,
+    const std::string& frame_name,
+    const GURL& target_url,
+    const std::string& partition_id,
+    content::SessionStorageNamespace* session_storage_namespace) {
+  DCHECK_EQ(web_contents, web_contents_.get());
+
+  // Prevent any child WebContents (popup windows, tabs, etc.) from spawning.
+  // TODO(crbug.com/888131): Implement support for popup windows.
+  NOTIMPLEMENTED() << "Ignored popup window request for URL: "
+                   << target_url.spec();
+
+  return false;
+}
+
+bool FrameImpl::DidAddMessageToConsole(content::WebContents* source,
+                                       int32_t level,
+                                       const base::string16& message,
+                                       int32_t line_no,
+                                       const base::string16& source_id) {
+  if (log_level_ > level) {
+    return false;
+  }
+
+  std::string formatted_message =
+      base::StringPrintf("%s:%d : %s", base::UTF16ToUTF8(source_id).data(),
+                         line_no, base::UTF16ToUTF8(message).data());
+  switch (level) {
+    case logging::LOG_VERBOSE:
+      LOG(INFO) << "debug:" << formatted_message;
+      break;
+    case logging::LOG_INFO:
+      LOG(INFO) << "info:" << formatted_message;
+      break;
+    case logging::LOG_WARNING:
+      LOG(WARNING) << "warn:" << formatted_message;
+      break;
+    case logging::LOG_ERROR:
+      LOG(ERROR) << "error:" << formatted_message;
+      break;
+    default:
+      DLOG(WARNING) << "Unknown log level: " << level;
+      return false;
+  }
+
+  if (console_log_message_hook_)
+    console_log_message_hook_.Run(formatted_message);
+
+  return true;
 }
 
 void FrameImpl::DidFinishLoad(content::RenderFrameHost* render_frame_host,
@@ -623,48 +708,3 @@
 void FrameImpl::TitleWasSet(content::NavigationEntry* entry) {
   OnNavigationEntryChanged(entry);
 }
-
-bool FrameImpl::DidAddMessageToConsole(content::WebContents* source,
-                                       int32_t level,
-                                       const base::string16& message,
-                                       int32_t line_no,
-                                       const base::string16& source_id) {
-  if (static_cast<std::underlying_type<chromium::web::LogLevel>::type>(
-          log_level_) > level) {
-    return false;
-  }
-
-  std::string formatted_message =
-      base::StringPrintf("%s:%d : %s", base::UTF16ToUTF8(source_id).data(),
-                         line_no, base::UTF16ToUTF8(message).data());
-  switch (level) {
-    case static_cast<std::underlying_type<chromium::web::LogLevel>::type>(
-        chromium::web::LogLevel::DEBUG):
-      LOG(INFO) << "debug:" << formatted_message;
-      break;
-    case static_cast<std::underlying_type<chromium::web::LogLevel>::type>(
-        chromium::web::LogLevel::INFO):
-      LOG(INFO) << "info:" << formatted_message;
-      break;
-    case static_cast<std::underlying_type<chromium::web::LogLevel>::type>(
-        chromium::web::LogLevel::WARN):
-      LOG(WARNING) << "warn:" << formatted_message;
-      break;
-    case static_cast<std::underlying_type<chromium::web::LogLevel>::type>(
-        chromium::web::LogLevel::ERROR):
-      LOG(ERROR) << "error:" << formatted_message;
-      break;
-    default:
-      DLOG(WARNING) << "Unknown log level: " << level;
-      return false;
-  }
-
-  if (console_log_message_hook_)
-    console_log_message_hook_.Run(formatted_message);
-
-  return true;
-}
-
-void FrameImpl::SetEnableInput(bool enable_input) {
-  discarding_event_filter_.set_discard_events(!enable_input);
-}
diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h
index f036fc5..ab527388 100644
--- a/fuchsia/engine/browser/frame_impl.h
+++ b/fuchsia/engine/browser/frame_impl.h
@@ -5,6 +5,7 @@
 #ifndef FUCHSIA_ENGINE_BROWSER_FRAME_IMPL_H_
 #define FUCHSIA_ENGINE_BROWSER_FRAME_IMPL_H_
 
+#include <fuchsia/web/cpp/fidl.h>
 #include <lib/fidl/cpp/binding_set.h>
 #include <lib/zx/channel.h>
 #include <list>
@@ -21,7 +22,6 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "fuchsia/engine/browser/discarding_event_filter.h"
 #include "fuchsia/engine/on_load_script_injector.mojom.h"
-#include "fuchsia/fidl/chromium/web/cpp/fidl.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/wm/core/focus_controller.h"
 #include "url/gurl.h"
@@ -36,48 +36,17 @@
 
 class ContextImpl;
 
-// Implementation of Frame from //fuchsia/fidl/frame.fidl.
-// Implements a Frame service, which is a wrapper for a WebContents instance.
-class FrameImpl : public chromium::web::Frame,
-                  public chromium::web::NavigationController,
+// Implementation of fuchsia.web.Frame based on content::WebContents.
+class FrameImpl : public fuchsia::web::Frame,
+                  public fuchsia::web::NavigationController,
                   public content::WebContentsObserver,
                   public content::WebContentsDelegate {
  public:
   FrameImpl(std::unique_ptr<content::WebContents> web_contents,
             ContextImpl* context,
-            fidl::InterfaceRequest<chromium::web::Frame> frame_request);
+            fidl::InterfaceRequest<fuchsia::web::Frame> frame_request);
   ~FrameImpl() override;
 
-  // chromium::web::Frame implementation.
-  void CreateView(fuchsia::ui::views::ViewToken view_token) override;
-  void CreateView2(
-      zx::eventpair view_token,
-      fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> incoming_services,
-      fidl::InterfaceHandle<fuchsia::sys::ServiceProvider> outgoing_services)
-      override;
-  void GetNavigationController(
-      fidl::InterfaceRequest<chromium::web::NavigationController> controller)
-      override;
-  void SetJavaScriptLogLevel(chromium::web::LogLevel level) override;
-  void SetNavigationEventObserver(
-      fidl::InterfaceHandle<chromium::web::NavigationEventObserver> observer)
-      override;
-  void ExecuteJavaScript(std::vector<std::string> origins,
-                         fuchsia::mem::Buffer script,
-                         chromium::web::ExecuteMode mode,
-                         ExecuteJavaScriptCallback callback) override;
-  void PostMessage(chromium::web::WebMessage message,
-                   std::string target_origin,
-                   PostMessageCallback callback) override;
-  void SetEnableInput(bool enable_input) override;
-  void AddJavaScriptBindings(uint64_t id,
-                             std::vector<std::string> origins,
-                             fuchsia::mem::Buffer script,
-                             AddJavaScriptBindingsCallback callback) override;
-  void RemoveJavaScriptBindings(
-      uint64_t id,
-      RemoveJavaScriptBindingsCallback callback) override;
-
   zx::unowned_channel GetBindingChannelForTest() const;
   content::WebContents* web_contents_for_test() { return web_contents_.get(); }
   bool has_view_for_test() { return window_tree_host_ != nullptr; }
@@ -93,6 +62,30 @@
   FRIEND_TEST_ALL_PREFIXES(FrameImplTest, ReloadFrame);
   FRIEND_TEST_ALL_PREFIXES(FrameImplTest, Stop);
 
+  // fuchsia::web::Frame implementation.
+  void CreateView(fuchsia::ui::views::ViewToken view_token) override;
+  void GetNavigationController(
+      fidl::InterfaceRequest<fuchsia::web::NavigationController> controller)
+      override;
+  void ExecuteJavaScriptNoResult(
+      std::vector<std::string> origins,
+      fuchsia::mem::Buffer script,
+      ExecuteJavaScriptNoResultCallback callback) override;
+  void AddBeforeLoadJavaScript(
+      uint64_t id,
+      std::vector<std::string> origins,
+      fuchsia::mem::Buffer script,
+      AddBeforeLoadJavaScriptCallback callback) override;
+  void RemoveBeforeLoadJavaScript(uint64_t id) override;
+  void PostMessage(std::string origin,
+                   fuchsia::web::WebMessage message,
+                   fuchsia::web::Frame::PostMessageCallback callback) override;
+  void SetNavigationEventListener(
+      fidl::InterfaceHandle<fuchsia::web::NavigationEventListener> listener)
+      override;
+  void SetJavaScriptLogLevel(fuchsia::web::ConsoleLogLevel level) override;
+  void SetEnableInput(bool enable_input) override;
+
   class OriginScopedScript {
    public:
     OriginScopedScript();
@@ -126,12 +119,14 @@
   // to be reported.
   void MaybeSendNavigationEvent();
 
-  // chromium::web::NavigationController implementation.
-  void LoadUrl(std::string url, chromium::web::LoadUrlParams params) override;
+  // fuchsia::web::NavigationController implementation.
+  void LoadUrl(std::string url,
+               fuchsia::web::LoadUrlParams params,
+               LoadUrlCallback callback) override;
   void GoBack() override;
   void GoForward() override;
   void Stop() override;
-  void Reload(chromium::web::ReloadType type) override;
+  void Reload(fuchsia::web::ReloadType type) override;
   void GetVisibleEntry(GetVisibleEntryCallback callback) override;
 
   // content::WebContentsDelegate implementation.
@@ -166,20 +161,19 @@
   std::unique_ptr<wm::FocusController> focus_controller_;
 
   DiscardingEventFilter discarding_event_filter_;
-  chromium::web::NavigationEventObserverPtr navigation_observer_;
-  chromium::web::NavigationEntry cached_navigation_state_;
-  chromium::web::NavigationEvent pending_navigation_event_;
+  fuchsia::web::NavigationEventListenerPtr navigation_listener_;
+  fuchsia::web::NavigationState cached_navigation_state_;
+  fuchsia::web::NavigationState pending_navigation_event_;
   bool waiting_for_navigation_event_ack_;
   bool pending_navigation_event_is_dirty_;
-  chromium::web::LogLevel log_level_ = chromium::web::LogLevel::NONE;
+  logging::LogSeverity log_level_;
   std::map<uint64_t, OriginScopedScript> before_load_scripts_;
   std::vector<uint64_t> before_load_scripts_order_;
   ContextImpl* context_ = nullptr;
-  uint64_t next_transitional_bindings_id_ = 0x80000000;
   base::RepeatingCallback<void(base::StringPiece)> console_log_message_hook_;
 
-  fidl::Binding<chromium::web::Frame> binding_;
-  fidl::BindingSet<chromium::web::NavigationController> controller_bindings_;
+  fidl::Binding<fuchsia::web::Frame> binding_;
+  fidl::BindingSet<fuchsia::web::NavigationController> controller_bindings_;
 
   base::WeakPtrFactory<FrameImpl> weak_factory_;
 
diff --git a/fuchsia/engine/browser/frame_impl_browsertest.cc b/fuchsia/engine/browser/frame_impl_browsertest.cc
index 84306bc..2bf2017 100644
--- a/fuchsia/engine/browser/frame_impl_browsertest.cc
+++ b/fuchsia/engine/browser/frame_impl_browsertest.cc
@@ -531,7 +531,7 @@
   controller->LoadUrl(url.spec(), chromium::web::LoadUrlParams());
   navigation_observer_.RunUntilNavigationEquals(url, kPage1Title);
 
-  EXPECT_FALSE(*remove_result);
+  EXPECT_TRUE(*remove_result);
 }
 
 // Test JS injection by using Javascript to trigger document navigation.
@@ -1221,32 +1221,3 @@
   EXPECT_THAT(iter->second.headers,
               testing::Contains(testing::Key("X-2ExtraHeaders")));
 }
-
-// TODO(crbug.com/931831): Remove this test once the transition is complete.
-IN_PROC_BROWSER_TEST_F(RequestMonitoringFrameImplBrowserTest,
-                       DeprecatedExtraHeaders) {
-  chromium::web::FramePtr frame = CreateFrame();
-
-  chromium::web::LoadUrlParams load_url_params;
-  load_url_params.set_headers({StringToUnsignedVector("X-ExtraHeaders: 1"),
-                               StringToUnsignedVector("X-2ExtraHeaders: 2")});
-
-  chromium::web::NavigationControllerPtr controller;
-  frame->GetNavigationController(controller.NewRequest());
-
-  const GURL page_url(embedded_test_server()->GetURL(kPage1Path));
-
-  controller->LoadUrl(page_url.spec(), std::move(load_url_params));
-  navigation_observer_.RunUntilNavigationEquals(page_url, kPage1Title);
-
-  base::RunLoop().RunUntilIdle();
-
-  // At this point, the page should be loaded, the server should have received
-  // the request and the request should be in the map.
-  const auto iter = accumulated_requests_.find(page_url);
-  ASSERT_NE(iter, accumulated_requests_.end());
-  EXPECT_THAT(iter->second.headers,
-              testing::Contains(testing::Key("X-ExtraHeaders")));
-  EXPECT_THAT(iter->second.headers,
-              testing::Contains(testing::Key("X-2ExtraHeaders")));
-}
diff --git a/fuchsia/engine/browser/legacy_context_bridge.cc b/fuchsia/engine/browser/legacy_context_bridge.cc
new file mode 100644
index 0000000..ef18ecca
--- /dev/null
+++ b/fuchsia/engine/browser/legacy_context_bridge.cc
@@ -0,0 +1,33 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "fuchsia/engine/browser/legacy_context_bridge.h"
+
+#include "base/fuchsia/fuchsia_logging.h"
+#include "fuchsia/engine/browser/legacy_frame_bridge.h"
+
+LegacyContextBridge::LegacyContextBridge(
+    fidl::InterfaceRequest<chromium::web::Context> request,
+    fuchsia::web::ContextPtr handle)
+    : binding_(this, std::move(request)), context_(std::move(handle)) {
+  binding_.set_error_handler([this](zx_status_t status) {
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " |binding_| disconnected.";
+    delete this;
+  });
+  context_.set_error_handler([this](zx_status_t status) {
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " |context_| disconnected.";
+    delete this;
+  });
+}
+
+LegacyContextBridge::~LegacyContextBridge() = default;
+
+void LegacyContextBridge::CreateFrame(
+    fidl::InterfaceRequest<chromium::web::Frame> frame) {
+  fuchsia::web::FramePtr fuchsia_frame;
+  context_->CreateFrame(fuchsia_frame.NewRequest());
+  new LegacyFrameBridge(std::move(frame), std::move(fuchsia_frame));
+}
diff --git a/fuchsia/engine/browser/legacy_context_bridge.h b/fuchsia/engine/browser/legacy_context_bridge.h
new file mode 100644
index 0000000..3d3996e
--- /dev/null
+++ b/fuchsia/engine/browser/legacy_context_bridge.h
@@ -0,0 +1,37 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FUCHSIA_ENGINE_BROWSER_LEGACY_CONTEXT_BRIDGE_H_
+#define FUCHSIA_ENGINE_BROWSER_LEGACY_CONTEXT_BRIDGE_H_
+
+#include <fuchsia/web/cpp/fidl.h>
+#include <lib/fidl/cpp/binding.h>
+
+#include "base/macros.h"
+#include "fuchsia/fidl/chromium/web/cpp/fidl.h"
+
+// Allows chromium::web::Context clients to connect to fuchsia::web::Context
+// instances.
+//
+// LegacyContextBridge instances are self-managed; they destroy themselves when
+// the connection with either end is terminated.
+class LegacyContextBridge : public chromium::web::Context {
+ public:
+  LegacyContextBridge(fidl::InterfaceRequest<chromium::web::Context> request,
+                      fuchsia::web::ContextPtr handle);
+
+ private:
+  // Non-public to ensure that only this object may destroy itself.
+  ~LegacyContextBridge() override;
+
+  // chromium::web::Context implementation.
+  void CreateFrame(fidl::InterfaceRequest<chromium::web::Frame> frame) override;
+
+  fidl::Binding<chromium::web::Context> binding_;
+  fuchsia::web::ContextPtr context_;
+
+  DISALLOW_COPY_AND_ASSIGN(LegacyContextBridge);
+};
+
+#endif  // FUCHSIA_ENGINE_BROWSER_LEGACY_CONTEXT_BRIDGE_H_
diff --git a/fuchsia/engine/browser/legacy_frame_bridge.cc b/fuchsia/engine/browser/legacy_frame_bridge.cc
new file mode 100644
index 0000000..4bede06
--- /dev/null
+++ b/fuchsia/engine/browser/legacy_frame_bridge.cc
@@ -0,0 +1,164 @@
+// 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 "fuchsia/engine/browser/legacy_frame_bridge.h"
+
+#include "base/fuchsia/fuchsia_logging.h"
+#include "fuchsia/engine/browser/legacy_message_port_bridge.h"
+#include "fuchsia/engine/browser/legacy_navigation_controller_bridge.h"
+#include "fuchsia/engine/browser/legacy_navigation_event_listener_bridge.h"
+
+namespace {
+
+// All the active LegacyFrameBridge instances. Used for testing.
+std::set<LegacyFrameBridge*> g_legacy_bridges;
+
+}  // namespace
+
+LegacyFrameBridge::LegacyFrameBridge(
+    fidl::InterfaceRequest<chromium::web::Frame> request,
+    fuchsia::web::FramePtr handle)
+    : binding_(this, std::move(request)), frame_(std::move(handle)) {
+  binding_.set_error_handler([this](zx_status_t status) {
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " |binding_| disconnected.";
+    delete this;
+  });
+  frame_.set_error_handler([this](zx_status_t status) {
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " |frame_| disconnected.";
+    delete this;
+  });
+  g_legacy_bridges.insert(this);
+}
+
+// static
+fuchsia::web::FramePtr* LegacyFrameBridge::GetFramePtrForTest(
+    chromium::web::FramePtr* frame_ptr) {
+  // Find the LegacyFrameBridge whose channel is connected to |frame_ptr| by
+  // inspecting the related_koids of active LegacyFrameBridges.
+  zx_info_handle_basic_t handle_info;
+  zx_status_t status = frame_ptr->channel().get_info(
+      ZX_INFO_HANDLE_BASIC, &handle_info, sizeof(zx_info_handle_basic_t),
+      nullptr, nullptr);
+  ZX_CHECK(status == ZX_OK, status) << "zx_object_get_info";
+  zx_handle_t client_handle_koid = handle_info.koid;
+
+  for (LegacyFrameBridge* legacy_frame : g_legacy_bridges) {
+    status = legacy_frame->binding_.channel().get_info(
+        ZX_INFO_HANDLE_BASIC, &handle_info, sizeof(zx_info_handle_basic_t),
+        nullptr, nullptr);
+    ZX_CHECK(status == ZX_OK, status) << "zx_object_get_info";
+
+    if (client_handle_koid == handle_info.related_koid)
+      return &legacy_frame->frame_;
+  }
+
+  return nullptr;
+}
+
+LegacyFrameBridge::~LegacyFrameBridge() {
+  g_legacy_bridges.erase(this);
+}
+
+void LegacyFrameBridge::CreateView(fuchsia::ui::views::ViewToken view_token) {
+  frame_->CreateView(std::move(view_token));
+}
+
+void LegacyFrameBridge::CreateView2(
+    zx::eventpair view_token_value,
+    fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> incoming_services,
+    fidl::InterfaceHandle<fuchsia::sys::ServiceProvider> outgoing_services) {
+  fuchsia::ui::views::ViewToken view_token;
+  view_token.value = std::move(view_token_value);
+  CreateView(std::move(view_token));
+}
+
+void LegacyFrameBridge::GetNavigationController(
+    fidl::InterfaceRequest<chromium::web::NavigationController> controller) {
+  fuchsia::web::NavigationControllerPtr fuchsia_controller;
+  frame_->GetNavigationController(fuchsia_controller.NewRequest());
+  new LegacyNavigationControllerBridge(std::move(controller),
+                                       std::move(fuchsia_controller));
+}
+
+void LegacyFrameBridge::ExecuteJavaScript(std::vector<std::string> origins,
+                                          fuchsia::mem::Buffer script,
+                                          chromium::web::ExecuteMode mode,
+                                          ExecuteJavaScriptCallback callback) {
+  if (mode == chromium::web::ExecuteMode::ON_PAGE_LOAD) {
+    AddJavaScriptBindings(next_transitional_bindings_id_++, std::move(origins),
+                          std::move(script), std::move(callback));
+    return;
+  } else if (mode != chromium::web::ExecuteMode::IMMEDIATE_ONCE) {
+    // Unknown mode, ignored.
+    callback(false);
+    return;
+  }
+
+  frame_->ExecuteJavaScriptNoResult(
+      std::move(origins), std::move(script),
+      [callback = std::move(callback)](
+          fuchsia::web::Frame_ExecuteJavaScriptNoResult_Result result) {
+        callback(result.is_response());
+      });
+}
+
+void LegacyFrameBridge::AddJavaScriptBindings(
+    uint64_t id,
+    std::vector<std::string> origins,
+    fuchsia::mem::Buffer script,
+    AddJavaScriptBindingsCallback callback) {
+  frame_->AddBeforeLoadJavaScript(
+      id, std::move(origins), std::move(script),
+      [callback = std::move(callback)](
+          fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
+        callback(result.is_response());
+      });
+}
+
+void LegacyFrameBridge::RemoveJavaScriptBindings(
+    uint64_t id,
+    RemoveJavaScriptBindingsCallback callback) {
+  frame_->RemoveBeforeLoadJavaScript(id);
+  callback(true);
+}
+
+void LegacyFrameBridge::PostMessage(
+    chromium::web::WebMessage message,
+    std::string target_origin,
+    chromium::web::Frame::PostMessageCallback callback) {
+  base::Optional<fuchsia::web::WebMessage> converted =
+      LegacyMessagePortBridge::ConvertFromLegacyWebMessage(message);
+  if (!converted) {
+    callback(false);
+    return;
+  }
+  frame_->PostMessage(std::move(target_origin), std::move(converted.value()),
+                      [callback = std::move(callback)](
+                          fuchsia::web::Frame_PostMessage_Result result) {
+                        callback(result.is_response());
+                      });
+}
+
+void LegacyFrameBridge::SetNavigationEventObserver(
+    fidl::InterfaceHandle<chromium::web::NavigationEventObserver> observer) {
+  if (observer) {
+    fuchsia::web::NavigationEventListenerPtr listener;
+    new LegacyNavigationEventListenerBridge(listener.NewRequest(),
+                                            observer.Bind());
+    frame_->SetNavigationEventListener(std::move(listener));
+  } else {
+    frame_->SetNavigationEventListener(nullptr);
+  }
+}
+
+void LegacyFrameBridge::SetJavaScriptLogLevel(chromium::web::LogLevel level) {
+  frame_->SetJavaScriptLogLevel(
+      static_cast<fuchsia::web::ConsoleLogLevel>(level));
+}
+
+void LegacyFrameBridge::SetEnableInput(bool enable_input) {
+  frame_->SetEnableInput(enable_input);
+}
diff --git a/fuchsia/engine/browser/legacy_frame_bridge.h b/fuchsia/engine/browser/legacy_frame_bridge.h
new file mode 100644
index 0000000..d13f72f
--- /dev/null
+++ b/fuchsia/engine/browser/legacy_frame_bridge.h
@@ -0,0 +1,70 @@
+// 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 FUCHSIA_ENGINE_BROWSER_LEGACY_FRAME_BRIDGE_H_
+#define FUCHSIA_ENGINE_BROWSER_LEGACY_FRAME_BRIDGE_H_
+
+#include <fuchsia/web/cpp/fidl.h>
+#include <lib/fidl/cpp/binding.h>
+#include <set>
+
+#include "base/containers/unique_ptr_adapters.h"
+#include "base/macros.h"
+#include "fuchsia/fidl/chromium/web/cpp/fidl.h"
+
+// Allows chromium::web::Frame clients to connect to fuchsia::web::Frame
+// instances.
+//
+// LegacyFrameBridge instances are self-managed; they destroy themselves
+// when the connection with either end is terminated.
+class LegacyFrameBridge : public chromium::web::Frame {
+ public:
+  LegacyFrameBridge(fidl::InterfaceRequest<chromium::web::Frame> request,
+                    fuchsia::web::FramePtr handle);
+
+  static fuchsia::web::FramePtr* GetFramePtrForTest(
+      chromium::web::FramePtr* frame_ptr);
+
+ private:
+  // Non-public to ensure that only this object may destroy itself.
+  ~LegacyFrameBridge() override;
+
+  // chromium::web::Frame implementation.
+  void CreateView(fuchsia::ui::views::ViewToken view_token) override;
+  void CreateView2(
+      zx::eventpair view_token,
+      fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> incoming_services,
+      fidl::InterfaceHandle<fuchsia::sys::ServiceProvider> outgoing_services)
+      override;
+  void GetNavigationController(
+      fidl::InterfaceRequest<chromium::web::NavigationController> controller)
+      override;
+  void ExecuteJavaScript(std::vector<std::string> origins,
+                         fuchsia::mem::Buffer script,
+                         chromium::web::ExecuteMode mode,
+                         ExecuteJavaScriptCallback callback) override;
+  void AddJavaScriptBindings(uint64_t id,
+                             std::vector<std::string> origins,
+                             fuchsia::mem::Buffer script,
+                             AddJavaScriptBindingsCallback callback) override;
+  void RemoveJavaScriptBindings(
+      uint64_t id,
+      RemoveJavaScriptBindingsCallback callback) override;
+  void PostMessage(chromium::web::WebMessage message,
+                   std::string target_origin,
+                   PostMessageCallback callback) override;
+  void SetNavigationEventObserver(
+      fidl::InterfaceHandle<chromium::web::NavigationEventObserver> observer)
+      override;
+  void SetJavaScriptLogLevel(chromium::web::LogLevel level) override;
+  void SetEnableInput(bool enable_input) override;
+
+  fidl::Binding<chromium::web::Frame> binding_;
+  fuchsia::web::FramePtr frame_;
+  uint64_t next_transitional_bindings_id_ = 0x80000000;
+
+  DISALLOW_COPY_AND_ASSIGN(LegacyFrameBridge);
+};
+
+#endif  // FUCHSIA_ENGINE_BROWSER_LEGACY_FRAME_BRIDGE_H_
diff --git a/fuchsia/engine/browser/legacy_message_port_bridge.cc b/fuchsia/engine/browser/legacy_message_port_bridge.cc
index 5c8537d..bc089431 100644
--- a/fuchsia/engine/browser/legacy_message_port_bridge.cc
+++ b/fuchsia/engine/browser/legacy_message_port_bridge.cc
@@ -7,21 +7,34 @@
 #include "base/fuchsia/fuchsia_logging.h"
 
 // static
-mojo::ScopedMessagePipeHandle LegacyMessagePortBridge::FromFidl(
-    fidl::InterfaceRequest<chromium::web::MessagePort> port) {
-  fuchsia::web::MessagePortPtr fuchsia_port;
-  mojo::ScopedMessagePipeHandle content_port =
-      MessagePortImpl::FromFidl(fuchsia_port.NewRequest());
+base::Optional<fuchsia::web::WebMessage>
+LegacyMessagePortBridge::ConvertFromLegacyWebMessage(
+    chromium::web::WebMessage& message) {
+  fuchsia::web::WebMessage converted;
+  converted.set_data(std::move(message.data));
 
-  new LegacyMessagePortBridge(std::move(port), std::move(fuchsia_port));
-  return content_port;
+  if (message.outgoing_transfer) {
+    if (!message.outgoing_transfer->is_message_port())
+      return base::nullopt;
+
+    fuchsia::web::OutgoingTransferable outgoing;
+    fuchsia::web::MessagePortPtr fuchsia_port;
+    outgoing.set_message_port(fuchsia_port.NewRequest());
+    new LegacyMessagePortBridge(
+        std::move(message.outgoing_transfer->message_port()),
+        std::move(fuchsia_port));
+    std::vector<fuchsia::web::OutgoingTransferable> transferables;
+    transferables.push_back(std::move(outgoing));
+    converted.set_outgoing_transfer(std::move(transferables));
+  }
+
+  return converted;
 }
 
 LegacyMessagePortBridge::LegacyMessagePortBridge(
     fidl::InterfaceRequest<chromium::web::MessagePort> request,
     fuchsia::web::MessagePortPtr handle)
-    : binding_(this), message_port_(std::move(handle)) {
-  binding_.Bind(std::move(request));
+    : binding_(this, std::move(request)), message_port_(std::move(handle)) {
   binding_.set_error_handler([this](zx_status_t status) {
     ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
         << " |binding_| disconnected.";
@@ -38,27 +51,15 @@
 
 void LegacyMessagePortBridge::PostMessage(chromium::web::WebMessage message,
                                           PostMessageCallback callback) {
-  fuchsia::web::WebMessage converted;
-  converted.set_data(std::move(message.data));
-
-  if (message.outgoing_transfer) {
-    if (!message.outgoing_transfer->is_message_port()) {
-      callback(false);
-      return;
-    }
-    fuchsia::web::OutgoingTransferable outgoing;
-    fuchsia::web::MessagePortPtr fuchsia_port;
-    outgoing.set_message_port(fuchsia_port.NewRequest());
-    new LegacyMessagePortBridge(
-        std::move(message.outgoing_transfer->message_port()),
-        std::move(fuchsia_port));
-    std::vector<fuchsia::web::OutgoingTransferable> transferables;
-    transferables.push_back(std::move(outgoing));
-    converted.set_outgoing_transfer(std::move(transferables));
+  base::Optional<fuchsia::web::WebMessage> converted =
+      ConvertFromLegacyWebMessage(message);
+  if (!converted) {
+    callback(false);
+    return;
   }
 
   message_port_->PostMessage(
-      std::move(converted),
+      std::move(*converted),
       [callback = std::move(callback)](
           fuchsia::web::MessagePort_PostMessage_Result result) {
         callback(result.is_response());
diff --git a/fuchsia/engine/browser/legacy_message_port_bridge.h b/fuchsia/engine/browser/legacy_message_port_bridge.h
index ab5f86d0..cde670c 100644
--- a/fuchsia/engine/browser/legacy_message_port_bridge.h
+++ b/fuchsia/engine/browser/legacy_message_port_bridge.h
@@ -7,20 +7,19 @@
 
 #include <lib/fidl/cpp/binding.h>
 
+#include "base/optional.h"
 #include "fuchsia/engine/browser/message_port_impl.h"
 #include "fuchsia/fidl/chromium/web/cpp/fidl.h"
 
-// Bridges chromium::web::MessagePort and fuchsia::web::MessagePort calls.
+// Allows chromium::web::MessagePort clients to connect to
+// fuchsia::web::MessagePort instances.
 //
 // LegacyMessagePortBridge are self-managed; they destroy themselves when
-// the connection with either the chromium::web::MessagePort or
-// fuchsia::web::MessagePort is terminated.
+// the connection with either end is terminated.
 class LegacyMessagePortBridge : public chromium::web::MessagePort {
  public:
-  // Creates a connected MessagePort from a FIDL MessagePort request and
-  // returns a handle to its peer Mojo pipe.
-  static mojo::ScopedMessagePipeHandle FromFidl(
-      fidl::InterfaceRequest<chromium::web::MessagePort> port);
+  static base::Optional<fuchsia::web::WebMessage> ConvertFromLegacyWebMessage(
+      chromium::web::WebMessage& message);
 
  private:
   explicit LegacyMessagePortBridge(
diff --git a/fuchsia/engine/browser/legacy_navigation_controller_bridge.cc b/fuchsia/engine/browser/legacy_navigation_controller_bridge.cc
new file mode 100644
index 0000000..4ad1850
--- /dev/null
+++ b/fuchsia/engine/browser/legacy_navigation_controller_bridge.cc
@@ -0,0 +1,121 @@
+// 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 "fuchsia/engine/browser/legacy_navigation_controller_bridge.h"
+
+#include "base/fuchsia/fuchsia_logging.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "fuchsia/engine/browser/legacy_frame_bridge.h"
+
+namespace {
+
+std::unique_ptr<chromium::web::NavigationEntry> ConvertToLegacyNavigationEntry(
+    const fuchsia::web::NavigationState& entry) {
+  chromium::web::NavigationEntry converted;
+  bool is_changed = false;
+
+  if (entry.has_title()) {
+    converted.title = entry.title();
+    is_changed = true;
+  }
+  if (entry.has_url()) {
+    converted.url = entry.url();
+    is_changed = true;
+  }
+  if (entry.has_page_type()) {
+    converted.is_error = entry.page_type() == fuchsia::web::PageType::ERROR;
+    is_changed = true;
+  }
+
+  return is_changed
+             ? std::make_unique<chromium::web::NavigationEntry>(converted)
+             : nullptr;
+}
+
+std::vector<uint8_t> StringToUnsignedVector(base::StringPiece str) {
+  const uint8_t* raw_data = reinterpret_cast<const uint8_t*>(str.data());
+  return std::vector<uint8_t>(raw_data, raw_data + str.length());
+}
+
+}  // namespace
+
+LegacyNavigationControllerBridge::LegacyNavigationControllerBridge(
+    fidl::InterfaceRequest<chromium::web::NavigationController> request,
+    fuchsia::web::NavigationControllerPtr handle)
+    : binding_(this, std::move(request)),
+      navigation_controller_(std::move(handle)) {
+  binding_.set_error_handler([this](zx_status_t status) {
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " |binding_| disconnected.";
+    delete this;
+  });
+  navigation_controller_.set_error_handler([this](zx_status_t status) {
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " |navigation_controller_| disconnected.";
+    delete this;
+  });
+}
+
+LegacyNavigationControllerBridge::~LegacyNavigationControllerBridge() = default;
+
+void LegacyNavigationControllerBridge::LoadUrl(
+    std::string url,
+    chromium::web::LoadUrlParams params) {
+  fuchsia::web::LoadUrlParams converted;
+  if (params.has_type())
+    converted.set_type(static_cast<fuchsia::web::LoadUrlReason>(params.type()));
+  if (params.has_referrer_url())
+    converted.set_referrer_url(std::move(*params.mutable_referrer_url()));
+  if (params.has_was_user_activated())
+    converted.set_was_user_activated(params.was_user_activated());
+  if (params.has_headers()) {
+    std::vector<fuchsia::net::http::Header> headers;
+    headers.reserve(params.headers().size());
+    for (const auto& header : params.headers()) {
+      base::StringPiece full_header(
+          reinterpret_cast<const char*>(header.data()));
+      std::vector<std::string> values = base::SplitString(
+          full_header, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+      if (values.size() != 2) {
+        // Badly formed header. Ignore.
+        continue;
+      }
+      fuchsia::net::http::Header http_header;
+      http_header.name = StringToUnsignedVector(values[0]);
+      http_header.value = StringToUnsignedVector(values[1]);
+      headers.emplace_back(http_header);
+    }
+    converted.set_headers(std::move(headers));
+  }
+
+  navigation_controller_->LoadUrl(
+      std::move(url), std::move(converted),
+      [](fuchsia::web::NavigationController_LoadUrl_Result) {});
+}
+
+void LegacyNavigationControllerBridge::GoBack() {
+  navigation_controller_->GoBack();
+}
+
+void LegacyNavigationControllerBridge::GoForward() {
+  navigation_controller_->GoForward();
+}
+
+void LegacyNavigationControllerBridge::Stop() {
+  navigation_controller_->Stop();
+}
+
+void LegacyNavigationControllerBridge::Reload(chromium::web::ReloadType type) {
+  navigation_controller_->Reload(static_cast<fuchsia::web::ReloadType>(type));
+}
+
+void LegacyNavigationControllerBridge::GetVisibleEntry(
+    GetVisibleEntryCallback callback) {
+  navigation_controller_->GetVisibleEntry(
+      [callback = std::move(callback)](
+          fuchsia::web::NavigationState navigation_entry) {
+        callback(ConvertToLegacyNavigationEntry(navigation_entry));
+      });
+}
diff --git a/fuchsia/engine/browser/legacy_navigation_controller_bridge.h b/fuchsia/engine/browser/legacy_navigation_controller_bridge.h
new file mode 100644
index 0000000..72920881
--- /dev/null
+++ b/fuchsia/engine/browser/legacy_navigation_controller_bridge.h
@@ -0,0 +1,45 @@
+// 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 FUCHSIA_ENGINE_BROWSER_LEGACY_NAVIGATION_CONTROLLER_BRIDGE_H_
+#define FUCHSIA_ENGINE_BROWSER_LEGACY_NAVIGATION_CONTROLLER_BRIDGE_H_
+
+#include <fuchsia/web/cpp/fidl.h>
+#include <lib/fidl/cpp/binding.h>
+#include <string>
+
+#include "base/macros.h"
+#include "fuchsia/fidl/chromium/web/cpp/fidl.h"
+
+// Allows chromium::web::gNavigationControllerePort clients to connect to
+// fuchsia::web::NavigationController instances.
+//
+// LegacyNavigationControllerBridge instances are self-managed; they destroy
+// themselves when the connection with either end is terminated.
+class LegacyNavigationControllerBridge
+    : public chromium::web::NavigationController {
+ public:
+  LegacyNavigationControllerBridge(
+      fidl::InterfaceRequest<chromium::web::NavigationController> request,
+      fuchsia::web::NavigationControllerPtr handle);
+
+ private:
+  // Non-public to ensure that only this object may destroy itself.
+  ~LegacyNavigationControllerBridge() override;
+
+  // chromium::web::NavigationController implementation.
+  void LoadUrl(std::string url, chromium::web::LoadUrlParams params) override;
+  void GoBack() override;
+  void GoForward() override;
+  void Stop() override;
+  void Reload(chromium::web::ReloadType type) override;
+  void GetVisibleEntry(GetVisibleEntryCallback callback) override;
+
+  fidl::Binding<chromium::web::NavigationController> binding_;
+  fuchsia::web::NavigationControllerPtr navigation_controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(LegacyNavigationControllerBridge);
+};
+
+#endif  // FUCHSIA_ENGINE_BROWSER_LEGACY_NAVIGATION_CONTROLLER_BRIDGE_H_
diff --git a/fuchsia/engine/browser/legacy_navigation_event_listener_bridge.cc b/fuchsia/engine/browser/legacy_navigation_event_listener_bridge.cc
new file mode 100644
index 0000000..c398d4f
--- /dev/null
+++ b/fuchsia/engine/browser/legacy_navigation_event_listener_bridge.cc
@@ -0,0 +1,52 @@
+// 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 "fuchsia/engine/browser/legacy_navigation_event_listener_bridge.h"
+
+#include "base/fuchsia/fuchsia_logging.h"
+
+namespace {
+
+chromium::web::NavigationEvent ConvertToLegacyNavigationEvent(
+    const fuchsia::web::NavigationState& entry) {
+  chromium::web::NavigationEvent converted;
+
+  if (entry.has_title())
+    converted.title = entry.title();
+  if (entry.has_url())
+    converted.url = entry.url();
+  if (entry.has_page_type())
+    converted.is_error = entry.page_type() == fuchsia::web::PageType::ERROR;
+
+  return converted;
+}
+
+}  // namespace
+
+LegacyNavigationEventListenerBridge::LegacyNavigationEventListenerBridge(
+    fidl::InterfaceRequest<fuchsia::web::NavigationEventListener> request,
+    chromium::web::NavigationEventObserverPtr handle)
+    : binding_(this, std::move(request)), observer_(std::move(handle)) {
+  binding_.set_error_handler([this](zx_status_t status) {
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " |binding_| disconnected.";
+    delete this;
+  });
+  observer_.set_error_handler([this](zx_status_t status) {
+    ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
+        << " |observer_| disconnected.";
+    delete this;
+  });
+}
+
+LegacyNavigationEventListenerBridge::~LegacyNavigationEventListenerBridge() =
+    default;
+
+void LegacyNavigationEventListenerBridge::OnNavigationStateChanged(
+    fuchsia::web::NavigationState change,
+    OnNavigationStateChangedCallback callback) {
+  observer_->OnNavigationStateChanged(ConvertToLegacyNavigationEvent(change),
+                                      std::move(callback));
+  // [callback = std::move(callback)]() { callback(); });
+}
diff --git a/fuchsia/engine/browser/legacy_navigation_event_listener_bridge.h b/fuchsia/engine/browser/legacy_navigation_event_listener_bridge.h
new file mode 100644
index 0000000..c6cedf8
--- /dev/null
+++ b/fuchsia/engine/browser/legacy_navigation_event_listener_bridge.h
@@ -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.
+
+#ifndef FUCHSIA_ENGINE_BROWSER_LEGACY_NAVIGATION_EVENT_LISTENER_BRIDGE_H_
+#define FUCHSIA_ENGINE_BROWSER_LEGACY_NAVIGATION_EVENT_LISTENER_BRIDGE_H_
+
+#include <fuchsia/web/cpp/fidl.h>
+#include <lib/fidl/cpp/binding.h>
+
+#include "base/macros.h"
+#include "fuchsia/fidl/chromium/web/cpp/fidl.h"
+
+// Allows fuchsia::web::NavigationEventListener clients to connect to
+// chromium::web::NavigationEventObserver instances.
+//
+// LegacyNavigationEventListenerBridge instances are self-managed; they destroy
+// themselves when the connection with either end is terminated.
+class LegacyNavigationEventListenerBridge
+    : public fuchsia::web::NavigationEventListener {
+ public:
+  LegacyNavigationEventListenerBridge(
+      fidl::InterfaceRequest<fuchsia::web::NavigationEventListener> request,
+      chromium::web::NavigationEventObserverPtr handle);
+
+ private:
+  // Non-public to ensure that only this object may destroy itself.
+  ~LegacyNavigationEventListenerBridge() override;
+
+  // fuchsia::web::NavigationEventListener implementation.
+  void OnNavigationStateChanged(
+      fuchsia::web::NavigationState change,
+      OnNavigationStateChangedCallback callback) override;
+
+  fidl::Binding<fuchsia::web::NavigationEventListener> binding_;
+  chromium::web::NavigationEventObserverPtr observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(LegacyNavigationEventListenerBridge);
+};
+
+#endif  // FUCHSIA_ENGINE_BROWSER_LEGACY_NAVIGATION_EVENT_LISTENER_BRIDGE_H_
diff --git a/fuchsia/engine/browser/web_engine_browser_main_parts.cc b/fuchsia/engine/browser/web_engine_browser_main_parts.cc
index ad40fc259..5021c69 100644
--- a/fuchsia/engine/browser/web_engine_browser_main_parts.cc
+++ b/fuchsia/engine/browser/web_engine_browser_main_parts.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "content/public/browser/render_frame_host.h"
 #include "fuchsia/engine/browser/context_impl.h"
+#include "fuchsia/engine/browser/legacy_context_bridge.h"
 #include "fuchsia/engine/browser/web_engine_browser_context.h"
 #include "fuchsia/engine/browser/web_engine_screen.h"
 #include "fuchsia/engine/common.h"
@@ -46,9 +47,12 @@
 
   context_service_ = std::make_unique<ContextImpl>(browser_context_.get());
 
-  context_binding_ = std::make_unique<fidl::Binding<chromium::web::Context>>(
-      context_service_.get(), fidl::InterfaceRequest<chromium::web::Context>(
-                                  std::move(context_channel_)));
+  fuchsia::web::ContextPtr fuchsia_context;
+  context_binding_ = std::make_unique<fidl::Binding<fuchsia::web::Context>>(
+      context_service_.get(), fuchsia_context.NewRequest());
+  new LegacyContextBridge(fidl::InterfaceRequest<chromium::web::Context>(
+                              std::move(context_channel_)),
+                          std::move(fuchsia_context));
 
   // Quit the browser main loop when the Context connection is dropped.
   context_binding_->set_error_handler([this](zx_status_t status) {
diff --git a/fuchsia/engine/browser/web_engine_browser_main_parts.h b/fuchsia/engine/browser/web_engine_browser_main_parts.h
index 3418b262..35a1933b 100644
--- a/fuchsia/engine/browser/web_engine_browser_main_parts.h
+++ b/fuchsia/engine/browser/web_engine_browser_main_parts.h
@@ -5,6 +5,7 @@
 #ifndef FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_BROWSER_MAIN_PARTS_H_
 #define FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_BROWSER_MAIN_PARTS_H_
 
+#include <fuchsia/web/cpp/fidl.h>
 #include <lib/fidl/cpp/binding.h>
 #include <memory>
 
@@ -13,7 +14,6 @@
 #include "content/public/browser/browser_main_parts.h"
 #include "fuchsia/engine/browser/context_impl.h"
 #include "fuchsia/engine/browser/web_engine_browser_context.h"
-#include "fuchsia/fidl/chromium/web/cpp/fidl.h"
 
 namespace display {
 class Screen;
@@ -40,7 +40,7 @@
   std::unique_ptr<display::Screen> screen_;
   std::unique_ptr<WebEngineBrowserContext> browser_context_;
   std::unique_ptr<ContextImpl> context_service_;
-  std::unique_ptr<fidl::Binding<chromium::web::Context>> context_binding_;
+  std::unique_ptr<fidl::Binding<fuchsia::web::Context>> context_binding_;
 
   base::OnceClosure quit_closure_;
 
diff --git a/fuchsia/fidl/web/frame.fidl b/fuchsia/fidl/web/frame.fidl
index 8533fb1..58648d32 100644
--- a/fuchsia/fidl/web/frame.fidl
+++ b/fuchsia/fidl/web/frame.fidl
@@ -99,7 +99,7 @@
                         fuchsia.mem.Buffer script) -> (bool success);
 
   /// Removes a previously added JavaScript snippet identified by |id|.
-  /// Returns |true| if the script was found and removed.
+  /// Always returns |true|, it is safe to ignore the return value.
   RemoveJavaScriptBindings(uint64 id) -> (bool removed);
 
   /// Posts a message to the frame's onMessage handler.
diff --git a/gpu/ipc/service/direct_composition_child_surface_win.cc b/gpu/ipc/service/direct_composition_child_surface_win.cc
index 16726c5b..edbd2c3 100644
--- a/gpu/ipc/service/direct_composition_child_surface_win.cc
+++ b/gpu/ipc/service/direct_composition_child_surface_win.cc
@@ -59,14 +59,13 @@
       return false;
     }
     Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
-    d3d11_device.CopyTo(dxgi_device.GetAddressOf());
+    d3d11_device.As(&dxgi_device);
     DCHECK(dxgi_device);
     Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
-    dxgi_device->GetAdapter(dxgi_adapter.GetAddressOf());
+    dxgi_device->GetAdapter(&dxgi_adapter);
     DCHECK(dxgi_adapter);
     Microsoft::WRL::ComPtr<IDXGIFactory5> dxgi_factory;
-    if (FAILED(dxgi_adapter->GetParent(
-            IID_PPV_ARGS(dxgi_factory.GetAddressOf())))) {
+    if (FAILED(dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)))) {
       DLOG(ERROR) << "Not using swap chain tearing because failed to retrieve "
                      "IDXGIFactory5 interface";
       return false;
@@ -166,7 +165,7 @@
         // may flicker black when it's first presented.
         first_swap_ = false;
         Microsoft::WRL::ComPtr<IDXGIDevice2> dxgi_device2;
-        d3d11_device_.CopyTo(dxgi_device2.GetAddressOf());
+        d3d11_device_.As(&dxgi_device2);
         DCHECK(dxgi_device2);
         base::WaitableEvent event(
             base::WaitableEvent::ResetPolicy::AUTOMATIC,
@@ -294,7 +293,7 @@
     // become transparent.
     HRESULT hr = dcomp_device_->CreateSurface(
         size_.width(), size_.height(), output_format,
-        DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.GetAddressOf());
+        DXGI_ALPHA_MODE_PREMULTIPLIED, &dcomp_surface_);
     if (FAILED(hr)) {
       DLOG(ERROR) << "CreateSurface failed with error " << std::hex << hr;
       return false;
@@ -307,13 +306,13 @@
     DXGI_ALPHA_MODE alpha_mode =
         has_alpha_ ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE;
     Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
-    d3d11_device_.CopyTo(dxgi_device.GetAddressOf());
+    d3d11_device_.As(&dxgi_device);
     DCHECK(dxgi_device);
     Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
-    dxgi_device->GetAdapter(dxgi_adapter.GetAddressOf());
+    dxgi_device->GetAdapter(&dxgi_adapter);
     DCHECK(dxgi_adapter);
     Microsoft::WRL::ComPtr<IDXGIFactory2> dxgi_factory;
-    dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.GetAddressOf()));
+    dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory));
     DCHECK(dxgi_factory);
 
     DXGI_SWAP_CHAIN_DESC1 desc = {};
@@ -330,7 +329,7 @@
     desc.Flags =
         IsSwapChainTearingSupported() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
     HRESULT hr = dxgi_factory->CreateSwapChainForComposition(
-        d3d11_device_.Get(), &desc, nullptr, swap_chain_.GetAddressOf());
+        d3d11_device_.Get(), &desc, nullptr, &swap_chain_);
     first_swap_ = true;
     if (FAILED(hr)) {
       DLOG(ERROR) << "CreateSwapChainForComposition failed with error "
@@ -345,15 +344,15 @@
   if (dcomp_surface_) {
     POINT update_offset;
     const RECT rect = rectangle.ToRECT();
-    HRESULT hr = dcomp_surface_->BeginDraw(
-        &rect, IID_PPV_ARGS(draw_texture_.GetAddressOf()), &update_offset);
+    HRESULT hr = dcomp_surface_->BeginDraw(&rect, IID_PPV_ARGS(&draw_texture_),
+                                           &update_offset);
     if (FAILED(hr)) {
       DLOG(ERROR) << "BeginDraw failed with error " << std::hex << hr;
       return false;
     }
     draw_offset_ = gfx::Point(update_offset) - rectangle.origin();
   } else {
-    swap_chain_->GetBuffer(0, IID_PPV_ARGS(draw_texture_.GetAddressOf()));
+    swap_chain_->GetBuffer(0, IID_PPV_ARGS(&draw_texture_));
   }
   DCHECK(draw_texture_);
 
diff --git a/gpu/ipc/service/direct_composition_surface_win.cc b/gpu/ipc/service/direct_composition_surface_win.cc
index 7404e5d0..d8470b1 100644
--- a/gpu/ipc/service/direct_composition_surface_win.cc
+++ b/gpu/ipc/service/direct_composition_surface_win.cc
@@ -182,20 +182,20 @@
   }
 
   Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
-  if (FAILED(d3d11_device.CopyTo(dxgi_device.GetAddressOf()))) {
+  if (FAILED(d3d11_device.As(&dxgi_device))) {
     DLOG(ERROR) << "Failed to retrieve DXGI device";
     return;
   }
 
   Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
-  if (FAILED(dxgi_device->GetAdapter(dxgi_adapter.GetAddressOf()))) {
+  if (FAILED(dxgi_device->GetAdapter(&dxgi_adapter))) {
     DLOG(ERROR) << "Failed to retrieve DXGI adapter";
     return;
   }
 
   // This will fail if the D3D device is "Microsoft Basic Display Adapter".
   Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device;
-  if (FAILED(d3d11_device.CopyTo(video_device.GetAddressOf()))) {
+  if (FAILED(d3d11_device.As(&video_device))) {
     DLOG(ERROR) << "Failed to retrieve video device";
     return;
   }
@@ -204,11 +204,11 @@
   unsigned int i = 0;
   while (true) {
     Microsoft::WRL::ComPtr<IDXGIOutput> output;
-    if (FAILED(dxgi_adapter->EnumOutputs(i++, output.GetAddressOf())))
+    if (FAILED(dxgi_adapter->EnumOutputs(i++, &output)))
       break;
     DCHECK(output);
     Microsoft::WRL::ComPtr<IDXGIOutput3> output3;
-    if (FAILED(output.CopyTo(output3.GetAddressOf())))
+    if (FAILED(output.As(&output3)))
       continue;
     DCHECK(output3);
 
@@ -224,7 +224,7 @@
       if (info.overlay_format == OverlayFormat::kNV12) {
         UINT color_space_support_flags = 0;
         Microsoft::WRL::ComPtr<IDXGIOutput4> output4;
-        if (FAILED(output.CopyTo(output4.GetAddressOf())))
+        if (FAILED(output.As(&output4)))
           continue;
 
         if (FAILED(output4->CheckOverlayColorSpaceSupport(
@@ -338,28 +338,10 @@
                   Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device,
                   Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device);
 
-  // Information about the back buffer surface.  Cached on every frame to check
-  // if back buffer changed from previous frame.  Back buffer uses either a swap
-  // chain, or a direct composition surface depending on whether layers are used
-  // or not (see DirectCompositionSurfaceChildWin).
-  struct BackbufferInfo {
-    // Set if backbuffer is using a swap chain currently.
-    Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain;
-
-    // Set if backbuffer is using a direct composition surface currently.
-    Microsoft::WRL::ComPtr<IDCompositionSurface> dcomp_surface;
-    uint64_t dcomp_surface_serial;
-
-    bool operator!=(const BackbufferInfo& other) const {
-      return std::tie(swap_chain, dcomp_surface, dcomp_surface_serial) !=
-             std::tie(other.swap_chain, other.dcomp_surface,
-                      other.dcomp_surface_serial);
-    }
-  };
   // Present pending overlay layers, and perform a direct composition commit if
-  // necessary using provided backbuffer info for creating backbuffer visual.
-  // Returns true if presentation and commit succeeded.
-  bool CommitAndClearPendingOverlays(BackbufferInfo backbuffer_info);
+  // necessary.  Returns true if presentation and commit succeeded.
+  bool CommitAndClearPendingOverlays(
+      DirectCompositionChildSurfaceWin* root_surface);
 
   // Schedule an overlay layer for the next CommitAndClearPendingOverlays call.
   bool ScheduleDCLayer(const ui::DCRendererLayerParams& params);
@@ -371,6 +353,8 @@
   bool InitializeVideoProcessor(const gfx::Size& input_size,
                                 const gfx::Size& output_size);
 
+  void SetNeedsCommit() { needs_commit_ = true; }
+
   const Microsoft::WRL::ComPtr<ID3D11VideoDevice>& video_device() const {
     return video_device_;
   }
@@ -396,10 +380,6 @@
  private:
   class SwapChainPresenter;
 
-  // Update backbuffer visual with provided info.  Returns true if the visual
-  // changed, and a direct composition commit is needed.
-  bool UpdateBackbufferVisual(BackbufferInfo info);
-
   const GpuDriverBugWorkarounds workarounds_;
 
   Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
@@ -418,14 +398,21 @@
   gfx::Size video_input_size_;
   gfx::Size video_output_size_;
 
-  // Direct composition visual for window.
-  Microsoft::WRL::ComPtr<IDCompositionVisual2> root_visual_;
+  // Set to true if a direct composition commit is needed.
+  bool needs_commit_ = false;
 
-  // Direct composition for backbuffer surface.
-  Microsoft::WRL::ComPtr<IDCompositionVisual2> backbuffer_visual_;
+  // Set if root surface is using a swap chain currently.
+  Microsoft::WRL::ComPtr<IDXGISwapChain1> root_swap_chain_;
 
-  // Cached backbuffer info for last frame.
-  BackbufferInfo backbuffer_info_;
+  // Set if root surface is using a direct composition surface currently.
+  Microsoft::WRL::ComPtr<IDCompositionSurface> root_dcomp_surface_;
+  uint64_t root_dcomp_surface_serial_;
+
+  // Direct composition visual for root surface.
+  Microsoft::WRL::ComPtr<IDCompositionVisual2> root_surface_visual_;
+
+  // Root direct composition visual for window dcomp target.
+  Microsoft::WRL::ComPtr<IDCompositionVisual2> dcomp_root_visual_;
 
   // List of pending overlay layers from ScheduleDCLayer().
   std::vector<std::unique_ptr<ui::DCRendererLayerParams>> pending_overlays_;
@@ -446,11 +433,8 @@
                      Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device);
   ~SwapChainPresenter();
 
-  // Present the given overlay to swap chain.  |needs_commit| is true if direct
-  // composition visuals changed, and a commit is needed.  Returns true on
-  // success.
-  bool PresentToSwapChain(const ui::DCRendererLayerParams& overlay,
-                          bool* needs_commit);
+  // Present the given overlay to swap chain.  Returns true on success.
+  bool PresentToSwapChain(const ui::DCRendererLayerParams& overlay);
 
   const Microsoft::WRL::ComPtr<IDXGISwapChain1>& swap_chain() const {
     return swap_chain_;
@@ -516,18 +500,23 @@
   // Returns optimal swap chain size for given layer.
   gfx::Size CalculateSwapChainSize(const ui::DCRendererLayerParams& params);
 
-  // Update direct composition visuals for layer with given swap chain size, and
-  // returns true if a commit is needed.
-  bool UpdateVisuals(const ui::DCRendererLayerParams& params,
+  // Update direct composition visuals for layer with given swap chain size.
+  void UpdateVisuals(const ui::DCRendererLayerParams& params,
                      const gfx::Size& swap_chain_size);
 
+  // Try presenting to a decode swap chain based on various conditions such as
+  // global state (e.g. finch, NV12 support), texture flags, and transform.
+  // Returns true on success.  See PresentToDecodeSwapChain() for more info.
+  bool TryPresentToDecodeSwapChain(gl::GLImageDXGI* image_dxgi,
+                                   const gfx::Rect& content_rect,
+                                   const gfx::Size& swap_chain_size);
+
   // Present to a decode swap chain created from compatible video decoder
   // buffers using given |image_dxgi| with destination size |swap_chain_size|.
-  // Sets |needs_commit| to true if a commit is needed. Returns true on success.
+  // Returns true on success.
   bool PresentToDecodeSwapChain(gl::GLImageDXGI* image_dxgi,
                                 const gfx::Rect& content_rect,
-                                const gfx::Size& swap_chain_size,
-                                bool* needs_commit);
+                                const gfx::Size& swap_chain_size);
 
   // Records presentation statistics in UMA and traces (for pixel tests) for the
   // current swap chain which could either be a regular flip swap chain or a
@@ -623,24 +612,24 @@
   dcomp_device_ = std::move(dcomp_device);
 
   Microsoft::WRL::ComPtr<IDCompositionDesktopDevice> desktop_device;
-  dcomp_device_.CopyTo(desktop_device.GetAddressOf());
+  dcomp_device_.As(&desktop_device);
   DCHECK(desktop_device);
 
-  HRESULT hr = desktop_device->CreateTargetForHwnd(
-      window, TRUE, dcomp_target_.GetAddressOf());
+  HRESULT hr =
+      desktop_device->CreateTargetForHwnd(window, TRUE, &dcomp_target_);
   if (FAILED(hr)) {
     DLOG(ERROR) << "CreateTargetForHwnd failed with error 0x" << std::hex << hr;
     return false;
   }
 
-  dcomp_device_->CreateVisual(root_visual_.GetAddressOf());
-  DCHECK(root_visual_);
-  dcomp_target_->SetRoot(root_visual_.Get());
+  dcomp_device_->CreateVisual(&dcomp_root_visual_);
+  DCHECK(dcomp_root_visual_);
+  dcomp_target_->SetRoot(dcomp_root_visual_.Get());
   // A visual inherits the interpolation mode of the parent visual by default.
   // If no visuals set the interpolation mode, the default for the entire visual
   // tree is nearest neighbor interpolation.
   // Set the interpolation mode to Linear to get a better upscaling quality.
-  root_visual_->SetBitmapInterpolationMode(
+  dcomp_root_visual_->SetBitmapInterpolationMode(
       DCOMPOSITION_BITMAP_INTERPOLATION_MODE_LINEAR);
 
   return true;
@@ -650,16 +639,16 @@
                                            const gfx::Size& output_size) {
   if (!video_device_) {
     // This can fail if the D3D device is "Microsoft Basic Display Adapter".
-    if (FAILED(d3d11_device_.CopyTo(video_device_.GetAddressOf()))) {
+    if (FAILED(d3d11_device_.As(&video_device_))) {
       DLOG(ERROR) << "Failed to retrieve video device from D3D11 device";
       return false;
     }
     DCHECK(video_device_);
 
     Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
-    d3d11_device_->GetImmediateContext(context.GetAddressOf());
+    d3d11_device_->GetImmediateContext(&context);
     DCHECK(context);
-    context.CopyTo(video_context_.GetAddressOf());
+    context.As(&video_context_);
     DCHECK(video_context_);
   }
 
@@ -683,7 +672,7 @@
   desc.OutputHeight = output_size.height();
   desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
   HRESULT hr = video_device_->CreateVideoProcessorEnumerator(
-      &desc, video_processor_enumerator_.GetAddressOf());
+      &desc, &video_processor_enumerator_);
   if (FAILED(hr)) {
     DLOG(ERROR) << "CreateVideoProcessorEnumerator failed with error 0x"
                 << std::hex << hr;
@@ -691,7 +680,7 @@
   }
 
   hr = video_device_->CreateVideoProcessor(video_processor_enumerator_.Get(), 0,
-                                           video_processor_.GetAddressOf());
+                                           &video_processor_);
   if (FAILED(hr)) {
     DLOG(ERROR) << "CreateVideoProcessor failed with error 0x" << std::hex
                 << hr;
@@ -799,8 +788,8 @@
     desc.MiscFlags = 0;
     desc.SampleDesc.Count = 1;
     Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
-    HRESULT hr = d3d11_device_->CreateTexture2D(
-        &desc, nullptr, staging_texture_.GetAddressOf());
+    HRESULT hr =
+        d3d11_device_->CreateTexture2D(&desc, nullptr, &staging_texture_);
     if (FAILED(hr)) {
       DLOG(ERROR) << "Creating D3D11 video upload texture failed: " << std::hex
                   << hr;
@@ -811,7 +800,7 @@
   }
 
   Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
-  d3d11_device_->GetImmediateContext(context.GetAddressOf());
+  d3d11_device_->GetImmediateContext(&context);
   // TODO(crbug.com/890227): Temporary CHECK for debugging.
   CHECK(context);
 
@@ -917,19 +906,17 @@
   return swap_chain_size;
 }
 
-bool DCLayerTree::SwapChainPresenter::UpdateVisuals(
+void DCLayerTree::SwapChainPresenter::UpdateVisuals(
     const ui::DCRendererLayerParams& params,
     const gfx::Size& swap_chain_size) {
-  bool needs_commit = false;
-
   if (!content_visual_) {
     DCHECK(!clip_visual_);
-    dcomp_device_->CreateVisual(clip_visual_.GetAddressOf());
+    dcomp_device_->CreateVisual(&clip_visual_);
     DCHECK(clip_visual_);
-    dcomp_device_->CreateVisual(content_visual_.GetAddressOf());
+    dcomp_device_->CreateVisual(&content_visual_);
     DCHECK(content_visual_);
     clip_visual_->AddVisual(content_visual_.Get(), FALSE, nullptr);
-    needs_commit = true;
+    layer_tree_->SetNeedsCommit();
   }
 
   // Visual offset is applied before transform so it behaves similar to how the
@@ -951,13 +938,13 @@
   if (visual_info_.offset != offset || visual_info_.transform != transform) {
     visual_info_.offset = offset;
     visual_info_.transform = transform;
-    needs_commit = true;
+    layer_tree_->SetNeedsCommit();
 
     content_visual_->SetOffsetX(offset.x());
     content_visual_->SetOffsetY(offset.y());
 
     Microsoft::WRL::ComPtr<IDCompositionMatrixTransform> dcomp_transform;
-    dcomp_device_->CreateMatrixTransform(dcomp_transform.GetAddressOf());
+    dcomp_device_->CreateMatrixTransform(&dcomp_transform);
     DCHECK(dcomp_transform);
     // SkMatrix44 is column-major, but D2D_MATRIX_3x2_F is row-major.
     D2D_MATRIX_3X2_F d2d_matrix = {
@@ -972,13 +959,13 @@
       visual_info_.clip_rect != params.clip_rect) {
     visual_info_.is_clipped = params.is_clipped;
     visual_info_.clip_rect = params.clip_rect;
-    needs_commit = true;
+    layer_tree_->SetNeedsCommit();
     // DirectComposition clips happen in the pre-transform visual space, while
     // cc/ clips happen post-transform. So the clip needs to go on a separate
     // parent visual that's untransformed.
     if (params.is_clipped) {
       Microsoft::WRL::ComPtr<IDCompositionRectangleClip> clip;
-      dcomp_device_->CreateRectangleClip(clip.GetAddressOf());
+      dcomp_device_->CreateRectangleClip(&clip);
       DCHECK(clip);
       clip->SetLeft(params.clip_rect.x());
       clip->SetRight(params.clip_rect.right());
@@ -989,14 +976,85 @@
       clip_visual_->SetClip(nullptr);
     }
   }
-  return needs_commit;
+}
+
+bool DCLayerTree::SwapChainPresenter::TryPresentToDecodeSwapChain(
+    gl::GLImageDXGI* image_dxgi,
+    const gfx::Rect& content_rect,
+    const gfx::Size& swap_chain_size) {
+  if (!base::FeatureList::IsEnabled(
+          features::kDirectCompositionUseNV12DecodeSwapChain))
+    return false;
+
+  auto not_used_reason = DecodeSwapChainNotUsedReason::kFailedToPresent;
+
+  bool nv12_supported = g_overlay_format_used == OverlayFormat::kNV12;
+  // TODO(sunnyps): Try using decode swap chain for uploaded video images.
+  if (image_dxgi && nv12_supported && !failed_to_present_decode_swapchain_) {
+    D3D11_TEXTURE2D_DESC texture_desc = {};
+    image_dxgi->texture()->GetDesc(&texture_desc);
+
+    bool is_decoder_texture = texture_desc.BindFlags & D3D11_BIND_DECODER;
+
+    // Decode swap chains do not support shared resources.
+    // TODO(sunnyps): Find a workaround for when the decoder moves to its own
+    // thread and D3D device.  See https://crbug.com/911847
+    bool is_shared_texture =
+        texture_desc.MiscFlags &
+        (D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX |
+         D3D11_RESOURCE_MISC_SHARED_NTHANDLE);
+
+    // Rotated videos are not promoted to overlays.  We plan to implement
+    // rotation using video processor instead of via direct composition.  Also
+    // check for skew and any downscaling specified to direct composition.
+    bool is_overlay_supported_transform =
+        visual_info_.transform.IsPositiveScaleOrTranslation();
+
+    // Downscaled video isn't promoted to hardware overlays.  We prefer to
+    // blit into the smaller size so that it can be promoted to a hardware
+    // overlay.
+    float swap_chain_scale_x =
+        swap_chain_size.width() * 1.0f / content_rect.width();
+    float swap_chain_scale_y =
+        swap_chain_size.height() * 1.0f / content_rect.height();
+
+    is_overlay_supported_transform = is_overlay_supported_transform &&
+                                     (swap_chain_scale_x >= 1.0f) &&
+                                     (swap_chain_scale_y >= 1.0f);
+
+    if (is_decoder_texture && !is_shared_texture &&
+        is_overlay_supported_transform) {
+      if (PresentToDecodeSwapChain(image_dxgi, content_rect, swap_chain_size))
+        return true;
+      ReleaseSwapChainResources();
+      failed_to_present_decode_swapchain_ = true;
+      not_used_reason = DecodeSwapChainNotUsedReason::kFailedToPresent;
+      DLOG(ERROR)
+          << "Present to decode swap chain failed - falling back to blit";
+    } else if (!is_decoder_texture) {
+      not_used_reason = DecodeSwapChainNotUsedReason::kNonDecoderTexture;
+    } else if (is_shared_texture) {
+      not_used_reason = DecodeSwapChainNotUsedReason::kSharedTexture;
+    } else if (!is_overlay_supported_transform) {
+      not_used_reason = DecodeSwapChainNotUsedReason::kIncompatibleTransform;
+    }
+  } else if (!image_dxgi) {
+    not_used_reason = DecodeSwapChainNotUsedReason::kSoftwareFrame;
+  } else if (!nv12_supported) {
+    not_used_reason = DecodeSwapChainNotUsedReason::kNv12NotSupported;
+  } else if (failed_to_present_decode_swapchain_) {
+    not_used_reason = DecodeSwapChainNotUsedReason::kFailedToPresent;
+  }
+
+  UMA_HISTOGRAM_ENUMERATION(
+      "GPU.DirectComposition.DecodeSwapChainNotUsedReason", not_used_reason);
+  return false;
 }
 
 bool DCLayerTree::SwapChainPresenter::PresentToDecodeSwapChain(
     gl::GLImageDXGI* image_dxgi,
     const gfx::Rect& content_rect,
-    const gfx::Size& swap_chain_size,
-    bool* needs_commit) {
+    const gfx::Size& swap_chain_size) {
   DCHECK(!swap_chain_size.IsEmpty());
 
   Microsoft::WRL::ComPtr<IDXGIResource> decode_resource;
@@ -1074,7 +1132,7 @@
     DCHECK(decode_surface_);
 
     content_visual_->SetContent(decode_surface_.Get());
-    *needs_commit = true;
+    layer_tree_->SetNeedsCommit();
   } else if (last_y_image_ == image_dxgi && last_uv_image_ == image_dxgi &&
              swap_chain_size_ == swap_chain_size) {
     // Early out if we're presenting the same image again.
@@ -1136,10 +1194,7 @@
 }
 
 bool DCLayerTree::SwapChainPresenter::PresentToSwapChain(
-    const ui::DCRendererLayerParams& params,
-    bool* needs_commit) {
-  *needs_commit = false;
-
+    const ui::DCRendererLayerParams& params) {
   gl::GLImageDXGI* image_dxgi =
       gl::GLImageDXGI::FromGLImage(params.y_image.get());
   gl::GLImageMemory* y_image_memory =
@@ -1160,80 +1215,16 @@
     if (swap_chain_) {
       ReleaseSwapChainResources();
       content_visual_->SetContent(nullptr);
-      *needs_commit = true;
+      layer_tree_->SetNeedsCommit();
     }
     return true;
   }
 
-  if (UpdateVisuals(params, swap_chain_size))
-    *needs_commit = true;
+  UpdateVisuals(params, swap_chain_size);
 
-  if (base::FeatureList::IsEnabled(
-          features::kDirectCompositionUseNV12DecodeSwapChain)) {
-    auto not_used_reason = DecodeSwapChainNotUsedReason::kFailedToPresent;
-
-    bool nv12_supported = g_overlay_format_used == OverlayFormat::kNV12;
-    // TODO(sunnyps): Try using decode swap chain for uploaded video images.
-    if (image_dxgi && nv12_supported && !failed_to_present_decode_swapchain_) {
-      D3D11_TEXTURE2D_DESC texture_desc = {};
-      image_dxgi->texture()->GetDesc(&texture_desc);
-
-      bool is_decoder_texture = texture_desc.BindFlags & D3D11_BIND_DECODER;
-
-      // Decode swap chains do not support shared resources.
-      // TODO(sunnyps): Find a workaround for when the decoder moves to its own
-      // thread and D3D device.  See https://crbug.com/911847
-      bool is_shared_texture =
-          texture_desc.MiscFlags &
-          (D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX |
-           D3D11_RESOURCE_MISC_SHARED_NTHANDLE);
-
-      // Rotated videos are not promoted to overlays.  We plan to implement
-      // rotation using video processor instead of via direct composition.  Also
-      // check for skew and any downscaling specified to direct composition.
-      bool is_overlay_supported_transform =
-          visual_info_.transform.IsPositiveScaleOrTranslation();
-
-      // Downscaled video isn't promoted to hardware overlays.  We prefer to
-      // blit into the smaller size so that it can be promoted to a hardware
-      // overlay.
-      float swap_chain_scale_x =
-          swap_chain_size.width() * 1.0f / params.content_rect.width();
-      float swap_chain_scale_y =
-          swap_chain_size.height() * 1.0f / params.content_rect.height();
-
-      is_overlay_supported_transform = is_overlay_supported_transform &&
-                                       (swap_chain_scale_x >= 1.0f) &&
-                                       (swap_chain_scale_y >= 1.0f);
-
-      if (is_decoder_texture && !is_shared_texture &&
-          is_overlay_supported_transform) {
-        if (PresentToDecodeSwapChain(image_dxgi, params.content_rect,
-                                     swap_chain_size, needs_commit)) {
-          return true;
-        }
-        ReleaseSwapChainResources();
-        failed_to_present_decode_swapchain_ = true;
-        not_used_reason = DecodeSwapChainNotUsedReason::kFailedToPresent;
-        DLOG(ERROR)
-            << "Present to decode swap chain failed - falling back to blit";
-      } else if (!is_decoder_texture) {
-        not_used_reason = DecodeSwapChainNotUsedReason::kNonDecoderTexture;
-      } else if (is_shared_texture) {
-        not_used_reason = DecodeSwapChainNotUsedReason::kSharedTexture;
-      } else if (!is_overlay_supported_transform) {
-        not_used_reason = DecodeSwapChainNotUsedReason::kIncompatibleTransform;
-      }
-    } else if (!image_dxgi) {
-      not_used_reason = DecodeSwapChainNotUsedReason::kSoftwareFrame;
-    } else if (!nv12_supported) {
-      not_used_reason = DecodeSwapChainNotUsedReason::kNv12NotSupported;
-    } else if (failed_to_present_decode_swapchain_) {
-      not_used_reason = DecodeSwapChainNotUsedReason::kFailedToPresent;
-    }
-
-    UMA_HISTOGRAM_ENUMERATION(
-        "GPU.DirectComposition.DecodeSwapChainNotUsedReason", not_used_reason);
+  if (TryPresentToDecodeSwapChain(image_dxgi, params.content_rect,
+                                  swap_chain_size)) {
+    return true;
   }
 
   bool swap_chain_resized = swap_chain_size_ != swap_chain_size;
@@ -1251,7 +1242,7 @@
       return false;
     }
     content_visual_->SetContent(swap_chain_.Get());
-    *needs_commit = true;
+    layer_tree_->SetNeedsCommit();
   } else if (last_y_image_ == params.y_image &&
              last_uv_image_ == params.uv_image) {
     // The swap chain is presenting the same images as last swap, which means
@@ -1313,13 +1304,13 @@
     // first Present() after this needs to have SyncInterval > 0, or else the
     // workaround doesn't help.
     Microsoft::WRL::ComPtr<ID3D11Texture2D> dest_texture;
-    swap_chain_->GetBuffer(0, IID_PPV_ARGS(dest_texture.GetAddressOf()));
+    swap_chain_->GetBuffer(0, IID_PPV_ARGS(&dest_texture));
     DCHECK(dest_texture);
     Microsoft::WRL::ComPtr<ID3D11Texture2D> src_texture;
-    hr = swap_chain_->GetBuffer(1, IID_PPV_ARGS(src_texture.GetAddressOf()));
+    hr = swap_chain_->GetBuffer(1, IID_PPV_ARGS(&src_texture));
     DCHECK(src_texture);
     Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
-    d3d11_device_->GetImmediateContext(context.GetAddressOf());
+    d3d11_device_->GetImmediateContext(&context);
     DCHECK(context);
     context->CopyResource(dest_texture.Get(), src_texture.Get());
 
@@ -1327,7 +1318,7 @@
     // there still may be a black flicker when presenting expensive content
     // (e.g. 4k video).
     Microsoft::WRL::ComPtr<IDXGIDevice2> dxgi_device2;
-    d3d11_device_.CopyTo(dxgi_device2.GetAddressOf());
+    d3d11_device_.As(&dxgi_device2);
     DCHECK(dxgi_device2);
     base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                               base::WaitableEvent::InitialState::NOT_SIGNALED);
@@ -1429,8 +1420,8 @@
 
   Microsoft::WRL::ComPtr<IDXGISwapChain3> swap_chain3;
   Microsoft::WRL::ComPtr<ID3D11VideoContext1> context1;
-  if (SUCCEEDED(swap_chain_.CopyTo(swap_chain3.GetAddressOf())) &&
-      SUCCEEDED(video_context.CopyTo(context1.GetAddressOf()))) {
+  if (SUCCEEDED(swap_chain_.As(&swap_chain3)) &&
+      SUCCEEDED(video_context.As(&context1))) {
     DCHECK(swap_chain3);
     DCHECK(context1);
     // Set input color space.
@@ -1487,7 +1478,7 @@
     Microsoft::WRL::ComPtr<ID3D11VideoProcessorInputView> input_view;
     HRESULT hr = video_device->CreateVideoProcessorInputView(
         input_texture.Get(), video_processor_enumerator.Get(), &input_desc,
-        input_view.GetAddressOf());
+        &input_view);
     if (FAILED(hr)) {
       DLOG(ERROR) << "CreateVideoProcessorInputView failed with error 0x"
                   << std::hex << hr;
@@ -1512,7 +1503,7 @@
 
     if (!output_view_) {
       Microsoft::WRL::ComPtr<ID3D11Texture2D> swap_chain_buffer;
-      swap_chain_->GetBuffer(0, IID_PPV_ARGS(swap_chain_buffer.GetAddressOf()));
+      swap_chain_->GetBuffer(0, IID_PPV_ARGS(&swap_chain_buffer));
 
       D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC output_desc = {};
       output_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
@@ -1520,7 +1511,7 @@
 
       hr = video_device->CreateVideoProcessorOutputView(
           swap_chain_buffer.Get(), video_processor_enumerator.Get(),
-          &output_desc, output_view_.GetAddressOf());
+          &output_desc, &output_view_);
       if (FAILED(hr)) {
         DLOG(ERROR) << "CreateVideoProcessorOutputView failed with error 0x"
                     << std::hex << hr;
@@ -1601,13 +1592,13 @@
   ReleaseSwapChainResources();
 
   Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
-  d3d11_device_.CopyTo(dxgi_device.GetAddressOf());
+  d3d11_device_.As(&dxgi_device);
   DCHECK(dxgi_device);
   Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
-  dxgi_device->GetAdapter(dxgi_adapter.GetAddressOf());
+  dxgi_device->GetAdapter(&dxgi_adapter);
   DCHECK(dxgi_adapter);
   Microsoft::WRL::ComPtr<IDXGIFactoryMedia> media_factory;
-  dxgi_adapter->GetParent(IID_PPV_ARGS(media_factory.GetAddressOf()));
+  dxgi_adapter->GetParent(IID_PPV_ARGS(&media_factory));
   DCHECK(media_factory);
 
   // The composition surface handle is only used to create YUV swap chains since
@@ -1648,7 +1639,7 @@
   if (use_yuv_swap_chain) {
     HRESULT hr = media_factory->CreateSwapChainForCompositionSurfaceHandle(
         d3d11_device_.Get(), swap_chain_handle_.Get(), &desc, nullptr,
-        swap_chain_.GetAddressOf());
+        &swap_chain_);
     is_yuv_swapchain_ = SUCCEEDED(hr);
     failed_to_create_yuv_swapchain_ = !is_yuv_swapchain_;
 
@@ -1677,7 +1668,7 @@
 
     HRESULT hr = media_factory->CreateSwapChainForCompositionSurfaceHandle(
         d3d11_device_.Get(), swap_chain_handle_.Get(), &desc, nullptr,
-        swap_chain_.GetAddressOf());
+        &swap_chain_);
 
     base::UmaHistogramSparse(kSwapChainCreationResultByFormatUmaPrefix +
                                  OverlayFormatToString(OverlayFormat::kBGRA),
@@ -1696,46 +1687,42 @@
   return true;
 }
 
-bool DCLayerTree::UpdateBackbufferVisual(BackbufferInfo info) {
-  bool needs_commit = false;
-
-  if (!backbuffer_visual_) {
-    dcomp_device_->CreateVisual(backbuffer_visual_.GetAddressOf());
-    needs_commit = true;
-  }
-
-  if (backbuffer_info_ != info) {
-    backbuffer_info_ = std::move(info);
-    backbuffer_visual_->SetContent(
-        backbuffer_info_.dcomp_surface
-            ? static_cast<IUnknown*>(backbuffer_info_.dcomp_surface.Get())
-            : static_cast<IUnknown*>(backbuffer_info_.swap_chain.Get()));
-    needs_commit = true;
-  }
-
-  return needs_commit;
-}
-
 bool DCLayerTree::CommitAndClearPendingOverlays(
-    BackbufferInfo backbuffer_info) {
-  bool needs_commit = false;
+    DirectCompositionChildSurfaceWin* root_surface) {
+  DCHECK(!needs_commit_);
+  // Check if root surface visual needs a commit first.
+  if (!root_surface_visual_) {
+    dcomp_device_->CreateVisual(&root_surface_visual_);
+    needs_commit_ = true;
+  }
 
-  // Check if backbuffer visual needs a commit first.
-  if (UpdateBackbufferVisual(std::move(backbuffer_info)))
-    needs_commit = true;
+  if (root_surface->swap_chain() != root_swap_chain_ ||
+      root_surface->dcomp_surface() != root_dcomp_surface_ ||
+      root_surface->dcomp_surface_serial() != root_dcomp_surface_serial_) {
+    root_swap_chain_ = root_surface->swap_chain();
+    root_dcomp_surface_ = root_surface->dcomp_surface();
+    root_dcomp_surface_serial_ = root_surface->dcomp_surface_serial();
+    root_surface_visual_->SetContent(
+        root_swap_chain_ ? static_cast<IUnknown*>(root_swap_chain_.Get())
+                         : static_cast<IUnknown*>(root_dcomp_surface_.Get()));
+    needs_commit_ = true;
+  }
+
+  std::vector<std::unique_ptr<ui::DCRendererLayerParams>> overlays;
+  std::swap(pending_overlays_, overlays);
 
   // Sort layers by z-order.
-  std::sort(pending_overlays_.begin(), pending_overlays_.end(),
+  std::sort(overlays.begin(), overlays.end(),
             [](const auto& a, const auto& b) -> bool {
               return a->z_order < b->z_order;
             });
 
   // If we need to grow or shrink swap chain presenters, we'll need to add or
   // remove visuals.
-  if (video_swap_chains_.size() != pending_overlays_.size()) {
+  if (video_swap_chains_.size() != overlays.size()) {
     // Grow or shrink list of swap chain presenters to match pending overlays.
     std::vector<std::unique_ptr<SwapChainPresenter>> new_video_swap_chains;
-    for (size_t i = 0; i < pending_overlays_.size(); ++i) {
+    for (size_t i = 0; i < overlays.size(); ++i) {
       // TODO(sunnyps): Try to find a matching swap chain based on size, type of
       // swap chain, gl image, etc.
       if (i < video_swap_chains_.size()) {
@@ -1746,46 +1733,43 @@
       }
     }
     video_swap_chains_.swap(new_video_swap_chains);
-    needs_commit = true;
+    needs_commit_ = true;
   }
 
   // Present to each swap chain.
-  for (size_t i = 0; i < pending_overlays_.size(); ++i) {
+  for (size_t i = 0; i < overlays.size(); ++i) {
     auto& video_swap_chain = video_swap_chains_[i];
-    bool video_needs_commit = false;
-    if (!video_swap_chain->PresentToSwapChain(*pending_overlays_[i],
-                                              &video_needs_commit)) {
+    if (!video_swap_chain->PresentToSwapChain(*overlays[i])) {
       DLOG(ERROR) << "PresentToSwapChain failed";
       return false;
     }
-    needs_commit = needs_commit || video_needs_commit;
   }
 
   // Rebuild visual tree and commit if any visual changed.
-  if (needs_commit) {
-    root_visual_->RemoveAllVisuals();
+  if (needs_commit_) {
+    needs_commit_ = false;
+    dcomp_root_visual_->RemoveAllVisuals();
 
     // Add layers with negative z-order first.
     size_t i = 0;
-    for (; i < pending_overlays_.size() && pending_overlays_[i]->z_order < 0;
-         ++i) {
+    for (; i < overlays.size() && overlays[i]->z_order < 0; ++i) {
       IDCompositionVisual2* visual = video_swap_chains_[i]->visual().Get();
       // We call AddVisual with insertAbove FALSE and referenceVisual nullptr
       // which is equivalent to saying that the visual should be below no other
       // visual, or in other words it should be above all other visuals.
-      root_visual_->AddVisual(visual, FALSE, nullptr);
+      dcomp_root_visual_->AddVisual(visual, FALSE, nullptr);
     }
 
-    // Add backbuffer visual at z-order 0.
-    root_visual_->AddVisual(backbuffer_visual_.Get(), FALSE, nullptr);
+    // Add root surface visual at z-order 0.
+    dcomp_root_visual_->AddVisual(root_surface_visual_.Get(), FALSE, nullptr);
 
     // Add visuals with positive z-order.
-    for (; i < pending_overlays_.size(); ++i) {
+    for (; i < overlays.size(); ++i) {
       // There shouldn't be a layer with z-order 0.  Otherwise, we can't tell
-      // its order with respect to backbuffer.
-      DCHECK_GT(pending_overlays_[i]->z_order, 0);
+      // its order with respect to root surface.
+      DCHECK_GT(overlays[i]->z_order, 0);
       IDCompositionVisual2* visual = video_swap_chains_[i]->visual().Get();
-      root_visual_->AddVisual(visual, FALSE, nullptr);
+      dcomp_root_visual_->AddVisual(visual, FALSE, nullptr);
     }
 
     HRESULT hr = dcomp_device_->Commit();
@@ -1795,7 +1779,6 @@
     }
   }
 
-  pending_overlays_.clear();
   return true;
 }
 
@@ -1854,7 +1837,7 @@
 
     // This will fail if the D3D device is "Microsoft Basic Display Adapter".
     Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device;
-    if (FAILED(d3d11_device.CopyTo(video_device.GetAddressOf()))) {
+    if (FAILED(d3d11_device.As(&video_device))) {
       DLOG(ERROR) << "Failed to retrieve video device";
       return false;
     }
@@ -1925,7 +1908,7 @@
 
   HRESULT hr = S_OK;
   Microsoft::WRL::ComPtr<IDXGIFactory> factory;
-  hr = CreateDXGIFactory(IID_PPV_ARGS(factory.GetAddressOf()));
+  hr = CreateDXGIFactory(IID_PPV_ARGS(&factory));
   if (FAILED(hr)) {
     DLOG(ERROR) << "Failed to create DXGI factory.";
     return false;
@@ -1934,7 +1917,7 @@
   bool hdr_monitor_found = false;
   for (UINT adapter_index = 0;; ++adapter_index) {
     Microsoft::WRL::ComPtr<IDXGIAdapter> adapter;
-    hr = factory->EnumAdapters(adapter_index, adapter.GetAddressOf());
+    hr = factory->EnumAdapters(adapter_index, &adapter);
     if (hr == DXGI_ERROR_NOT_FOUND)
       break;
     if (FAILED(hr)) {
@@ -1944,7 +1927,7 @@
 
     for (UINT output_index = 0;; ++output_index) {
       Microsoft::WRL::ComPtr<IDXGIOutput> output;
-      hr = adapter->EnumOutputs(output_index, output.GetAddressOf());
+      hr = adapter->EnumOutputs(output_index, &output);
       if (hr == DXGI_ERROR_NOT_FOUND)
         break;
       if (FAILED(hr)) {
@@ -1953,7 +1936,7 @@
       }
 
       Microsoft::WRL::ComPtr<IDXGIOutput6> output6;
-      hr = output->QueryInterface(IID_PPV_ARGS(output6.GetAddressOf()));
+      hr = output->QueryInterface(IID_PPV_ARGS(&output6));
       if (FAILED(hr)) {
         DLOG(WARNING) << "IDXGIOutput6 is required for HDR detection.";
         continue;
@@ -2049,12 +2032,7 @@
       gfx::SwapResult::SWAP_FAILED)
     succeeded = false;
 
-  DCLayerTree::BackbufferInfo backbuffer_info = {
-      root_surface_->swap_chain().Get(),
-      root_surface_->dcomp_surface().Get(),
-      root_surface_->dcomp_surface_serial(),
-  };
-  if (!layer_tree_->CommitAndClearPendingOverlays(std::move(backbuffer_info)))
+  if (!layer_tree_->CommitAndClearPendingOverlays(root_surface_.get()))
     succeeded = false;
 
   auto swap_result =
diff --git a/gpu/ipc/service/direct_composition_surface_win_unittest.cc b/gpu/ipc/service/direct_composition_surface_win_unittest.cc
index aca23603..88a3195 100644
--- a/gpu/ipc/service/direct_composition_surface_win_unittest.cc
+++ b/gpu/ipc/service/direct_composition_surface_win_unittest.cc
@@ -140,8 +140,7 @@
   data.SysMemPitch = size.width();
 
   Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
-  HRESULT hr =
-      d3d11_device->CreateTexture2D(&desc, &data, texture.GetAddressOf());
+  HRESULT hr = d3d11_device->CreateTexture2D(&desc, &data, &texture);
   CHECK(SUCCEEDED(hr));
   return texture;
 }
@@ -896,7 +895,7 @@
   Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
       CreateNV12Texture(d3d11_device, texture_size, true);
   Microsoft::WRL::ComPtr<IDXGIResource1> resource;
-  texture.CopyTo(resource.GetAddressOf());
+  texture.As(&resource);
   HANDLE handle = 0;
   resource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr,
                                &handle);
@@ -947,7 +946,7 @@
   Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
       CreateNV12Texture(d3d11_device, texture_size, true);
   Microsoft::WRL::ComPtr<IDXGIResource1> resource;
-  texture.CopyTo(resource.GetAddressOf());
+  texture.As(&resource);
   HANDLE handle = 0;
   resource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr,
                                &handle);
@@ -1003,7 +1002,7 @@
   Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
       CreateNV12Texture(d3d11_device, texture_size, true);
   Microsoft::WRL::ComPtr<IDXGIResource1> resource;
-  texture.CopyTo(resource.GetAddressOf());
+  texture.As(&resource);
   HANDLE handle = 0;
   resource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr,
                                &handle);
@@ -1058,7 +1057,7 @@
   Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
       CreateNV12Texture(d3d11_device, texture_size, true);
   Microsoft::WRL::ComPtr<IDXGIResource1> resource;
-  texture.CopyTo(resource.GetAddressOf());
+  texture.As(&resource);
   HANDLE handle = 0;
   resource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr,
                                &handle);
@@ -1124,7 +1123,7 @@
   Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
       CreateNV12Texture(d3d11_device, texture_size, true);
   Microsoft::WRL::ComPtr<IDXGIResource1> resource;
-  texture.CopyTo(resource.GetAddressOf());
+  texture.As(&resource);
   HANDLE handle = 0;
   resource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr,
                                &handle);
@@ -1192,7 +1191,7 @@
   Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
       CreateNV12Texture(d3d11_device, texture_size, true);
   Microsoft::WRL::ComPtr<IDXGIResource1> resource;
-  texture.CopyTo(resource.GetAddressOf());
+  texture.As(&resource);
   HANDLE handle = 0;
   resource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr,
                                &handle);
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index 3345a58..a9d1609a 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -437,6 +437,12 @@
 }
 
 builder_mixins {
+  name: "mac-dawn-ci"
+  mixins: "mac"
+  mixins: "dawn-ci"
+}
+
+builder_mixins {
   name: "memory-ci"
   mixins: "goma-many-jobs-for-ci"
   recipe {
@@ -2043,6 +2049,18 @@
       mixins: "win-dawn-ci"
     }
 
+    # chromium.dawn Mac bots (to be folded in to the section above once working)
+    builders {
+      name: "Dawn Mac x64 Builder"
+      mixins: "mac-dawn-ci"
+    }
+    builders {
+      name: "Dawn Mac x64 Release (AMD)"
+      # Note the use of linux-dawn-ci for this Mac bot. We are attempting to use
+      # a thin Linux VM for the tester.
+      mixins: "linux-dawn-ci"
+    }
+
     # Code coverage reports generation bots.
     builders {
       name: "ios-simulator-code-coverage"
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index 79a77ad..aa2f085 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -3407,6 +3407,16 @@
     short_name: "x64"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Dawn Mac x64 Builder"
+    category: "ToT|Mac|Builder"
+    short_name: "x64"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/Dawn Mac x64 Release (AMD)"
+    category: "ToT|Mac|AMD"
+    short_name: "x64"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Dawn Linux x64 DEPS Builder"
     category: "DEPS|Linux|Builder"
     short_name: "x64"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index e456176..39ab2d6 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -145,6 +145,7 @@
   triggers: "CrWinGomaStaging"
   triggers: "Dawn Linux x64 Builder"
   triggers: "Dawn Linux x64 DEPS Builder"
+  triggers: "Dawn Mac x64 Builder"
   triggers: "Dawn Win10 x64 Builder"
   triggers: "Dawn Win10 x64 DEPS Builder"
   triggers: "Dawn Win10 x86 Builder"
@@ -2049,6 +2050,27 @@
 }
 
 job {
+  id: "Dawn Mac x64 Builder"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Dawn Mac x64 Builder"
+  }
+}
+
+job {
+  id: "Dawn Mac x64 Release (AMD)"
+  # Triggered by "Dawn Mac x64 Builder"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Dawn Mac x64 Release (AMD)"
+  }
+}
+
+job {
   id: "GPU FYI Mac Builder"
   acl_sets: "default"
   buildbucket: {
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm b/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm
index d957e70..efdd1b3 100644
--- a/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm
@@ -152,9 +152,10 @@
   self.dispatcher = static_cast<id<ApplicationCommands>>(_commandDispatcher);
 }
 
-- (BOOL)presentingInfobarBanner {
+- (BOOL)isPresentingInfobarBanner {
   DCHECK(IsInfobarUIRebootEnabled());
-  return self.infobarViewController ? YES : NO;
+  _presentingInfobarBanner = self.infobarViewController ? YES : NO;
+  return _presentingInfobarBanner;
 }
 
 #pragma mark - InfobarConsumer
diff --git a/ios/web/find_in_page/find_in_page_manager_impl.h b/ios/web/find_in_page/find_in_page_manager_impl.h
index 5620ce8d..9265b1e 100644
--- a/ios/web/find_in_page/find_in_page_manager_impl.h
+++ b/ios/web/find_in_page/find_in_page_manager_impl.h
@@ -31,6 +31,7 @@
   // FindInPageManager overrides
   void Find(NSString* query, FindInPageOptions options) override;
   void StopFinding() override;
+  bool CanSearchContent() override;
   FindInPageManagerDelegate* GetDelegate() override;
   void SetDelegate(FindInPageManagerDelegate* delegate) override;
 
diff --git a/ios/web/find_in_page/find_in_page_manager_impl.mm b/ios/web/find_in_page/find_in_page_manager_impl.mm
index 65d7fd8..55260a5 100644
--- a/ios/web/find_in_page/find_in_page_manager_impl.mm
+++ b/ios/web/find_in_page/find_in_page_manager_impl.mm
@@ -224,6 +224,8 @@
 }
 
 void FindInPageManagerImpl::Find(NSString* query, FindInPageOptions options) {
+  DCHECK(CanSearchContent());
+
   switch (options) {
     case FindInPageOptions::FindInPageSearch:
       DCHECK(query);
@@ -277,6 +279,10 @@
 
 void FindInPageManagerImpl::StopFinding() {}
 
+bool FindInPageManagerImpl::CanSearchContent() {
+  return web_state_->ContentIsHTML();
+}
+
 void FindInPageManagerImpl::ProcessFindInPageResult(const std::string& frame_id,
                                                     const int unique_id,
                                                     const base::Value* result) {
diff --git a/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm b/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm
index 0014e5ff..05393ffd 100644
--- a/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm
+++ b/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm
@@ -591,4 +591,16 @@
   }));
 }
 
+// Tests that Find in Page SetContentIsHTML() returns true if the web state's
+// content is HTML and returns false if the web state's content is not HTML.
+TEST_F(FindInPageManagerImplTest, FindInPageCanSearchContent) {
+  test_web_state_->SetContentIsHTML(false);
+
+  EXPECT_FALSE(GetFindInPageManager()->CanSearchContent());
+
+  test_web_state_->SetContentIsHTML(true);
+
+  EXPECT_TRUE(GetFindInPageManager()->CanSearchContent());
+}
+
 }  // namespace web
diff --git a/ios/web/public/find_in_page/find_in_page_manager.h b/ios/web/public/find_in_page/find_in_page_manager.h
index 2e5bae1..1bd01d0 100644
--- a/ios/web/public/find_in_page/find_in_page_manager.h
+++ b/ios/web/public/find_in_page/find_in_page_manager.h
@@ -18,8 +18,7 @@
 enum class FindInPageOptions {
   // Searches for a string. Highlights all matches. Selects and scrolls to the
   // first result if string is found. Selecting refers to highlighting in a
-  // unique manner different from the other matches. TODO(crbug.com/925149):
-  // Does not support strings with non-ascii.
+  // unique manner different from the other matches.
   FindInPageSearch = 1,
   // Selects and scrolls to the next result if there is one. Otherwise, nothing
   // will change. Loop back to the first result if currently on last result. If
@@ -38,6 +37,7 @@
   // on |options|. |query| must not be null if |options| is |FindInPageSearch|.
   // |query| is ignored if |options| is not |FindInPageSearch|. If new search is
   // started before previous search finishes, old request will be discarded.
+  // Check CanSearchContent() before calling Find().
   //
   // FindInPageManagerDelegate::DidHighlightMatches() will be called to return
   // the total matches found if FindInPageSearch is passed, assuming it hasn't
@@ -50,6 +50,10 @@
   // FindInPageOptions::FindInPageSearch is never called.
   virtual void StopFinding() = 0;
 
+  // Returns false if page content can not be searched (for example: an image)
+  // or if search is not supported (for example: PDF files).
+  virtual bool CanSearchContent() = 0;
+
   virtual FindInPageManagerDelegate* GetDelegate() = 0;
   virtual void SetDelegate(FindInPageManagerDelegate* delegate) = 0;
 
diff --git a/ios/web/public/web_state/ui/crw_web_view_proxy.h b/ios/web/public/web_state/ui/crw_web_view_proxy.h
index ec1a1430..3b6f02d 100644
--- a/ios/web/public/web_state/ui/crw_web_view_proxy.h
+++ b/ios/web/public/web_state/ui/crw_web_view_proxy.h
@@ -64,6 +64,7 @@
 - (void)addSubview:(UIView*)view;
 
 // Returns YES if it makes sense to search for text right now.
+// TODO(crbug.com/949651): Remove once JSFindInPageManager is removed.
 - (BOOL)hasSearchableTextContent;
 
 // Returns the currently visible keyboard accessory, or nil.
diff --git a/ios/web/web_state/js/find_in_page_js_unittest.mm b/ios/web/web_state/js/find_in_page_js_unittest.mm
index 250ceec..9bf26c4 100644
--- a/ios/web/web_state/js/find_in_page_js_unittest.mm
+++ b/ios/web/web_state/js/find_in_page_js_unittest.mm
@@ -346,4 +346,31 @@
                   @"document.getElementsByClassName('find_selected').length"));
 }
 
+// Tests that FindInPage works when searching for strings with non-ascii
+// characters.
+TEST_F(FindInPageJsTest, SearchForNonAscii) {
+  ASSERT_TRUE(LoadHtml("<span>école francais</span>"));
+  base::TimeDelta kCallJavascriptFunctionTimeout =
+      base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return frames_manager()->GetAllWebFrames().size() == 1;
+  }));
+  __block bool message_received = false;
+  std::vector<base::Value> params;
+  params.push_back(base::Value("école"));
+  params.push_back(base::Value(kPumpSearchTimeout));
+  main_web_frame()->CallJavaScriptFunction(
+      kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) {
+        ASSERT_TRUE(result);
+        ASSERT_TRUE(result->is_double());
+        double count = result->GetDouble();
+        ASSERT_EQ(1.0, count);
+        message_received = true;
+      }),
+      kCallJavascriptFunctionTimeout);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return message_received;
+  }));
+}
+
 }  // namespace web
diff --git a/media/audio/audio_manager_unittest.cc b/media/audio/audio_manager_unittest.cc
index aec1d2a..27cb93f 100644
--- a/media/audio/audio_manager_unittest.cc
+++ b/media/audio/audio_manager_unittest.cc
@@ -56,7 +56,7 @@
 #if defined(USE_CRAS)
 #include "chromeos/audio/audio_devices_pref_handler_stub.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/fake_cras_audio_client.h"
+#include "chromeos/dbus/audio/fake_cras_audio_client.h"
 #include "media/audio/cras/audio_manager_cras.h"
 #endif  // defined(USE_CRAS)
 
diff --git a/media/audio/cras/cras_input_unittest.cc b/media/audio/cras/cras_input_unittest.cc
index 08bd484..fc1ce1b2 100644
--- a/media/audio/cras/cras_input_unittest.cc
+++ b/media/audio/cras/cras_input_unittest.cc
@@ -15,7 +15,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/fake_cras_audio_client.h"
+#include "chromeos/dbus/audio/fake_cras_audio_client.h"
 #include "media/audio/audio_device_description.h"
 #include "media/audio/cras/audio_manager_cras.h"
 #include "media/audio/fake_audio_log_factory.h"
diff --git a/media/audio/cras/cras_unified_unittest.cc b/media/audio/cras/cras_unified_unittest.cc
index a811cd4..9f036f6 100644
--- a/media/audio/cras/cras_unified_unittest.cc
+++ b/media/audio/cras/cras_unified_unittest.cc
@@ -15,7 +15,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/cras_audio_client.h"
+#include "chromeos/dbus/audio/cras_audio_client.h"
 #include "media/audio/audio_device_description.h"
 #include "media/audio/cras/audio_manager_cras.h"
 #include "media/audio/fake_audio_log_factory.h"
diff --git a/media/capture/video/OWNERS b/media/capture/video/OWNERS
index 8b3d667..ea5ac3b3 100644
--- a/media/capture/video/OWNERS
+++ b/media/capture/video/OWNERS
@@ -1,9 +1,7 @@
 emircan@chromium.org
 chfremer@chromium.org
+mcasas@chromium.org
 tommi@chromium.org
 
-# Original (legacy) owner.
-mcasas@chromium.org
-
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia>WebCam
-# TEAM: webrtc-dev@chromium.org
diff --git a/media/capture/video/android/java/src/org/chromium/media/OWNERS b/media/capture/video/android/java/src/org/chromium/media/OWNERS
index 939f3d261..e34b150738 100644
--- a/media/capture/video/android/java/src/org/chromium/media/OWNERS
+++ b/media/capture/video/android/java/src/org/chromium/media/OWNERS
@@ -1,7 +1,5 @@
+mcasas@chromium.org
 qinmin@chromium.org
 
-# Original (legacy) owner.
-mcasas@chromium.org
-
+# media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia>WebCam
-# TEAM: webrtc-dev@chromium.org
diff --git a/media/learning/common/learning_task.h b/media/learning/common/learning_task.h
index 3c24aca8..0e4eb5a 100644
--- a/media/learning/common/learning_task.h
+++ b/media/learning/common/learning_task.h
@@ -30,6 +30,9 @@
   enum class Model {
     kExtraTrees,
     kLookupTable,
+
+    // For the fuzzer.
+    kMaxValue = kLookupTable
   };
 
   enum class Ordering {
@@ -44,6 +47,9 @@
     // ints that represent the number of elapsed milliseconds are numerically
     // ordered in a meaningful way.
     kNumeric,
+
+    // For the fuzzer.
+    kMaxValue = kNumeric
   };
 
   enum class PrivacyMode {
@@ -53,6 +59,9 @@
 
     // Value does not represent private information, such as video width.
     kPublic,
+
+    // For the fuzzer.
+    kMaxValue = kPublic
   };
 
   // Description of how a Value should be interpreted.
diff --git a/media/learning/impl/BUILD.gn b/media/learning/impl/BUILD.gn
index 1400eee1..27ed8c2 100644
--- a/media/learning/impl/BUILD.gn
+++ b/media/learning/impl/BUILD.gn
@@ -2,10 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//testing/libfuzzer/fuzzer_test.gni")
+
 component("impl") {
   output_name = "learning_impl"
   visibility = [
     "//media/learning/impl:unit_tests",
+    "//media/learning/impl:learning_fuzzer",
 
     # Actual clients.
     "//content/browser",
@@ -82,3 +85,14 @@
     "//testing/gtest",
   ]
 }
+
+fuzzer_test("learning_fuzzer") {
+  sources = [
+    "learning_fuzzertest.cc",
+  ]
+  deps = [
+    ":impl",
+    "//base",
+    "//base/test:test_support",
+  ]
+}
diff --git a/media/learning/impl/learning_fuzzertest.cc b/media/learning/impl/learning_fuzzertest.cc
new file mode 100644
index 0000000..122d031a
--- /dev/null
+++ b/media/learning/impl/learning_fuzzertest.cc
@@ -0,0 +1,72 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/fuzzed_data_provider.h"
+#include "base/test/scoped_task_environment.h"
+#include "media/learning/impl/learning_task_controller_impl.h"
+
+using media::learning::FeatureValue;
+using media::learning::FeatureVector;
+using media::learning::LearningTask;
+using ValueDescription = media::learning::LearningTask::ValueDescription;
+using media::learning::LearningTaskControllerImpl;
+using media::learning::ObservationCompletion;
+using media::learning::TargetValue;
+
+ValueDescription ConsumeValueDescription(base::FuzzedDataProvider* provider) {
+  ValueDescription desc;
+  desc.name = provider->ConsumeRandomLengthString(100);
+  desc.ordering = provider->ConsumeEnum<LearningTask::Ordering>();
+  desc.privacy_mode = provider->ConsumeEnum<LearningTask::PrivacyMode>();
+  return desc;
+}
+
+double ConsumeDouble(base::FuzzedDataProvider* provider) {
+  std::vector<uint8_t> v = provider->ConsumeBytes(sizeof(double));
+  if (v.size() == sizeof(double))
+    return reinterpret_cast<double*>(v.data())[0];
+
+  return 0;
+}
+
+FeatureVector ConsumeFeatureVector(base::FuzzedDataProvider* provider) {
+  FeatureVector features;
+  int n = provider->ConsumeIntegralInRange(0, 100);
+  while (n-- > 0)
+    features.push_back(FeatureValue(ConsumeDouble(provider)));
+
+  return features;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  base::test::ScopedTaskEnvironment scoped_task_environment;
+  base::FuzzedDataProvider provider(data, size);
+
+  LearningTask task;
+  task.name = provider.ConsumeRandomLengthString(100);
+  task.model = provider.ConsumeEnum<LearningTask::Model>();
+  task.use_one_hot_conversion = provider.ConsumeBool();
+  task.uma_hacky_confusion_matrix = provider.ConsumeRandomLengthString(10);
+  int n_features = provider.ConsumeIntegralInRange(0, 100);
+  int subset_size = provider.ConsumeIntegralInRange<uint8_t>(0, n_features);
+  if (subset_size)
+    task.feature_subset_size = subset_size;
+  for (int i = 0; i < n_features; i++)
+    task.feature_descriptions.push_back(ConsumeValueDescription(&provider));
+  task.target_description = ConsumeValueDescription(&provider);
+
+  LearningTaskControllerImpl controller(task);
+
+  // Build random examples.
+  while (provider.remaining_bytes() > 0) {
+    base::UnguessableToken id = base::UnguessableToken::Create();
+    controller.BeginObservation(id, ConsumeFeatureVector(&provider));
+    controller.CompleteObservation(
+        id, ObservationCompletion(TargetValue(ConsumeDouble(&provider)),
+                                  ConsumeDouble(&provider)));
+    scoped_task_environment.RunUntilIdle();
+  }
+
+  return 0;
+}
diff --git a/media/learning/impl/learning_task_controller_helper.cc b/media/learning/impl/learning_task_controller_helper.cc
index 82d0165..01c8972e 100644
--- a/media/learning/impl/learning_task_controller_helper.cc
+++ b/media/learning/impl/learning_task_controller_helper.cc
@@ -44,7 +44,8 @@
     base::UnguessableToken id,
     const ObservationCompletion& completion) {
   auto iter = pending_examples_.find(id);
-  DCHECK(iter != pending_examples_.end());
+  if (iter == pending_examples_.end())
+    return;
 
   iter->second.example.target_value = completion.target_value;
   iter->second.example.weight = completion.weight;
@@ -55,8 +56,8 @@
 void LearningTaskControllerHelper::CancelObservation(
     base::UnguessableToken id) {
   auto iter = pending_examples_.find(id);
-  // If the example has already been completed, then we shouldn't be called.
-  DCHECK(iter != pending_examples_.end());
+  if (iter == pending_examples_.end())
+    return;
 
   // This would have to check for pending predictions, if we supported them, and
   // defer destruction until the features arrive.
diff --git a/media/learning/impl/learning_task_controller_impl.cc b/media/learning/impl/learning_task_controller_impl.cc
index fc4597a..c663f5b 100644
--- a/media/learning/impl/learning_task_controller_impl.cc
+++ b/media/learning/impl/learning_task_controller_impl.cc
@@ -21,18 +21,19 @@
     SequenceBoundFeatureProvider feature_provider)
     : task_(task),
       training_data_(std::make_unique<TrainingData>()),
-      reporter_(std::move(reporter)) {
+      reporter_(std::move(reporter)),
+      helper_(std::make_unique<LearningTaskControllerHelper>(
+          task,
+          base::BindRepeating(&LearningTaskControllerImpl::AddFinishedExample,
+                              AsWeakPtr()),
+          std::move(feature_provider))),
+      expected_feature_count_(task_.feature_descriptions.size()) {
+  // Note that |helper_| uses the full set of features.
+
   // TODO(liberato): Make this compositional.  FeatureSubsetTaskController?
   if (task_.feature_subset_size)
     DoFeatureSubsetSelection();
 
-  // Now that we have the updated task, create a helper for it.
-  helper_ = std::make_unique<LearningTaskControllerHelper>(
-      task,
-      base::BindRepeating(&LearningTaskControllerImpl::AddFinishedExample,
-                          AsWeakPtr()),
-      std::move(feature_provider));
-
   switch (task_.model) {
     case LearningTask::Model::kExtraTrees:
       trainer_ = std::make_unique<ExtraTreesTrainer>();
@@ -48,30 +49,49 @@
 void LearningTaskControllerImpl::BeginObservation(
     base::UnguessableToken id,
     const FeatureVector& features) {
-  // Copy just the subset we care about.
-  FeatureVector new_features;
-  if (task_.feature_subset_size) {
-    for (auto& iter : feature_indices_)
-      new_features.push_back(features[iter]);
-  } else {
-    // Use them all.
-    new_features = features;
-  }
+  // TODO(liberato): Should we enforce that the right number of features are
+  // present here?  Right now, we allow it to be shorter, so that features from
+  // a FeatureProvider may be omitted.  Of course, they have to be at the end in
+  // that case.  If we start enforcing it here, make sure that LearningHelper
+  // starts adding the placeholder features.
+  if (!trainer_)
+    return;
 
-  helper_->BeginObservation(id, new_features);
+  helper_->BeginObservation(id, features);
 }
 
 void LearningTaskControllerImpl::CompleteObservation(
     base::UnguessableToken id,
     const ObservationCompletion& completion) {
+  if (!trainer_)
+    return;
   helper_->CompleteObservation(id, completion);
 }
 
 void LearningTaskControllerImpl::CancelObservation(base::UnguessableToken id) {
+  if (!trainer_)
+    return;
   helper_->CancelObservation(id);
 }
 
 void LearningTaskControllerImpl::AddFinishedExample(LabelledExample example) {
+  // Verify that we have a trainer and that we got the right number of features.
+  // We don't compare to |task_.feature_descriptions.size()| since that has been
+  // adjusted to the subset size already.  We expect the original count.
+  if (!trainer_ || example.features.size() != expected_feature_count_)
+    return;
+
+  // Now that we have the whole set of features, select the subset we want.
+  FeatureVector new_features;
+  if (task_.feature_subset_size) {
+    for (auto& iter : feature_indices_)
+      new_features.push_back(example.features[iter]);
+    example.features = std::move(new_features);
+  }  // else use them all.
+
+  // The features should now match the task.
+  DCHECK_EQ(example.features.size(), task_.feature_descriptions.size());
+
   if (training_data_->size() >= task_.max_data_set_size) {
     // Replace a random example.  We don't necessarily want to replace the
     // oldest, since we don't necessarily want to enforce an ad-hoc recency
@@ -156,7 +176,8 @@
 
   task_.feature_descriptions = adjusted_descriptions;
 
-  reporter_->SetFeatureSubset(feature_indices_);
+  if (reporter_)
+    reporter_->SetFeatureSubset(feature_indices_);
 }
 
 }  // namespace learning
diff --git a/media/learning/impl/learning_task_controller_impl.h b/media/learning/impl/learning_task_controller_impl.h
index 86f007baf..ea9d95e 100644
--- a/media/learning/impl/learning_task_controller_impl.h
+++ b/media/learning/impl/learning_task_controller_impl.h
@@ -91,6 +91,9 @@
   // randomly chosen subset of features.
   std::set<int> feature_indices_;
 
+  // Number of features that we expect in each observation.
+  size_t expected_feature_count_;
+
   friend class LearningTaskControllerImplTest;
 };
 
diff --git a/media/learning/impl/learning_task_controller_impl_unittest.cc b/media/learning/impl/learning_task_controller_impl_unittest.cc
index 1b5f6c5..fdabda3 100644
--- a/media/learning/impl/learning_task_controller_impl_unittest.cc
+++ b/media/learning/impl/learning_task_controller_impl_unittest.cc
@@ -191,6 +191,7 @@
 TEST_F(LearningTaskControllerImplTest, FeatureProviderIsUsed) {
   // If a FeatureProvider factory is provided, make sure that it's used to
   // adjust new examples.
+  task_.feature_descriptions.push_back({"AddedByFeatureProvider"});
   SequenceBoundFeatureProvider feature_provider =
       base::SequenceBound<FakeFeatureProvider>(
           base::SequencedTaskRunnerHandle::Get());
diff --git a/media/muxers/OWNERS b/media/muxers/OWNERS
index 92570f5..2198557 100644
--- a/media/muxers/OWNERS
+++ b/media/muxers/OWNERS
@@ -1,7 +1,4 @@
+mcasas@chromium.org
 miu@chromium.org
 
-# Original (legacy) owner.
-mcasas@chromium.org
-
 # COMPONENT: Blink>MediaRecording
-# TEAM: webrtc-dev@chromium.org
diff --git a/mojo/core/channel_mac.cc b/mojo/core/channel_mac.cc
index 0043335..450bd17e 100644
--- a/mojo/core/channel_mac.cc
+++ b/mojo/core/channel_mac.cc
@@ -528,6 +528,12 @@
       }
       OnError(Error::kDisconnected);
       return;
+    } else if (header->msgh_id == MACH_NOTIFY_SEND_ONCE) {
+      // Notification of an extant send-once right being destroyed. This is
+      // sent for the right allocated in RequestSendDeadNameNotification(),
+      // and no action needs to be taken. Since it is ignored, the kernel
+      // audit token need not be checked.
+      return;
     }
 
     if (header->msgh_size < sizeof(mach_msg_base_t)) {
diff --git a/mojo/public/cpp/bindings/lib/message.cc b/mojo/public/cpp/bindings/lib/message.cc
index da2238e0..fa28aa4 100644
--- a/mojo/public/cpp/bindings/lib/message.cc
+++ b/mojo/public/cpp/bindings/lib/message.cc
@@ -93,16 +93,14 @@
   }
 }
 
-void CreateSerializedMessageObject(
-    uint32_t name,
-    uint32_t flags,
-    uint32_t trace_id,
-    size_t payload_size,
-    size_t payload_interface_id_count,
-    std::vector<ScopedHandle>* handles,
-    const std::vector<MojoAppendMessageDataHandleOptions>* handle_options,
-    ScopedMessageHandle* out_handle,
-    internal::Buffer* out_buffer) {
+void CreateSerializedMessageObject(uint32_t name,
+                                   uint32_t flags,
+                                   uint32_t trace_id,
+                                   size_t payload_size,
+                                   size_t payload_interface_id_count,
+                                   std::vector<ScopedHandle>* handles,
+                                   ScopedMessageHandle* out_handle,
+                                   internal::Buffer* out_buffer) {
   TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
                          "mojo::Message Send", MANGLE_MESSAGE_ID(trace_id),
                          TRACE_EVENT_FLAG_FLOW_OUT);
@@ -112,12 +110,6 @@
   DCHECK_EQ(MOJO_RESULT_OK, rv);
   DCHECK(handle.is_valid());
 
-  MojoAppendMessageDataOptions append_options = {0};
-  append_options.struct_size = sizeof(append_options);
-  append_options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_NONE;
-  if (handle_options)
-    append_options.handle_options = handle_options->data();
-
   void* buffer;
   uint32_t buffer_size;
   size_t total_size = internal::ComputeSerializedMessageSize(
@@ -128,8 +120,8 @@
   rv = MojoAppendMessageData(
       handle->value(), static_cast<uint32_t>(total_size),
       handles ? reinterpret_cast<MojoHandle*>(handles->data()) : nullptr,
-      handles ? static_cast<uint32_t>(handles->size()) : 0, &append_options,
-      &buffer, &buffer_size);
+      handles ? static_cast<uint32_t>(handles->size()) : 0, nullptr, &buffer,
+      &buffer_size);
   DCHECK_EQ(MOJO_RESULT_OK, rv);
   if (handles) {
     // Handle ownership has been taken by MojoAppendMessageData.
@@ -242,24 +234,10 @@
                  uint32_t flags,
                  size_t payload_size,
                  size_t payload_interface_id_count,
-                 std::vector<ScopedHandle>* handles)
-    : Message(name,
-              flags,
-              payload_size,
-              payload_interface_id_count,
-              handles,
-              nullptr) {}
-
-Message::Message(
-    uint32_t name,
-    uint32_t flags,
-    size_t payload_size,
-    size_t payload_interface_id_count,
-    std::vector<ScopedHandle>* handles,
-    const std::vector<MojoAppendMessageDataHandleOptions>* handle_options) {
+                 std::vector<ScopedHandle>* handles) {
   CreateSerializedMessageObject(name, flags, GetTraceId(this), payload_size,
-                                payload_interface_id_count, handles,
-                                handle_options, &handle_, &payload_buffer_);
+                                payload_interface_id_count, handles, &handle_,
+                                &payload_buffer_);
   transferable_ = true;
   serialized_ = true;
 }
@@ -387,8 +365,7 @@
     return;
   }
 
-  if (context->associated_endpoint_handles()->empty() &&
-      !context->has_handles_with_shared_message_order()) {
+  if (context->associated_endpoint_handles()->empty()) {
     // Attaching only non-associated handles is easier since we don't have to
     // modify the message header. Faster path for that.
     payload_buffer_.AttachHandles(context->mutable_handles());
@@ -404,8 +381,7 @@
   uint32_t payload_size = payload_num_bytes();
   mojo::Message new_message(name(), header()->flags, payload_size,
                             context->associated_endpoint_handles()->size(),
-                            context->mutable_handles(),
-                            context->handle_options());
+                            context->mutable_handles());
   std::swap(*context->mutable_associated_endpoint_handles(),
             new_message.associated_endpoint_handles_);
   memcpy(new_message.payload_buffer()->AllocateAndGet(payload_size), payload(),
diff --git a/mojo/public/cpp/bindings/lib/serialization_context.cc b/mojo/public/cpp/bindings/lib/serialization_context.cc
index 5085327..267b541 100644
--- a/mojo/public/cpp/bindings/lib/serialization_context.cc
+++ b/mojo/public/cpp/bindings/lib/serialization_context.cc
@@ -25,16 +25,6 @@
     DCHECK_LT(handles_.size(), std::numeric_limits<uint32_t>::max());
     out_data->value = static_cast<uint32_t>(handles_.size());
     handles_.emplace_back(std::move(handle));
-
-    MojoAppendMessageDataHandleOptions options = {0};
-    options.struct_size = sizeof(options);
-    options.flags = share_message_order_for_new_handles_
-                        ? MOJO_APPEND_MESSAGE_DATA_HANDLE_FLAG_SPLICE
-                        : MOJO_APPEND_MESSAGE_DATA_HANDLE_FLAG_NONE;
-    handle_options_.push_back(options);
-
-    if (share_message_order_for_new_handles_)
-      has_handles_with_shared_message_order_ = true;
   }
 }
 
diff --git a/mojo/public/cpp/bindings/lib/serialization_context.h b/mojo/public/cpp/bindings/lib/serialization_context.h
index 7491190a..0e3c0788 100644
--- a/mojo/public/cpp/bindings/lib/serialization_context.h
+++ b/mojo/public/cpp/bindings/lib/serialization_context.h
@@ -29,14 +29,6 @@
   SerializationContext();
   ~SerializationContext();
 
-  void set_share_message_order_for_new_handles(bool share) {
-    share_message_order_for_new_handles_ = share;
-  }
-
-  bool has_handles_with_shared_message_order() const {
-    return has_handles_with_shared_message_order_;
-  }
-
   // Adds a handle to the handle list and outputs its serialized form in
   // |*out_data|.
   void AddHandle(mojo::ScopedHandle handle, Handle_Data* out_data);
@@ -62,11 +54,6 @@
   const std::vector<mojo::ScopedHandle>* handles() { return &handles_; }
   std::vector<mojo::ScopedHandle>* mutable_handles() { return &handles_; }
 
-  const std::vector<MojoAppendMessageDataHandleOptions>* handle_options()
-      const {
-    return &handle_options_;
-  }
-
   const std::vector<ScopedInterfaceEndpointHandle>*
   associated_endpoint_handles() const {
     return &associated_endpoint_handles_;
@@ -94,22 +81,11 @@
       const AssociatedEndpointHandle_Data& encoded_handle);
 
  private:
-  // Whenever this is |true|, newly added interface handles are marked for
-  // splicing into the sendng interface pipe upon message transmission.
-  bool share_message_order_for_new_handles_ = false;
-
-  // Indicates whether any handles were added to this context while
-  // |share_message_order_for_new_handles_| was |true|.
-  bool has_handles_with_shared_message_order_ = false;
-
   // Handles owned by this object. Used during serialization to hold onto
   // handles accumulated during pre-serialization, and used during
   // deserialization to hold onto handles extracted from a message.
   std::vector<mojo::ScopedHandle> handles_;
 
-  // Options for each of the attached handles.
-  std::vector<MojoAppendMessageDataHandleOptions> handle_options_;
-
   // Stashes ScopedInterfaceEndpointHandles encoded in a message by index.
   std::vector<ScopedInterfaceEndpointHandle> associated_endpoint_handles_;
 
diff --git a/mojo/public/cpp/bindings/message.h b/mojo/public/cpp/bindings/message.h
index 7117e70b..791cb53b 100644
--- a/mojo/public/cpp/bindings/message.h
+++ b/mojo/public/cpp/bindings/message.h
@@ -68,16 +68,6 @@
           size_t payload_interface_id_count,
           std::vector<ScopedHandle>* handles);
 
-  // Same as above, but with additional per-handle options to control how
-  // each handle in |handles| is attached.
-  Message(
-      uint32_t name,
-      uint32_t flags,
-      size_t payload_size,
-      size_t payload_interface_id_count,
-      std::vector<ScopedHandle>* handles,
-      const std::vector<MojoAppendMessageDataHandleOptions>* handle_options);
-
   // Constructs a new serialized Message object from an existing
   // ScopedMessageHandle; e.g., one read from a message pipe.
   //
diff --git a/mojo/public/cpp/bindings/tests/BUILD.gn b/mojo/public/cpp/bindings/tests/BUILD.gn
index 1d82337d..a73a8736 100644
--- a/mojo/public/cpp/bindings/tests/BUILD.gn
+++ b/mojo/public/cpp/bindings/tests/BUILD.gn
@@ -37,7 +37,6 @@
     "router_test_util.h",
     "sample_service_unittest.cc",
     "serialization_warning_unittest.cc",
-    "share_message_order_unittest.cc",
     "struct_unittest.cc",
     "sync_handle_registry_unittest.cc",
     "sync_method_unittest.cc",
@@ -53,11 +52,9 @@
     ":mojo_public_bindings_test_utils",
     "//base/test:test_support",
     "//mojo/core/embedder",
-    "//mojo/core/test:test_support",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
     "//mojo/public/cpp/test_support:test_utils",
-    "//mojo/public/interfaces/bindings/tests:cpp_only_test_interfaces",
     "//mojo/public/interfaces/bindings/tests:other_test_interfaces",
     "//mojo/public/interfaces/bindings/tests:test_associated_interfaces",
     "//mojo/public/interfaces/bindings/tests:test_export_component",
diff --git a/mojo/public/cpp/bindings/tests/share_message_order_unittest.cc b/mojo/public/cpp/bindings/tests/share_message_order_unittest.cc
deleted file mode 100644
index 753e036..0000000
--- a/mojo/public/cpp/bindings/tests/share_message_order_unittest.cc
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/macros.h"
-#include "base/optional.h"
-#include "base/run_loop.h"
-#include "base/test/scoped_task_environment.h"
-#include "mojo/core/test/mojo_test_base.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "mojo/public/interfaces/bindings/tests/share_message_order.test-mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace test {
-namespace share_message_order {
-
-using ShareMessageOrderTest = mojo::core::test::MojoTestBase;
-
-class CounterObserverImpl : public mojom::CounterObserver {
- public:
-  CounterObserverImpl() = default;
-  ~CounterObserverImpl() override = default;
-
-  uint32_t counter_value() const { return counter_value_; }
-
-  PendingRemote<mojom::CounterObserver> MakeRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
-  void WaitForNextIncrement() {
-    if (!wait_loop_)
-      wait_loop_.emplace();
-    wait_loop_->Run();
-    wait_loop_.reset();
-  }
-
-  // mojom::CounterObserver:
-  void OnIncrement(uint32_t value) override {
-    counter_value_ = value;
-    if (wait_loop_)
-      wait_loop_->Quit();
-  }
-
- private:
-  uint32_t counter_value_ = 0;
-  Receiver<mojom::CounterObserver> receiver_{this};
-  base::Optional<base::RunLoop> wait_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(CounterObserverImpl);
-};
-
-class CounterImpl : public mojom::Counter, public mojom::Doubler {
- public:
-  explicit CounterImpl(PendingReceiver<mojom::Counter> receiver)
-      : receiver_(this, std::move(receiver)) {
-    receiver_.set_disconnect_handler(wait_for_disconnect_loop_.QuitClosure());
-  }
-
-  ~CounterImpl() override = default;
-
-  void WaitForDisconnect() { wait_for_disconnect_loop_.Run(); }
-
- private:
-  // mojom::Counter:
-  void Increment(IncrementCallback callback) override {
-    ++value_;
-    std::move(callback).Run();
-    for (const auto& observer : observers_)
-      observer->OnIncrement(value_);
-  }
-
-  void AddObserver(PendingRemote<mojom::CounterObserver> observer) override {
-    observers_.emplace_back(std::move(observer));
-  }
-
-  void AddDoubler(PendingReceiver<mojom::Doubler> receiver) override {
-    doubler_receiver_.Bind(std::move(receiver));
-  }
-
-  // mojom::Doubler:
-  void Double() override { value_ *= 2; }
-
-  base::RunLoop wait_for_disconnect_loop_;
-  uint32_t value_ = 0;
-  Receiver<mojom::Counter> receiver_;
-  Receiver<mojom::Doubler> doubler_receiver_{this};
-  std::vector<Remote<mojom::CounterObserver>> observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(CounterImpl);
-};
-
-TEST_F(ShareMessageOrderTest, Ordering) {
-  // Setup two child processes, one for a CounterImpl and one for its client.
-  // They will use additional interfaces with shared message ordering. We use
-  // a multi-process test environment because it introduces sufficient internal
-  // timing variations to exercise our ordering constraints.
-  RunTestClient("CounterImpl", [&](MojoHandle h) {
-    MojoHandle receiver_handle, remote_handle;
-    CreateMessagePipe(&receiver_handle, &remote_handle);
-
-    WriteMessageWithHandles(h, "hi", &receiver_handle, 1);
-    RunTestClient("CounterClient", [&](MojoHandle h) {
-      WriteMessageWithHandles(h, "hi", &remote_handle, 1);
-      EXPECT_EQ("ok", ReadMessage(h));
-      WriteMessage(h, "bye");
-    });
-  });
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CounterImpl, ShareMessageOrderTest, h) {
-  base::test::ScopedTaskEnvironment task_environment;
-
-  MojoHandle receiver_handle;
-  EXPECT_EQ("hi", ReadMessageWithHandles(h, &receiver_handle, 1));
-
-  CounterImpl counter_impl{PendingReceiver<mojom::Counter>(
-      ScopedMessagePipeHandle(MessagePipeHandle(receiver_handle)))};
-  counter_impl.WaitForDisconnect();
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CounterClient, ShareMessageOrderTest, h) {
-  base::test::ScopedTaskEnvironment task_environment;
-
-  MojoHandle remote_handle;
-  EXPECT_EQ("hi", ReadMessageWithHandles(h, &remote_handle, 1));
-
-  Remote<mojom::Counter> counter{PendingRemote<mojom::Counter>(
-      ScopedMessagePipeHandle(MessagePipeHandle(remote_handle)), 0)};
-
-  // By the mojom definition of AddDoubler, the Doubler's own pipe will share
-  // message ordering with the Counter's pipe once this message is sent.
-  Remote<mojom::Doubler> doubler;
-  counter->AddDoubler(doubler.BindNewPipeAndPassReceiver());
-
-  // And the CounterObserver's pipe will share messaging ordering as well,
-  // specifically its received messages will be ordered with replies received
-  // by our Remote<mojom::Counter>.
-  CounterObserverImpl observer;
-  counter->AddObserver(observer.MakeRemote());
-
-  {
-    base::RunLoop loop;
-    counter->Increment(loop.QuitClosure());
-    loop.Run();
-  }
-
-  // The observer should not have dispatched an observed event yet, since it
-  // must arrive after the reply which just terminated our RunLoop.
-  //
-  // If there are ordering violations, this may flakily fail with an unexpected
-  // value of 1.
-  EXPECT_EQ(0u, observer.counter_value());
-  observer.WaitForNextIncrement();
-
-  EXPECT_EQ(1u, observer.counter_value());
-
-  // Also verify ordering of messages on the Doubler.
-
-  {
-    base::RunLoop loop;
-    counter->Increment(base::DoNothing());   // Increment to 2
-    doubler->Double();                       // Double to 4
-    counter->Increment(loop.QuitClosure());  // Increment to 5
-    loop.Run();
-  }
-
-  // Because of strict message ordering constraints, at this point the observer
-  // should have seen the increment to 2 above, but not the increment to 5.
-  //
-  // If there are ordering violations, this may flakily fail with an unexpected
-  // value of 2, 3, or 4.
-  EXPECT_EQ(2u, observer.counter_value());
-
-  observer.WaitForNextIncrement();
-
-  // If there are ordering violations, this may flakily fail with an unexpected
-  // value of 3 or 4.
-  EXPECT_EQ(5u, observer.counter_value());
-
-  WriteMessage(h, "ok");
-  EXPECT_EQ("bye", ReadMessage(h));
-}
-
-class SyncPingImpl : public mojom::SyncPing {
- public:
-  SyncPingImpl(mojo::PendingReceiver<mojom::SyncPing> receiver)
-      : receiver_(this, std::move(receiver)) {}
-  ~SyncPingImpl() override = default;
-
-  // mojom::SyncPing:
-  void PingAsync(PingCallback callback) override { std::move(callback).Run(); }
-  void Ping(PingCallback callback) override { std::move(callback).Run(); }
-
- private:
-  mojo::Receiver<mojom::SyncPing> receiver_;
-
-  DISALLOW_COPY_AND_ASSIGN(SyncPingImpl);
-};
-
-class SyncEchoImpl : public mojom::SyncEcho {
- public:
-  SyncEchoImpl(mojo::PendingReceiver<mojom::SyncEcho> receiver)
-      : receiver_(this, std::move(receiver)) {}
-  ~SyncEchoImpl() override = default;
-
-  // mojom::SyncEcho:
-  void PingThenEcho(mojo::PendingRemote<mojom::SyncPing> remote_ping,
-                    const std::string& x,
-                    PingThenEchoCallback callback) override {
-    mojo::Remote<mojom::SyncPing> ping(std::move(remote_ping));
-
-    base::RunLoop loop;
-    ping->PingAsync(loop.QuitClosure());
-    loop.Run();
-
-    CHECK(ping->Ping());
-
-    std::move(callback).Run(x);
-  }
-
- private:
-  mojo::Receiver<mojom::SyncEcho> receiver_;
-
-  DISALLOW_COPY_AND_ASSIGN(SyncEchoImpl);
-};
-
-TEST_F(ShareMessageOrderTest, NestedSyncCall) {
-  base::test::ScopedTaskEnvironment task_environment;
-
-  mojo::PendingRemote<mojom::SyncPing> ping;
-  SyncPingImpl ping_impl(ping.InitWithNewPipeAndPassReceiver());
-
-  mojo::Remote<mojom::SyncEcho> echo;
-  SyncEchoImpl echo_impl(echo.BindNewPipeAndPassReceiver());
-
-  const std::string kTestString = "ok hello";
-  std::string echoed_string;
-  EXPECT_TRUE(echo->PingThenEcho(std::move(ping), kTestString, &echoed_string));
-  EXPECT_EQ(kTestString, echoed_string);
-}
-
-}  // namespace share_message_order
-}  // namespace test
-}  // namespace mojo
diff --git a/mojo/public/interfaces/bindings/tests/BUILD.gn b/mojo/public/interfaces/bindings/tests/BUILD.gn
index aa238a6..a5efd42 100644
--- a/mojo/public/interfaces/bindings/tests/BUILD.gn
+++ b/mojo/public/interfaces/bindings/tests/BUILD.gn
@@ -493,14 +493,6 @@
   ]
 }
 
-mojom("cpp_only_test_interfaces") {
-  testonly = true
-  cpp_only = true
-  sources = [
-    "share_message_order.test-mojom",
-  ]
-}
-
 # Ensure that some target forces JS and Java bindings generation when all
 # targets are built. This provides a basic generation smoke test for new
 # endpoint types in mojom.
diff --git a/mojo/public/interfaces/bindings/tests/share_message_order.test-mojom b/mojo/public/interfaces/bindings/tests/share_message_order.test-mojom
deleted file mode 100644
index 5807e32..0000000
--- a/mojo/public/interfaces/bindings/tests/share_message_order.test-mojom
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mojo.test.share_message_order.mojom;
-
-interface CounterObserver {
-  // Called every time the associated Counter has its value incremented.
-  OnIncrement(uint32 value);
-};
-
-interface Doubler {
-  // Requests that the Doubler's associated Counter double its current count.
-  Double();
-};
-
-interface Counter {
-  Increment() => ();
-
-  // Adds an observer which will be notified after every invocation of
-  // |Increment()|. Observers are always notified *after* the Increment response
-  // is sent.
-  AddObserver([ShareMessageOrder] pending_remote<CounterObserver> observer);
-
-  // Gets an interface which can be used to double the current count retained by
-  // this Counter.
-  AddDoubler([ShareMessageOrder] pending_receiver<Doubler> receiver);
-};
-
-interface SyncPing {
-  PingAsync() => ();
-  [Sync] Ping() => ();
-};
-
-interface SyncEcho {
-  [Sync] PingThenEcho([ShareMessageOrder] pending_remote<SyncPing> ping,
-                      string x)
-             => (string x);
-};
-
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
index e0bd720..7c6b9cd 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
@@ -25,10 +25,6 @@
 {%-   set kind = pf.field.kind %}
 {%-   set serializer_type = kind|unmapped_type_for_serializer %}
 
-{%-   if pf.field|share_message_order %}
-      ({{context}})->set_share_message_order_for_new_handles(true);
-{%-   endif %}
-
 {%-   if kind|is_object_kind or kind|is_any_handle_or_interface_kind %}
 {%-     set original_input_field = input_field_pattern|format(name) %}
 {%-     set input_field = "in_%s"|format(name) if input_may_be_temp
@@ -90,11 +86,6 @@
 {%-   else %}
   {{writer}}->{{name}} = {{input_field}};
 {%-   endif %}
-
-{%-   if pf.field|share_message_order %}
-      ({{context}})->set_share_message_order_for_new_handles(false);
-{%-   endif %}
-
 {%- endfor %}
 {%- endmacro -%}
 
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index 1d1fbe5..b8070e6 100644
--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -368,7 +368,6 @@
       "is_typemapped_kind": self._IsTypemappedKind,
       "is_union_kind": mojom.IsUnionKind,
       "passes_associated_kinds": mojom.PassesAssociatedKinds,
-      "share_message_order": mojom.FieldOrParamSharesMessageOrder,
       "struct_constructors": self._GetStructConstructors,
       "under_to_camel": generator.ToCamel,
       "unmapped_type_for_serializer": self._GetUnmappedTypeForSerializer,
@@ -751,8 +750,7 @@
 
     # TODO(crbug.com/753433): Support lazy serialization for methods which pass
     # associated handles.
-    if mojom.MethodPassesAssociatedKinds(method) or \
-       mojom.MethodParametersShareMessageOrder(method):
+    if mojom.MethodPassesAssociatedKinds(method):
       return False
 
     return not any(self._KindMustBeSerialized(param.kind) for param in
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
index b1201f97..18a4101 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/module.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
@@ -221,7 +221,6 @@
 ATTRIBUTE_MIN_VERSION = 'MinVersion'
 ATTRIBUTE_EXTENSIBLE = 'Extensible'
 ATTRIBUTE_SYNC = 'Sync'
-ATTRIBUTE_SHARE_MESSAGE_ORDER = 'ShareMessageOrder'
 
 
 class NamedValue(object):
@@ -302,11 +301,6 @@
     return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
         if self.attributes else None
 
-  @property
-  def share_message_order(self):
-    return self.attributes.get(ATTRIBUTE_SHARE_MESSAGE_ORDER, False) \
-        if self.attributes else False
-
 
 class StructField(Field): pass
 
@@ -571,11 +565,6 @@
     return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
         if self.attributes else None
 
-  @property
-  def share_message_order(self):
-    return self.attributes.get(ATTRIBUTE_SHARE_MESSAGE_ORDER, False) \
-        if self.attributes else False
-
 
 class Method(object):
   def __init__(self, interface, mojom_name, ordinal=None, attributes=None):
@@ -874,11 +863,6 @@
 def IsAssociatedInterfaceRequestKind(kind):
   return isinstance(kind, AssociatedInterfaceRequest)
 
-
-def FieldOrParamSharesMessageOrder(field_or_param):
-  return field_or_param.share_message_order
-
-
 def IsPendingRemoteKind(kind):
   return isinstance(kind, PendingRemote)
 
@@ -953,7 +937,7 @@
   return False
 
 
-def _AnyParameterKindRecursive(method, predicate, visited_kinds=None):
+def _AnyMethodParameterRecursive(method, predicate, visited_kinds=None):
   def _HasProperty(kind):
     if kind in visited_kinds:
       # No need to examine the kind again.
@@ -985,53 +969,16 @@
   return False
 
 
-def _AnyFieldRecursive(fields_or_params, predicate, visited_kinds=None):
-  if not fields_or_params:
-    return False
-
-  def _HasProperty(kind):
-    if kind in visited_kinds:
-      return False
-    if IsStructKind(kind) or IsUnionKind(kind):
-      visited_kinds.add(kind)
-      return _AnyFieldRecursive(kind.fields, predicate, visited_kinds)
-    if IsArrayKind(kind):
-      return _HasProperty(kind.kind)
-    if IsMapKind(kind):
-      if _HasProperty(kind.key_kind) or _HasProperty(kind.value_kind):
-        return True
-    return False
-
-  if visited_kinds is None:
-    visited_kinds = set()
-
-  for field_or_param in fields_or_params:
-    if predicate(field_or_param):
-      return True
-    if _HasProperty(field_or_param.kind):
-      return True
-
-  return False
-
-
 # Finds out whether a method passes associated interfaces and associated
 # interface requests.
 def MethodPassesAssociatedKinds(method, visited_kinds=None):
-  return _AnyParameterKindRecursive(method, IsAssociatedKind,
+  return _AnyMethodParameterRecursive(method, IsAssociatedKind,
                                       visited_kinds=visited_kinds)
 
 
 # Determines whether a method passes interfaces.
 def MethodPassesInterfaces(method):
-  return _AnyParameterKindRecursive(method, IsInterfaceKind)
-
-
-def MethodParametersShareMessageOrder(method, visited_kinds=None):
-  return _AnyFieldRecursive(method.parameters, FieldOrParamSharesMessageOrder,
-                            visited_kinds=visited_kinds) or \
-         _AnyFieldRecursive(method.response_parameters,
-                            FieldOrParamSharesMessageOrder,
-                            visited_kinds=visited_kinds)
+  return _AnyMethodParameterRecursive(method, IsInterfaceKind)
 
 
 def HasSyncMethods(interface):
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn
index d6fb54bd..a3bdb220 100644
--- a/net/dns/BUILD.gn
+++ b/net/dns/BUILD.gn
@@ -75,10 +75,24 @@
       "serial_worker.h",
     ]
 
-    if (is_posix || is_fuchsia) {
-      sources += [ "dns_config_service_posix.cc" ]
+    if (is_fuchsia) {
+      sources += [
+        "dns_config_service_fuchsia.cc",
+        "dns_config_service_fuchsia.h",
+      ]
+    }
 
-      if (enable_built_in_dns) {
+    if (is_posix) {
+      sources += [
+        "dns_config_service_posix.cc",
+        "dns_config_service_posix.h",
+      ]
+    }
+
+    if (enable_built_in_dns) {
+      sources += [ "dns_client.cc" ]
+
+      if (is_posix || is_fuchsia) {
         sources += [
           "address_sorter_posix.cc",
           "address_sorter_posix.h",
@@ -86,10 +100,6 @@
       }
     }
 
-    if (enable_built_in_dns) {
-      sources += [ "dns_client.cc" ]
-    }
-
     if (enable_mdns) {
       sources += [
         "mdns_cache.cc",
@@ -374,7 +384,7 @@
     "serial_worker_unittest.cc",
   ]
 
-  if (is_posix || is_fuchsia) {
+  if (is_posix) {
     sources += [ "dns_config_service_posix_unittest.cc" ]
   }
 
diff --git a/net/dns/dns_config_service_fuchsia.cc b/net/dns/dns_config_service_fuchsia.cc
new file mode 100644
index 0000000..d4fca47
--- /dev/null
+++ b/net/dns/dns_config_service_fuchsia.cc
@@ -0,0 +1,36 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/dns/dns_config_service_fuchsia.h"
+
+#include <memory>
+
+#include "net/dns/dns_config.h"
+#include "net/dns/dns_hosts.h"
+
+namespace net {
+namespace internal {
+
+DnsConfigServiceFuchsia::DnsConfigServiceFuchsia() = default;
+DnsConfigServiceFuchsia::~DnsConfigServiceFuchsia() = default;
+
+void DnsConfigServiceFuchsia::ReadNow() {
+  // TODO(crbug.com/950717): Implement this method.
+  OnConfigRead(DnsConfig());
+  OnHostsRead(DnsHosts());
+}
+
+bool DnsConfigServiceFuchsia::StartWatching() {
+  // TODO(crbug.com/950717): Implement this method.
+  return false;
+}
+
+}  // namespace internal
+
+// static
+std::unique_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
+  return std::make_unique<internal::DnsConfigServiceFuchsia>();
+}
+
+}  // namespace net
\ No newline at end of file
diff --git a/net/dns/dns_config_service_fuchsia.h b/net/dns/dns_config_service_fuchsia.h
new file mode 100644
index 0000000..79488e66
--- /dev/null
+++ b/net/dns/dns_config_service_fuchsia.h
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_DNS_DNS_CONFIG_SERVICE_FUCHSIA_H_
+#define NET_DNS_DNS_CONFIG_SERVICE_FUCHSIA_H_
+
+#include "base/macros.h"
+#include "net/dns/dns_config_service.h"
+
+namespace net {
+namespace internal {
+
+// DnsConfigService implementation for Fuchsia. Currently is a stub that returns
+// an empty config (which means DNS resolver always falls back to
+// getaddrinfo()).
+class NET_EXPORT_PRIVATE DnsConfigServiceFuchsia : public DnsConfigService {
+ public:
+  DnsConfigServiceFuchsia();
+  ~DnsConfigServiceFuchsia() override;
+
+ protected:
+  // DnsConfigService overrides.
+  void ReadNow() override;
+  bool StartWatching() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DnsConfigServiceFuchsia);
+};
+
+}  // namespace internal
+}  // namespace net
+
+#endif  // NET_DNS_DNS_CONFIG_SERVICE_FUCHSIA_H_
diff --git a/net/ssl/client_cert_identity.cc b/net/ssl/client_cert_identity.cc
index 19878813..fcb9f13 100644
--- a/net/ssl/client_cert_identity.cc
+++ b/net/ssl/client_cert_identity.cc
@@ -4,6 +4,8 @@
 
 #include "net/ssl/client_cert_identity.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "net/cert/x509_util.h"
 #include "net/ssl/ssl_private_key.h"
@@ -14,10 +16,9 @@
 
 void IdentityOwningPrivateKeyCallback(
     std::unique_ptr<ClientCertIdentity> identity,
-    const base::Callback<void(scoped_refptr<SSLPrivateKey>)>&
-        private_key_callback,
+    base::OnceCallback<void(scoped_refptr<SSLPrivateKey>)> private_key_callback,
     scoped_refptr<SSLPrivateKey> private_key) {
-  private_key_callback.Run(std::move(private_key));
+  std::move(private_key_callback).Run(std::move(private_key));
 }
 
 }  // namespace
@@ -29,13 +30,13 @@
 // static
 void ClientCertIdentity::SelfOwningAcquirePrivateKey(
     std::unique_ptr<ClientCertIdentity> self,
-    const base::Callback<void(scoped_refptr<SSLPrivateKey>)>&
+    base::OnceCallback<void(scoped_refptr<SSLPrivateKey>)>
         private_key_callback) {
   ClientCertIdentity* self_ptr = self.get();
   auto wrapped_private_key_callback =
-      base::Bind(&IdentityOwningPrivateKeyCallback, base::Passed(&self),
-                 private_key_callback);
-  self_ptr->AcquirePrivateKey(wrapped_private_key_callback);
+      base::BindOnce(&IdentityOwningPrivateKeyCallback, std::move(self),
+                     std::move(private_key_callback));
+  self_ptr->AcquirePrivateKey(std::move(wrapped_private_key_callback));
 }
 
 void ClientCertIdentity::SetIntermediates(
diff --git a/net/ssl/client_cert_identity.h b/net/ssl/client_cert_identity.h
index 6848217..155786f9 100644
--- a/net/ssl/client_cert_identity.h
+++ b/net/ssl/client_cert_identity.h
@@ -36,7 +36,7 @@
   // run synchronously or asynchronously.  The caller is responsible for
   // keeping the ClientCertIdentity alive until the callback is run.
   virtual void AcquirePrivateKey(
-      const base::Callback<void(scoped_refptr<SSLPrivateKey>)>&
+      base::OnceCallback<void(scoped_refptr<SSLPrivateKey>)>
           private_key_callback) = 0;
 
 #if defined(OS_MACOSX)
@@ -49,7 +49,7 @@
   // are the same as for AcquirePrivateKey above.
   static void SelfOwningAcquirePrivateKey(
       std::unique_ptr<ClientCertIdentity> identity,
-      const base::Callback<void(scoped_refptr<SSLPrivateKey>)>&
+      base::OnceCallback<void(scoped_refptr<SSLPrivateKey>)>
           private_key_callback);
 
   // Sets the intermediates of |certificate()| to |intermediates|. Note that
diff --git a/net/ssl/client_cert_identity_mac.cc b/net/ssl/client_cert_identity_mac.cc
index 34c27156..c9f62fa 100644
--- a/net/ssl/client_cert_identity_mac.cc
+++ b/net/ssl/client_cert_identity_mac.cc
@@ -17,12 +17,12 @@
 ClientCertIdentityMac::~ClientCertIdentityMac() = default;
 
 void ClientCertIdentityMac::AcquirePrivateKey(
-    const base::Callback<void(scoped_refptr<SSLPrivateKey>)>&
+    base::OnceCallback<void(scoped_refptr<SSLPrivateKey>)>
         private_key_callback) {
   // This only adds a ref to and returns the private key from identity_ so it
   // doesn't need to run on a worker thread.
-  private_key_callback.Run(
-      CreateSSLPrivateKeyForSecIdentity(certificate(), identity_.get()));
+  std::move(private_key_callback)
+      .Run(CreateSSLPrivateKeyForSecIdentity(certificate(), identity_.get()));
 }
 
 SecIdentityRef ClientCertIdentityMac::sec_identity_ref() const {
diff --git a/net/ssl/client_cert_identity_mac.h b/net/ssl/client_cert_identity_mac.h
index 8ae543f..0fbbb05 100644
--- a/net/ssl/client_cert_identity_mac.h
+++ b/net/ssl/client_cert_identity_mac.h
@@ -20,9 +20,8 @@
                         base::ScopedCFTypeRef<SecIdentityRef> sec_identity);
   ~ClientCertIdentityMac() override;
 
-  void AcquirePrivateKey(
-      const base::Callback<void(scoped_refptr<SSLPrivateKey>)>&
-          private_key_callback) override;
+  void AcquirePrivateKey(base::OnceCallback<void(scoped_refptr<SSLPrivateKey>)>
+                             private_key_callback) override;
   SecIdentityRef sec_identity_ref() const override;
 
  private:
diff --git a/net/ssl/client_cert_identity_test_util.cc b/net/ssl/client_cert_identity_test_util.cc
index d1cb669..32209b6 100644
--- a/net/ssl/client_cert_identity_test_util.cc
+++ b/net/ssl/client_cert_identity_test_util.cc
@@ -5,6 +5,7 @@
 #include "net/ssl/client_cert_identity_test_util.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -71,9 +72,9 @@
 }
 
 void FakeClientCertIdentity::AcquirePrivateKey(
-    const base::Callback<void(scoped_refptr<SSLPrivateKey>)>&
+    base::OnceCallback<void(scoped_refptr<SSLPrivateKey>)>
         private_key_callback) {
-  private_key_callback.Run(key_);
+  std::move(private_key_callback).Run(key_);
 }
 
 #if defined(OS_MACOSX)
diff --git a/net/ssl/client_cert_identity_test_util.h b/net/ssl/client_cert_identity_test_util.h
index 85049e1a..b7e5dfef 100644
--- a/net/ssl/client_cert_identity_test_util.h
+++ b/net/ssl/client_cert_identity_test_util.h
@@ -42,9 +42,8 @@
   SSLPrivateKey* ssl_private_key() const { return key_.get(); }
 
   // ClientCertIdentity implementation:
-  void AcquirePrivateKey(
-      const base::Callback<void(scoped_refptr<SSLPrivateKey>)>&
-          private_key_callback) override;
+  void AcquirePrivateKey(base::OnceCallback<void(scoped_refptr<SSLPrivateKey>)>
+                             private_key_callback) override;
 #if defined(OS_MACOSX)
   SecIdentityRef sec_identity_ref() const override;
 #endif
diff --git a/net/ssl/client_cert_store.h b/net/ssl/client_cert_store.h
index cbe7eed..b0c1c65 100644
--- a/net/ssl/client_cert_store.h
+++ b/net/ssl/client_cert_store.h
@@ -23,14 +23,15 @@
  public:
   virtual ~ClientCertStore() {}
 
-  using ClientCertListCallback = base::Callback<void(ClientCertIdentityList)>;
+  using ClientCertListCallback =
+      base::OnceCallback<void(ClientCertIdentityList)>;
 
   // Get client certs matching the |cert_request_info| and pass them to the
   // |callback|.  The |callback| may be called sychronously. The caller must
   // ensure the ClientCertStore and |cert_request_info| remain alive until the
   // callback has been run.
   virtual void GetClientCerts(const SSLCertRequestInfo& cert_request_info,
-                              const ClientCertListCallback& callback) = 0;
+                              ClientCertListCallback callback) = 0;
 
  protected:
   ClientCertStore() {}
diff --git a/net/ssl/client_cert_store_mac.cc b/net/ssl/client_cert_store_mac.cc
index a64f448..fc448f4 100644
--- a/net/ssl/client_cert_store_mac.cc
+++ b/net/ssl/client_cert_store_mac.cc
@@ -394,20 +394,14 @@
 
 ClientCertStoreMac::~ClientCertStoreMac() {}
 
-void ClientCertStoreMac::GetClientCerts(
-    const SSLCertRequestInfo& request,
-    const ClientCertListCallback& callback) {
-  if (base::PostTaskAndReplyWithResult(
-          GetSSLPlatformKeyTaskRunner().get(), FROM_HERE,
-          // Caller is responsible for keeping the |request| alive
-          // until the callback is run, so std::cref is safe.
-          base::Bind(&GetClientCertsOnBackgroundThread, std::cref(request)),
-          callback)) {
-    return;
-  }
-
-  // If the task could not be posted, behave as if there were no certificates.
-  callback.Run(ClientCertIdentityList());
+void ClientCertStoreMac::GetClientCerts(const SSLCertRequestInfo& request,
+                                        ClientCertListCallback callback) {
+  base::PostTaskAndReplyWithResult(
+      GetSSLPlatformKeyTaskRunner().get(), FROM_HERE,
+      // Caller is responsible for keeping the |request| alive
+      // until the callback is run, so std::cref is safe.
+      base::BindOnce(&GetClientCertsOnBackgroundThread, std::cref(request)),
+      std::move(callback));
 }
 
 bool ClientCertStoreMac::SelectClientCertsForTesting(
diff --git a/net/ssl/client_cert_store_mac.h b/net/ssl/client_cert_store_mac.h
index cc06ec60..7dc3b4c 100644
--- a/net/ssl/client_cert_store_mac.h
+++ b/net/ssl/client_cert_store_mac.h
@@ -20,7 +20,7 @@
 
   // ClientCertStore:
   void GetClientCerts(const SSLCertRequestInfo& cert_request_info,
-                      const ClientCertListCallback& callback) override;
+                      ClientCertListCallback callback) override;
 
  private:
   friend class ClientCertStoreMacTest;
diff --git a/net/ssl/client_cert_store_nss.cc b/net/ssl/client_cert_store_nss.cc
index 0265a20a..6bb552a 100644
--- a/net/ssl/client_cert_store_nss.cc
+++ b/net/ssl/client_cert_store_nss.cc
@@ -45,17 +45,17 @@
         password_delegate_(std::move(password_delegate)) {}
   ~ClientCertIdentityNSS() override = default;
 
-  void AcquirePrivateKey(
-      const base::Callback<void(scoped_refptr<SSLPrivateKey>)>&
-          private_key_callback) override {
+  void AcquirePrivateKey(base::OnceCallback<void(scoped_refptr<SSLPrivateKey>)>
+                             private_key_callback) override {
     // Caller is responsible for keeping the ClientCertIdentity alive until
     // the |private_key_callback| is run, so it's safe to use Unretained here.
     base::PostTaskWithTraitsAndReplyWithResult(
         FROM_HERE,
         {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-        base::Bind(&FetchClientCertPrivateKey, base::Unretained(certificate()),
-                   cert_certificate_.get(), password_delegate_),
-        private_key_callback);
+        base::BindOnce(&FetchClientCertPrivateKey,
+                       base::Unretained(certificate()), cert_certificate_.get(),
+                       password_delegate_),
+        std::move(private_key_callback));
   }
 
  private:
@@ -72,21 +72,20 @@
 
 ClientCertStoreNSS::~ClientCertStoreNSS() = default;
 
-void ClientCertStoreNSS::GetClientCerts(
-    const SSLCertRequestInfo& request,
-    const ClientCertListCallback& callback) {
+void ClientCertStoreNSS::GetClientCerts(const SSLCertRequestInfo& request,
+                                        ClientCertListCallback callback) {
   scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate;
   if (!password_delegate_factory_.is_null())
     password_delegate = password_delegate_factory_.Run(request.host_and_port);
   base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE,
       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::Bind(&ClientCertStoreNSS::GetAndFilterCertsOnWorkerThread,
-                 // Caller is responsible for keeping the ClientCertStore
-                 // alive until the callback is run.
-                 base::Unretained(this), std::move(password_delegate),
-                 base::Unretained(&request)),
-      callback);
+      base::BindOnce(&ClientCertStoreNSS::GetAndFilterCertsOnWorkerThread,
+                     // Caller is responsible for keeping the ClientCertStore
+                     // alive until the callback is run.
+                     base::Unretained(this), std::move(password_delegate),
+                     base::Unretained(&request)),
+      std::move(callback));
 }
 
 // static
diff --git a/net/ssl/client_cert_store_nss.h b/net/ssl/client_cert_store_nss.h
index 465569ec..95313553 100644
--- a/net/ssl/client_cert_store_nss.h
+++ b/net/ssl/client_cert_store_nss.h
@@ -23,8 +23,9 @@
 
 class NET_EXPORT ClientCertStoreNSS : public ClientCertStore {
  public:
-  typedef base::Callback<crypto::CryptoModuleBlockingPasswordDelegate*(
-      const HostPortPair& /* server */)> PasswordDelegateFactory;
+  typedef base::RepeatingCallback<crypto::CryptoModuleBlockingPasswordDelegate*(
+      const HostPortPair& /* server */)>
+      PasswordDelegateFactory;
 
   using CertFilter = base::RepeatingCallback<bool(CERTCertificate*)>;
 
@@ -34,7 +35,7 @@
 
   // ClientCertStore:
   void GetClientCerts(const SSLCertRequestInfo& cert_request_info,
-                      const ClientCertListCallback& callback) override;
+                      ClientCertListCallback callback) override;
 
   // Examines the certificates in |identities| to find all certificates that
   // match the client certificate request in |request|, removing any that don't.
diff --git a/net/ssl/client_cert_store_nss_unittest.cc b/net/ssl/client_cert_store_nss_unittest.cc
index ded63b21..c6c7f29 100644
--- a/net/ssl/client_cert_store_nss_unittest.cc
+++ b/net/ssl/client_cert_store_nss_unittest.cc
@@ -122,8 +122,8 @@
     scoped_refptr<SSLPrivateKey> ssl_private_key;
     base::RunLoop key_loop;
     selected_identities[0]->AcquirePrivateKey(
-        base::Bind(SavePrivateKeyAndQuitCallback, &ssl_private_key,
-                   key_loop.QuitClosure()));
+        base::BindOnce(SavePrivateKeyAndQuitCallback, &ssl_private_key,
+                       key_loop.QuitClosure()));
     key_loop.Run();
 
     ASSERT_TRUE(ssl_private_key);
@@ -159,8 +159,8 @@
     scoped_refptr<SSLPrivateKey> ssl_private_key;
     base::RunLoop key_loop;
     selected_identities[0]->AcquirePrivateKey(
-        base::Bind(SavePrivateKeyAndQuitCallback, &ssl_private_key,
-                   key_loop.QuitClosure()));
+        base::BindOnce(SavePrivateKeyAndQuitCallback, &ssl_private_key,
+                       key_loop.QuitClosure()));
     key_loop.Run();
     ASSERT_TRUE(ssl_private_key);
     EXPECT_EQ(expected, ssl_private_key->GetAlgorithmPreferences());
@@ -232,7 +232,7 @@
 
   scoped_refptr<SSLPrivateKey> ssl_private_key;
   base::RunLoop key_loop;
-  selected_identities[0]->AcquirePrivateKey(base::Bind(
+  selected_identities[0]->AcquirePrivateKey(base::BindOnce(
       SavePrivateKeyAndQuitCallback, &ssl_private_key, key_loop.QuitClosure()));
   key_loop.Run();
 
diff --git a/net/ssl/client_cert_store_win.cc b/net/ssl/client_cert_store_win.cc
index fed21b8f..8621dbc 100644
--- a/net/ssl/client_cert_store_win.cc
+++ b/net/ssl/client_cert_store_win.cc
@@ -16,6 +16,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/single_thread_task_runner.h"
@@ -35,34 +36,25 @@
 
 class ClientCertIdentityWin : public ClientCertIdentity {
  public:
-  // Takes ownership of |cert_context|.
   ClientCertIdentityWin(
       scoped_refptr<net::X509Certificate> cert,
-      PCCERT_CONTEXT cert_context,
+      ScopedPCCERT_CONTEXT cert_context,
       scoped_refptr<base::SingleThreadTaskRunner> key_task_runner)
       : ClientCertIdentity(std::move(cert)),
-        cert_context_(cert_context),
-        key_task_runner_(key_task_runner) {}
-  ~ClientCertIdentityWin() override {
-    CertFreeCertificateContext(cert_context_);
-  }
+        cert_context_(std::move(cert_context)),
+        key_task_runner_(std::move(key_task_runner)) {}
 
-  void AcquirePrivateKey(
-      const base::Callback<void(scoped_refptr<SSLPrivateKey>)>&
-          private_key_callback) override {
-    if (base::PostTaskAndReplyWithResult(
-            key_task_runner_.get(), FROM_HERE,
-            base::Bind(&FetchClientCertPrivateKey,
-                       base::Unretained(certificate()), cert_context_),
-            private_key_callback)) {
-      return;
-    }
-    // If the task could not be posted, behave as if there was no key.
-    private_key_callback.Run(nullptr);
+  void AcquirePrivateKey(base::OnceCallback<void(scoped_refptr<SSLPrivateKey>)>
+                             private_key_callback) override {
+    base::PostTaskAndReplyWithResult(
+        key_task_runner_.get(), FROM_HERE,
+        base::BindOnce(&FetchClientCertPrivateKey,
+                       base::Unretained(certificate()), cert_context_.get()),
+        std::move(private_key_callback));
   }
 
  private:
-  PCCERT_CONTEXT cert_context_;
+  ScopedPCCERT_CONTEXT cert_context_;
   scoped_refptr<base::SingleThreadTaskRunner> key_task_runner_;
 };
 
@@ -155,15 +147,18 @@
     PCCERT_CONTEXT cert_context =
         chain_context->rgpChain[0]->rgpElement[0]->pCertContext;
     // Copy the certificate, so that it is valid after |cert_store| is closed.
-    PCCERT_CONTEXT cert_context2 = nullptr;
+    ScopedPCCERT_CONTEXT cert_context2;
+    PCCERT_CONTEXT raw = nullptr;
     BOOL ok = CertAddCertificateContextToStore(
-        nullptr, cert_context, CERT_STORE_ADD_USE_EXISTING, &cert_context2);
+        nullptr, cert_context, CERT_STORE_ADD_USE_EXISTING, &raw);
     if (!ok) {
       NOTREACHED();
       continue;
     }
+    cert_context2.reset(raw);
 
     // Grab the intermediates, if any.
+    std::vector<ScopedPCCERT_CONTEXT> intermediates_storage;
     std::vector<PCCERT_CONTEXT> intermediates;
     for (DWORD i = 1; i < chain_context->rgpChain[0]->cElement; ++i) {
       PCCERT_CONTEXT chain_intermediate =
@@ -172,8 +167,10 @@
       ok = CertAddCertificateContextToStore(nullptr, chain_intermediate,
                                             CERT_STORE_ADD_USE_EXISTING,
                                             &copied_intermediate);
-      if (ok)
+      if (ok) {
         intermediates.push_back(copied_intermediate);
+        intermediates_storage.emplace_back(copied_intermediate);
+      }
     }
 
     // Drop the self-signed root, if any. Match Internet Explorer in not sending
@@ -185,8 +182,8 @@
     // in that case, assume it is a configuration error.
     if (!intermediates.empty() &&
         x509_util::IsSelfSigned(intermediates.back())) {
-      CertFreeCertificateContext(intermediates.back());
       intermediates.pop_back();
+      intermediates_storage.pop_back();
     }
 
     // Allow UTF-8 inside PrintableStrings in client certificates. See
@@ -195,16 +192,14 @@
     options.printable_string_is_utf8 = true;
     scoped_refptr<X509Certificate> cert =
         x509_util::CreateX509CertificateFromCertContexts(
-            cert_context2, intermediates, options);
+            cert_context2.get(), intermediates, options);
     if (cert) {
       selected_identities.push_back(std::make_unique<ClientCertIdentityWin>(
           std::move(cert),
-          cert_context2,     // Takes ownership of |cert_context2|.
+          std::move(cert_context2),  // Takes ownership of |cert_context2|.
           current_thread));  // The key must be acquired on the same thread, as
                              // the PCCERT_CONTEXT may not be thread safe.
     }
-    for (size_t i = 0; i < intermediates.size(); ++i)
-      CertFreeCertificateContext(intermediates[i]);
   }
 
   std::sort(selected_identities.begin(), selected_identities.end(),
@@ -223,31 +218,25 @@
 
 ClientCertStoreWin::~ClientCertStoreWin() {}
 
-void ClientCertStoreWin::GetClientCerts(
-    const SSLCertRequestInfo& request,
-    const ClientCertListCallback& callback) {
+void ClientCertStoreWin::GetClientCerts(const SSLCertRequestInfo& request,
+                                        ClientCertListCallback callback) {
   if (cert_store_) {
     // Use the existing client cert store. Note: Under some situations,
     // it's possible for this to return certificates that aren't usable
     // (see below).
     // When using caller provided HCERTSTORE, assume that it should be accessed
     // on the current thread.
-    callback.Run(GetClientCertsImpl(cert_store_, request));
+    std::move(callback).Run(GetClientCertsImpl(cert_store_, request));
     return;
   }
 
-  if (base::PostTaskAndReplyWithResult(
-          GetSSLPlatformKeyTaskRunner().get(), FROM_HERE,
-          // Caller is responsible for keeping the |request| alive
-          // until the callback is run, so std::cref is safe.
-          base::Bind(&ClientCertStoreWin::GetClientCertsWithMyCertStore,
+  base::PostTaskAndReplyWithResult(
+      GetSSLPlatformKeyTaskRunner().get(), FROM_HERE,
+      // Caller is responsible for keeping the |request| alive
+      // until the callback is run, so std::cref is safe.
+      base::BindOnce(&ClientCertStoreWin::GetClientCertsWithMyCertStore,
                      std::cref(request)),
-          callback)) {
-    return;
-  }
-
-  // If the task could not be posted, behave as if there were no certificates.
-  callback.Run(ClientCertIdentityList());
+      std::move(callback));
 }
 
 // static
diff --git a/net/ssl/client_cert_store_win.h b/net/ssl/client_cert_store_win.h
index 4db6d475..184ed6b 100644
--- a/net/ssl/client_cert_store_win.h
+++ b/net/ssl/client_cert_store_win.h
@@ -28,7 +28,7 @@
   // will use that. Otherwise it will use the current user's "MY" cert store
   // instead.
   void GetClientCerts(const SSLCertRequestInfo& cert_request_info,
-                      const ClientCertListCallback& callback) override;
+                      ClientCertListCallback callback) override;
 
  private:
   using ScopedHCERTSTORE = crypto::ScopedCAPIHandle<
diff --git a/net/tools/cert_verify_tool/cert_verify_tool.cc b/net/tools/cert_verify_tool/cert_verify_tool.cc
index 5129002..57c200c 100644
--- a/net/tools/cert_verify_tool/cert_verify_tool.cc
+++ b/net/tools/cert_verify_tool/cert_verify_tool.cc
@@ -284,7 +284,7 @@
   base::FilePath target_path = base::FilePath(args[0]);
 
   base::FilePath crlset_path = command_line.GetSwitchValuePath("crlset");
-  scoped_refptr<net::CRLSet> crl_set;
+  scoped_refptr<net::CRLSet> crl_set = net::CRLSet::BuiltinCRLSet();
   if (!crlset_path.empty()) {
     std::string crl_set_bytes;
     if (!ReadFromFile(crlset_path, &crl_set_bytes))
diff --git a/remoting/host/token_validator_base.cc b/remoting/host/token_validator_base.cc
index d78637ea..041f7fb 100644
--- a/remoting/host/token_validator_base.cc
+++ b/remoting/host/token_validator_base.cc
@@ -219,8 +219,9 @@
   // give it a WeakPtr for |this|, and ownership of the other parameters.
   client_cert_store->GetClientCerts(
       *cert_request_info,
-      base::Bind(&TokenValidatorBase::OnCertificatesSelected,
-                 weak_factory_.GetWeakPtr(), base::Owned(client_cert_store)));
+      base::BindOnce(&TokenValidatorBase::OnCertificatesSelected,
+                     weak_factory_.GetWeakPtr(),
+                     base::Owned(client_cert_store)));
 }
 
 void TokenValidatorBase::OnCertificatesSelected(
@@ -246,8 +247,8 @@
         (*best_match_position)->certificate();
     net::ClientCertIdentity::SelfOwningAcquirePrivateKey(
         std::move(*best_match_position),
-        base::Bind(&TokenValidatorBase::ContinueWithCertificate,
-                   weak_factory_.GetWeakPtr(), std::move(cert)));
+        base::BindOnce(&TokenValidatorBase::ContinueWithCertificate,
+                       weak_factory_.GetWeakPtr(), std::move(cert)));
   }
 }
 
diff --git a/services/device/geolocation/OWNERS b/services/device/geolocation/OWNERS
index 2596b2d..2ce1e4a 100644
--- a/services/device/geolocation/OWNERS
+++ b/services/device/geolocation/OWNERS
@@ -1,8 +1,6 @@
 mattreynolds@chromium.org
-
-# Original (legacy) owners.
 mcasas@chromium.org
 timvolodine@chromium.org
 
-# COMPONENT: Blink>Geolocation
 # TEAM: device-dev@chromium.org
+# COMPONENT: Blink>Location
diff --git a/services/shape_detection/OWNERS b/services/shape_detection/OWNERS
index 7a97495..0e57d5f 100644
--- a/services/shape_detection/OWNERS
+++ b/services/shape_detection/OWNERS
@@ -1,7 +1,5 @@
-reillyg@chromium.org
-
-# Original (legacy) owner.
-mcasas@chromium.org
-
 # COMPONENT: Blink>ImageCapture
-# TEAM: device-dev@chromium.org
+# TEAM: media-dev@chromium.org
+
+mcasas@chromium.org
+reillyg@chromium.org
diff --git a/services/tracing/public/cpp/perfetto/perfetto_config.cc b/services/tracing/public/cpp/perfetto/perfetto_config.cc
index 2d73c53..b21ba02a 100644
--- a/services/tracing/public/cpp/perfetto/perfetto_config.cc
+++ b/services/tracing/public/cpp/perfetto/perfetto_config.cc
@@ -76,6 +76,9 @@
       perfetto_config.add_data_sources()->mutable_config();
   trace_metadata_config->set_name(tracing::mojom::kMetaDataSourceName);
   trace_metadata_config->set_target_buffer(0);
+  auto* metadata_chrome_config = trace_metadata_config->mutable_chrome_config();
+  metadata_chrome_config->set_trace_config(chrome_config_string);
+  // TODO(ssid): Also set privacy_filtering_enabled here.
 
   return perfetto_config;
 }
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
index f13da240..32a58a48 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
@@ -23,6 +23,7 @@
 #include "services/tracing/public/cpp/perfetto/thread_local_event_sink.h"
 #include "services/tracing/public/cpp/perfetto/traced_value_proto_writer.h"
 #include "services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h"
+#include "services/tracing/public/cpp/trace_event_args_whitelist.h"
 #include "services/tracing/public/mojom/constants.mojom.h"
 #include "third_party/perfetto/include/perfetto/tracing/core/shared_memory_arbiter.h"
 #include "third_party/perfetto/include/perfetto/tracing/core/startup_trace_writer.h"
@@ -42,7 +43,11 @@
 
 TraceEventMetadataSource::TraceEventMetadataSource()
     : DataSourceBase(mojom::kMetaDataSourceName),
-      origin_task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
+      origin_task_runner_(base::SequencedTaskRunnerHandle::Get()) {
+  AddGeneratorFunction(base::BindRepeating(
+      &TraceEventMetadataSource::GenerateTraceConfigMetadataDict,
+      base::Unretained(this)));
+}
 
 TraceEventMetadataSource::~TraceEventMetadataSource() = default;
 
@@ -52,6 +57,30 @@
   generator_functions_.push_back(generator);
 }
 
+std::unique_ptr<base::DictionaryValue>
+TraceEventMetadataSource::GenerateTraceConfigMetadataDict() {
+  if (chrome_config_.empty()) {
+    return nullptr;
+  }
+
+  base::trace_event::TraceConfig parsed_chrome_config(chrome_config_);
+
+  auto metadata_dict = std::make_unique<base::DictionaryValue>();
+  // If argument filtering is enabled, we need to check if the trace config is
+  // whitelisted before emitting it.
+  // TODO(eseckler): Figure out a way to solve this without calling directly
+  // into IsMetadataWhitelisted().
+  if (!parsed_chrome_config.IsArgumentFilterEnabled() ||
+      IsMetadataWhitelisted("trace-config")) {
+    metadata_dict->SetString("trace-config", chrome_config_);
+  } else {
+    metadata_dict->SetString("trace-config", "__stripped__");
+  }
+
+  chrome_config_ = std::string();
+  return metadata_dict;
+}
+
 void TraceEventMetadataSource::GenerateMetadata(
     std::unique_ptr<perfetto::TraceWriter> trace_writer) {
   DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
@@ -91,6 +120,7 @@
   // sense to emit the metadata on startup, so the UI can display it right away.
   privacy_filtering_enabled_ =
       data_source_config.chrome_config().privacy_filtering_enabled();
+  chrome_config_ = data_source_config.chrome_config().trace_config();
   trace_writer_ =
       producer_client->CreateTraceWriter(data_source_config.target_buffer());
 }
@@ -107,6 +137,7 @@
         std::move(stop_complete_callback));
   } else {
     trace_writer_.reset();
+    chrome_config_ = std::string();
     std::move(stop_complete_callback).Run();
   }
 }
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.h b/services/tracing/public/cpp/perfetto/trace_event_data_source.h
index f316150..0d9a9a02 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.h
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.h
@@ -51,11 +51,13 @@
 
  private:
   void GenerateMetadata(std::unique_ptr<perfetto::TraceWriter> trace_writer);
+  std::unique_ptr<base::DictionaryValue> GenerateTraceConfigMetadataDict();
 
   std::vector<MetadataGeneratorFunction> generator_functions_;
   scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
   std::unique_ptr<perfetto::TraceWriter> trace_writer_;
   bool privacy_filtering_enabled_ = false;
+  std::string chrome_config_;
 
   DISALLOW_COPY_AND_ASSIGN(TraceEventMetadataSource);
 };
diff --git a/services/video_capture/OWNERS b/services/video_capture/OWNERS
index 495d7a5..c3dbbd03 100644
--- a/services/video_capture/OWNERS
+++ b/services/video_capture/OWNERS
@@ -1,8 +1,6 @@
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
+# COMPONENT: Blink>GetUserMedia
+
 chfremer@chromium.org
 emircan@chromium.org
-
-# Original (legacy) owner.
-per-file *video*=mcasas@chromium.org
-
-# COMPONENT: Blink>GetUserMedia
-# TEAM: webrtc-dev@chromium.org
+mcasas@chromium.org
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 9a3d3be..5cc162df 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -169,6 +169,10 @@
 #define SK_SUPPORT_LEGACY_AAA_CHOICE
 #endif
 
+#ifndef SK_SUPPORT_LEGACY_COLORFILTER_FACTORIES
+#define SK_SUPPORT_LEGACY_COLORFILTER_FACTORIES
+#endif
+
 #ifndef SK_ENABLE_LEGACY_TEXT_COLOR
 #define SK_ENABLE_LEGACY_TEXT_COLOR
 #endif
diff --git a/testing/buildbot/chromium.dawn.json b/testing/buildbot/chromium.dawn.json
index d545aea8..0c1caf8 100644
--- a/testing/buildbot/chromium.dawn.json
+++ b/testing/buildbot/chromium.dawn.json
@@ -159,6 +159,30 @@
       }
     ]
   },
+  "Dawn Mac x64 Builder": {},
+  "Dawn Mac x64 Release (AMD)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac-10.13.6",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "dawn_end2end_tests"
+      }
+    ]
+  },
   "Dawn Win10 x64 Builder": {},
   "Dawn Win10 x64 DEPS Builder": {},
   "Dawn Win10 x64 DEPS Release (Intel HD 630)": {
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 5a01153..5440ddf 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -10850,7 +10850,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10858,7 +10858,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -10877,7 +10877,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10885,7 +10885,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -10905,7 +10905,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10913,7 +10913,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -10930,7 +10930,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10938,7 +10938,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -10956,7 +10956,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10964,7 +10964,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -10980,7 +10980,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -10988,7 +10988,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11004,7 +11004,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11012,7 +11012,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11025,7 +11025,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11033,7 +11033,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11050,7 +11050,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11058,7 +11058,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11071,7 +11071,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11079,7 +11079,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11105,7 +11105,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11114,7 +11114,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11137,7 +11137,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11146,7 +11146,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11169,7 +11169,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11178,7 +11178,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11201,7 +11201,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11210,7 +11210,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11237,7 +11237,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11246,7 +11246,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11276,7 +11276,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11285,7 +11285,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11323,7 +11323,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11332,7 +11332,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11356,7 +11356,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11365,7 +11365,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11388,7 +11388,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11397,7 +11397,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11422,7 +11422,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11431,7 +11431,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -11455,7 +11455,7 @@
           "dimension_sets": [
             {
               "gpu": "1002:6821",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11464,7 +11464,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -11486,7 +11486,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11494,7 +11494,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -11513,7 +11513,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11521,7 +11521,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11541,7 +11541,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11549,7 +11549,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11566,7 +11566,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11574,7 +11574,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -11592,7 +11592,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11600,7 +11600,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11616,7 +11616,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11624,7 +11624,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11640,7 +11640,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11648,7 +11648,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11661,7 +11661,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11669,7 +11669,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11686,7 +11686,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11694,7 +11694,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11707,7 +11707,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11715,7 +11715,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11741,7 +11741,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11750,7 +11750,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11773,7 +11773,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11782,7 +11782,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11805,7 +11805,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11814,7 +11814,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11837,7 +11837,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11846,7 +11846,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11873,7 +11873,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11882,7 +11882,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11912,7 +11912,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11921,7 +11921,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11959,7 +11959,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -11968,7 +11968,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -11992,7 +11992,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12001,7 +12001,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12024,7 +12024,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12033,7 +12033,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12058,7 +12058,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12067,7 +12067,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -12091,7 +12091,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12100,7 +12100,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -12122,7 +12122,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12130,7 +12130,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -12149,7 +12149,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12157,7 +12157,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12177,7 +12177,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12185,7 +12185,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12202,7 +12202,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12210,7 +12210,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -12228,7 +12228,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12236,7 +12236,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12252,7 +12252,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12260,7 +12260,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12276,7 +12276,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12284,7 +12284,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12297,7 +12297,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12305,7 +12305,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12322,7 +12322,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12330,7 +12330,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12343,7 +12343,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12351,7 +12351,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12377,7 +12377,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12386,7 +12386,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12409,7 +12409,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12418,7 +12418,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12441,7 +12441,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12450,7 +12450,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12473,7 +12473,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12482,7 +12482,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12509,7 +12509,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12518,7 +12518,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12548,7 +12548,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12557,7 +12557,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12595,7 +12595,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12604,7 +12604,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12628,7 +12628,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12637,7 +12637,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12660,7 +12660,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12669,7 +12669,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           }
@@ -12694,7 +12694,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12703,7 +12703,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -12727,7 +12727,7 @@
           "dimension_sets": [
             {
               "gpu": "10de:0fe9",
-              "os": "Mac-10.14.3",
+              "os": "Mac-10.14.4",
               "pool": "Chrome-GPU"
             }
           ],
@@ -12736,7 +12736,7 @@
           "optional_dimensions": {
             "600": [
               {
-                "os": "Mac-10.14.4"
+                "os": "Mac-10.14.3"
               }
             ]
           },
@@ -16453,32 +16453,6 @@
           ],
           "idempotent": false
         }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=debug",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "name": "webgl_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:0fe9",
-              "hidpi": "1",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "idempotent": false,
-          "shards": 2
-        }
       }
     ]
   },
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index 9d0e449..8919d21 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -331,14 +331,14 @@
   'mac_10.14': {
     'swarming': {
       'dimensions': {
-        'os': 'Mac-10.14.3',
+        'os': 'Mac-10.14.4',
       },
       'optional_dimensions': {
         # Wait 10 minutes for 10.14.4, then fall back to 10.14.3.
         # The format for optional dimensions is: expiration: [{key, value}, ..].
         600: [
           {
-            'os': 'Mac-10.14.4',
+            'os': 'Mac-10.14.3',
           },
         ],
       },
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 528592e..e995d343 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1523,6 +1523,11 @@
         ]
       },
     },
+    'remove_from': [
+      # Too slow on this configuration, which is severely hardware
+      # constrained. crbug.com/950690
+      'Mac FYI Retina Debug (NVIDIA)',
+    ],
   },
   'webgl_conformance_vulkan_passthrough_tests': {
     'remove_from': [
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index ad46626..cd922fa 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1050,6 +1050,17 @@
           'gtest_tests': 'gpu_dawn_gtests',
         },
       },
+      'Dawn Mac x64 Builder' : {},
+      'Dawn Mac x64 Release (AMD)': {
+        'os_type': 'mac',
+        'browser_config': 'release',
+        'mixins': [
+          'mac_retina_amd_gpu',
+        ],
+        'test_suites': {
+          'gtest_tests': 'gpu_dawn_gtests',
+        },
+      },
       'Dawn Win10 x64 Builder' : {},
       'Dawn Win10 x64 DEPS Builder' : {},
       'Dawn Win10 x64 DEPS Release (Intel HD 630)': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 6b34d2f..6506460 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3311,6 +3311,7 @@
                         "OmniboxRichEntitySuggestions",
                         "OmniboxTailSuggestions",
                         "OmniboxUIExperimentMaxAutocompleteMatches",
+                        "QueryInOmnibox",
                         "ZeroSuggestRedirectToChrome",
                         "ZeroSuggestSwapTitleAndUrl"
                     ]
diff --git a/third_party/blink/common/mediastream/OWNERS b/third_party/blink/common/mediastream/OWNERS
index 7f3f570..ed7be739 100644
--- a/third_party/blink/common/mediastream/OWNERS
+++ b/third_party/blink/common/mediastream/OWNERS
@@ -4,5 +4,5 @@
 per-file *_mojom_traits*.*=set noparent
 per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
 
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia
diff --git a/third_party/blink/public/common/mediastream/OWNERS b/third_party/blink/public/common/mediastream/OWNERS
index f247c7f..155e1a8b 100644
--- a/third_party/blink/public/common/mediastream/OWNERS
+++ b/third_party/blink/public/common/mediastream/OWNERS
@@ -6,5 +6,5 @@
 per-file *.typemap=set noparent
 per-file *.typemap=file://ipc/SECURITY_OWNERS
 
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia
diff --git a/third_party/blink/public/mojom/mediastream/OWNERS b/third_party/blink/public/mojom/mediastream/OWNERS
index 1ec01e1..ff62c9c4 100644
--- a/third_party/blink/public/mojom/mediastream/OWNERS
+++ b/third_party/blink/public/mojom/mediastream/OWNERS
@@ -4,5 +4,5 @@
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
 
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia
diff --git a/third_party/blink/public/platform/modules/mediastream/OWNERS b/third_party/blink/public/platform/modules/mediastream/OWNERS
index 32889cc..c205d4f9 100644
--- a/third_party/blink/public/platform/modules/mediastream/OWNERS
+++ b/third_party/blink/public/platform/modules/mediastream/OWNERS
@@ -2,5 +2,5 @@
 
 per-file media_stream_audio_processor*=aluebs@chromium.org
 
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia
diff --git a/third_party/blink/public/web/modules/mediastream/OWNERS b/third_party/blink/public/web/modules/mediastream/OWNERS
index 9d70184..4d93338 100644
--- a/third_party/blink/public/web/modules/mediastream/OWNERS
+++ b/third_party/blink/public/web/modules/mediastream/OWNERS
@@ -1,4 +1,4 @@
 file://third_party/blink/common/mediastream/OWNERS
 
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer.cc b/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
index de5a461..b0bfc8a 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
@@ -44,7 +44,8 @@
   ~SourceStream() override = default;
 
   // Called by V8 on a background thread. Should block until we can return
-  // some data.
+  // some data. Ownership of the |src| data buffer is passed to the caller,
+  // unless |src| is null.
   size_t GetMoreData(const uint8_t** src) override {
     DCHECK(!IsMainThread());
     CHECK(ready_to_run_.IsSet());
@@ -61,7 +62,11 @@
 
     if (initial_data_) {
       CHECK_GT(initial_data_len_, 0u);
-      *src = initial_data_.release();
+      if (src) {
+        *src = initial_data_.release();
+      } else {
+        initial_data_.reset();
+      }
       size_t len = initial_data_len_;
       initial_data_len_ = 0;
       return len;
@@ -83,8 +88,12 @@
           // num_bytes could only be 0 if the handle was being read elsewhere.
           CHECK_GT(num_bytes, 0u);
 
-          auto copy_for_script_stream = std::make_unique<uint8_t[]>(num_bytes);
-          memcpy(copy_for_script_stream.get(), buffer, num_bytes);
+          if (src) {
+            auto copy_for_script_stream =
+                std::make_unique<uint8_t[]>(num_bytes);
+            memcpy(copy_for_script_stream.get(), buffer, num_bytes);
+            *src = copy_for_script_stream.release();
+          }
 
           // TODO(leszeks): It would be nice to get rid of this second copy, and
           // either share ownership of the chunks, or only give chunks back to
@@ -100,7 +109,6 @@
           result = data_pipe_->EndReadData(num_bytes);
           CHECK_EQ(result, MOJO_RESULT_OK);
 
-          *src = copy_for_script_stream.release();
           return num_bytes;
         }
 
@@ -152,8 +160,7 @@
     if (!finished_) {
       // Keep reading data until we finish (returning 0). It won't be streaming
       // compiled any more, but it will continue being forwarded to the client.
-      const uint8_t* ignored_data;
-      while (GetMoreData(&ignored_data) != 0) {
+      while (GetMoreData(nullptr) != 0) {
       }
     }
     CHECK(finished_);
diff --git a/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_individual.py b/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_individual.py
index 992d4db..0bafc86 100755
--- a/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_individual.py
+++ b/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_individual.py
@@ -112,22 +112,22 @@
     return posixpath.join(relative_dir, output_file_basename + '.h')
 
 
-def get_implements_from_definitions(definitions, definition_name):
-    left_interfaces = []
-    right_interfaces = []
-    for implement in definitions.implements:
-        if definition_name == implement.left_interface:
-            right_interfaces.append(implement.right_interface)
-        elif definition_name == implement.right_interface:
-            left_interfaces.append(implement.left_interface)
+def get_includes_from_definitions(definitions, definition_name):
+    interfaces = []
+    mixins = []
+    for include in definitions.includes:
+        if definition_name == include.interface:
+            mixins.append(include.mixin)
+        elif definition_name == include.mixin:
+            interfaces.append(include.interface)
         else:
             raise IdlBadFilenameError(
-                'implements statement found in unrelated IDL file.\n'
+                'includes statement found in unrelated IDL file.\n'
                 'Statement is:\n'
-                '    %s implements %s;\n'
+                '    %s includes %s;\n'
                 'but filename is unrelated "%s.idl"' %
-                (implement.left_interface, implement.right_interface, definition_name))
-    return left_interfaces, right_interfaces
+                (include.interface, include.mixin, definition_name))
+    return interfaces, mixins
 
 
 def get_put_forward_interfaces_from_definition(definition):
@@ -298,11 +298,10 @@
                     {'cpp_includes': {component: set([this_include_path])}})
             return
 
-        # 'implements' statements can be included in either the file for the
-        # implement*ing* interface (lhs of 'implements') or implement*ed* interface
-        # (rhs of 'implements'). Store both for now, then merge to implement*ing*
-        # interface later.
-        left_interfaces, right_interfaces = get_implements_from_definitions(
+        # 'includes' statements can be included in either the file for the
+        # interface (lhs of 'includes') or mixin (rhs of 'includes'). Store both
+        # for now, then merge to the interface later.
+        includes_interfaces, includes_mixins = get_includes_from_definitions(
             definitions, definition.name)
 
         interface_info.update({
@@ -310,8 +309,8 @@
             'full_path': full_path,
             'union_types': this_union_types,
             'implemented_as': implemented_as,
-            'implemented_by_interfaces': left_interfaces,
-            'implements_interfaces': right_interfaces,
+            'included_by_interfaces': includes_interfaces,
+            'including_mixins': includes_mixins,
             'include_path': this_include_path,
             # FIXME: temporary private field, while removing old treatement of
             # 'implements': http://crbug.com/360435
diff --git a/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_overall.py b/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_overall.py
index 10dabe7..449aad69 100755
--- a/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_overall.py
+++ b/third_party/blink/renderer/bindings/scripts/compute_interfaces_info_overall.py
@@ -50,7 +50,7 @@
 
 Current keys are:
 * dependencies:
-    'implements_interfaces': targets of 'implements' statements
+    'including_mixins': targets of 'includes' statements
     'referenced_interfaces': reference interfaces that are introspected
                              (currently just targets of [PutForwards])
 
@@ -111,7 +111,7 @@
 
 
 class IdlInterfaceFileNotFoundError(Exception):
-    """Raised if the IDL file implementing an interface cannot be found."""
+    """Raised if an IDL file that contains the mixin cannot be found."""
     pass
 
 
@@ -226,17 +226,17 @@
         compute_inheritance_info(interface_name)
 
     # Compute dependencies
-    # Move implements info from implement*ed* interface (rhs of 'implements')
-    # to implement*ing* interface (lhs of 'implements').
-    # Note that moving an 'implements' statement between implementing and
-    # implemented files does not change the info (or hence cause a rebuild)!
-    for right_interface_name, interface_info in interfaces_info.iteritems():
-        for left_interface_name in interface_info['implemented_by_interfaces']:
-            interfaces_info[left_interface_name]['implements_interfaces'].append(right_interface_name)
-        del interface_info['implemented_by_interfaces']
+    # Move includes info from mixin (rhs of 'includes') to interface (lhs of
+    # 'includes').
+    # Note that moving an 'includes' statement between files does not change the
+    # info itself (or hence cause a rebuild)!
+    for mixin_name, interface_info in interfaces_info.iteritems():
+        for interface_name in interface_info['included_by_interfaces']:
+            interfaces_info[interface_name]['including_mixins'].append(mixin_name)
+        del interface_info['included_by_interfaces']
 
     # An IDL file's dependencies are partial interface files that extend it,
-    # and files for other interfaces that this interfaces implements.
+    # and files for other interfaces that this interfaces include.
     for interface_name, interface_info in interfaces_info.iteritems():
         partial_interface_paths = partial_interface_files[interface_name]
         partial_interfaces_full_paths = partial_interface_paths['full_paths']
@@ -244,29 +244,24 @@
         # implemented in separate classes from the main interface.
         partial_interfaces_include_paths = partial_interface_paths['include_paths']
 
-        implemented_interfaces = interface_info['implements_interfaces']
+        mixins = interface_info['including_mixins']
         try:
-            implemented_interfaces_info = [
-                interfaces_info[interface]
-                for interface in implemented_interfaces]
+            mixins_info = [interfaces_info[mixin] for mixin in mixins]
         except KeyError as key_name:
-            raise IdlInterfaceFileNotFoundError('Could not find the IDL file where the following implemented interface is defined: %s' % key_name)
-        implemented_interfaces_full_paths = [
-            implemented_interface_info['full_path']
-            for implemented_interface_info in implemented_interfaces_info]
-        # Implemented interfaces don't need includes, as this is handled in
-        # the Blink implementation (they are implemented on |impl| itself,
-        # hence header is included in implementing class).
-        # However, they are needed for legacy implemented interfaces that
-        # are being treated as partial interfaces, until we remove these.
-        # http://crbug.com/360435
-        implemented_interfaces_include_paths = [
-            implemented_interface_info['include_path']
-            for implemented_interface_info in implemented_interfaces_info
-            if implemented_interface_info['is_legacy_treat_as_partial_interface']]
+            raise IdlInterfaceFileNotFoundError('Could not find the IDL file where the following mixin is defined: %s' % key_name)
+        mixins_full_paths = [mixin_info['full_path'] for mixin_info in mixins_info]
+        # Mixins don't need include files, as this is handled in the Blink
+        # implementation (they are implemented on |impl| itself, hence header
+        # declaration is included in the interface class).
+        # However, they are needed for legacy mixins that are being treated as
+        # partial interfaces, until we remove these.
+        # https://crbug.com/360435
+        mixins_include_paths = [
+            mixin_info['include_path'] for mixin_info in mixins_info
+            if mixin_info['is_legacy_treat_as_partial_interface']]
 
-        dependencies_full_paths = implemented_interfaces_full_paths
-        dependencies_include_paths = implemented_interfaces_include_paths
+        dependencies_full_paths = mixins_full_paths
+        dependencies_include_paths = mixins_include_paths
         dependencies_other_component_full_paths = []
         dependencies_other_component_include_paths = []
 
diff --git a/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py b/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
index 6e4950e..9eb6063b 100755
--- a/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
+++ b/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
@@ -68,10 +68,10 @@
 def read_idl_file(reader, idl_filename):
     definitions = reader.read_idl_file(idl_filename)
     interfaces = definitions.interfaces
-    implements = definitions.implements
+    includes = definitions.includes
     # There should only be a single interface defined in an IDL file. Return it.
     assert len(interfaces) == 1
-    return (interfaces.values()[0], implements)
+    return (interfaces.values()[0], includes)
 
 
 def interface_is_global(interface):
@@ -90,40 +90,32 @@
     """
     features_for_type = defaultdict(set)
     types_for_feature = defaultdict(set)
-    includes = set()
-
-    # Gather interfaces which are implemented by other interfaces.
-    implemented_interfaces = set()
-    for name, interface_info in info_provider.interfaces_info.iteritems():
-        # Skip special entries such as 'dictionaries' or 'ancestors'.
-        if name.lower() == name:
-            continue
-        implemented_interfaces.update(interface_info.get('implements_interfaces'))
+    include_files = set()
 
     for idl_filename in idl_filenames:
-        interface, implements = read_idl_file(reader, idl_filename)
+        interface, includes = read_idl_file(reader, idl_filename)
         feature_names = get_origin_trial_feature_names_from_interface(interface)
 
-        # If this interface is implemented by other interfaces, we don't generate
-        # V8 bindings code for it.
-        if interface.name in implemented_interfaces:
+        # If this interface is a mixin, we don't generate V8 bindings code for
+        # it.
+        if interface.is_mixin:
             continue
 
-        # If this interface implements another one,
+        # If this interface include another one,
         # it inherits any conditional features from it.
-        for implement in implements:
-            assert implement.left_interface == interface.name
-            implemented_interface, _ = read_idl_file(
+        for include in includes:
+            assert include.interface == interface.name
+            mixin, _ = read_idl_file(
                 reader,
-                info_provider.interfaces_info[implement.right_interface].get('full_path'))
-            feature_names |= get_origin_trial_feature_names_from_interface(implemented_interface)
+                info_provider.interfaces_info[include.mixin].get('full_path'))
+            feature_names |= get_origin_trial_feature_names_from_interface(mixin)
 
         feature_names = list(feature_names)
         if feature_names:
             is_global = interface_is_global(interface)
             if interface.is_partial:
                 # For partial interfaces, we need to generate different
-                # includes if the parent interface is in a different
+                # |include_files| if the parent interface is in a different
                 # component.
                 parent_interface_info = info_provider.interfaces_info[interface.name]
                 parent_interface, _ = read_idl_file(
@@ -132,13 +124,13 @@
                 parent_component = idl_filename_to_component(
                     parent_interface_info.get('full_path'))
             if interface.is_partial and target_component != parent_component:
-                includes.add('bindings/%s/v8/%s' %
-                             (parent_component, binding_header_filename(interface.name)))
-                includes.add('bindings/%s/v8/%s' %
-                             (target_component, binding_header_filename(interface.name + 'Partial')))
+                include_files.add('bindings/%s/v8/%s' %
+                                  (parent_component, binding_header_filename(interface.name)))
+                include_files.add('bindings/%s/v8/%s' %
+                                  (target_component, binding_header_filename(interface.name + 'Partial')))
             else:
-                includes.add('bindings/%s/v8/%s' %
-                             (target_component, binding_header_filename(interface.name)))
+                include_files.add('bindings/%s/v8/%s' %
+                                  (target_component, binding_header_filename(interface.name)))
                 # If this is a partial interface in the same component as
                 # its parent, then treat it as a non-partial interface.
                 interface.is_partial = False
@@ -151,17 +143,17 @@
                 features_for_type[interface_info].add(feature_name)
                 types_for_feature[feature_name].add(interface_info)
 
-    return features_for_type, types_for_feature, includes
+    return features_for_type, types_for_feature, include_files
 
 
 def origin_trial_features_context(generator_name, feature_info):
     context = {'code_generator': generator_name}
 
     # Unpack the feature info tuple.
-    features_for_type, types_for_feature, includes = feature_info
+    features_for_type, types_for_feature, include_files = feature_info
 
     # Add includes needed for cpp code and normalize.
-    includes.update([
+    include_files.update([
         'core/context_features/context_feature_settings.h',
         'core/execution_context/execution_context.h',
         'core/frame/frame.h',
@@ -174,7 +166,7 @@
         # here because the ContextFeatureSettings code needs it.
         'bindings/core/v8/v8_window.h',
     ])
-    context['includes'] = normalize_and_sort_includes(includes)
+    context['includes'] = normalize_and_sort_includes(include_files)
 
     # For each interface, collect a list of bindings installation functions to
     # call, organized by conditional feature.
diff --git a/third_party/blink/renderer/bindings/scripts/idl_definitions.py b/third_party/blink/renderer/bindings/scripts/idl_definitions.py
index c83c71f..58d091b 100644
--- a/third_party/blink/renderer/bindings/scripts/idl_definitions.py
+++ b/third_party/blink/renderer/bindings/scripts/idl_definitions.py
@@ -98,7 +98,7 @@
         self.callback_functions = {}
         self.dictionaries = {}
         self.enumerations = {}
-        self.implements = []
+        self.includes = []
         self.interfaces = {}
         self.first_name = None
         self.typedefs = {}
@@ -124,8 +124,8 @@
             elif child_class == 'Callback':
                 callback_function = IdlCallbackFunction(child)
                 self.callback_functions[callback_function.name] = callback_function
-            elif child_class == 'Implements' or child_class == 'Includes':
-                self.implements.append(IdlImplement(child))
+            elif child_class == 'Includes':
+                self.includes.append(IdlIncludes(child))
             elif child_class == 'Dictionary':
                 dictionary = IdlDictionary(child)
                 self.dictionaries[dictionary.name] = dictionary
@@ -144,8 +144,8 @@
             dictionary.accept(visitor)
         for enumeration in self.enumerations.itervalues():
             enumeration.accept(visitor)
-        for implement in self.implements:
-            implement.accept(visitor)
+        for include in self.includes:
+            include.accept(visitor)
         for typedef in self.typedefs.itervalues():
             typedef.accept(visitor)
 
@@ -752,20 +752,16 @@
 
 
 ################################################################################
-# Implement statements / includes statements
+# Includes statements
 ################################################################################
 
-class IdlImplement(object):
-    """
-    IdlImplement class represents an implements statement or an includes
-    statement.
-    """
+class IdlIncludes(object):
     def __init__(self, node):
-        self.left_interface = node.GetName()
-        self.right_interface = node.GetProperty('REFERENCE')
+        self.interface = node.GetName()
+        self.mixin = node.GetProperty('REFERENCE')
 
     def accept(self, visitor):
-        visitor.visit_implement(self)
+        visitor.visit_include(self)
 
 
 ################################################################################
@@ -1023,7 +1019,7 @@
     def visit_enumeration(self, enumeration):
         pass
 
-    def visit_implement(self, implement):
+    def visit_include(self, include):
         pass
 
     def visit_interface(self, interface):
diff --git a/third_party/blink/renderer/bindings/scripts/interface_dependency_resolver.py b/third_party/blink/renderer/bindings/scripts/interface_dependency_resolver.py
index 318f9e6b..7e81deb 100644
--- a/third_party/blink/renderer/bindings/scripts/interface_dependency_resolver.py
+++ b/third_party/blink/renderer/bindings/scripts/interface_dependency_resolver.py
@@ -29,7 +29,7 @@
 """Resolve interface dependencies, producing a merged IdlDefinitions object.
 
 This library computes interface dependencies (partial interfaces and
-implements), reads the dependency files, and merges them to the IdlDefinitions
+includes), reads the dependency files, and merges them to the IdlDefinitions
 for the main IDL file, producing an IdlDefinitions object representing the
 entire interface.
 
@@ -68,13 +68,13 @@
         """Resolve dependencies, merging them into IDL definitions of main file.
 
         Dependencies consist of 'partial interface' for the same interface as
-        in the main file, and other interfaces that this interface 'implements'.
+        in the main file, and mixins that this interface 'includes'.
         These are merged into the main IdlInterface, as the main IdlInterface
         implements all these members.
 
-        Referenced interfaces are added to IdlDefinitions, but not merged into
-        the main IdlInterface, as these are only referenced (their members are
-        introspected, but not implemented in this interface).
+        Partial interfaces and mixins are added to IdlDefinitions, but not
+        merged into the main IdlInterface, as these are only referenced (their
+        members are introspected, but not implemented in this interface).
 
         Inherited extended attributes are also added to the main IdlInterface.
 
@@ -96,8 +96,8 @@
                 or a given IdlDefinitions object has incorrect referenced
                 interfaces.
         """
-        # FIXME: we need to resolve dependency when we implement partial
-        # dictionary.
+        # TODO(crbug.com/579896): we need to resolve dependency when we
+        # support partial dictionary.
         if not definitions.interfaces:
             raise Exception('No need to resolve any dependencies of '
                             'this definition: %s, because this should '
@@ -222,7 +222,7 @@
             # - An interface defined in core cannot include an interface mixin
             #   defined in modules.
             if not dependency_interface.is_mixin:
-                raise Exception('The interface:%s cannot implement '
+                raise Exception('The interface:%s cannot include '
                                 'the non-mixin interface: %s.' % (
                                     target_interface.name,
                                     dependency_interface.name))
@@ -236,9 +236,9 @@
                                     dependency_component))
 
             resolved_definitions[component].update(dependency_definitions)  # merges partial interfaces
-            # Implemented interfaces (non-partial dependencies) are also merged
-            # into the target interface, so Code Generator can just iterate
-            # over one list (and not need to handle 'implements' itself).
+            # Mixins are also merged into the target interface, so Code
+            # Generator can just iterate over one list (and not need to handle
+            # 'includes' itself).
             target_interface.merge(dependency_interface)
 
     return resolved_definitions
@@ -282,9 +282,7 @@
     # which class implemented interfaces are implemented.
     #
     # Currently [LegacyTreatAsPartialInterface] can be used to have partial
-    # interface behavior on implemented interfaces, but this is being removed
-    # as legacy cruft:
-    # FIXME: Remove [LegacyTreatAsPartialInterface]
+    # interface behavior on mixins, but this is being removed as legacy cruft:
     # http://crbug.com/360435
     #
     # Note that [ImplementedAs] is used with different meanings on interfaces
diff --git a/third_party/blink/renderer/core/animation/element_animation.idl b/third_party/blink/renderer/core/animation/element_animation.idl
index 3e56e3d..1c596d3 100644
--- a/third_party/blink/renderer/core/animation/element_animation.idl
+++ b/third_party/blink/renderer/core/animation/element_animation.idl
@@ -32,7 +32,7 @@
 // https://drafts.csswg.org/web-animations/#extensions-to-the-element-interface
 
 // TODO(dstockwell): This should be an Animatable interface, where Element
-// implements Animatable.
+// includes Animatable.
 
 [
     ImplementedAs=ElementAnimation
diff --git a/third_party/blink/renderer/core/dom/accessibility_role.idl b/third_party/blink/renderer/core/dom/accessibility_role.idl
index 22454d63..3685a82 100644
--- a/third_party/blink/renderer/core/dom/accessibility_role.idl
+++ b/third_party/blink/renderer/core/dom/accessibility_role.idl
@@ -10,4 +10,4 @@
   [CEReactions, Reflect] attribute DOMString? role;
 };
 
-Element implements AccessibilityRole;
+Element includes AccessibilityRole;
diff --git a/third_party/blink/renderer/core/dom/aria_attributes.idl b/third_party/blink/renderer/core/dom/aria_attributes.idl
index e4271c3..d0ad259 100644
--- a/third_party/blink/renderer/core/dom/aria_attributes.idl
+++ b/third_party/blink/renderer/core/dom/aria_attributes.idl
@@ -53,4 +53,4 @@
     [CEReactions, Reflect=aria_valuetext] attribute DOMString? ariaValueText;
 };
 
-Element implements AriaAttributes;
+Element includes AriaAttributes;
diff --git a/third_party/blink/renderer/core/dom/character_data.idl b/third_party/blink/renderer/core/dom/character_data.idl
index 30b22212..40df5dd 100644
--- a/third_party/blink/renderer/core/dom/character_data.idl
+++ b/third_party/blink/renderer/core/dom/character_data.idl
@@ -29,5 +29,5 @@
     [RaisesException] void replaceData(unsigned long offset, unsigned long count, DOMString data);
 };
 
-CharacterData implements ChildNode;
-CharacterData implements NonDocumentTypeChildNode;
+CharacterData includes ChildNode;
+CharacterData includes NonDocumentTypeChildNode;
diff --git a/third_party/blink/renderer/core/dom/document.idl b/third_party/blink/renderer/core/dom/document.idl
index c28eba7..53d4e05 100644
--- a/third_party/blink/renderer/core/dom/document.idl
+++ b/third_party/blink/renderer/core/dom/document.idl
@@ -208,9 +208,9 @@
     attribute EventHandler onvisibilitychange;
 };
 
-Document implements GlobalEventHandlers;
-Document implements DocumentAndElementEventHandlers;
-Document implements ParentNode;
-Document implements NonElementParentNode;
-Document implements DocumentOrShadowRoot;
-Document implements FontFaceSource;
+Document includes GlobalEventHandlers;
+Document includes DocumentAndElementEventHandlers;
+Document includes ParentNode;
+Document includes NonElementParentNode;
+Document includes DocumentOrShadowRoot;
+Document includes FontFaceSource;
diff --git a/third_party/blink/renderer/core/dom/document_fragment.idl b/third_party/blink/renderer/core/dom/document_fragment.idl
index ab728d2..892a8fbc 100644
--- a/third_party/blink/renderer/core/dom/document_fragment.idl
+++ b/third_party/blink/renderer/core/dom/document_fragment.idl
@@ -25,5 +25,5 @@
 ] interface DocumentFragment : Node {
 };
 
-DocumentFragment implements ParentNode;
-DocumentFragment implements NonElementParentNode;
+DocumentFragment includes ParentNode;
+DocumentFragment includes NonElementParentNode;
diff --git a/third_party/blink/renderer/core/dom/document_type.idl b/third_party/blink/renderer/core/dom/document_type.idl
index 1b7f4112..836148a 100644
--- a/third_party/blink/renderer/core/dom/document_type.idl
+++ b/third_party/blink/renderer/core/dom/document_type.idl
@@ -25,4 +25,4 @@
     readonly attribute DOMString systemId;
 };
 
-DocumentType implements ChildNode;
+DocumentType includes ChildNode;
diff --git a/third_party/blink/renderer/core/dom/element.idl b/third_party/blink/renderer/core/dom/element.idl
index df946e6a..39aeb5b 100644
--- a/third_party/blink/renderer/core/dom/element.idl
+++ b/third_party/blink/renderer/core/dom/element.idl
@@ -144,6 +144,6 @@
     [RuntimeEnabled=DisplayLocking, ImplementedAs=getDisplayLockForBindings] readonly attribute DisplayLockContext displayLock;
 };
 
-Element implements ParentNode;
-Element implements ChildNode;
-Element implements NonDocumentTypeChildNode;
+Element includes ParentNode;
+Element includes ChildNode;
+Element includes NonDocumentTypeChildNode;
diff --git a/third_party/blink/renderer/core/dom/processing_instruction.idl b/third_party/blink/renderer/core/dom/processing_instruction.idl
index e4662081..a58cfbf 100644
--- a/third_party/blink/renderer/core/dom/processing_instruction.idl
+++ b/third_party/blink/renderer/core/dom/processing_instruction.idl
@@ -23,7 +23,7 @@
 interface ProcessingInstruction : CharacterData {
     readonly attribute DOMString target;
 
-    // ProcessingInstruction implements LinkStyle
+    // ProcessingInstruction includes LinkStyle
     // https://drafts.csswg.org/cssom/#requirements-on-user-agents-implementing-the-xml-stylesheet-processing-instruction
     readonly attribute StyleSheet? sheet;
 };
diff --git a/third_party/blink/renderer/core/dom/shadow_root.idl b/third_party/blink/renderer/core/dom/shadow_root.idl
index 1fb0c53..851c72e 100644
--- a/third_party/blink/renderer/core/dom/shadow_root.idl
+++ b/third_party/blink/renderer/core/dom/shadow_root.idl
@@ -33,4 +33,4 @@
     readonly attribute boolean delegatesFocus;
 };
 
-ShadowRoot implements DocumentOrShadowRoot;
+ShadowRoot includes DocumentOrShadowRoot;
diff --git a/third_party/blink/renderer/core/fetch/request.idl b/third_party/blink/renderer/core/fetch/request.idl
index 0e5f9c14..7459022 100644
--- a/third_party/blink/renderer/core/fetch/request.idl
+++ b/third_party/blink/renderer/core/fetch/request.idl
@@ -54,4 +54,4 @@
     [RaisesException, CallWith=ScriptState, DoNotTestNewObject, NewObject] Request clone();
 };
 
-Request implements Body;
+Request includes Body;
diff --git a/third_party/blink/renderer/core/fetch/response.idl b/third_party/blink/renderer/core/fetch/response.idl
index 0b5cdb7..dac40e5 100644
--- a/third_party/blink/renderer/core/fetch/response.idl
+++ b/third_party/blink/renderer/core/fetch/response.idl
@@ -30,4 +30,4 @@
     [MeasureAs=FetchBodyStream] readonly attribute ReadableStream? body;
 };
 
-Response implements Body;
+Response includes Body;
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 5fc087b..b661fab5 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -1477,35 +1477,6 @@
 
   WebWindowFeatures window_features = GetWindowFeaturesFromString(features);
 
-  FrameLoadRequest frame_request(active_document,
-                                 ResourceRequest(completed_url),
-                                 target.IsEmpty() ? "_blank" : target);
-  frame_request.SetNavigationPolicy(
-      NavigationPolicyForCreateWindow(window_features));
-  frame_request.SetFeaturesForWindowOpen(window_features);
-  frame_request.SetShouldSetOpener(window_features.noopener ? kNeverSetOpener
-                                                            : kMaybeSetOpener);
-
-  // Normally, FrameLoader would take care of setting the referrer for a
-  // navigation that is triggered from javascript. However, creating a window
-  // goes through sufficient processing that it eventually enters FrameLoader as
-  // an embedder-initiated navigation.  FrameLoader assumes no responsibility
-  // for generating an embedder-initiated navigation's referrer, so we need to
-  // ensure the proper referrer is set now.
-  // TODO(domfarolino): Stop setting ResourceRequest's HTTP Referrer and store
-  // this is a separate member. See https://crbug.com/850813.
-  frame_request.GetResourceRequest().SetHttpReferrer(
-      SecurityPolicy::GenerateReferrer(active_document->GetReferrerPolicy(),
-                                       completed_url,
-                                       active_document->OutgoingReferrer()));
-
-  frame_request.GetResourceRequest().SetHasUserGesture(
-      LocalFrame::HasTransientUserActivation(GetFrame()));
-  GetFrame()->MaybeLogAdClickNavigation();
-
-  if (const WebInputEvent* input_event = CurrentInputEvent::Get())
-    frame_request.SetInputStartTime(input_event->TimeStamp());
-
   // Get the target frame for the special cases of _top and _parent.
   // In those cases, we schedule a location change right now and return early.
   Frame* target_frame = nullptr;
@@ -1533,23 +1504,25 @@
     }
   }
 
-  bool created = false;
-  if (!target_frame)
-    target_frame = CreateNewWindow(*GetFrame(), frame_request, created);
-  if (!target_frame)
-    return nullptr;
+  if (!target_frame) {
+    return CreateWindow(completed_url, target, window_features,
+                        *incumbent_window, *GetFrame());
+  }
 
   if (!active_document->GetFrame() ||
       !active_document->GetFrame()->CanNavigate(*target_frame)) {
     return nullptr;
   }
 
-  if ((!completed_url.IsEmpty() || created) &&
+  if (!url_string.IsEmpty() &&
       !target_frame->DomWindow()->IsInsecureScriptAccess(*incumbent_window,
                                                          completed_url)) {
-    frame_request.SetFrameName("_self");
-    frame_request.SetNavigationPolicy(kNavigationPolicyCurrentTab);
-    target_frame->Navigate(frame_request, WebFrameLoadType::kStandard);
+    FrameLoadRequest request(active_document, ResourceRequest(completed_url));
+    request.GetResourceRequest().SetHasUserGesture(
+        LocalFrame::HasTransientUserActivation(GetFrame()));
+    if (const WebInputEvent* input_event = CurrentInputEvent::Get())
+      request.SetInputStartTime(input_event->TimeStamp());
+    target_frame->Navigate(request, WebFrameLoadType::kStandard);
   }
 
   // TODO(japhet): window-open-noopener.html?_top and several tests in
@@ -1565,8 +1538,7 @@
 
   if (window_features.noopener)
     return nullptr;
-  if (!created)
-    target_frame->Client()->SetOpener(GetFrame());
+  target_frame->Client()->SetOpener(GetFrame());
   return target_frame->DomWindow();
 }
 
diff --git a/third_party/blink/renderer/core/frame/navigator.idl b/third_party/blink/renderer/core/frame/navigator.idl
index 9b1c330..a309bef4 100644
--- a/third_party/blink/renderer/core/frame/navigator.idl
+++ b/third_party/blink/renderer/core/frame/navigator.idl
@@ -32,11 +32,11 @@
     [HighEntropy, MeasureAs=NavigatorVendor] readonly attribute DOMString vendor;
 };
 
-Navigator implements NavigatorConcurrentHardware;
-Navigator implements NavigatorCookies;
-Navigator implements NavigatorDeviceMemory;
-Navigator implements NavigatorID;
-Navigator implements NavigatorLanguage;
-Navigator implements NavigatorOnLine;
-Navigator implements NavigatorAutomationInformation;
-Navigator implements NavigatorUserAgent;
+Navigator includes NavigatorConcurrentHardware;
+Navigator includes NavigatorCookies;
+Navigator includes NavigatorDeviceMemory;
+Navigator includes NavigatorID;
+Navigator includes NavigatorLanguage;
+Navigator includes NavigatorOnLine;
+Navigator includes NavigatorAutomationInformation;
+Navigator includes NavigatorUserAgent;
diff --git a/third_party/blink/renderer/core/frame/window.idl b/third_party/blink/renderer/core/frame/window.idl
index e681b67b..9f3ed35 100644
--- a/third_party/blink/renderer/core/frame/window.idl
+++ b/third_party/blink/renderer/core/frame/window.idl
@@ -218,6 +218,6 @@
     [OriginTrialEnabled=TrustedDOMTypes, Unforgeable] readonly attribute TrustedTypePolicyFactory TrustedTypes;
 };
 
-Window implements GlobalEventHandlers;
-Window implements WindowEventHandlers;
-Window implements WindowOrWorkerGlobalScope;
+Window includes GlobalEventHandlers;
+Window includes WindowEventHandlers;
+Window includes WindowOrWorkerGlobalScope;
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.idl b/third_party/blink/renderer/core/html/html_anchor_element.idl
index 2cd0d37..96902d9 100644
--- a/third_party/blink/renderer/core/html/html_anchor_element.idl
+++ b/third_party/blink/renderer/core/html/html_anchor_element.idl
@@ -42,4 +42,4 @@
     [CEReactions, Reflect] attribute DOMString shape;
 };
 
-HTMLAnchorElement implements HTMLHyperlinkElementUtils;
+HTMLAnchorElement includes HTMLHyperlinkElementUtils;
diff --git a/third_party/blink/renderer/core/html/html_area_element.idl b/third_party/blink/renderer/core/html/html_area_element.idl
index 468cda2..a6d1728c 100644
--- a/third_party/blink/renderer/core/html/html_area_element.idl
+++ b/third_party/blink/renderer/core/html/html_area_element.idl
@@ -36,4 +36,4 @@
     [CEReactions, Reflect] attribute boolean noHref;
 };
 
-HTMLAreaElement implements HTMLHyperlinkElementUtils;
+HTMLAreaElement includes HTMLHyperlinkElementUtils;
diff --git a/third_party/blink/renderer/core/html/html_attribute_names.json5 b/third_party/blink/renderer/core/html/html_attribute_names.json5
index 5d34a3e..3ff9569 100644
--- a/third_party/blink/renderer/core/html/html_attribute_names.json5
+++ b/third_party/blink/renderer/core/html/html_attribute_names.json5
@@ -118,7 +118,7 @@
     "leftmargin",
     "link",
     "list",
-    "load",
+    "loading",
     "longdesc",
     "loop",
     "low",
diff --git a/third_party/blink/renderer/core/html/html_body_element.idl b/third_party/blink/renderer/core/html/html_body_element.idl
index da075c8..c616fb17 100644
--- a/third_party/blink/renderer/core/html/html_body_element.idl
+++ b/third_party/blink/renderer/core/html/html_body_element.idl
@@ -31,7 +31,7 @@
     [CEReactions, Reflect] attribute DOMString background;
 
     // TODO(foolip): These event handler attributes should be inherited from
-    // HTMLElement (which implements GlobalEventHandlers), but have different
+    // HTMLElement (which includes GlobalEventHandlers), but have different
     // behavior. See https://www.w3.org/Bugs/Public/show_bug.cgi?id=28166
     attribute EventHandler onblur;
     attribute EventHandler onerror;
@@ -45,4 +45,4 @@
     [RuntimeEnabled=OrientationEvent] attribute EventHandler onorientationchange;
 };
 
-HTMLBodyElement implements WindowEventHandlers;
+HTMLBodyElement includes WindowEventHandlers;
diff --git a/third_party/blink/renderer/core/html/html_element.idl b/third_party/blink/renderer/core/html/html_element.idl
index cb792372..181d3f3 100644
--- a/third_party/blink/renderer/core/html/html_element.idl
+++ b/third_party/blink/renderer/core/html/html_element.idl
@@ -40,7 +40,7 @@
     [CEReactions] attribute boolean spellcheck;
     [Measure] attribute DOMString autocapitalize;
 
-    // HTMLElement implements ElementContentEditable
+    // HTMLElement includes ElementContentEditable
     // https://html.spec.whatwg.org/C/#contenteditable
     [CEReactions, CustomElementCallbacks, RaisesException=Setter] attribute DOMString contentEditable;
     [ImplementedAs=isContentEditableForBinding] readonly attribute boolean isContentEditable;
@@ -67,6 +67,6 @@
     [Affects=Nothing, CEReactions, CustomElementCallbacks, RaisesException=Setter, MeasureAs=HTMLElementOuterText] attribute [TreatNullAs=EmptyString] DOMString outerText;
 };
 
-HTMLElement implements GlobalEventHandlers;
-HTMLElement implements DocumentAndElementEventHandlers;
-HTMLElement implements NoncedElement;
+HTMLElement includes GlobalEventHandlers;
+HTMLElement includes DocumentAndElementEventHandlers;
+HTMLElement includes NoncedElement;
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
index 2e4b86d..4065bb9 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.cc
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -385,14 +385,14 @@
     const KURL& url,
     const AtomicString& frame_name,
     bool replace_current_item) {
-  // Update the |should_lazy_load_children_| value according to the "lazyload"
+  // Update the |should_lazy_load_children_| value according to the "loading"
   // attribute immediately, so that it still gets respected even if the "src"
-  // attribute gets parsed in ParseAttribute() before the "lazyload" attribute
+  // attribute gets parsed in ParseAttribute() before the "loading" attribute
   // does. Note that when the *feature policy* for "lazyload" is disabled, the
-  // attribute value "off" for "lazyload" is ignored (i.e., interpreted as
+  // attribute value loading="eager" is ignored (i.e., interpreted as
   // "auto" instead).
   if (should_lazy_load_children_ &&
-      EqualIgnoringASCIICase(FastGetAttribute(html_names::kLoadAttr),
+      EqualIgnoringASCIICase(FastGetAttribute(html_names::kLoadingAttr),
                              "eager") &&
       !GetDocument().IsLazyLoadPolicyEnforced()) {
     should_lazy_load_children_ = false;
@@ -446,10 +446,11 @@
     request.SetSkipServiceWorker(true);
 
   if (!lazy_load_frame_observer_ &&
-      IsFrameLazyLoadable(GetDocument(), url,
-                          EqualIgnoringASCIICase(
-                              FastGetAttribute(html_names::kLoadAttr), "lazy"),
-                          should_lazy_load_children_)) {
+      IsFrameLazyLoadable(
+          GetDocument(), url,
+          EqualIgnoringASCIICase(FastGetAttribute(html_names::kLoadingAttr),
+                                 "lazy"),
+          should_lazy_load_children_)) {
     // By default, avoid deferring subresources inside a lazily loaded frame.
     // This will make it possible for subresources in hidden frames to load that
     // will never be visible, as well as make it so that deferred frames that
@@ -496,9 +497,9 @@
 
 void HTMLFrameOwnerElement::ParseAttribute(
     const AttributeModificationParams& params) {
-  if (params.name == html_names::kLoadAttr) {
+  if (params.name == html_names::kLoadingAttr) {
     // Note that when the *feature policy* for "lazyload" is disabled, the
-    // attribute value "off" for "lazyload" is ignored (i.e., interpreted as
+    // attribute value loading="eager" is ignored (i.e., interpreted as
     // "auto" instead).
     if (EqualIgnoringASCIICase(params.new_value, "eager") &&
         !GetDocument().IsLazyLoadPolicyEnforced()) {
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.idl b/third_party/blink/renderer/core/html/html_frame_set_element.idl
index 54a4bcb0..6a6733ed 100644
--- a/third_party/blink/renderer/core/html/html_frame_set_element.idl
+++ b/third_party/blink/renderer/core/html/html_frame_set_element.idl
@@ -29,7 +29,7 @@
     [CEReactions, Reflect] attribute DOMString rows;
 
     // TODO(foolip): These event handler attributes should be inherited from
-    // HTMLElement (which implements GlobalEventHandlers), but have different
+    // HTMLElement (which includes GlobalEventHandlers), but have different
     // behavior. See https://www.w3.org/Bugs/Public/show_bug.cgi?id=28166
     attribute EventHandler onblur;
     attribute EventHandler onerror;
@@ -42,4 +42,4 @@
     [RuntimeEnabled=OrientationEvent] attribute EventHandler onorientationchange;
 };
 
-HTMLFrameSetElement implements WindowEventHandlers;
+HTMLFrameSetElement includes WindowEventHandlers;
diff --git a/third_party/blink/renderer/core/html/html_iframe_element.idl b/third_party/blink/renderer/core/html/html_iframe_element.idl
index cbb6e27..9532b1d 100644
--- a/third_party/blink/renderer/core/html/html_iframe_element.idl
+++ b/third_party/blink/renderer/core/html/html_iframe_element.idl
@@ -46,7 +46,7 @@
     // https://w3c.github.io/webappsec-feature-policy/#the-policy-object
     [RuntimeEnabled=FeaturePolicyJavaScriptInterface] readonly attribute FeaturePolicy featurePolicy;
 
-    [RuntimeEnabled=LazyFrameLoading, CEReactions, Reflect, ReflectOnly=("lazy", "eager", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString load;
+    [RuntimeEnabled=LazyFrameLoading, CEReactions, Reflect, ReflectOnly=("lazy", "eager", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString loading;
 
     // obsolete members
     // https://html.spec.whatwg.org/C/#HTMLIFrameElement-partial
diff --git a/third_party/blink/renderer/core/html/html_image_element.cc b/third_party/blink/renderer/core/html/html_image_element.cc
index eca9ea1f..b8af2cc 100644
--- a/third_party/blink/renderer/core/html/html_image_element.cc
+++ b/third_party/blink/renderer/core/html/html_image_element.cc
@@ -314,7 +314,7 @@
     if (intrinsic_size_changed && GetLayoutObject() &&
         GetLayoutObject()->IsLayoutImage())
       ToLayoutImage(GetLayoutObject())->IntrinsicSizeChanged();
-  } else if (name == kLoadAttr &&
+  } else if (name == kLoadingAttr &&
              EqualIgnoringASCIICase(params.new_value, "eager") &&
              !GetDocument().IsLazyLoadPolicyEnforced()) {
     GetImageLoader().LoadDeferredImage(referrer_policy_);
diff --git a/third_party/blink/renderer/core/html/html_image_element.idl b/third_party/blink/renderer/core/html/html_image_element.idl
index 560705b..f7f066d 100644
--- a/third_party/blink/renderer/core/html/html_image_element.idl
+++ b/third_party/blink/renderer/core/html/html_image_element.idl
@@ -44,7 +44,7 @@
     [CEReactions, MeasureAs=PriorityHints, OriginTrialEnabled=PriorityHints, Reflect, ReflectOnly=("low", "auto", "high"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString importance;
     // https://github.com/ojanvafai/intrinsicsize-attribute/blob/master/README.md
     [RuntimeEnabled=ExperimentalProductivityFeatures, CEReactions, Reflect] attribute DOMString intrinsicSize;
-    [RuntimeEnabled=LazyImageLoading, CEReactions, Reflect, ReflectOnly=("lazy", "eager", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString load;
+    [RuntimeEnabled=LazyImageLoading, CEReactions, Reflect, ReflectOnly=("lazy", "eager", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString loading;
 
     // obsolete members
     // https://html.spec.whatwg.org/C/#HTMLImageElement-partial
diff --git a/third_party/blink/renderer/core/html/html_link_element.idl b/third_party/blink/renderer/core/html/html_link_element.idl
index 8f9737f..2390dbb 100644
--- a/third_party/blink/renderer/core/html/html_link_element.idl
+++ b/third_party/blink/renderer/core/html/html_link_element.idl
@@ -45,7 +45,7 @@
     [CEReactions, Reflect] attribute DOMString rev;
     [CEReactions, Reflect] attribute DOMString target;
 
-    // HTMLLinkElement implements LinkStyle
+    // HTMLLinkElement includes LinkStyle
     // https://drafts.csswg.org/cssom/#the-linkstyle-interface
     readonly attribute StyleSheet? sheet;
 
diff --git a/third_party/blink/renderer/core/html/html_style_element.idl b/third_party/blink/renderer/core/html/html_style_element.idl
index 143638e..f2134900 100644
--- a/third_party/blink/renderer/core/html/html_style_element.idl
+++ b/third_party/blink/renderer/core/html/html_style_element.idl
@@ -27,7 +27,7 @@
     [CEReactions, Reflect] attribute DOMString media;
     [CEReactions, Reflect] attribute DOMString type;
 
-    // HTMLStyleElement implements LinkStyle
+    // HTMLStyleElement includes LinkStyle
     // https://drafts.csswg.org/cssom/#the-linkstyle-interface
     readonly attribute StyleSheet? sheet;
 };
diff --git a/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc b/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc
index ebff844..bd2622e 100644
--- a/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc
+++ b/third_party/blink/renderer/core/html/lazy_load_frame_observer_test.cc
@@ -750,7 +750,7 @@
         <body onload='console.log("main body onload");'>
         <div style='height: %dpx;'></div>
         <iframe src='https://crossorigin.com/subframe.html'
-             style='width: 200px; height: 200px;' load='eager'
+             style='width: 200px; height: 200px;' loading='eager'
              onload='console.log("child frame element onload");'></iframe>
         </body>)HTML",
       kViewportHeight + GetLoadingDistanceThreshold() + 100));
@@ -798,7 +798,7 @@
           <body onload='console.log("main body onload");'>
           <div style='height: %dpx;'></div>
           <iframe src='https://example.com/subframe.html'
-               style='width: 400px; height: 400px;' load='lazy'
+               style='width: 400px; height: 400px;' loading='lazy'
                onload='console.log("child frame element onload");'></iframe>
           </body>)HTML",
       kViewportHeight + GetLoadingDistanceThreshold() + 100));
@@ -916,7 +916,7 @@
 
   Element* child_frame_element = GetDocument().getElementById("child_frame");
   ASSERT_TRUE(child_frame_element);
-  child_frame_element->setAttribute(html_names::kLoadAttr, "eager");
+  child_frame_element->setAttribute(html_names::kLoadingAttr, "eager");
 
   ExpectInitialDeferralActionHistogramSamplesIfApplicable(
       LazyLoadFrameObserver::FrameInitialDeferralAction::kDeferred, 1);
@@ -962,14 +962,14 @@
   // There's another nested cross origin iframe inside the first child frame,
   // even further down such that it's not near the viewport. If LazyLoad is
   // enabled, it should be deferred even though it's nested inside a frame that
-  // was previously deferred, because it has the attribute load=lazy.
+  // was previously deferred, because it has the attribute loading=lazy.
   base::Optional<SimRequest> nested_frame_resource;
   if (!RuntimeEnabledFeatures::LazyFrameLoadingEnabled())
     nested_frame_resource.emplace("https://test.com/", "text/html");
 
   child_frame_resource->Complete(
       String::Format("<div style='height: %dpx;'></div>"
-                     "<iframe src='https://test.com/' load='lazy'"
+                     "<iframe src='https://test.com/' loading='lazy'"
                      "     style='width: 200px; height: 200px;'>"
                      "</iframe>",
                      kViewportHeight + GetLoadingDistanceThreshold() + 100));
@@ -1001,7 +1001,7 @@
         <body onload='console.log("main body onload");'>
         <div style='height: %dpx;'></div>
         <iframe src='https://crossorigin.com/subframe.html'
-             style='width: 200px; height: 200px;' load='eager'
+             style='width: 200px; height: 200px;' loading='eager'
              onload='console.log("child frame element onload");'></iframe>
         </body>)HTML",
       kViewportHeight + GetLoadingDistanceThreshold() + 100));
@@ -1011,15 +1011,16 @@
 
   // There's another nested cross origin iframe inside the first child frame,
   // even further down such that it's not near the viewport. If LazyLoad is
-  // enabled, it should be deferred because it has the attribute load=lazy,
-  // even though it's nested inside a frame that has the attribute load=eager.
+  // enabled, it should be deferred because it has the attribute loading=lazy,
+  // even though it's nested inside a frame that has the attribute
+  // loading=eager.
   base::Optional<SimRequest> nested_frame_resource;
   if (!RuntimeEnabledFeatures::LazyFrameLoadingEnabled())
     nested_frame_resource.emplace("https://test.com/", "text/html");
 
   child_frame_resource.Complete(
       String::Format("<div style='height: %dpx;'></div>"
-                     "<iframe src='https://test.com/' load='lazy'"
+                     "<iframe src='https://test.com/' loading='lazy'"
                      "     style='width: 200px; height: 200px;'>"
                      "</iframe>",
                      kViewportHeight + GetLoadingDistanceThreshold() + 100));
@@ -1051,7 +1052,7 @@
         <body onload='console.log("main body onload");'>
         <div style='height: %dpx;'></div>
         <iframe src='https://crossorigin.com/subframe.html'
-             style='width: 200px; height: 200px;' load='eager'
+             style='width: 200px; height: 200px;' loading='eager'
              onload='console.log("child frame element onload");'></iframe>
         </body>)HTML",
       kViewportHeight + GetLoadingDistanceThreshold() + 100));
@@ -1061,14 +1062,14 @@
 
   // There's another nested cross origin iframe inside the first child frame,
   // even further down such that it's not near the viewport. Since it has the
-  // attribute load=eager, it shouldn't be deferred. Note that this also
+  // attribute loading=eager, it shouldn't be deferred. Note that this also
   // matches the default behavior that would happen if the load attribute was
   // omitted on the nested iframe entirely.
   SimRequest nested_frame_resource("https://test.com/", "text/html");
 
   child_frame_resource.Complete(
       String::Format("<div style='height: %dpx;'></div>"
-                     "<iframe src='https://test.com/' load='eager'"
+                     "<iframe src='https://test.com/' loading='eager'"
                      "     style='width: 200px; height: 200px;'>"
                      "</iframe>",
                      kViewportHeight + GetLoadingDistanceThreshold() + 100));
@@ -1211,7 +1212,7 @@
   ScopedRestrictLazyFrameLoadingToDataSaverForTest
       scoped_restrict_lazy_frame_loading_to_data_saver_for_test_(false);
 
-  TestCrossOriginFrameIsImmediatelyLoaded("load='eager'");
+  TestCrossOriginFrameIsImmediatelyLoaded("loading='eager'");
 }
 
 TEST_F(LazyLoadFramesTest, LazyLoadWhenDataSaverDisabledAndRestricted) {
@@ -1231,7 +1232,7 @@
 
   GetNetworkStateNotifier().SetSaveDataEnabled(true);
   WebView().GetPage()->GetSettings().SetDataSaverHoldbackWebApi(true);
-  TestCrossOriginFrameIsLazilyLoaded("load='lazy'");
+  TestCrossOriginFrameIsLazilyLoaded("loading='lazy'");
   TestCrossOriginFrameIsImmediatelyLoaded("");
 }
 
@@ -1254,7 +1255,7 @@
   WebView().GetPage()->GetSettings().SetDataSaverHoldbackWebApi(false);
 
   // Even when restricted to data saver, the attribute should be respected.
-  TestCrossOriginFrameIsLazilyLoaded("load='lazy'");
+  TestCrossOriginFrameIsLazilyLoaded("loading='lazy'");
   TestCrossOriginFrameIsImmediatelyLoaded("");
 }
 
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
index c9b55ed..b814db9 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
@@ -150,7 +150,7 @@
         referrer_policy_(network::mojom::ReferrerPolicy::kDefault),
         integrity_attr_set_(false),
         integrity_features_(features),
-        load_attr_value_(LoadAttrValue::kAuto),
+        loading_attr_value_(LoadingAttrValue::kAuto),
         width_attr_small_absolute_(false),
         height_attr_small_absolute_(false),
         inline_style_dimensions_small_(false),
@@ -288,10 +288,10 @@
     request->SetCharset(Charset());
     request->SetDefer(defer_);
 
-    // If the 'lazyload' feature policy is enforced, the attribute value "lazy"
-    // for the 'load' attribute is considered as 'auto'.
-    if (load_attr_value_ != LoadAttrValue::kLazy &&
-        ((load_attr_value_ == LoadAttrValue::kEager &&
+    // If the 'lazyload' feature policy is enforced, the attribute value
+    // loading='lazy' is considered as 'auto'.
+    if (loading_attr_value_ != LoadingAttrValue::kLazy &&
+        ((loading_attr_value_ == LoadingAttrValue::kEager &&
           !document_parameters.lazyload_policy_enforced) ||
          (width_attr_small_absolute_ && height_attr_small_absolute_) ||
          inline_style_dimensions_small_)) {
@@ -310,7 +310,7 @@
   }
 
  private:
-  enum class LoadAttrValue { kAuto, kLazy, kEager };
+  enum class LoadingAttrValue { kAuto, kLazy, kEager };
 
   template <typename NameType>
   void ProcessScriptAttribute(const NameType& attribute_name,
@@ -368,14 +368,15 @@
                Match(attribute_name, kImportanceAttr) &&
                priority_hints_origin_trial_enabled_) {
       SetImportance(attribute_value);
-    } else if (load_attr_value_ == LoadAttrValue::kAuto &&
-               Match(attribute_name, kLoadAttr) &&
+    } else if (loading_attr_value_ == LoadingAttrValue::kAuto &&
+               Match(attribute_name, kLoadingAttr) &&
                RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
-      load_attr_value_ = EqualIgnoringASCIICase(attribute_value, "eager")
-                             ? LoadAttrValue::kEager
-                             : EqualIgnoringASCIICase(attribute_value, "lazy")
-                                   ? LoadAttrValue::kLazy
-                                   : LoadAttrValue::kAuto;
+      loading_attr_value_ =
+          EqualIgnoringASCIICase(attribute_value, "eager")
+              ? LoadingAttrValue::kEager
+              : EqualIgnoringASCIICase(attribute_value, "lazy")
+                    ? LoadingAttrValue::kLazy
+                    : LoadingAttrValue::kAuto;
     } else if (!width_attr_small_absolute_ &&
                Match(attribute_name, kWidthAttr) &&
                RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
@@ -697,7 +698,7 @@
   bool integrity_attr_set_;
   IntegrityMetadataSet integrity_metadata_;
   SubresourceIntegrity::IntegrityFeatures integrity_features_;
-  LoadAttrValue load_attr_value_;
+  LoadingAttrValue loading_attr_value_;
   bool width_attr_small_absolute_;
   bool height_attr_small_absolute_;
   bool inline_style_dimensions_small_;
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
index 6131a3f..f6473aa 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
@@ -1231,12 +1231,12 @@
 TEST_F(HTMLPreloadScannerTest, LazyImageLoadAttributePassed) {
   ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test(true);
   LazyImageLoadTestCase test_cases[] = {
-      {"<img src='foo.jpg' load='auto'>", false},
-      {"<img src='foo.jpg' load='lazy'>", false},
-      {"<img src='foo.jpg' load='eager'>", true},
-      // load=lazy should override other conditions.
-      {"<img src='foo.jpg' style='height: 1px;' load='lazy'>", false},
-      {"<img src='foo.jpg' style='height: 1px; width: 1px' load='lazy'>",
+      {"<img src='foo.jpg' loading='auto'>", false},
+      {"<img src='foo.jpg' loading='lazy'>", false},
+      {"<img src='foo.jpg' loading='eager'>", true},
+      // loading=lazy should override other conditions.
+      {"<img src='foo.jpg' style='height: 1px;' loading='lazy'>", false},
+      {"<img src='foo.jpg' style='height: 1px; width: 1px' loading='lazy'>",
        false},
   };
   for (const auto& test_case : test_cases)
diff --git a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
index 5a80930..8cdfb10 100644
--- a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
@@ -294,8 +294,7 @@
           *GetLayoutGrid(), child, child_block_direction)) {
     SetOverrideContainingBlockContentSizeForChild(child, child_block_direction,
                                                   LayoutUnit(-1));
-    child.SetNeedsLayout(layout_invalidation_reason::kGridChanged,
-                         kMarkOnlyThis);
+    child.SetSelfNeedsLayoutForAvailableSpace(true);
   }
 
   child.LayoutIfNeeded();
@@ -325,8 +324,7 @@
 
   if (UpdateOverrideContainingBlockContentSizeForChild(
           child, child_inline_direction)) {
-    child.SetNeedsLayout(layout_invalidation_reason::kGridChanged,
-                         kMarkOnlyThis);
+    child.SetSelfNeedsLayoutForAvailableSpace(true);
   }
   return LogicalHeightForChild(child);
 }
@@ -350,8 +348,7 @@
 
   if (UpdateOverrideContainingBlockContentSizeForChild(
           child, child_inline_direction)) {
-    child.SetNeedsLayout(layout_invalidation_reason::kGridChanged,
-                         kMarkOnlyThis);
+    child.SetSelfNeedsLayoutForAvailableSpace(true);
   }
   return LogicalHeightForChild(child);
 }
@@ -540,8 +537,7 @@
     LayoutBox& child,
     bool override_size_has_changed) const {
   if (override_size_has_changed) {
-    child.SetNeedsLayout(layout_invalidation_reason::kGridChanged,
-                         kMarkOnlyThis);
+    child.SetSelfNeedsLayoutForAvailableSpace(true);
     child.LayoutIfNeeded();
   }
 }
@@ -583,8 +579,7 @@
     LayoutBox& child,
     bool override_size_has_changed) const {
   if (override_size_has_changed && Direction() != kForColumns) {
-    child.SetNeedsLayout(layout_invalidation_reason::kGridChanged,
-                         kMarkOnlyThis);
+    child.SetSelfNeedsLayoutForAvailableSpace(true);
     child.LayoutIfNeeded();
   }
 }
diff --git a/third_party/blink/renderer/core/layout/layout_grid.cc b/third_party/blink/renderer/core/layout/layout_grid.cc
index 3b11250..21ba0e0 100644
--- a/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -156,7 +156,7 @@
                                    *child) ||
           SelfAlignmentChangedSize(kGridColumnAxis, *old_style, new_style,
                                    *child)) {
-        child->SetNeedsLayout(layout_invalidation_reason::kGridChanged);
+        child->SetSelfNeedsLayoutForAvailableSpace(true);
       }
     }
   }
@@ -1220,8 +1220,7 @@
       OverrideSizeChanged(child, kForRows, grid_area_logical_size);
   if (grid_area_width_changed ||
       (grid_area_height_changed && HasRelativeBlockAxisSize(*this, child))) {
-    child.SetNeedsLayout(layout_invalidation_reason::kGridChanged,
-                         kMarkOnlyThis);
+    child.SetSelfNeedsLayoutForAvailableSpace(true);
   }
 
   child.SetOverrideContainingBlockContentLogicalWidth(
@@ -1507,7 +1506,7 @@
       // TODO (lajava): Can avoid laying out here in some cases. See
       // https://webkit.org/b/87905.
       child.SetLogicalHeight(LayoutUnit());
-      child.SetNeedsLayout(layout_invalidation_reason::kGridChanged);
+      child.SetSelfNeedsLayoutForAvailableSpace(true);
     }
   }
 }
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index b8659aed..4a61837 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -120,6 +120,20 @@
 
 namespace {
 
+// In order for an image to be rendered from the content property, there can be
+// at most one piece of image content data, followed by some optional
+// alternative text.
+bool ShouldUseContentData(const ContentData* content_data) {
+  if (!content_data)
+    return false;
+  if (!content_data->IsImage())
+    return false;
+  if (content_data->Next() && !content_data->Next()->IsAltText())
+    return false;
+
+  return true;
+}
+
 template <typename Predicate>
 LayoutObject* FindAncestorByPredicate(const LayoutObject* descendant,
                                       LayoutObject::AncestorSkipInfo* skip_info,
@@ -213,16 +227,16 @@
   DCHECK(IsAllowedToModifyLayoutTreeStructure(element->GetDocument()));
 
   // Minimal support for content properties replacing an entire element.
-  // Works only if we have exactly one piece of content and it's a URL.
-  // Otherwise acts as if we didn't support this feature.
+  // Works only if we have exactly one piece of content and it's a URL, with
+  // some optional alternative text. Otherwise acts as if we didn't support this
+  // feature.
   const ContentData* content_data = style.GetContentData();
-  if (content_data && !content_data->Next() && content_data->IsImage() &&
-      !element->IsPseudoElement()) {
+  if (!element->IsPseudoElement() && ShouldUseContentData(content_data)) {
     LayoutImage* image = new LayoutImage(element);
-    // LayoutImageResourceStyleImage requires a style being present on the image
-    // but we don't want to trigger a style change now as the node is not fully
-    // attached. Moving this code to style change doesn't make sense as it
-    // should be run once at layoutObject creation.
+    // LayoutImageResourceStyleImage requires a style being present on the
+    // image but we don't want to trigger a style change now as the node is
+    // not fully attached. Moving this code to style change doesn't make sense
+    // as it should be run once at layoutObject creation.
     image->SetStyleInternal(const_cast<ComputedStyle*>(&style));
     if (const StyleImage* style_image =
             To<ImageContentData>(content_data)->GetImage()) {
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 f74eb42..ee045cad 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
@@ -233,6 +233,11 @@
   scoped_refptr<const NGLayoutResult> layout_result =
       box_->CachedLayoutResult(constraint_space, break_token);
   if (layout_result) {
+    // We may have to update the margins on box_; we reuse the layout result
+    // even if a percentage margin may have changed.
+    if (UNLIKELY(Style().MayHaveMargin() && !IsTableCell()))
+      box_->SetMargin(ComputePhysicalMargins(constraint_space, Style()));
+
     // TODO(layoutng): Figure out why these two call can't be inside the
     // !constraint_space.IsIntermediateLayout() block below.
     UpdateShapeOutsideInfoIfNeeded(
diff --git a/third_party/blink/renderer/core/loader/frame_load_request.h b/third_party/blink/renderer/core/loader/frame_load_request.h
index b8e69efa..fdb5216 100644
--- a/third_party/blink/renderer/core/loader/frame_load_request.h
+++ b/third_party/blink/renderer/core/loader/frame_load_request.h
@@ -29,7 +29,6 @@
 #include "services/network/public/mojom/request_context_frame_type.mojom-shared.h"
 #include "third_party/blink/public/mojom/blob/blob_url_store.mojom-blink.h"
 #include "third_party/blink/public/web/web_triggering_event_info.h"
-#include "third_party/blink/public/web/web_window_features.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/frame_types.h"
 #include "third_party/blink/renderer/core/loader/frame_loader_types.h"
@@ -147,15 +146,6 @@
 
   base::TimeTicks GetInputStartTime() const { return input_start_time_; }
 
-  const WebWindowFeatures& GetWindowFeatures() const {
-    return window_features_;
-  }
-  void SetFeaturesForWindowOpen(const WebWindowFeatures& features) {
-    window_features_ = features;
-    is_window_open_ = true;
-  }
-  bool IsWindowOpen() const { return is_window_open_; }
-
  private:
   Member<Document> origin_document_;
   ResourceRequest resource_request_;
@@ -175,8 +165,6 @@
   base::TimeTicks input_start_time_;
   network::mojom::RequestContextFrameType frame_type_ =
       network::mojom::RequestContextFrameType::kNone;
-  WebWindowFeatures window_features_;
-  bool is_window_open_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index b735a3bf..cec7e21 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -797,32 +797,22 @@
   if (!PrepareRequestForThisFrame(request))
     return;
 
-  SetReferrerForFrameRequest(request);
+  Frame* target_frame = frame_->FindFrameForNavigation(
+      AtomicString(request.FrameName()), *frame_, url);
 
-  // A GetNavigationPolicy() value other than kNavigationPolicyCurrentTab at
-  // this point indicates that a user event modified the navigation policy
-  // (e.g., a ctrl-click). Let the user's action override any target attribute.
-  if (request.GetNavigationPolicy() == kNavigationPolicyCurrentTab) {
-    Frame* target_frame = frame_->FindFrameForNavigation(
-        AtomicString(request.FrameName()), *frame_, url);
-    if (!target_frame) {
-      request.SetNavigationPolicy(kNavigationPolicyNewForegroundTab);
-      bool created = false;
-      target_frame = CreateNewWindow(*frame_.Get(), request, created);
-      if (!target_frame)
-        return;
-    }
+  // Downloads and navigations which specifically target a *new* frame
+  // (e.g. because of a ctrl-click) should ignore the target.
+  bool should_navigate_target_frame =
+      request.GetNavigationPolicy() == kNavigationPolicyCurrentTab;
 
-    if (target_frame != frame_) {
-      bool was_in_same_page = target_frame->GetPage() == frame_->GetPage();
-      request.SetFrameName("_self");
-      request.SetNavigationPolicy(kNavigationPolicyCurrentTab);
-      target_frame->Navigate(request, frame_load_type);
-      Page* page = target_frame->GetPage();
-      if (!was_in_same_page && page)
-        page->GetChromeClient().Focus(frame_);
-      return;
-    }
+  if (target_frame && target_frame != frame_ && should_navigate_target_frame) {
+    bool was_in_same_page = target_frame->GetPage() == frame_->GetPage();
+    request.SetFrameName("_self");
+    target_frame->Navigate(request, frame_load_type);
+    Page* page = target_frame->GetPage();
+    if (!was_in_same_page && page)
+      page->GetChromeClient().Focus(frame_);
+    return;
   }
 
   // Block renderer-initiated loads of data: and filesystem: URLs in the top
@@ -847,6 +837,16 @@
     return;
   }
 
+  SetReferrerForFrameRequest(request);
+
+  if (!target_frame && !request.FrameName().IsEmpty() &&
+      should_navigate_target_frame) {
+    request.SetFrameType(network::mojom::RequestContextFrameType::kAuxiliary);
+    request.SetNavigationPolicy(kNavigationPolicyNewForegroundTab);
+    CreateWindowForRequest(request, *frame_);
+    return;  // Navigation will be handled by the new frame/window.
+  }
+
   // TODO(dgozman): merge page dismissal check and FrameNavigationDisabler.
   if (!frame_->IsNavigationAllowed() ||
       frame_->GetDocument()->PageDismissalEventBeingDispatched() !=
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc
index 5cfff2c..89635e0b 100644
--- a/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -75,7 +75,7 @@
     return false;
 
   if (EqualIgnoringASCIICase(
-          html_image->FastGetAttribute(html_names::kLoadAttr), "lazy"))
+          html_image->FastGetAttribute(html_names::kLoadingAttr), "lazy"))
     return true;
 
   // Do not lazyload image elements created from javascript.
@@ -83,7 +83,7 @@
     return false;
 
   if (EqualIgnoringASCIICase(
-          html_image->FastGetAttribute(html_names::kLoadAttr), "eager") &&
+          html_image->FastGetAttribute(html_names::kLoadingAttr), "eager") &&
       !frame->GetDocument()->IsLazyLoadPolicyEnforced()) {
     return false;
   }
diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc
index dab84de..023516a 100644
--- a/third_party/blink/renderer/core/page/create_window.cc
+++ b/third_party/blink/renderer/core/page/create_window.cc
@@ -33,15 +33,19 @@
 #include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/frame/from_ad_state.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/web/web_view_client.h"
 #include "third_party/blink/public/web/web_window_features.h"
 #include "third_party/blink/renderer/core/core_initializer.h"
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/events/current_input_event.h"
 #include "third_party/blink/renderer/core/exported/web_view_impl.h"
 #include "third_party/blink/renderer/core/frame/ad_tracker.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/frame_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -49,6 +53,8 @@
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.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/weborigin/security_policy.h"
 
 namespace blink {
 
@@ -201,43 +207,20 @@
   }
 }
 
-Frame* CreateNewWindow(LocalFrame& opener_frame,
-                       FrameLoadRequest& request,
-                       bool& created) {
+static Frame* CreateNewWindow(LocalFrame& opener_frame,
+                              const FrameLoadRequest& request,
+                              const WebWindowFeatures& features,
+                              bool& created) {
   DCHECK(request.GetResourceRequest().RequestorOrigin() ||
          opener_frame.GetDocument()->Url().IsEmpty());
-
-  // Exempting window.open() from this check here is necessary to support a
-  // special policy that will be removed in Chrome 82.
-  // See https://crbug.com/937569
-  if (!request.IsWindowOpen() &&
-      opener_frame.GetDocument()->PageDismissalEventBeingDispatched() !=
-          Document::kNoDismissal) {
-    return nullptr;
-  }
-
-  request.SetFrameType(network::mojom::RequestContextFrameType::kAuxiliary);
+  DCHECK_EQ(request.GetFrameType(),
+            network::mojom::RequestContextFrameType::kAuxiliary);
 
   const KURL& url = request.GetResourceRequest().Url();
-  if (url.ProtocolIsJavaScript() &&
-      opener_frame.GetDocument()->GetContentSecurityPolicy() &&
-      !ContentSecurityPolicy::ShouldBypassMainWorld(
-          opener_frame.GetDocument())) {
-    String script_source = DecodeURLEscapeSequences(
-        url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
-
-    if (!opener_frame.GetDocument()->GetContentSecurityPolicy()->AllowInline(
-            ContentSecurityPolicy::InlineType::kNavigation,
-            nullptr /* element */, script_source, String() /* nonce */,
-            opener_frame.GetDocument()->Url(), OrdinalNumber())) {
-      return nullptr;
-    }
-  }
-
-  const WebWindowFeatures& features = request.GetWindowFeatures();
   probe::WindowOpen(opener_frame.GetDocument(), url, request.FrameName(),
                     features,
                     LocalFrame::HasTransientUserActivation(&opener_frame));
+  created = false;
 
   // Sandboxed frames cannot open new auxiliary browsing contexts.
   if (opener_frame.GetDocument()->IsSandboxed(WebSandboxFlags::kPopups)) {
@@ -282,16 +265,6 @@
   if (!page)
     return nullptr;
 
-  auto* new_local_frame = DynamicTo<LocalFrame>(page->MainFrame());
-  if (request.GetShouldSendReferrer() == kMaybeSendReferrer) {
-    // TODO(japhet): Does network::mojom::ReferrerPolicy need to be proagated
-    // for RemoteFrames?
-    if (new_local_frame) {
-      new_local_frame->GetDocument()->SetReferrerPolicy(
-          opener_frame.GetDocument()->GetReferrerPolicy());
-    }
-  }
-
   if (page == old_page) {
     Frame* frame = &opener_frame.Tree().Top();
     if (!opener_frame.CanNavigate(*frame))
@@ -326,4 +299,122 @@
   return &frame;
 }
 
+DOMWindow* CreateWindow(const KURL& completed_url,
+                        const AtomicString& frame_name,
+                        const WebWindowFeatures& window_features,
+                        LocalDOMWindow& incumbent_window,
+                        LocalFrame& opener_frame) {
+  LocalFrame* active_frame = incumbent_window.GetFrame();
+  DCHECK(active_frame);
+
+  if (completed_url.ProtocolIsJavaScript() &&
+      opener_frame.GetDocument()->GetContentSecurityPolicy() &&
+      !ContentSecurityPolicy::ShouldBypassMainWorld(
+          opener_frame.GetDocument())) {
+    String script_source = DecodeURLEscapeSequences(
+        completed_url.GetString(), DecodeURLMode::kUTF8OrIsomorphic);
+
+    if (!opener_frame.GetDocument()->GetContentSecurityPolicy()->AllowInline(
+            ContentSecurityPolicy::InlineType::kNavigation,
+            nullptr /* element */, script_source, String() /* nonce */,
+            opener_frame.GetDocument()->Url(), OrdinalNumber())) {
+      return nullptr;
+    }
+  }
+
+  FrameLoadRequest frame_request(incumbent_window.document(),
+                                 ResourceRequest(completed_url), frame_name);
+  frame_request.SetNavigationPolicy(
+      NavigationPolicyForCreateWindow(window_features));
+  frame_request.SetShouldSetOpener(window_features.noopener ? kNeverSetOpener
+                                                            : kMaybeSetOpener);
+  frame_request.SetFrameType(
+      network::mojom::RequestContextFrameType::kAuxiliary);
+
+  // Normally, FrameLoader would take care of setting the referrer for a
+  // navigation that is triggered from javascript. However, creating a window
+  // goes through sufficient processing that it eventually enters FrameLoader as
+  // an embedder-initiated navigation.  FrameLoader assumes no responsibility
+  // for generating an embedder-initiated navigation's referrer, so we need to
+  // ensure the proper referrer is set now.
+  // TODO(domfarolino): Stop setting ResourceRequest's HTTP Referrer and store
+  // this is a separate member. See https://crbug.com/850813.
+  frame_request.GetResourceRequest().SetHttpReferrer(
+      SecurityPolicy::GenerateReferrer(
+          active_frame->GetDocument()->GetReferrerPolicy(), completed_url,
+          active_frame->GetDocument()->OutgoingReferrer()));
+
+  // Records HasUserGesture before the value is invalidated inside
+  // createWindow(LocalFrame& openerFrame, ...).
+  // This value will be set in ResourceRequest loaded in a new LocalFrame.
+  bool has_user_gesture = LocalFrame::HasTransientUserActivation(&opener_frame);
+  opener_frame.MaybeLogAdClickNavigation();
+
+  // We pass the opener frame for the lookupFrame in case the active frame is
+  // different from the opener frame, and the name references a frame relative
+  // to the opener frame.
+  bool created;
+  Frame* new_frame =
+      CreateNewWindow(opener_frame, frame_request, window_features, created);
+  if (!new_frame)
+    return nullptr;
+  if (new_frame->DomWindow()->IsInsecureScriptAccess(incumbent_window,
+                                                     completed_url))
+    return window_features.noopener ? nullptr : new_frame->DomWindow();
+
+  if (created || !completed_url.IsEmpty()) {
+    FrameLoadRequest request(incumbent_window.document(),
+                             ResourceRequest(completed_url));
+    request.GetResourceRequest().SetHasUserGesture(has_user_gesture);
+    if (const WebInputEvent* input_event = CurrentInputEvent::Get()) {
+      request.SetInputStartTime(input_event->TimeStamp());
+    }
+    new_frame->Navigate(request, WebFrameLoadType::kStandard);
+  }
+  return window_features.noopener ? nullptr : new_frame->DomWindow();
+}
+
+void CreateWindowForRequest(const FrameLoadRequest& request,
+                            LocalFrame& opener_frame) {
+  DCHECK(request.GetResourceRequest().RequestorOrigin() ||
+         (opener_frame.GetDocument() &&
+          opener_frame.GetDocument()->Url().IsEmpty()));
+
+  if (opener_frame.GetDocument()->PageDismissalEventBeingDispatched() !=
+      Document::kNoDismissal)
+    return;
+
+  if (opener_frame.GetDocument() &&
+      opener_frame.GetDocument()->IsSandboxed(WebSandboxFlags::kPopups))
+    return;
+
+  WebWindowFeatures features;
+  features.noopener = request.GetShouldSetOpener() == kNeverSetOpener;
+  bool created;
+  Frame* new_frame = CreateNewWindow(opener_frame, request, features, created);
+  if (!new_frame)
+    return;
+  auto* new_local_frame = DynamicTo<LocalFrame>(new_frame);
+  if (request.GetShouldSendReferrer() == kMaybeSendReferrer) {
+    // TODO(japhet): Does network::mojom::ReferrerPolicy need to be proagated
+    // for RemoteFrames?
+    if (new_local_frame) {
+      new_local_frame->GetDocument()->SetReferrerPolicy(
+          opener_frame.GetDocument()->GetReferrerPolicy());
+    }
+  }
+
+  // TODO(japhet): Form submissions on RemoteFrames don't work yet.
+  FrameLoadRequest new_request(nullptr, request.GetResourceRequest());
+  new_request.SetForm(request.Form());
+  if (const WebInputEvent* input_event = CurrentInputEvent::Get()) {
+    new_request.SetInputStartTime(input_event->TimeStamp());
+  }
+  auto blob_url_token = request.GetBlobURLToken();
+  if (blob_url_token)
+    new_request.SetBlobURLToken(std::move(blob_url_token));
+  if (new_local_frame)
+    new_local_frame->Loader().StartNavigation(new_request);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/create_window.h b/third_party/blink/renderer/core/page/create_window.h
index d11a26b..11e635ae4 100644
--- a/third_party/blink/renderer/core/page/create_window.h
+++ b/third_party/blink/renderer/core/page/create_window.h
@@ -28,17 +28,23 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_CREATE_WINDOW_H_
 
 #include "third_party/blink/public/web/web_window_features.h"
-#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
+// To avoid conflicts with the CreateWindow macro from the Windows SDK...
+#undef CreateWindow
+
 namespace blink {
-class Frame;
 class LocalFrame;
 struct FrameLoadRequest;
 
-Frame* CreateNewWindow(LocalFrame& opener_frame,
-                       FrameLoadRequest&,
-                       bool& created);
+DOMWindow* CreateWindow(const KURL& completed_url,
+                        const AtomicString& frame_name,
+                        const WebWindowFeatures&,
+                        LocalDOMWindow& incumbent_window,
+                        LocalFrame& opener_frame);
+
+void CreateWindowForRequest(const FrameLoadRequest&, LocalFrame& opener_frame);
 
 CORE_EXPORT WebWindowFeatures GetWindowFeaturesFromString(const String&);
 
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.cc b/third_party/blink/renderer/core/page/spatial_navigation.cc
index 5da6a2b..7c018421 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -49,10 +49,7 @@
 static void DeflateIfOverlapped(LayoutRect&, LayoutRect&);
 
 FocusCandidate::FocusCandidate(Node* node, SpatialNavigationDirection direction)
-    : visible_node(nullptr),
-      focusable_node(nullptr),
-      is_offscreen(true),
-      is_offscreen_after_scrolling(true) {
+    : visible_node(nullptr), focusable_node(nullptr), is_offscreen(true) {
   DCHECK(node);
   DCHECK(node->IsElementNode());
 
@@ -73,8 +70,6 @@
 
   focusable_node = node;
   is_offscreen = IsOffscreen(visible_node);
-  is_offscreen_after_scrolling =
-      IsOffscreenAfterFrameScroll(visible_node, direction);
 }
 
 bool IsSpatialNavigationEnabled(const LocalFrame* frame) {
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.h b/third_party/blink/renderer/core/page/spatial_navigation.h
index 44c0c02..eccdac7 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.h
+++ b/third_party/blink/renderer/core/page/spatial_navigation.h
@@ -51,10 +51,7 @@
 
  public:
   FocusCandidate()
-      : visible_node(nullptr),
-        focusable_node(nullptr),
-        is_offscreen(true),
-        is_offscreen_after_scrolling(true) {}
+      : visible_node(nullptr), focusable_node(nullptr), is_offscreen(true) {}
 
   FocusCandidate(Node*, SpatialNavigationDirection);
   explicit FocusCandidate(HTMLAreaElement*, SpatialNavigationDirection);
@@ -71,13 +68,10 @@
   Member<Node> focusable_node;
   LayoutRect rect_in_root_frame;
   bool is_offscreen;
-  bool is_offscreen_after_scrolling;
 };
 
 CORE_EXPORT bool HasRemoteFrame(const Node*);
 CORE_EXPORT bool IsOffscreen(const Node*);
-CORE_EXPORT bool IsOffscreenAfterFrameScroll(const Node*,
-                                             SpatialNavigationDirection);
 bool ScrollInDirection(Node* container, SpatialNavigationDirection);
 CORE_EXPORT bool IsScrollableNode(const Node* node);
 CORE_EXPORT bool IsScrollableAreaOrDocument(const Node*);
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
index 3f4cd49..7b2b3b94 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -81,7 +81,7 @@
 
   // Ignore off-screen focusables that are not exposed after one "scroll step"
   // in the direction.
-  if (candidate.is_offscreen && candidate.is_offscreen_after_scrolling)
+  if (candidate.is_offscreen)
     return;
 
   double distance =
diff --git a/third_party/blink/renderer/core/svg/svg_a_element.idl b/third_party/blink/renderer/core/svg/svg_a_element.idl
index c8a8956a..29e46a3 100644
--- a/third_party/blink/renderer/core/svg/svg_a_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_a_element.idl
@@ -29,4 +29,4 @@
     [ImplementedAs=svgTarget, Measure] readonly attribute SVGAnimatedString target;
 };
 
-SVGAElement implements SVGURIReference;
+SVGAElement includes SVGURIReference;
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.idl b/third_party/blink/renderer/core/svg/svg_animation_element.idl
index a56ef3d..23be2805 100644
--- a/third_party/blink/renderer/core/svg/svg_animation_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_animation_element.idl
@@ -43,4 +43,4 @@
     [MeasureAs=SVGSMILBeginEndAnimationElement] void endElementAt(float offset);
 };
 
-SVGAnimationElement implements SVGTests;
+SVGAnimationElement includes SVGTests;
diff --git a/third_party/blink/renderer/core/svg/svg_element.idl b/third_party/blink/renderer/core/svg/svg_element.idl
index c98affb..57a07d3 100644
--- a/third_party/blink/renderer/core/svg/svg_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_element.idl
@@ -36,6 +36,6 @@
     void blur();
 };
 
-SVGElement implements GlobalEventHandlers;
-SVGElement implements DocumentAndElementEventHandlers;
-SVGElement implements NoncedElement;
+SVGElement includes GlobalEventHandlers;
+SVGElement includes DocumentAndElementEventHandlers;
+SVGElement includes NoncedElement;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_blend_element.idl b/third_party/blink/renderer/core/svg/svg_fe_blend_element.idl
index 5f7487b..a59c5700 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_blend_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_blend_element.idl
@@ -53,4 +53,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration mode;
 };
 
-SVGFEBlendElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEBlendElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.idl b/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.idl
index c39f3cc..48a98cd 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.idl
@@ -40,4 +40,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumberList values;
 };
 
-SVGFEColorMatrixElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEColorMatrixElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.idl b/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.idl
index b8cd25b..dcb417db5 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.idl
@@ -29,4 +29,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1;
 };
 
-SVGFEComponentTransferElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEComponentTransferElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_composite_element.idl b/third_party/blink/renderer/core/svg/svg_fe_composite_element.idl
index af2826ce..4723b018 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_composite_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_composite_element.idl
@@ -46,4 +46,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber k4;
 };
 
-SVGFECompositeElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFECompositeElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.idl b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.idl
index e628d4a..d1b8c08 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.idl
@@ -48,4 +48,4 @@
     [Measure] readonly attribute SVGAnimatedBoolean preserveAlpha;
 };
 
-SVGFEConvolveMatrixElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEConvolveMatrixElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.idl b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.idl
index a7dd44b..b03edec 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.idl
@@ -33,4 +33,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber kernelUnitLengthY;
 };
 
-SVGFEDiffuseLightingElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEDiffuseLightingElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.idl b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.idl
index 4c765273..c2879c4c 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.idl
@@ -42,4 +42,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration yChannelSelector;
 };
 
-SVGFEDisplacementMapElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEDisplacementMapElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.idl b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.idl
index 801e5de9..d07d5b45 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.idl
@@ -29,4 +29,4 @@
     [MeasureAs=SVG1DOMFilter] void setStdDeviation(float stdDeviationX, float stdDeviationY);
 };
 
-SVGFEDropShadowElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEDropShadowElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_flood_element.idl b/third_party/blink/renderer/core/svg/svg_fe_flood_element.idl
index 08924a0d..973cc2e 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_flood_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_flood_element.idl
@@ -28,4 +28,4 @@
 interface SVGFEFloodElement : SVGElement {
 };
 
-SVGFEFloodElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEFloodElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.idl b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.idl
index 02487e2..a0fc0861 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.idl
@@ -33,4 +33,4 @@
     [MeasureAs=SVG1DOMFilter] void setStdDeviation(float stdDeviationX, float stdDeviationY);
 };
 
-SVGFEGaussianBlurElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEGaussianBlurElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_image_element.idl b/third_party/blink/renderer/core/svg/svg_fe_image_element.idl
index 585f4b9..b9c4661 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_image_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_image_element.idl
@@ -29,5 +29,5 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
 };
 
-SVGFEImageElement implements SVGFilterPrimitiveStandardAttributes;
-SVGFEImageElement implements SVGURIReference;
+SVGFEImageElement includes SVGFilterPrimitiveStandardAttributes;
+SVGFEImageElement includes SVGURIReference;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_merge_element.idl b/third_party/blink/renderer/core/svg/svg_fe_merge_element.idl
index ab157b85..d53acda 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_merge_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_merge_element.idl
@@ -28,4 +28,4 @@
 interface SVGFEMergeElement : SVGElement {
 };
 
-SVGFEMergeElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEMergeElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.idl b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.idl
index 185408d..9187763 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.idl
@@ -39,4 +39,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber radiusY;
 };
 
-SVGFEMorphologyElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEMorphologyElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_offset_element.idl b/third_party/blink/renderer/core/svg/svg_fe_offset_element.idl
index 02f3c46..5278f274 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_offset_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_offset_element.idl
@@ -31,4 +31,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber dy;
 };
 
-SVGFEOffsetElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFEOffsetElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.idl b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.idl
index c9a5924..56470b1e 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.idl
@@ -34,4 +34,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber kernelUnitLengthY;
 };
 
-SVGFESpecularLightingElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFESpecularLightingElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_tile_element.idl b/third_party/blink/renderer/core/svg/svg_fe_tile_element.idl
index 703b2ff..39cd920 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_tile_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_tile_element.idl
@@ -29,4 +29,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1;
 };
 
-SVGFETileElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFETileElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.idl b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.idl
index b7049138..6259e4bb 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.idl
@@ -46,4 +46,4 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration type;
 };
 
-SVGFETurbulenceElement implements SVGFilterPrimitiveStandardAttributes;
+SVGFETurbulenceElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_filter_element.idl b/third_party/blink/renderer/core/svg/svg_filter_element.idl
index e7fd4458..598013f 100644
--- a/third_party/blink/renderer/core/svg/svg_filter_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_filter_element.idl
@@ -35,5 +35,5 @@
     [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedLength      height;
 };
 
-SVGFilterElement implements SVGURIReference;
-// SVGFilterElement implements SVGUnitTypes;
+SVGFilterElement includes SVGURIReference;
+// SVGFilterElement includes SVGUnitTypes;
diff --git a/third_party/blink/renderer/core/svg/svg_gradient_element.idl b/third_party/blink/renderer/core/svg/svg_gradient_element.idl
index d3abb19..5fb065d 100644
--- a/third_party/blink/renderer/core/svg/svg_gradient_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_gradient_element.idl
@@ -39,5 +39,5 @@
     [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedEnumeration   spreadMethod;
 };
 
-SVGGradientElement implements SVGURIReference;
-// SVGGradientElement implements SVGUnitTypes;
+SVGGradientElement includes SVGURIReference;
+// SVGGradientElement includes SVGUnitTypes;
diff --git a/third_party/blink/renderer/core/svg/svg_graphics_element.idl b/third_party/blink/renderer/core/svg/svg_graphics_element.idl
index f27e75d..5f9b1d6e 100644
--- a/third_party/blink/renderer/core/svg/svg_graphics_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_graphics_element.idl
@@ -44,4 +44,4 @@
     [MeasureAs=SVGLocatableFarthestViewportElement] readonly attribute SVGElement farthestViewportElement;
 };
 
-SVGGraphicsElement implements SVGTests;
+SVGGraphicsElement includes SVGTests;
diff --git a/third_party/blink/renderer/core/svg/svg_image_element.idl b/third_party/blink/renderer/core/svg/svg_image_element.idl
index b4339886..951eee16 100644
--- a/third_party/blink/renderer/core/svg/svg_image_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_image_element.idl
@@ -41,4 +41,4 @@
     [CallWith=ScriptState, RaisesException] Promise<void> decode();
 };
 
-SVGImageElement implements SVGURIReference;
+SVGImageElement includes SVGURIReference;
diff --git a/third_party/blink/renderer/core/svg/svg_marker_element.idl b/third_party/blink/renderer/core/svg/svg_marker_element.idl
index 610dfaf..edd8c75 100644
--- a/third_party/blink/renderer/core/svg/svg_marker_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_marker_element.idl
@@ -50,4 +50,4 @@
     [MeasureAs=SVG1DOMMarkerElement] void setOrientToAngle(SVGAngle angle);
 };
 
-SVGMarkerElement implements SVGFitToViewBox;
+SVGMarkerElement includes SVGFitToViewBox;
diff --git a/third_party/blink/renderer/core/svg/svg_mask_element.idl b/third_party/blink/renderer/core/svg/svg_mask_element.idl
index 471df3da..6cb896b 100644
--- a/third_party/blink/renderer/core/svg/svg_mask_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_mask_element.idl
@@ -34,7 +34,7 @@
     [MeasureAs=SVG1DOMMaskElement] readonly attribute SVGAnimatedLength height;
 };
 
-// SVGMaskElement implements SVGUnitTypes;
+// SVGMaskElement includes SVGUnitTypes;
 
 // TODO(foolip): The following is not part of any spec. https://crbug.com/701893
-SVGMaskElement implements SVGTests;
+SVGMaskElement includes SVGTests;
diff --git a/third_party/blink/renderer/core/svg/svg_mpath_element.idl b/third_party/blink/renderer/core/svg/svg_mpath_element.idl
index 7889bbb..332e69aa 100644
--- a/third_party/blink/renderer/core/svg/svg_mpath_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_mpath_element.idl
@@ -28,4 +28,4 @@
 interface SVGMPathElement : SVGElement {
 };
 
-SVGMPathElement implements SVGURIReference;
+SVGMPathElement includes SVGURIReference;
diff --git a/third_party/blink/renderer/core/svg/svg_pattern_element.idl b/third_party/blink/renderer/core/svg/svg_pattern_element.idl
index fba4f7b..121f9b0 100644
--- a/third_party/blink/renderer/core/svg/svg_pattern_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_pattern_element.idl
@@ -35,10 +35,10 @@
     [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength height;
 };
 
-SVGPatternElement implements SVGFitToViewBox;
-SVGPatternElement implements SVGURIReference;
-// SVGPatternElement implements SVGUnitTypes;
+SVGPatternElement includes SVGFitToViewBox;
+SVGPatternElement includes SVGURIReference;
+// SVGPatternElement includes SVGUnitTypes;
 
 // TODO(foolip): The following was part of SVG 1.1. https://crbug.com/701893
 // http://www.w3.org/TR/SVG11/pservers.html#InterfaceSVGPatternElement
-SVGPatternElement implements SVGTests;
+SVGPatternElement includes SVGTests;
diff --git a/third_party/blink/renderer/core/svg/svg_script_element.idl b/third_party/blink/renderer/core/svg/svg_script_element.idl
index 52d84e7..8ab0ade 100644
--- a/third_party/blink/renderer/core/svg/svg_script_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_script_element.idl
@@ -29,4 +29,4 @@
     [Reflect] attribute DOMString type;
 };
 
-SVGScriptElement implements SVGURIReference;
+SVGScriptElement includes SVGURIReference;
diff --git a/third_party/blink/renderer/core/svg/svg_style_element.idl b/third_party/blink/renderer/core/svg/svg_style_element.idl
index 47965340..59fe6ac 100644
--- a/third_party/blink/renderer/core/svg/svg_style_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_style_element.idl
@@ -31,7 +31,7 @@
     attribute DOMString media;
     [MeasureAs=SVGStyleElementTitle] attribute DOMString title;
 
-    // SVGStyleElement implements LinkStyle
+    // SVGStyleElement includes LinkStyle
     // https://drafts.csswg.org/cssom/#the-linkstyle-interface
     readonly attribute StyleSheet? sheet;
 
diff --git a/third_party/blink/renderer/core/svg/svg_svg_element.idl b/third_party/blink/renderer/core/svg/svg_svg_element.idl
index 0643aed..898a11c 100644
--- a/third_party/blink/renderer/core/svg/svg_svg_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_svg_element.idl
@@ -66,5 +66,5 @@
     [MeasureAs=SVGSMILCurrentTime] void setCurrentTime(float seconds);
 };
 
-SVGSVGElement implements SVGFitToViewBox;
-SVGSVGElement implements SVGZoomAndPan;
+SVGSVGElement includes SVGFitToViewBox;
+SVGSVGElement includes SVGZoomAndPan;
diff --git a/third_party/blink/renderer/core/svg/svg_symbol_element.idl b/third_party/blink/renderer/core/svg/svg_symbol_element.idl
index f2c657ba..7b5298a8 100644
--- a/third_party/blink/renderer/core/svg/svg_symbol_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_symbol_element.idl
@@ -28,4 +28,4 @@
 interface SVGSymbolElement : SVGElement {
 };
 
-SVGSymbolElement implements SVGFitToViewBox;
+SVGSymbolElement includes SVGFitToViewBox;
diff --git a/third_party/blink/renderer/core/svg/svg_text_path_element.idl b/third_party/blink/renderer/core/svg/svg_text_path_element.idl
index 8aee74f..2aea585 100644
--- a/third_party/blink/renderer/core/svg/svg_text_path_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_text_path_element.idl
@@ -41,5 +41,5 @@
     [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedEnumeration spacing;
 };
 
-SVGTextPathElement implements SVGURIReference;
-//SVGTextPathElement implements SVGAnimatedPathData;
+SVGTextPathElement includes SVGURIReference;
+//SVGTextPathElement includes SVGAnimatedPathData;
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.idl b/third_party/blink/renderer/core/svg/svg_use_element.idl
index b096a2f9..487f78ad 100644
--- a/third_party/blink/renderer/core/svg/svg_use_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_use_element.idl
@@ -32,4 +32,4 @@
     [MeasureAs=SVG1DOMUseElement] readonly attribute SVGAnimatedLength   height;
 };
 
-SVGUseElement implements SVGURIReference;
+SVGUseElement includes SVGURIReference;
diff --git a/third_party/blink/renderer/core/svg/svg_view_element.idl b/third_party/blink/renderer/core/svg/svg_view_element.idl
index 731a978..53626f2 100644
--- a/third_party/blink/renderer/core/svg/svg_view_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_view_element.idl
@@ -28,5 +28,5 @@
 interface SVGViewElement : SVGElement {
 };
 
-SVGViewElement implements SVGFitToViewBox;
-SVGViewElement implements SVGZoomAndPan;
+SVGViewElement includes SVGFitToViewBox;
+SVGViewElement includes SVGZoomAndPan;
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 6a8ddc20..9fe4d52 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -174,7 +174,7 @@
 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
 #include "third_party/blink/renderer/platform/text/layout_locale.h"
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
-#include "third_party/blink/renderer/platform/wtf/dtoa.h"
+#include "third_party/blink/renderer/platform/wtf/dtoa/dtoa.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
 #include "v8/include/v8.h"
diff --git a/third_party/blink/renderer/core/workers/shared_worker.idl b/third_party/blink/renderer/core/workers/shared_worker.idl
index 3f54076..74008ed 100644
--- a/third_party/blink/renderer/core/workers/shared_worker.idl
+++ b/third_party/blink/renderer/core/workers/shared_worker.idl
@@ -44,4 +44,4 @@
     readonly attribute MessagePort port;
 };
 
-SharedWorker implements AbstractWorker;
+SharedWorker includes AbstractWorker;
diff --git a/third_party/blink/renderer/core/workers/worker.idl b/third_party/blink/renderer/core/workers/worker.idl
index e66dd1cd..a0e36b3 100644
--- a/third_party/blink/renderer/core/workers/worker.idl
+++ b/third_party/blink/renderer/core/workers/worker.idl
@@ -42,4 +42,4 @@
     attribute EventHandler onmessage;
 };
 
-Worker implements AbstractWorker;
+Worker includes AbstractWorker;
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.cc b/third_party/blink/renderer/core/workers/worker_global_scope.cc
index 3378eca..9817b5b 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -254,9 +254,9 @@
     ErrorEvent* error_event = nullptr;
     SingleCachedMetadataHandler* handler(
         CreateWorkerScriptCachedMetadataHandler(complete_url,
-                                                cached_meta_data.get()));
+                                                std::move(cached_meta_data)));
     ReportingProxy().WillEvaluateImportedClassicScript(
-        source_code.length(), cached_meta_data ? cached_meta_data->size() : 0);
+        source_code.length(), handler ? handler->GetCodeCacheSize() : 0);
     ScriptController()->Evaluate(
         ScriptSourceCode(source_code, ScriptSourceLocationType::kUnknown,
                          handler, response_url),
@@ -404,11 +404,10 @@
   DCHECK(IsContextThread());
   SingleCachedMetadataHandler* handler =
       CreateWorkerScriptCachedMetadataHandler(script_url,
-                                              cached_meta_data.get());
+                                              std::move(cached_meta_data));
   DCHECK(!source_code.IsNull());
   ReportingProxy().WillEvaluateClassicScript(
-      source_code.length(),
-      cached_meta_data.get() ? cached_meta_data->size() : 0);
+      source_code.length(), handler ? handler->GetCodeCacheSize() : 0);
   // Cross-origin workers are disallowed, so use
   // SanitizeScriptErrors::kDoNotSanitize.
   bool success = ScriptController()->Evaluate(
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.h b/third_party/blink/renderer/core/workers/worker_global_scope.h
index 8626df0..c72cfc599 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.h
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -79,7 +79,7 @@
   // Returns null if caching is not supported.
   virtual SingleCachedMetadataHandler* CreateWorkerScriptCachedMetadataHandler(
       const KURL& script_url,
-      const Vector<uint8_t>* meta_data) {
+      std::unique_ptr<Vector<uint8_t>> meta_data) {
     return nullptr;
   }
 
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.idl b/third_party/blink/renderer/core/workers/worker_global_scope.idl
index ea15aa0..8d18ae2 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.idl
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.idl
@@ -79,6 +79,6 @@
     [RuntimeEnabled=OffscreenCanvasText] readonly attribute FontFaceSet fonts;
 };
 
-WorkerGlobalScope implements WindowOrWorkerGlobalScope;
+WorkerGlobalScope includes WindowOrWorkerGlobalScope;
 // TODO(fserb): this needs to be enabled once we get out of RuntimeEnabled.
-//WorkerGlobalScope implements FontFaceSource;
+//WorkerGlobalScope includes FontFaceSource;
diff --git a/third_party/blink/renderer/core/workers/worker_navigator.idl b/third_party/blink/renderer/core/workers/worker_navigator.idl
index 1fa072d4..a0fe35b 100644
--- a/third_party/blink/renderer/core/workers/worker_navigator.idl
+++ b/third_party/blink/renderer/core/workers/worker_navigator.idl
@@ -33,8 +33,8 @@
 ] interface WorkerNavigator {
 };
 
-WorkerNavigator implements NavigatorConcurrentHardware;
-WorkerNavigator implements NavigatorDeviceMemory;
-WorkerNavigator implements NavigatorID;
-WorkerNavigator implements NavigatorLanguage;
-WorkerNavigator implements NavigatorOnLine;
+WorkerNavigator includes NavigatorConcurrentHardware;
+WorkerNavigator includes NavigatorDeviceMemory;
+WorkerNavigator includes NavigatorID;
+WorkerNavigator includes NavigatorLanguage;
+WorkerNavigator includes NavigatorOnLine;
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelineFlameChartNetworkDataProvider.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelineFlameChartNetworkDataProvider.js
index f098af8..f67649ab 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/TimelineFlameChartNetworkDataProvider.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelineFlameChartNetworkDataProvider.js
@@ -199,7 +199,7 @@
 
     const /** @const */ minBarWidthPx = 2;
     const beginTime = request.beginTime();
-    const startTime = request.startTime;
+    const startTime = Math.min(request.startTime, request.timing && request.timing.requestTime * 1000 || Infinity);
     const endTime = request.endTime;
     const requestTime = request.timing.requestTime * 1000;
     const sendStart = Math.max(timeToPixel(requestTime + request.timing.sendStart), unclippedBarX);
@@ -208,8 +208,10 @@
     const start = timeToPixel(startTime);
     const end = Math.max(timeToPixel(endTime), finish);
 
+    // Draw waiting time.
     context.fillStyle = 'hsla(0, 100%, 100%, 0.8)';
     context.fillRect(sendStart + 0.5, barY + 0.5, headersEnd - sendStart - 0.5, barHeight - 2);
+    // Clear portions of initial rect to prepare for the ticks.
     context.fillStyle = UI.themeSupport.patchColorText('white', UI.ThemeSupport.ColorUsage.Background);
     context.fillRect(barX, barY - 0.5, sendStart - barX, barHeight);
     context.fillRect(finish, barY - 0.5, barX + barWidth - finish, barHeight);
diff --git a/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js b/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js
index d0665b7..fba0085 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js
@@ -1563,7 +1563,9 @@
    * @return {number}
    */
   beginTime() {
-    return Math.min(this.startTime, this.timing && this.timing.pushStart * 1000 || Infinity);
+    return Math.min(
+        this.startTime, this.timing && this.timing.requestTime * 1000 || Infinity,
+        this.timing && this.timing.pushStart * 1000 || Infinity);
   }
 };
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index bf07487..cd8cf29 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -187,13 +187,26 @@
 // |layout_object| and |node| correspond to an AXLayoutObject. |alt_text| is an
 // output parameter that will be populated if the AXLayoutObject is for a pseudo
 // element and contained the alternative text
-base::Optional<String> GetPseudoElementAltText(Node* node) {
-  if (node && node->IsPseudoElement()) {
+base::Optional<String> GetCSSAltText(Node* node) {
+  if (node && node->GetComputedStyle() &&
+      node->GetComputedStyle()->GetContentData()) {
     const ComputedStyle* style = node->GetComputedStyle();
-    for (const ContentData* content_data = style->GetContentData();
-         content_data; content_data = content_data->Next()) {
-      if (content_data->IsAltText())
-        return To<AltTextContentData>(content_data)->GetText();
+    // If the content property is used on a non-pseudo element, match the
+    // behaviour of LayoutObject::CreateObject and only honour the style if
+    // there is exactly one piece of content, which is an image.
+    if (node->IsPseudoElement()) {
+      for (const ContentData* content_data = style->GetContentData();
+           content_data; content_data = content_data->Next()) {
+        if (content_data->IsAltText())
+          return To<AltTextContentData>(content_data)->GetText();
+      }
+      return base::nullopt;
+    }
+
+    const ContentData* content_data = style->GetContentData();
+    if (content_data && content_data->IsImage() && content_data->Next() &&
+        content_data->Next()->IsAltText()) {
+      return To<AltTextContentData>(content_data->Next())->GetText();
     }
   }
   return base::nullopt;
@@ -259,7 +272,7 @@
 ax::mojom::Role AXLayoutObject::DetermineAccessibilityRole() {
   if (!layout_object_)
     return ax::mojom::Role::kUnknown;
-  if (GetPseudoElementAltText(GetNode())) {
+  if (GetCSSAltText(GetNode())) {
     const ComputedStyle* style = GetNode()->GetComputedStyle();
     ContentData* content_data = style->GetContentData();
 
@@ -856,7 +869,7 @@
       !GetAttribute(kTitleAttr).IsEmpty())
     return false;
 
-  base::Optional<String> alt_text = GetPseudoElementAltText(GetNode());
+  base::Optional<String> alt_text = GetCSSAltText(GetNode());
   if (alt_text)
     return alt_text->IsEmpty();
 
@@ -1401,8 +1414,11 @@
         break;
     }
 
-    if (!result && ParentObject())
-      result = ParentObject()->NextOnLine();
+    if (!result) {
+      AXObject* computed_parent = ComputeParent();
+      if (computed_parent)
+        result = computed_parent->NextOnLine();
+    }
   }
 
   // For consistency between the forward and backward directions, try to always
@@ -1471,8 +1487,11 @@
         break;
     }
 
-    if (!result && ParentObject())
-      result = ParentObject()->PreviousOnLine();
+    if (!result) {
+      AXObject* computed_parent = ComputeParent();
+      if (computed_parent)
+        result = computed_parent->PreviousOnLine();
+    }
   }
 
   // For consistency between the forward and backward directions, try to always
@@ -1558,8 +1577,7 @@
                                        AXRelatedObjectVector* related_objects,
                                        NameSources* name_sources) const {
   if (layout_object_) {
-    base::Optional<String> text_alternative =
-        GetPseudoElementAltText(GetNode());
+    base::Optional<String> text_alternative = GetCSSAltText(GetNode());
     bool found_text_alternative = false;
     if (text_alternative) {
       if (name_sources) {
@@ -2057,6 +2075,9 @@
       return parent;
   }
 
+  if (GetNode())
+    return AXNodeObject::ComputeParent();
+
   LayoutObject* parent_layout_obj = ParentLayoutObject(layout_object_);
   if (parent_layout_obj)
     return AXObjectCache().GetOrCreate(parent_layout_obj);
@@ -2085,6 +2106,9 @@
       return parent;
   }
 
+  if (GetNode())
+    return AXNodeObject::ComputeParentIfExists();
+
   LayoutObject* parent_layout_obj = ParentLayoutObject(layout_object_);
   if (parent_layout_obj)
     return AXObjectCache().Get(parent_layout_obj);
@@ -2102,9 +2126,19 @@
   if (IsDetached())
     return;
 
-  if (IsHTMLCanvasElement(GetNode()))
-    return AXNodeObject::AddChildren();
-
+  if (GetNode() && GetNode()->IsElementNode()) {
+    Element* element = ToElement(GetNode());
+    if (!IsHTMLMapElement(*element) &&   // Handled in AddImageMapChildren (img)
+        !IsHTMLRubyElement(*element) &&  // Special layout handling
+        !IsHTMLTableElement(*element) &&  // thead/tfoot move around
+        !element->IsPseudoElement()) {    // Not visited in layout traversal
+      AXNodeObject::AddChildren();
+      return;
+    }
+  }
+  Element* element = nullptr;
+  if (GetNode() && GetNode()->IsElementNode())
+    element = ToElement(GetNode());
   // If the need to add more children in addition to existing children arises,
   // childrenChanged should have been called, leaving the object with no
   // children.
@@ -2123,7 +2157,6 @@
 
   AddHiddenChildren();
   AddPopupChildren();
-  AddImageMapChildren();
   AddRemoteSVGChildren();
   AddTableChildren();
   AddInlineTextBoxChildren(false);
@@ -2142,7 +2175,7 @@
 bool AXLayoutObject::CanHaveChildren() const {
   if (!layout_object_)
     return false;
-  if (GetPseudoElementAltText(GetNode()))
+  if (GetCSSAltText(GetNode()))
     return false;
   return AXNodeObject::CanHaveChildren();
 }
@@ -3586,6 +3619,26 @@
   }
 }
 
+void AXLayoutObject::AddListMarker() {
+  if (!CanHaveChildren() || !GetLayoutObject() ||
+      !GetLayoutObject()->IsListItemIncludingNG()) {
+    return;
+  }
+  if (GetLayoutObject()->IsLayoutNGListItem()) {
+    LayoutNGListItem* list_item = ToLayoutNGListItem(GetLayoutObject());
+    LayoutObject* list_marker = list_item->Marker();
+    AXObject* list_marker_obj = AXObjectCache().GetOrCreate(list_marker);
+    if (list_marker_obj)
+      children_.push_back(list_marker_obj);
+    return;
+  }
+  LayoutListItem* list_item = ToLayoutListItem(GetLayoutObject());
+  LayoutObject* list_marker = list_item->Marker();
+  AXObject* list_marker_obj = AXObjectCache().GetOrCreate(list_marker);
+  if (list_marker_obj)
+    children_.push_back(list_marker_obj);
+}
+
 void AXLayoutObject::AddPopupChildren() {
   if (!IsHTMLInputElement(GetNode()))
     return;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
index c458081..d3d05a9 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
@@ -163,6 +163,10 @@
   AXObject* RawFirstChild() const override;
   AXObject* RawNextSibling() const override;
   void AddChildren() override;
+  void AddListMarker() override;
+  void AddInlineTextBoxChildren(bool force) override;
+  void AddImageMapChildren() override;
+  void AddHiddenChildren() override;
   bool CanHaveChildren() const override;
 
   // Properties of the object's owning document or page.
@@ -213,18 +217,14 @@
   bool IsValidSelectionBound(const AXObject*) const;
   AXObject* AccessibilityImageMapHitTest(HTMLAreaElement*,
                                          const IntPoint&) const;
-  LayoutObject* LayoutParentObject() const;
   bool IsSVGImage() const;
   void DetachRemoteSVGRoot();
   AXSVGRoot* RemoteSVGRootElement() const;
   AXObject* RemoteSVGElementHitTest(const IntPoint&) const;
   void OffsetBoundingBoxForRemoteSVGElement(LayoutRect&) const;
-  void AddHiddenChildren();
-  void AddImageMapChildren();
   void AddPopupChildren();
   void AddRemoteSVGChildren();
   void AddTableChildren();
-  void AddInlineTextBoxChildren(bool force);
   void AddValidationMessageChild();
   ax::mojom::Role DetermineTableCellRole() const;
   ax::mojom::Role DetermineTableRowRole() const;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc b/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc
index 3fe05dbe..d9330ea 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_list_box_option.cc
@@ -58,15 +58,16 @@
 }
 
 bool AXListBoxOption::IsParentPresentationalRole() const {
-  AXObject* parent = ParentObject();
+  LayoutObject* parent_layout_object = GetLayoutObject()->Parent();
+  if (!parent_layout_object)
+    return false;
+
+  AXObject* parent = AXObjectCache().GetOrCreate(parent_layout_object);
   if (!parent)
     return false;
 
-  LayoutObject* layout_object = parent->GetLayoutObject();
-  if (!layout_object)
-    return false;
-
-  if (layout_object->IsListBox() && parent->HasInheritedPresentationalRole())
+  if (parent_layout_object->IsListBox() &&
+      parent->HasInheritedPresentationalRole())
     return true;
 
   return false;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc b/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc
index c892b88..cdd8977 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list.cc
@@ -73,19 +73,19 @@
 
   AXObjectCacheImpl& cache = AXObjectCache();
 
-  AXObject* list = cache.GetOrCreate(ax::mojom::Role::kMenuListPopup);
-  if (!list)
+  AXObject* popup = cache.GetOrCreate(ax::mojom::Role::kMenuListPopup);
+  if (!popup)
     return;
 
-  ToAXMockObject(list)->SetParent(this);
-  if (list->AccessibilityIsIgnored()) {
-    cache.Remove(list->AXObjectID());
+  ToAXMockObject(popup)->SetParent(this);
+  if (popup->AccessibilityIsIgnored()) {
+    cache.Remove(popup->AXObjectID());
     return;
   }
 
-  children_.push_back(list);
+  children_.push_back(popup);
 
-  list->AddChildren();
+  popup->AddChildren();
 }
 
 bool AXMenuList::IsCollapsed() const {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index dbccf1c9..c63fd43b 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/aom/accessible_node.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
+#include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
 #include "third_party/blink/renderer/core/dom/node_traversal.h"
 #include "third_party/blink/renderer/core/dom/qualified_name.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
@@ -311,9 +312,9 @@
     return ax::mojom::Role::kDetails;
 
   if (IsHTMLSummaryElement(*GetNode())) {
-    ContainerNode* parent = FlatTreeTraversal::Parent(*GetNode());
+    ContainerNode* parent = LayoutTreeBuilderTraversal::Parent(*GetNode());
     if (parent && IsHTMLSlotElement(parent))
-      parent = FlatTreeTraversal::Parent(*parent);
+      parent = LayoutTreeBuilderTraversal::Parent(*parent);
     if (parent && IsHTMLDetailsElement(parent))
       return ax::mojom::Role::kDisclosureTriangle;
     return ax::mojom::Role::kUnknown;
@@ -661,13 +662,15 @@
   if (!parent)
     return nullptr;
 
-  for (Element* sibling = ElementTraversal::FirstChild(*parent); sibling;
-       sibling = ElementTraversal::NextSibling(*sibling)) {
+  for (Node* sibling = LayoutTreeBuilderTraversal::FirstChild(*parent); sibling;
+       sibling = LayoutTreeBuilderTraversal::NextSibling(*sibling)) {
+    if (!sibling->IsElementNode())
+      continue;
     const AtomicString& sibling_aria_role =
-        AccessibleNode::GetPropertyOrARIAAttribute(sibling,
+        AccessibleNode::GetPropertyOrARIAAttribute(ToElement(sibling),
                                                    AOMStringProperty::kRole);
     if (EqualIgnoringASCIICase(sibling_aria_role, role))
-      return sibling;
+      return ToElement(sibling);
   }
 
   return nullptr;
@@ -2080,17 +2083,7 @@
   if (!node)
     return nullptr;
 
-  Node* parent_node = nullptr;
-
-  // Skip over <optgroup> and consider the <select> the immediate parent of an
-  // <option>.
-  if (auto* option = ToHTMLOptionElementOrNull(node))
-    parent_node = option->OwnerSelectElement();
-
-  if (!parent_node)
-    parent_node = node->parentNode();
-
-  return parent_node;
+  return LayoutTreeBuilderTraversal::Parent(*node);
 }
 
 AXObject* AXNodeObject::ComputeParent() const {
@@ -2112,7 +2105,7 @@
   if (!GetNode())
     return nullptr;
 
-  Node* first_child = GetNode()->firstChild();
+  Node* first_child = LayoutTreeBuilderTraversal::FirstChild(*GetNode());
 
   if (!first_child)
     return nullptr;
@@ -2124,7 +2117,7 @@
   if (!GetNode())
     return nullptr;
 
-  Node* next_sibling = GetNode()->nextSibling();
+  Node* next_sibling = LayoutTreeBuilderTraversal::NextSibling(*GetNode());
   if (!next_sibling)
     return nullptr;
 
@@ -2141,34 +2134,38 @@
   DCHECK(!have_children_);
   have_children_ = true;
 
-  // The only time we add children from the DOM tree to a node with a
-  // layoutObject is when it's a canvas.
-  if (GetLayoutObject() && !IsHTMLCanvasElement(*node_))
-    return;
-
   AXObjectVector owned_children;
   ComputeAriaOwnsChildren(owned_children);
 
-  for (Node& child : NodeTraversal::ChildrenOf(*node_)) {
-    AXObject* child_obj = AXObjectCache().GetOrCreate(&child);
+  AddListMarker();
+
+  for (Node* child = LayoutTreeBuilderTraversal::FirstChild(*node_); child;
+       child = LayoutTreeBuilderTraversal::NextSibling(*child)) {
+    AXObject* child_obj = AXObjectCache().GetOrCreate(child);
     if (child_obj && !AXObjectCache().IsAriaOwned(child_obj))
       AddChild(child_obj);
   }
 
+  AddHiddenChildren();
+  AddImageMapChildren();
+  AddInlineTextBoxChildren(false);
+  AddAccessibleNodeChildren();
+
+  for (const auto& child : children_) {
+    if (!child->CachedParentObject())
+      child->SetParent(this);
+  }
+
   for (const auto& owned_child : owned_children)
     AddChild(owned_child);
-
-  for (const auto& child : children_)
-    child->SetParent(this);
-
-  AddAccessibleNodeChildren();
 }
 
 void AXNodeObject::AddChild(AXObject* child) {
-  InsertChild(child, children_.size());
+  unsigned index = children_.size();
+  InsertChild(child, index);
 }
 
-void AXNodeObject::InsertChild(AXObject* child, unsigned index) {
+void AXNodeObject::InsertChild(AXObject* child, unsigned& index) {
   if (!child)
     return;
 
@@ -2182,11 +2179,13 @@
   if (child->AccessibilityIsIgnored()) {
     const auto& children = child->Children();
     wtf_size_t length = children.size();
-    for (wtf_size_t i = 0; i < length; ++i)
-      children_.insert(index + i, children[i]);
-  } else {
-    DCHECK_EQ(child->ParentObject(), this);
+    for (wtf_size_t i = 0; i < length; ++i) {
+      InsertChild(children[i], index);
+    }
+  } else if (!child->IsMenuListOption()) {
+    // MenuListOptions must only added in AXMenuListPopup::AddChildren
     children_.insert(index, child);
+    index++;
   }
 }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.h b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
index 368c220a..b25675f 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
@@ -188,9 +188,14 @@
   AXObject* RawFirstChild() const override;
   AXObject* RawNextSibling() const override;
   void AddChildren() override;
+  virtual void AddListMarker() {}
+  virtual void AddInlineTextBoxChildren(bool force) {}
+  virtual void AddImageMapChildren() {}
+  virtual void AddHiddenChildren() {}
+
   bool CanHaveChildren() const override;
   void AddChild(AXObject*);
-  void InsertChild(AXObject*, unsigned index);
+  void InsertChild(AXObject*, unsigned& index);
   void ClearChildren() override;
   bool NeedsToUpdateChildren() const override { return children_dirty_; }
   void SetNeedsToUpdateChildren() override { children_dirty_ = true; }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc
index b09feae4..1f8b70a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -1645,6 +1645,7 @@
 
       String result = RecursiveTextAlternative(
           *ax_element, in_aria_labelledby_traversal, visited);
+      visited.insert(ax_element);
       local_related_objects.push_back(
           MakeGarbageCollected<NameSourceRelatedObject>(ax_element, result));
       if (!result.IsEmpty()) {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index 12e4718..f34adac 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -455,7 +455,7 @@
   if (node->GetLayoutObject() && !IsHTMLAreaElement(node))
     return GetOrCreate(node->GetLayoutObject());
 
-  if (!node->parentElement())
+  if (!LayoutTreeBuilderTraversal::Parent(*node))
     return nullptr;
 
   if (IsHTMLHeadElement(node))
@@ -500,7 +500,11 @@
   new_obj->Init();
   new_obj->SetLastKnownIsIgnoredValue(new_obj->AccessibilityIsIgnored());
   if (node) {
-    node_object_mapping_.Set(node, axid);
+    AXID prev_axid = node_object_mapping_.at(node);
+    if (prev_axid != 0 && prev_axid != axid) {
+      Remove(node);
+      node_object_mapping_.Set(node, axid);
+    }
     MaybeNewRelationTarget(node, new_obj);
   }
 
@@ -763,6 +767,10 @@
   if (!node)
     return;
 
+  // Something about the call chain for this method seems to leave distribution
+  // in a dirty state - update it before we call GetOrCreate so that we don't
+  // crash.
+  node->UpdateDistributionForFlatTreeTraversal();
   AXObject* ax_object = GetOrCreate(node);
   if (ax_object)
     ax_object->SelectionChanged();
@@ -973,9 +981,9 @@
     PostPlatformNotification(obj, notification);
 
     if (notification == ax::mojom::Event::kChildrenChanged &&
-        obj->ParentObjectIfExists() &&
+        obj->CachedParentObject() &&
         obj->LastKnownIsIgnoredValue() != obj->AccessibilityIsIgnored())
-      ChildrenChanged(obj->ParentObject());
+      ChildrenChanged(obj->CachedParentObject());
   }
 }
 
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.cc
index a7d066c..f7b235b 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.cc
@@ -54,10 +54,10 @@
                                  Gradient::ColorInterpolation::kUnpremultiplied,
                                  Gradient::DegenerateHandling::kDisallow)) {}
 
-void CanvasGradient::addColorStop(float value,
+void CanvasGradient::addColorStop(double value,
                                   const String& color_string,
                                   ExceptionState& exception_state) {
-  if (!(value >= 0 && value <= 1.0f)) {
+  if (!(value >= 0 && value <= 1.0)) {
     exception_state.ThrowDOMException(DOMExceptionCode::kIndexSizeError,
                                       "The provided value (" +
                                           String::Number(value) +
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.h
index c2d056cf..ec19265 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.h
@@ -49,7 +49,7 @@
 
   Gradient* GetGradient() const { return gradient_.get(); }
 
-  void addColorStop(float value, const String& color, ExceptionState&);
+  void addColorStop(double value, const String& color, ExceptionState&);
 
  private:
   scoped_refptr<Gradient> gradient_;
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.idl
index df921082..70731e4 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.idl
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.idl
@@ -23,10 +23,13 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
+// https://html.spec.whatwg.org/multipage/canvas.html#canvasgradient
+
 [
     Exposed(Worker OffscreenCanvas, Window StableBlinkFeatures)
 ] interface CanvasGradient {
 
-    [RaisesException] void addColorStop(float offset, DOMString color);
+    [RaisesException] void addColorStop(double offset, DOMString color);
 
 };
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc
index c3770835..772c8b2 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc
@@ -35,6 +35,7 @@
 
 #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h"
 
+#include "base/numerics/safe_conversions.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/transforms/affine_transform.h"
@@ -42,6 +43,9 @@
 
 namespace blink {
 
+// TODO(crbug.com/940846): Consider using double-type without casting and
+// DoublePoint & DoubleRect instead of FloatPoint & FloatRect.
+
 void CanvasPath::closePath() {
   if (path_.IsEmpty())
     return;
@@ -51,7 +55,9 @@
     path_.CloseSubpath();
 }
 
-void CanvasPath::moveTo(float x, float y) {
+void CanvasPath::moveTo(double double_x, double double_y) {
+  float x = base::saturated_cast<float>(double_x);
+  float y = base::saturated_cast<float>(double_y);
   if (!std::isfinite(x) || !std::isfinite(y))
     return;
   if (!IsTransformInvertible()) {
@@ -61,7 +67,9 @@
   path_.MoveTo(FloatPoint(x, y));
 }
 
-void CanvasPath::lineTo(float x, float y) {
+void CanvasPath::lineTo(double double_x, double double_y) {
+  float x = base::saturated_cast<float>(double_x);
+  float y = base::saturated_cast<float>(double_y);
   if (!std::isfinite(x) || !std::isfinite(y))
     return;
   FloatPoint p1 = FloatPoint(x, y);
@@ -76,7 +84,15 @@
   path_.AddLineTo(p1);
 }
 
-void CanvasPath::quadraticCurveTo(float cpx, float cpy, float x, float y) {
+void CanvasPath::quadraticCurveTo(double double_cpx,
+                                  double double_cpy,
+                                  double double_x,
+                                  double double_y) {
+  float cpx = base::saturated_cast<float>(double_cpx);
+  float cpy = base::saturated_cast<float>(double_cpy);
+  float x = base::saturated_cast<float>(double_x);
+  float y = base::saturated_cast<float>(double_y);
+
   if (!std::isfinite(cpx) || !std::isfinite(cpy) || !std::isfinite(x) ||
       !std::isfinite(y))
     return;
@@ -94,12 +110,18 @@
   path_.AddQuadCurveTo(cp, p1);
 }
 
-void CanvasPath::bezierCurveTo(float cp1x,
-                               float cp1y,
-                               float cp2x,
-                               float cp2y,
-                               float x,
-                               float y) {
+void CanvasPath::bezierCurveTo(double double_cp1x,
+                               double double_cp1y,
+                               double double_cp2x,
+                               double double_cp2y,
+                               double double_x,
+                               double double_y) {
+  float cp1x = base::saturated_cast<float>(double_cp1x);
+  float cp1y = base::saturated_cast<float>(double_cp1y);
+  float cp2x = base::saturated_cast<float>(double_cp2x);
+  float cp2y = base::saturated_cast<float>(double_cp2y);
+  float x = base::saturated_cast<float>(double_x);
+  float y = base::saturated_cast<float>(double_y);
   if (!std::isfinite(cp1x) || !std::isfinite(cp1y) || !std::isfinite(cp2x) ||
       !std::isfinite(cp2y) || !std::isfinite(x) || !std::isfinite(y))
     return;
@@ -119,12 +141,17 @@
   path_.AddBezierCurveTo(cp1, cp2, p1);
 }
 
-void CanvasPath::arcTo(float x1,
-                       float y1,
-                       float x2,
-                       float y2,
-                       float r,
+void CanvasPath::arcTo(double double_x1,
+                       double double_y1,
+                       double double_x2,
+                       double double_y2,
+                       double double_r,
                        ExceptionState& exception_state) {
+  float x1 = base::saturated_cast<float>(double_x1);
+  float y1 = base::saturated_cast<float>(double_y1);
+  float x2 = base::saturated_cast<float>(double_x2);
+  float y2 = base::saturated_cast<float>(double_y2);
+  float r = base::saturated_cast<float>(double_r);
   if (!std::isfinite(x1) || !std::isfinite(y1) || !std::isfinite(x2) ||
       !std::isfinite(y2) || !std::isfinite(r))
     return;
@@ -313,13 +340,18 @@
 
 }  // namespace
 
-void CanvasPath::arc(float x,
-                     float y,
-                     float radius,
-                     float start_angle,
-                     float end_angle,
+void CanvasPath::arc(double double_x,
+                     double double_y,
+                     double double_radius,
+                     double double_start_angle,
+                     double double_end_angle,
                      bool anticlockwise,
                      ExceptionState& exception_state) {
+  float x = base::saturated_cast<float>(double_x);
+  float y = base::saturated_cast<float>(double_y);
+  float radius = base::saturated_cast<float>(double_radius);
+  float start_angle = base::saturated_cast<float>(double_start_angle);
+  float end_angle = base::saturated_cast<float>(double_end_angle);
   if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(radius) ||
       !std::isfinite(start_angle) || !std::isfinite(end_angle))
     return;
@@ -345,15 +377,22 @@
                AdjustEndAngle(start_angle, end_angle, anticlockwise));
 }
 
-void CanvasPath::ellipse(float x,
-                         float y,
-                         float radius_x,
-                         float radius_y,
-                         float rotation,
-                         float start_angle,
-                         float end_angle,
+void CanvasPath::ellipse(double double_x,
+                         double double_y,
+                         double double_radius_x,
+                         double double_radius_y,
+                         double double_rotation,
+                         double double_start_angle,
+                         double double_end_angle,
                          bool anticlockwise,
                          ExceptionState& exception_state) {
+  float x = base::saturated_cast<float>(double_x);
+  float y = base::saturated_cast<float>(double_y);
+  float radius_x = base::saturated_cast<float>(double_radius_x);
+  float radius_y = base::saturated_cast<float>(double_radius_y);
+  float rotation = base::saturated_cast<float>(double_rotation);
+  float start_angle = base::saturated_cast<float>(double_start_angle);
+  float end_angle = base::saturated_cast<float>(double_end_angle);
   if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(radius_x) ||
       !std::isfinite(radius_y) || !std::isfinite(rotation) ||
       !std::isfinite(start_angle) || !std::isfinite(end_angle))
@@ -392,7 +431,14 @@
                    adjusted_end_angle);
 }
 
-void CanvasPath::rect(float x, float y, float width, float height) {
+void CanvasPath::rect(double double_x,
+                      double double_y,
+                      double double_width,
+                      double double_height) {
+  float x = base::saturated_cast<float>(double_x);
+  float y = base::saturated_cast<float>(double_y);
+  float width = base::saturated_cast<float>(double_width);
+  float height = base::saturated_cast<float>(double_height);
   if (!IsTransformInvertible())
     return;
 
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h
index 357ad28..38ede735 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h
@@ -46,38 +46,44 @@
   virtual ~CanvasPath() = default;
 
   void closePath();
-  void moveTo(float x, float y);
-  void lineTo(float x, float y);
-  void quadraticCurveTo(float cpx, float cpy, float x, float y);
-  void bezierCurveTo(float cp1x,
-                     float cp1y,
-                     float cp2x,
-                     float cp2y,
-                     float x,
-                     float y);
-  void arcTo(float x0,
-             float y0,
-             float x1,
-             float y1,
-             float radius,
+  void moveTo(double double_x, double double_y);
+  void lineTo(double double_x, double double_y);
+  void quadraticCurveTo(double double_cpx,
+                        double double_cpy,
+                        double double_x,
+                        double double_y);
+  void bezierCurveTo(double double_cp1x,
+                     double double_cp1y,
+                     double double_cp2x,
+                     double double_cp2y,
+                     double double_x,
+                     double double_y);
+  void arcTo(double double_x1,
+             double double_y1,
+             double double_x2,
+             double double_y2,
+             double double_radius,
              ExceptionState&);
-  void arc(float x,
-           float y,
-           float radius,
-           float start_angle,
-           float end_angle,
+  void arc(double double_x,
+           double double_y,
+           double double_radius,
+           double double_start_angle,
+           double double_end_angle,
            bool anticlockwise,
            ExceptionState&);
-  void ellipse(float x,
-               float y,
-               float radius_x,
-               float radius_y,
-               float rotation,
-               float start_angle,
-               float end_angle,
+  void ellipse(double double_x,
+               double double_y,
+               double double_radius_x,
+               double double_radius_y,
+               double double_rotation,
+               double double_start_angle,
+               double double_end_angle,
                bool anticlockwise,
                ExceptionState&);
-  void rect(float x, float y, float width, float height);
+  void rect(double double_x,
+            double double_y,
+            double double_width,
+            double double_height);
 
   virtual bool IsTransformInvertible() const { return true; }
   virtual AffineTransform Transform() const {
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl
index 81a279a2..0317df56 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.idl
@@ -7,12 +7,12 @@
 interface mixin CanvasPath {
     // shared path API methods
     void closePath();
-    void moveTo(unrestricted float x, unrestricted float y);
-    void lineTo(unrestricted float x, unrestricted float y);
-    void quadraticCurveTo(unrestricted float cpx, unrestricted float cpy, unrestricted float x, unrestricted float y);
-    void bezierCurveTo(unrestricted float cp1x, unrestricted float cp1y, unrestricted float cp2x, unrestricted float cp2y, unrestricted float x, unrestricted float y);
-    [RaisesException] void arcTo(unrestricted float x1, unrestricted float y1, unrestricted float x2, unrestricted float y2, unrestricted float radius);
-    void rect(unrestricted float x, unrestricted float y, unrestricted float width, unrestricted float height);
-    [RaisesException] void arc(unrestricted float x, unrestricted float y, unrestricted float radius, unrestricted float startAngle, unrestricted float endAngle, optional boolean anticlockwise = false);
-    [RaisesException] void ellipse(unrestricted float x, unrestricted float y, unrestricted float radiusX, unrestricted float radiusY, unrestricted float rotation, unrestricted float startAngle, unrestricted float endAngle, optional boolean anticlockwise = false);
+    void moveTo(unrestricted double x, unrestricted double y);
+    void lineTo(unrestricted double x, unrestricted double y);
+    void quadraticCurveTo(unrestricted double cpx, unrestricted double cpy, unrestricted double x, unrestricted double y);
+    void bezierCurveTo(unrestricted double cp1x, unrestricted double cp1y, unrestricted double cp2x, unrestricted double cp2y, unrestricted double x, unrestricted double y);
+    [RaisesException] void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radius);
+    void rect(unrestricted double x, unrestricted double y, unrestricted double width, unrestricted double height);
+    [RaisesException] void arc(unrestricted double x, unrestricted double y, unrestricted double radius, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false);
+    [RaisesException] void ellipse(unrestricted double x, unrestricted double y, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false);
 };
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl
index 8253c607..3e62a53 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl
@@ -160,4 +160,4 @@
 
 };
 
-CanvasRenderingContext2D implements CanvasPath;
+CanvasRenderingContext2D includes CanvasPath;
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/path_2d.idl b/third_party/blink/renderer/modules/canvas/canvas2d/path_2d.idl
index f2b4429..82032cca 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/path_2d.idl
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/path_2d.idl
@@ -35,4 +35,4 @@
     [RaisesException] void addPath(Path2D path, optional DOMMatrix2DInit transform);
 };
 
-Path2D implements CanvasPath;
+Path2D includes CanvasPath;
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl
index 416eb4cb..2c77305 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl
@@ -106,4 +106,4 @@
     [RuntimeEnabled=OffscreenCanvasText] attribute DOMString direction; // "inherit", "rtl", "ltr" (default: "inherit")
 };
 
-OffscreenCanvasRenderingContext2D implements CanvasPath;
+OffscreenCanvasRenderingContext2D includes CanvasPath;
diff --git a/third_party/blink/renderer/modules/credentialmanager/federated_credential.idl b/third_party/blink/renderer/modules/credentialmanager/federated_credential.idl
index efd7e22b..ac5d3021c0 100644
--- a/third_party/blink/renderer/modules/credentialmanager/federated_credential.idl
+++ b/third_party/blink/renderer/modules/credentialmanager/federated_credential.idl
@@ -15,4 +15,4 @@
     // TODO(mkwst): We don't really support this yet; it always returns ''.
     readonly attribute DOMString? protocol;
 };
-FederatedCredential implements CredentialUserData;
+FederatedCredential includes CredentialUserData;
diff --git a/third_party/blink/renderer/modules/credentialmanager/password_credential.idl b/third_party/blink/renderer/modules/credentialmanager/password_credential.idl
index 5aa501bd..4838796d 100644
--- a/third_party/blink/renderer/modules/credentialmanager/password_credential.idl
+++ b/third_party/blink/renderer/modules/credentialmanager/password_credential.idl
@@ -12,4 +12,4 @@
 ] interface PasswordCredential : Credential {
     readonly attribute DOMString password;
 };
-PasswordCredential implements CredentialUserData;
+PasswordCredential includes CredentialUserData;
diff --git a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
index a9a9f03..0f22522 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
+++ b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
@@ -80,4 +80,4 @@
     sequence<unrestricted double> getLineDash();
     attribute unrestricted double lineDashOffset;
 };
-PaintRenderingContext2D implements CanvasPath;
+PaintRenderingContext2D includes CanvasPath;
diff --git a/third_party/blink/renderer/modules/geolocation/OWNERS b/third_party/blink/renderer/modules/geolocation/OWNERS
index 2dbeb1a..51b1f3e2 100644
--- a/third_party/blink/renderer/modules/geolocation/OWNERS
+++ b/third_party/blink/renderer/modules/geolocation/OWNERS
@@ -1,7 +1,5 @@
 mattreynolds@chromium.org
-
-# Original (legacy) owner.
 mcasas@chromium.org
 
 # TEAM: device-dev@chromium.org
-# COMPONENT: Blink>Geolocation
+# COMPONENT: Blink>Location
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc b/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc
index 5ac71bf5..dcaa915 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_key_path.cc
@@ -28,7 +28,7 @@
 #include "third_party/blink/public/common/indexeddb/web_idb_types.h"
 #include "third_party/blink/renderer/platform/wtf/ascii_ctype.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/dtoa.h"
+#include "third_party/blink/renderer/platform/wtf/dtoa/dtoa.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
 #include "third_party/blink/renderer/platform/wtf/text/unicode.h"
 
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/OWNERS b/third_party/blink/renderer/modules/mediacapturefromelement/OWNERS
index 49f3612..14affd71 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/OWNERS
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/OWNERS
@@ -1,7 +1,5 @@
 emircan@chromium.org
-
-# Original (legacy) owner.
 mcasas@chromium.org
 
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>MediaStream>CaptureFromElement
diff --git a/third_party/blink/renderer/modules/mediarecorder/OWNERS b/third_party/blink/renderer/modules/mediarecorder/OWNERS
index 5f88414..c824512 100644
--- a/third_party/blink/renderer/modules/mediarecorder/OWNERS
+++ b/third_party/blink/renderer/modules/mediarecorder/OWNERS
@@ -1,7 +1,5 @@
+mcasas@chromium.org
 peter@chromium.org
 
-# Original (legacy) owner.
-mcasas@chromium.org
-
 # COMPONENT: Blink>MediaRecording
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-dev@chromium.org
diff --git a/third_party/blink/renderer/modules/mediastream/OWNERS b/third_party/blink/renderer/modules/mediastream/OWNERS
index 77d16fa..fa857a6 100644
--- a/third_party/blink/renderer/modules/mediastream/OWNERS
+++ b/third_party/blink/renderer/modules/mediastream/OWNERS
@@ -2,5 +2,5 @@
 hbos@chromium.org
 tommi@chromium.org
 
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker.idl b/third_party/blink/renderer/modules/service_worker/service_worker.idl
index 8ee3e02..ab4fbd7 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker.idl
+++ b/third_party/blink/renderer/modules/service_worker/service_worker.idl
@@ -52,4 +52,4 @@
     attribute EventHandler onstatechange;
 };
 
-ServiceWorker implements AbstractWorker;
+ServiceWorker includes AbstractWorker;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index f78a6e4..f05841d 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -594,9 +594,9 @@
 SingleCachedMetadataHandler*
 ServiceWorkerGlobalScope::CreateWorkerScriptCachedMetadataHandler(
     const KURL& script_url,
-    const Vector<uint8_t>* meta_data) {
+    std::unique_ptr<Vector<uint8_t>> meta_data) {
   return ServiceWorkerScriptCachedMetadataHandler::Create(this, script_url,
-                                                          meta_data);
+                                                          std::move(meta_data));
 }
 
 ScriptPromise ServiceWorkerGlobalScope::fetch(ScriptState* script_state,
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
index 04d38a0e..16f79d1 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -186,7 +186,7 @@
                      ExceptionState&) override;
   SingleCachedMetadataHandler* CreateWorkerScriptCachedMetadataHandler(
       const KURL& script_url,
-      const Vector<uint8_t>* meta_data) override;
+      std::unique_ptr<Vector<uint8_t>> meta_data) override;
   void ExceptionThrown(ErrorEvent*) override;
 
   void DidReceiveResponseForClassicScript(
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.cc b/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.cc
index fc05eac..cc88766 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.cc
@@ -15,11 +15,12 @@
     ServiceWorkerScriptCachedMetadataHandler(
         WorkerGlobalScope* worker_global_scope,
         const KURL& script_url,
-        const Vector<uint8_t>* meta_data)
+        std::unique_ptr<Vector<uint8_t>> meta_data)
     : worker_global_scope_(worker_global_scope), script_url_(script_url) {
-  if (meta_data)
-    cached_metadata_ = CachedMetadata::CreateFromSerializedData(
-        meta_data->data(), meta_data->size());
+  if (meta_data) {
+    cached_metadata_ =
+        CachedMetadata::CreateFromSerializedData(std::move(*meta_data));
+  }
 }
 
 ServiceWorkerScriptCachedMetadataHandler::
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h b/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h
index d39558322..46a52fa0 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h
@@ -22,14 +22,15 @@
   static ServiceWorkerScriptCachedMetadataHandler* Create(
       WorkerGlobalScope* worker_global_scope,
       const KURL& script_url,
-      const Vector<uint8_t>* meta_data) {
+      std::unique_ptr<Vector<uint8_t>> meta_data) {
     return MakeGarbageCollected<ServiceWorkerScriptCachedMetadataHandler>(
-        worker_global_scope, script_url, meta_data);
+        worker_global_scope, script_url, std::move(meta_data));
   }
 
-  ServiceWorkerScriptCachedMetadataHandler(WorkerGlobalScope*,
-                                           const KURL& script_url,
-                                           const Vector<uint8_t>* meta_data);
+  ServiceWorkerScriptCachedMetadataHandler(
+      WorkerGlobalScope*,
+      const KURL& script_url,
+      std::unique_ptr<Vector<uint8_t>> meta_data);
   ~ServiceWorkerScriptCachedMetadataHandler() override;
   void Trace(blink::Visitor*) override;
   void SetCachedMetadata(uint32_t data_type_id,
diff --git a/third_party/blink/renderer/modules/shapedetection/OWNERS b/third_party/blink/renderer/modules/shapedetection/OWNERS
index bb37d31..2a126b8 100644
--- a/third_party/blink/renderer/modules/shapedetection/OWNERS
+++ b/third_party/blink/renderer/modules/shapedetection/OWNERS
@@ -1,10 +1,8 @@
-reillyg@chromium.org
-
-# Original (legacy) owner.
 mcasas@chromium.org
+reillyg@chromium.org
 
 per-file *_type_converter*.*=set noparent
 per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
 
 # COMPONENT: Blink>ImageCapture
-# TEAM: device-dev@chromium.org
+# TEAM: media-dev@chromium.org
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context.idl b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context.idl
index 08e5755..402e4f1 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context.idl
+++ b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context.idl
@@ -6,6 +6,6 @@
     DoNotCheckConstants,
     Exposed(Worker WebGL2ComputeContext, Window WebGL2ComputeContext)
 ] interface WebGL2ComputeRenderingContext { };
-WebGL2ComputeRenderingContext implements WebGLRenderingContextBase;
-WebGL2ComputeRenderingContext implements WebGL2RenderingContextBase;
-WebGL2ComputeRenderingContext implements WebGL2ComputeRenderingContextBase;
+WebGL2ComputeRenderingContext includes WebGLRenderingContextBase;
+WebGL2ComputeRenderingContext includes WebGL2RenderingContextBase;
+WebGL2ComputeRenderingContext includes WebGL2ComputeRenderingContextBase;
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.idl b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.idl
index fedeb6c7..e039327 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.idl
+++ b/third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.idl
@@ -102,5 +102,5 @@
     void memoryBarrier(GLbitfield barriers);
     void memoryBarrierByRegion(GLbitfield barriers);
 };
-WebGL2ComputeRenderingContextBase implements WebGLRenderingContextBase;
-WebGL2ComputeRenderingContextBase implements WebGL2RenderingContextBase;
+WebGL2ComputeRenderingContextBase includes WebGLRenderingContextBase;
+WebGL2ComputeRenderingContextBase includes WebGL2RenderingContextBase;
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.idl b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.idl
index 7951887..0092b94 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.idl
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.idl
@@ -8,5 +8,5 @@
     DoNotCheckConstants,
     Exposed(Worker OffscreenCanvas, Window StableBlinkFeatures)
 ] interface WebGL2RenderingContext { };
-WebGL2RenderingContext implements WebGLRenderingContextBase;
-WebGL2RenderingContext implements WebGL2RenderingContextBase;
+WebGL2RenderingContext includes WebGLRenderingContextBase;
+WebGL2RenderingContext includes WebGL2RenderingContextBase;
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl
index 060d0be..1d3f5504 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl
@@ -535,4 +535,4 @@
     void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView dstData, GLintptr offset);
     void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLintptr offset);
 };
-WebGL2RenderingContextBase implements WebGLRenderingContextBase;
+WebGL2RenderingContextBase includes WebGLRenderingContextBase;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context.idl b/third_party/blink/renderer/modules/webgl/webgl_rendering_context.idl
index f8ac61a..f165428 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context.idl
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context.idl
@@ -29,4 +29,4 @@
     DoNotCheckConstants,
     Exposed(Worker OffscreenCanvas, Window StableBlinkFeatures)
 ] interface WebGLRenderingContext { };
-WebGLRenderingContext implements WebGLRenderingContextBase;
+WebGLRenderingContext includes WebGLRenderingContextBase;
diff --git a/third_party/blink/renderer/platform/exported/mediastream/OWNERS b/third_party/blink/renderer/platform/exported/mediastream/OWNERS
index 32889cc..c205d4f9 100644
--- a/third_party/blink/renderer/platform/exported/mediastream/OWNERS
+++ b/third_party/blink/renderer/platform/exported/mediastream/OWNERS
@@ -2,5 +2,5 @@
 
 per-file media_stream_audio_processor*=aluebs@chromium.org
 
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-capture-and-streams@grotations.appspotmail.com
 # COMPONENT: Blink>GetUserMedia
diff --git a/third_party/blink/renderer/platform/graphics/color.cc b/third_party/blink/renderer/platform/graphics/color.cc
index b2e5039..1a59ce5 100644
--- a/third_party/blink/renderer/platform/graphics/color.cc
+++ b/third_party/blink/renderer/platform/graphics/color.cc
@@ -29,7 +29,7 @@
 #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/decimal.h"
-#include "third_party/blink/renderer/platform/wtf/dtoa.h"
+#include "third_party/blink/renderer/platform/wtf/dtoa/dtoa.h"
 #include "third_party/blink/renderer/platform/wtf/hex_number.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
diff --git a/third_party/blink/renderer/platform/graphics/gradient.cc b/third_party/blink/renderer/platform/graphics/gradient.cc
index 8e93a5a..9fbdaee 100644
--- a/third_party/blink/renderer/platform/graphics/gradient.cc
+++ b/third_party/blink/renderer/platform/graphics/gradient.cc
@@ -98,14 +98,14 @@
 void Gradient::FillSkiaStops(ColorBuffer& colors, OffsetBuffer& pos) const {
   if (stops_.IsEmpty()) {
     // A gradient with no stops must be transparent black.
-    pos.push_back(WebCoreFloatToSkScalar(0));
+    pos.push_back(WebCoreDoubleToSkScalar(0));
     colors.push_back(SK_ColorTRANSPARENT);
   } else if (stops_.front().stop > 0) {
     // Copy the first stop to 0.0. The first stop position may have a slight
     // rounding error, but we don't care in this float comparison, since
     // 0.0 comes through cleanly and people aren't likely to want a gradient
     // with a stop at (0 + epsilon).
-    pos.push_back(WebCoreFloatToSkScalar(0));
+    pos.push_back(WebCoreDoubleToSkScalar(0));
     if (color_filter_) {
       colors.push_back(
           color_filter_->filterColor(MakeSkColor(stops_.front().color)));
@@ -115,7 +115,7 @@
   }
 
   for (const auto& stop : stops_) {
-    pos.push_back(WebCoreFloatToSkScalar(stop.stop));
+    pos.push_back(WebCoreDoubleToSkScalar(stop.stop));
     if (color_filter_)
       colors.push_back(color_filter_->filterColor(MakeSkColor(stop.color)));
     else
@@ -126,7 +126,7 @@
   // comparison.
   DCHECK(!pos.IsEmpty());
   if (pos.back() < 1) {
-    pos.push_back(WebCoreFloatToSkScalar(1));
+    pos.push_back(WebCoreDoubleToSkScalar(1));
     colors.push_back(colors.back());
   }
 }
diff --git a/third_party/blink/renderer/platform/graphics/gradient.h b/third_party/blink/renderer/platform/graphics/gradient.h
index 53eec6b..714b534e 100644
--- a/third_party/blink/renderer/platform/graphics/gradient.h
+++ b/third_party/blink/renderer/platform/graphics/gradient.h
@@ -95,13 +95,13 @@
 
   struct ColorStop {
     DISALLOW_NEW();
-    float stop;
+    double stop;
     Color color;
 
-    ColorStop(float s, const Color& c) : stop(s), color(c) {}
+    ColorStop(double s, const Color& c) : stop(s), color(c) {}
   };
   void AddColorStop(const ColorStop&);
-  void AddColorStop(float value, const Color& color) {
+  void AddColorStop(double value, const Color& color) {
     AddColorStop(ColorStop(value, color));
   }
   void AddColorStops(const Vector<Gradient::ColorStop>&);
diff --git a/third_party/blink/renderer/platform/loader/fetch/cached_metadata.cc b/third_party/blink/renderer/platform/loader/fetch/cached_metadata.cc
index 0da3bd5..677c2e0 100644
--- a/third_party/blink/renderer/platform/loader/fetch/cached_metadata.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/cached_metadata.cc
@@ -11,29 +11,35 @@
 scoped_refptr<CachedMetadata> CachedMetadata::CreateFromSerializedData(
     const uint8_t* data,
     size_t size) {
-  // Ensure the data is big enough, otherwise discard the data.
-  if (size < kCachedMetaDataStart ||
-      size > std::numeric_limits<wtf_size_t>::max()) {
+  if (size > std::numeric_limits<wtf_size_t>::max())
     return nullptr;
-  }
+  Vector<uint8_t> copied_data;
+  copied_data.Append(data, static_cast<wtf_size_t>(size));
+  return CreateFromSerializedData(std::move(copied_data));
+}
+
+scoped_refptr<CachedMetadata> CachedMetadata::CreateFromSerializedData(
+    Vector<uint8_t> data) {
+  // Ensure the data is big enough, otherwise discard the data.
+  if (data.size() < kCachedMetaDataStart)
+    return nullptr;
   // Ensure the marker matches, otherwise discard the data.
-  if (*reinterpret_cast<const uint32_t*>(data) !=
+  if (*reinterpret_cast<const uint32_t*>(data.data()) !=
       CachedMetadataHandler::kSingleEntry) {
     return nullptr;
   }
-  return base::AdoptRef(
-      new CachedMetadata(data, static_cast<wtf_size_t>(size)));
+  return base::AdoptRef(new CachedMetadata(std::move(data)));
 }
-CachedMetadata::CachedMetadata(const uint8_t* data, wtf_size_t size) {
+
+CachedMetadata::CachedMetadata(Vector<uint8_t> data) {
   // Serialized metadata should have non-empty data.
-  DCHECK_GT(size, kCachedMetaDataStart);
-  DCHECK(data);
+  DCHECK_GT(data.size(), kCachedMetaDataStart);
+  DCHECK(!data.IsEmpty());
   // Make sure that the first int in the data is the single entry marker.
-  CHECK_EQ(*reinterpret_cast<const uint32_t*>(data),
+  CHECK_EQ(*reinterpret_cast<const uint32_t*>(data.data()),
            CachedMetadataHandler::kSingleEntry);
 
-  serialized_data_.ReserveInitialCapacity(size);
-  serialized_data_.Append(data, size);
+  serialized_data_ = std::move(data);
 }
 
 CachedMetadata::CachedMetadata(uint32_t data_type_id,
diff --git a/third_party/blink/renderer/platform/loader/fetch/cached_metadata.h b/third_party/blink/renderer/platform/loader/fetch/cached_metadata.h
index 2c1aeb1..8f7a5aa1 100644
--- a/third_party/blink/renderer/platform/loader/fetch/cached_metadata.h
+++ b/third_party/blink/renderer/platform/loader/fetch/cached_metadata.h
@@ -65,6 +65,8 @@
   static scoped_refptr<CachedMetadata> CreateFromSerializedData(
       const uint8_t* data,
       size_t);
+  static scoped_refptr<CachedMetadata> CreateFromSerializedData(
+      Vector<uint8_t> data);
 
   ~CachedMetadata() = default;
 
@@ -87,7 +89,7 @@
   }
 
  private:
-  CachedMetadata(const uint8_t* data, wtf_size_t);
+  CachedMetadata(Vector<uint8_t> data);
   CachedMetadata(uint32_t data_type_id, const uint8_t* data, wtf_size_t);
 
   // Since the serialization format supports random access, storing it in
diff --git a/third_party/blink/renderer/platform/wtf/BUILD.gn b/third_party/blink/renderer/platform/wtf/BUILD.gn
index f4a73898..a8837798 100644
--- a/third_party/blink/renderer/platform/wtf/BUILD.gn
+++ b/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -56,8 +56,6 @@
     "decimal.h",
     "deque.h",
     "doubly_linked_list.h",
-    "dtoa.cc",
-    "dtoa.h",
     "dtoa/bignum-dtoa.cc",
     "dtoa/bignum-dtoa.h",
     "dtoa/bignum.cc",
@@ -69,6 +67,8 @@
     "dtoa/double-conversion.cc",
     "dtoa/double-conversion.h",
     "dtoa/double.h",
+    "dtoa/dtoa.cc",
+    "dtoa/dtoa.h",
     "dtoa/fast-dtoa.cc",
     "dtoa/fast-dtoa.h",
     "dtoa/fixed-dtoa.cc",
diff --git a/third_party/blink/renderer/platform/wtf/dtoa.cc b/third_party/blink/renderer/platform/wtf/dtoa/dtoa.cc
similarity index 98%
rename from third_party/blink/renderer/platform/wtf/dtoa.cc
rename to third_party/blink/renderer/platform/wtf/dtoa/dtoa.cc
index 25ea1e6..0e47ce5 100644
--- a/third_party/blink/renderer/platform/wtf/dtoa.cc
+++ b/third_party/blink/renderer/platform/wtf/dtoa/dtoa.cc
@@ -33,7 +33,7 @@
  * file.
  */
 
-#include "third_party/blink/renderer/platform/wtf/dtoa.h"
+#include "third_party/blink/renderer/platform/wtf/dtoa/dtoa.h"
 
 #include <string.h>
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
diff --git a/third_party/blink/renderer/platform/wtf/dtoa.h b/third_party/blink/renderer/platform/wtf/dtoa/dtoa.h
similarity index 96%
rename from third_party/blink/renderer/platform/wtf/dtoa.h
rename to third_party/blink/renderer/platform/wtf/dtoa/dtoa.h
index 86bec2e..4ebfc70 100644
--- a/third_party/blink/renderer/platform/wtf/dtoa.h
+++ b/third_party/blink/renderer/platform/wtf/dtoa/dtoa.h
@@ -18,8 +18,8 @@
  *
  */
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_DTOA_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_DTOA_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_DTOA_DTOA_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_DTOA_DTOA_H_
 
 #include "third_party/blink/renderer/platform/wtf/ascii_ctype.h"
 #include "third_party/blink/renderer/platform/wtf/dtoa/double-conversion.h"
@@ -77,10 +77,10 @@
 
 }  // namespace WTF
 
-using WTF::NumberToStringBuffer;
-using WTF::NumberToString;
 using WTF::NumberToFixedPrecisionString;
 using WTF::NumberToFixedWidthString;
+using WTF::NumberToString;
+using WTF::NumberToStringBuffer;
 using WTF::ParseDouble;
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_DTOA_H_
diff --git a/third_party/blink/renderer/platform/wtf/dtoa_test.cc b/third_party/blink/renderer/platform/wtf/dtoa_test.cc
index f00c2885..eb60c54 100644
--- a/third_party/blink/renderer/platform/wtf/dtoa_test.cc
+++ b/third_party/blink/renderer/platform/wtf/dtoa_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/wtf/dtoa.h"
+#include "third_party/blink/renderer/platform/wtf/dtoa/dtoa.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string.cc b/third_party/blink/renderer/platform/wtf/text/atomic_string.cc
index b66101ad..ddd988b 100644
--- a/third_party/blink/renderer/platform/wtf/text/atomic_string.cc
+++ b/third_party/blink/renderer/platform/wtf/text/atomic_string.cc
@@ -23,7 +23,7 @@
 
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 
-#include "third_party/blink/renderer/platform/wtf/dtoa.h"
+#include "third_party/blink/renderer/platform/wtf/dtoa/dtoa.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_table.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_impl.h"
 
diff --git a/third_party/blink/renderer/platform/wtf/text/string_builder.cc b/third_party/blink/renderer/platform/wtf/text/string_builder.cc
index d2482d0..40288c2 100644
--- a/third_party/blink/renderer/platform/wtf/text/string_builder.cc
+++ b/third_party/blink/renderer/platform/wtf/text/string_builder.cc
@@ -28,7 +28,7 @@
 
 #include <algorithm>
 #include "base/optional.h"
-#include "third_party/blink/renderer/platform/wtf/dtoa.h"
+#include "third_party/blink/renderer/platform/wtf/dtoa/dtoa.h"
 #include "third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/platform/wtf/text/string_to_number.cc b/third_party/blink/renderer/platform/wtf/text/string_to_number.cc
index a3d4dd9..7136eb9e 100644
--- a/third_party/blink/renderer/platform/wtf/text/string_to_number.cc
+++ b/third_party/blink/renderer/platform/wtf/text/string_to_number.cc
@@ -6,7 +6,7 @@
 
 #include <type_traits>
 #include "third_party/blink/renderer/platform/wtf/ascii_ctype.h"
-#include "third_party/blink/renderer/platform/wtf/dtoa.h"
+#include "third_party/blink/renderer/platform/wtf/dtoa/dtoa.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_impl.h"
 
 namespace WTF {
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 5dd32b4..8112baa1 100644
--- a/third_party/blink/renderer/platform/wtf/text/wtf_string.cc
+++ b/third_party/blink/renderer/platform/wtf/text/wtf_string.cc
@@ -28,7 +28,7 @@
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "third_party/blink/renderer/platform/wtf/ascii_ctype.h"
-#include "third_party/blink/renderer/platform/wtf/dtoa.h"
+#include "third_party/blink/renderer/platform/wtf/dtoa/dtoa.h"
 #include "third_party/blink/renderer/platform/wtf/hex_number.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
index 8379690..0417bf17 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -301,12 +301,13 @@
 crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
 crbug.com/591099 fast/block/float/4145535Crash.html [ Pass ]
 crbug.com/591099 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
-crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Pass ]
+crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-css-tables-collapsed.html [ Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-positioned.html [ Pass ]
-crbug.com/591099 fast/css-intrinsic-dimensions/height-tables.html [ Failure Pass ]
+crbug.com/591099 fast/css-intrinsic-dimensions/height-tables.html [ Pass ]
 crbug.com/591099 fast/css/absolute-inline-alignment-2.html [ Pass ]
 crbug.com/835484 fast/css/outline-narrowLine.html [ Failure ]
+crbug.com/591099 fast/css/outline-offset-large.html [ Failure ]
 crbug.com/855279 fast/css/text-overflow-ellipsis-vertical-hittest.html [ Pass ]
 crbug.com/591099 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under.html [ Failure ]
 crbug.com/591099 fast/events/before-unload-return-value-from-listener.html [ Pass ]
@@ -329,13 +330,12 @@
 crbug.com/591099 fast/writing-mode/table-percent-width-quirk.html [ Pass ]
 crbug.com/591099 http/tests/appcache/non-html.xhtml [ Crash Pass ]
 crbug.com/591099 http/tests/csspaint/invalidation-border-image.html [ Pass ]
-crbug.com/591099 http/tests/devtools/elements/highlight/highlight-css-grid.js [ Failure ]
 crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger/debugger-proto-property.js [ Pass ]
 crbug.com/591099 http/tests/devtools/tracing-session-id.js [ Pass ]
 crbug.com/591099 http/tests/devtools/tracing/console-timeline.js [ Pass ]
 crbug.com/591099 http/tests/html/validation-bubble-oopif-clip.html [ Pass ]
-crbug.com/591099 http/tests/media/autoplay/document-user-activation-cross-origin-feature-policy-disabled.html [ Failure ]
+crbug.com/591099 http/tests/media/autoplay/document-user-activation-cross-origin-feature-policy-disabled.html [ Failure Pass ]
 crbug.com/591099 http/tests/media/video-load-metadata-decode-error.html [ Pass ]
 crbug.com/591099 http/tests/security/inactive-document-with-empty-security-origin.html [ Pass ]
 crbug.com/591099 http/tests/security/upgrade-insecure-requests/iframe-upgrade.https.html [ Crash ]
@@ -357,7 +357,7 @@
 crbug.com/916511 virtual/composite-after-paint/paint/background/scrolling-background-with-negative-z-child.html [ Crash ]
 crbug.com/591099 virtual/composite-after-paint/paint/invalidation/box/margin.html [ Failure Pass ]
 Bug(none) virtual/disable-blink-gen-property-trees/ [ Skip ]
-crbug.com/917392 virtual/display-lock/display-lock/lock-after-append/acquire-after-resize.html [ Failure Pass ]
+crbug.com/917392 virtual/display-lock/display-lock/lock-after-append/acquire-after-resize.html [ Failure ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/measure-forced-layout-after-commit.html [ Failure ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/measure-forced-layout.html [ Failure ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/measure-updated-layout.html [ Failure ]
@@ -381,7 +381,6 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
 crbug.com/591099 virtual/new-remote-playback-pipeline/ [ Skip ]
-crbug.com/591099 virtual/nobinary-for-devtools/http/tests/devtools/elements/highlight/highlight-css-grid.js [ Failure ]
 crbug.com/591099 virtual/nobinary-for-devtools/http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js [ Crash Pass ]
 crbug.com/591099 virtual/nobinary-for-devtools/http/tests/devtools/tracing-session-id.js [ Pass ]
 crbug.com/591099 virtual/nobinary-for-devtools/http/tests/devtools/tracing/console-timeline.js [ Pass ]
@@ -400,6 +399,6 @@
 crbug.com/591099 virtual/user-activation-v2/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
 crbug.com/591099 virtual/video-surface-layer/media/W3C/video/networkState/networkState_during_progress.html [ Pass ]
 crbug.com/591099 virtual/video-surface-layer/media/color-profile-video-seek-filter.html [ Pass ]
-crbug.com/591099 virtual/video-surface-layer/media/stable/video-object-fit-stable.html [ Pass ]
+crbug.com/591099 virtual/video-surface-layer/media/stable/video-object-fit-stable.html [ Failure Pass ]
 crbug.com/591099 virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCIceTransport-extension.https.html [ Failure Pass ]
 crbug.com/591099 vr/getFrameData_oneframeupdate.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b9763d9..fe99636 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -429,6 +429,27 @@
 crbug.com/417223 external/wpt/css/css-position/position-relative-table-tr-top-absolute-child.html [ Failure ]
 crbug.com/417223 external/wpt/css/css-position/position-relative-table-tr-top.html [ Failure ]
 
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-color-001.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-position-above-left-001.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-position-above-left-002.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-position-above-right-001.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-position-above-right-002.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-position-below-left-001.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-position-below-left-002.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-position-below-right-001.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-position-below-right-002.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-002.html [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-006.html [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-007.html [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-008.html [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-010.html [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-012.html [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-021.html [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-filled-001.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-open-001.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-shape-001.xht [ Failure ]
+crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-style-string-001.xht [ Failure ]
+
 crbug.com/722825 media/controls/video-enter-exit-fullscreen-while-hovering-shows-controls.html [ Timeout Pass ]
 crbug.com/722825 virtual/video-surface-layer/media/controls/video-enter-exit-fullscreen-while-hovering-shows-controls.html [ Timeout Pass ]
 crbug.com/876050 virtual/video-surface-layer/media/controls/text-track-menu-pointer-selection.html [ Pass Failure ]
@@ -2158,27 +2179,6 @@
 crbug.com/905315 external/wpt/css/css-text/word-break/word-break-break-word-overflow-wrap-interactions.html [ Skip ]
 
 
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-color-001.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-position-above-left-001.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-position-above-left-002.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-position-above-right-001.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-position-above-right-002.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-position-below-left-001.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-position-below-left-002.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-position-below-right-001.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-position-below-right-002.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-002.html [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-006.html [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-007.html [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-008.html [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-010.html [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-012.html [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-021.html [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-filled-001.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-open-001.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-shape-001.xht [ Failure ]
-crbug.com/666657 external/wpt/css/css-text-decor/text-emphasis-style-string-001.xht [ Failure ]
-
 # These are added to W3CImportExpectations as Skip, remove when next import is done.
 crbug.com/666657 external/wpt/css/css-text/hanging-punctuation [ Skip ]
 
diff --git a/third_party/blink/web_tests/accessibility/css-alt-text.html b/third_party/blink/web_tests/accessibility/css-alt-text.html
index 796eb38d..8dd7e9ef 100644
--- a/third_party/blink/web_tests/accessibility/css-alt-text.html
+++ b/third_party/blink/web_tests/accessibility/css-alt-text.html
@@ -198,3 +198,66 @@
 }, "Pseudo elements that don't support the content property should not impact the accessibility tree if the property and alt text is supplied.");
 
 </script>
+
+<div id="divcontent">Div text content</div>
+<style>
+#divcontent {
+  content: url(bullet.png) / "alt";
+}
+</style>
+
+<script>
+
+test(function(t) {
+  var domAXNode = accessibilityController.accessibleElementById("divcontent");
+  assert_equals(domAXNode.role, "AXRole: AXImage");
+  assert_equals(domAXNode.name, "alt");
+},"Non pseudo elements which support the content property should have the alt text applied to the image that replaces their content.");
+
+</script>
+
+<!--- The following test cases are merely here to test that the addition of alt text support has not altered the default behaviour if the content property is incorrectly supplied -->
+
+<div id="divdoubleimage">DOM Text</div>
+
+<style>
+#divdoubleimage {
+  content: url(bullet.png) url(bullet.png) / "alt";
+}
+</style>
+
+<script>
+
+test(function(t) {
+  var domAXNode = accessibilityController.accessibleElementById("divdoubleimage");
+  assert_equals(domAXNode.role, "AXRole: AXGenericContainer");
+  assert_equals(domAXNode.childrenCount, 1);
+
+  var childAXNode = domAXNode.childAtIndex(0);
+  assert_equals(childAXNode.role, "AXRole: AXStaticText");
+  assert_equals(childAXNode.name, "DOM Text");
+},"A DOM Node with more than one image and alternative text should not impact the accessibility tree.");
+
+</script>
+
+<div id="divtextcontent">DOM Text</div>
+
+<style>
+#divtextcontent {
+  content: "text content replacement" / "alt";
+}
+</style>
+
+<script>
+
+test(function(t) {
+  var domAXNode = accessibilityController.accessibleElementById("divtextcontent");
+  assert_equals(domAXNode.role, "AXRole: AXGenericContainer");
+  assert_equals(domAXNode.childrenCount, 1);
+
+  var childAXNode = domAXNode.childAtIndex(0);
+  assert_equals(childAXNode.role, "AXRole: AXStaticText");
+  assert_equals(childAXNode.name, "DOM Text");
+},"A DOM Node with text replacement content and alt text should not impact the accessibility tree.");
+
+</script>
diff --git a/third_party/blink/web_tests/accessibility/editable-anonymous-block.html b/third_party/blink/web_tests/accessibility/editable-anonymous-block.html
index e4dfa764..833a949f 100644
--- a/third_party/blink/web_tests/accessibility/editable-anonymous-block.html
+++ b/third_party/blink/web_tests/accessibility/editable-anonymous-block.html
@@ -14,13 +14,11 @@
     assert_not_equals(editable, null);
     assert_equals(editable.childrenCount, 2);
 
-    let anonymousBlock = editable.childAtIndex(0);
-    assert_not_equals(anonymousBlock, null);
-    assert_equals(anonymousBlock.childrenCount, 1);
-    assert_equals(anonymousBlock.childAtIndex(0).role, 'AXRole: AXStaticText');
-    assert_equals(anonymousBlock.childAtIndex(0).name, 'Hello');
-
-    assert_true(anonymousBlock.isEditable);
-    assert_true(anonymousBlock.isRichlyEditable);
-  }, 'Ensure that anonymous blocks inside content editables are not ignored and are marked as editable.');
+    let staticText = editable.childAtIndex(0);
+    assert_not_equals(staticText, null);
+    assert_equals(staticText.role, 'AXRole: AXStaticText');
+    assert_equals(staticText.name, 'Hello');
+    assert_true(staticText.isEditable);
+    assert_true(staticText.isRichlyEditable);
+  }, 'This no longer really tests anything');
 </script>
diff --git a/third_party/blink/web_tests/accessibility/scroll-div-horiz-sends-notification.html b/third_party/blink/web_tests/accessibility/scroll-div-horiz-sends-notification.html
index 144b5b2f..b96bbf4 100644
--- a/third_party/blink/web_tests/accessibility/scroll-div-horiz-sends-notification.html
+++ b/third_party/blink/web_tests/accessibility/scroll-div-horiz-sends-notification.html
@@ -35,22 +35,25 @@
 <script>
 
 async_test_after_layout_and_paint((t) => {
-    var container = document.getElementById('container');
+  var container = document.getElementById('container');
 
-    accessibilityController.addNotificationListener(function (target, notification) {
-        if (target.role == 'AXRole: AXGenericContainer') {
-            console.log('Got notification on container div');
-            assert_equals(container.scrollLeft, 500);
-            t.done();
-        }
-    });
+  accessibilityController.addNotificationListener(t.step_func((target, notification) => {
+    if (target.role == 'AXRole: AXGenericContainer') {
+      console.log('Got notification on container div');
+      assert_equals(container.scrollLeft, 500);
+      t.done();
+    }
+  }));
 
-    window.setTimeout(function() {
-        container.scrollLeft = 500;
-    }, 0);
+  window.setTimeout(function() {
+    container.scrollLeft = 500;
+  }, 0);
+
+  window.setTimeout(t.step_func_done(() => {
+    assert_unreached();
+  }), 200);
 }, "This test ensures that scrolling the window sends a notification.");
 
-
 </script>
 
 </body>
diff --git a/third_party/blink/web_tests/accessibility/scroll-div-sends-notification.html b/third_party/blink/web_tests/accessibility/scroll-div-sends-notification.html
index 30ed8c2..987ba4a4 100644
--- a/third_party/blink/web_tests/accessibility/scroll-div-sends-notification.html
+++ b/third_party/blink/web_tests/accessibility/scroll-div-sends-notification.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-  <script src="../resources/testharness.js"></script>
-  <script src="../resources/testharnessreport.js"></script>
-  <script src="../resources/run-after-layout-and-paint.js"></script>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/run-after-layout-and-paint.js"></script>
 <style>
 .container {
   padding: 100px;
@@ -30,22 +30,25 @@
 <script>
 
 async_test_after_layout_and_paint((t) => {
-    var container = document.getElementById('container');
+  var container = document.getElementById('container');
 
-    accessibilityController.addNotificationListener(function (target, notification) {
-        if (target.role == 'AXRole: AXGenericContainer') {
-            console.log('Got notification on container div');
-            assert_equals(container.scrollTop, 500);
-            t.done();
-        }
-    });
+  accessibilityController.addNotificationListener(t.step_func((target, notification) => {
+    if (target.role == 'AXRole: AXGenericContainer') {
+      console.log('Got notification on container div');
+      assert_equals(container.scrollTop, 500);
+      accessibilityController.removeNotificationListener();
+      t.done();
+    }
+  }));
 
-    window.setTimeout(function() {
-        container.scrollTop = 500;
-    }, 0);
+  window.setTimeout(function() {
+    container.scrollTop = 500;
+  }, 0);
+  window.setTimeout(t.step_func_done(() => {
+    assert_unreached();
+  }), 200);
 }, "This test ensures that scrolling the window sends a notification.");
 
-
 </script>
 
 </body>
diff --git a/third_party/blink/web_tests/accessibility/scroll-window-horiz-sends-notification.html b/third_party/blink/web_tests/accessibility/scroll-window-horiz-sends-notification.html
index 6fd610d9..625aab5 100644
--- a/third_party/blink/web_tests/accessibility/scroll-window-horiz-sends-notification.html
+++ b/third_party/blink/web_tests/accessibility/scroll-window-horiz-sends-notification.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-  <script src="../resources/testharness.js"></script>
-  <script src="../resources/testharnessreport.js"></script>
-  <script src="../resources/run-after-layout-and-paint.js"></script>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/run-after-layout-and-paint.js"></script>
 <style>
 .bigbutton {
     display:block;
@@ -21,21 +21,24 @@
 <script>
 
 async_test_after_layout_and_paint((t) => {
+  window.scrollTo(0, 0);
+  assert_equals(window.pageXOffset, 0);
 
-    window.scrollTo(0, 0);
-    assert_equals(window.pageXOffset, 0);
+  accessibilityController.addNotificationListener(t.step_func((target, notification) => {
+    if (target.role == 'AXRole: AXWebArea' && notification == 'ScrollPositionChanged') {
+      console.log('Got notification on web area');
+      accessibilityController.removeNotificationListener();
+      assert_equals(window.pageXOffset, 500);
+      t.done();
+    }
+  }));
 
-    accessibilityController.addNotificationListener(function (target, notification) {
-        if (target.role == 'AXRole: AXWebArea' && notification == 'ScrollPositionChanged') {
-            console.log('Got notification on web area');
-            assert_equals(window.pageXOffset, 500);
-            t.done()();
-        }
-    });
-
-    window.setTimeout(function() {
-        window.scrollTo(500, 0);
-    }, 0);
+  window.setTimeout(function() {
+    window.scrollTo(500, 0);
+  }, 0);
+  window.setTimeout(t.step_func_done(() => {
+    assert_unreached();
+  }), 200);
 }, "This test ensures that scrolling the window sends a notification.");
 
 </script>
diff --git a/third_party/blink/web_tests/accessibility/scroll-window-sends-notification.html b/third_party/blink/web_tests/accessibility/scroll-window-sends-notification.html
index 4a21da6..084f0fa 100644
--- a/third_party/blink/web_tests/accessibility/scroll-window-sends-notification.html
+++ b/third_party/blink/web_tests/accessibility/scroll-window-sends-notification.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-  <script src="../resources/testharness.js"></script>
-  <script src="../resources/testharnessreport.js"></script>
-  <script src="../resources/run-after-layout-and-paint.js"></script>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/run-after-layout-and-paint.js"></script>
 <style>
 .bigbutton {
     display:block;
@@ -22,23 +22,27 @@
 <script>
 
 async_test_after_layout_and_paint((t) => {
-    window.scrollTo(0, 0);
-    assert_equals(window.pageYOffset, 0);
+  window.scrollTo(0, 0);
+  assert_equals(window.pageXOffset, 0);
 
-    accessibilityController.addNotificationListener(function (target, notification) {
-        if (target.role == 'AXRole: AXWebArea' && notification == 'ScrollPositionChanged') {
-            console.log('Got notification on web area');
-            assert_equals(window.pageYOffset, 500);
-            t.done()
-        }
-    });
+  accessibilityController.addNotificationListener(t.step_func((target, notification) => {
+    if (target.role == 'AXRole: AXWebArea' && notification == 'ScrollPositionChanged') {
+      console.log('Got notification on web area');
+      accessibilityController.removeNotificationListener();
+      assert_equals(window.pageYOffset, 500);
+      t.done();
+    }
+  }));
 
-    window.setTimeout(function() {
-        window.scrollTo(0, 500);
-    }, 0);
+  window.setTimeout(function() {
+    window.scrollTo(0, 500);
+  }, 0);
+
+  window.setTimeout(t.step_func_done(() => {
+    assert_unreached();
+  }), 500);
 }, "This test ensures that scrolling the window sends a notification.");
 
-
 </script>
 
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/common/security-features/resources/common.js b/third_party/blink/web_tests/external/wpt/common/security-features/resources/common.js
index 8b9bd0d..b18097b1 100644
--- a/third_party/blink/web_tests/external/wpt/common/security-features/resources/common.js
+++ b/third_party/blink/web_tests/external/wpt/common/security-features/resources/common.js
@@ -192,17 +192,62 @@
                        doBindEvents);
 }
 
-/**
- * requestVia*() functions return promises that are resolved on successful
- * requests with objects of the same "type", i.e. objects that contains
- * the same sets of keys that are fixed within one category of tests (e.g.
- * within wpt/referrer-policy tests).
- * wrapResult() (that should be defined outside this file) is used to convert
- * the response bodies of subresources into the expected result objects in some
- * cases, and in other cases the result objects are constructed more directly.
- * TODO(https://crbug.com/906850): Clean up the semantics around this, e.g.
- * use (or not use) wrapResult() consistently, unify the arguments, etc.
- */
+function wrapResult(server_data) {
+  if (typeof(server_data) === "string") {
+    throw server_data;
+  }
+  return {
+    referrer: server_data.headers.referer,
+    headers: server_data.headers
+  }
+}
+
+// `requestVia*()` functions return promises that are resolved on successful
+// requests with objects with the following keys:
+// - `headers`: HTTP request headers sent to server.
+// - `referrer`: Referrer.
+// - `location`: The URL of the subresource.
+//
+// Category 1:
+//     `headers`: set.
+//     `referrer`: set via `document.referrer`.
+//     `location`: set via `document.location`.
+//     See `template/document.html.template`.
+// Category 2:
+//     `headers`: set.
+//     `referrer`: set to `headers.referer` by `wrapResult()`.
+//     `location`: not set.
+// Category 3:
+//     All the keys listed above are NOT set.
+//
+// -------------------------------- -------- --------------------------
+// Function name                    Category Used in
+//                                           -------- ------- ---------
+//                                           referrer mixed-  upgrade-
+//                                           policy   content insecure-
+//                                           policy   content request
+// -------------------------------- -------- -------- ------- ---------
+// requestViaAnchor                 1        Y        Y       -
+// requestViaArea                   1        Y        Y       -
+// requestViaAudio                  3        -        Y       -
+// requestViaDedicatedWorker        2        Y        Y       Y
+// requestViaFetch                  2        Y        Y       -
+// requestViaForm                   3        -        Y       -
+// requestViaIframe                 1        Y        Y       -
+// requestViaImage                  3        -        Y       -
+// requestViaImageForReferrerPolicy 2        Y        -       -
+// requestViaLinkPrefetch           3        -        Y       -
+// requestViaLinkStylesheet         3        -        Y       -
+// requestViaObject                 3        -        Y       -
+// requestViaPicture                3        -        Y       -
+// requestViaScript                 2        Y        Y       -
+// requestViaSendBeacon             3        -        Y       -
+// requestViaSharedWorker           2        Y        -       -
+// requestViaVideo                  3        -        Y       -
+// requestViaWebSocket              3        -        Y       -
+// requestViaWorklet                3        -        Y       Y
+// requestViaXhr                    2        Y        Y       -
+// -------------------------------- -------- -------- ------- ---------
 
 /**
  * Creates a new iframe, binds load and error events, sets the src attribute and
@@ -383,8 +428,9 @@
 function dedicatedWorkerUrlThatFetches(url) {
   return `data:text/javascript,
     fetch('${url}')
-      .then(() => postMessage(''),
-            () => postMessage(''));`;
+      .then(r => r.json())
+      .then(j => postMessage(j))
+      .catch((e) => postMessage(e.message));`;
 }
 
 function workerUrlThatImports(url) {
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html
index 692db02..bf655a2 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html
@@ -10,7 +10,7 @@
           if (e.effectiveDirective == effective_directive)
             resolve(e);
         });
-	  });
+      });
     }
 
     async_test(t => {
@@ -70,7 +70,7 @@
 
       window.addEventListener("message", t.step_func(e => {
         if (e.source == i.contentWindow) {
-          if (e.data == (new URL(url)).origin) {
+          if (e.data.location == url) {
             waitForViolation(window, "frame-src")
               .then(t.step_func(e => {
                 reported = true;
@@ -78,7 +78,7 @@
                   t.done();
             }));
             i.contentWindow.location.href = navigate_to;
-          } else if (e.data == (new URL(upgraded)).origin) {
+          } else if (e.data.location == upgraded) {
             loaded = true;
             if (reported)
               t.done();
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-image-tentative.sub.html b/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-image-tentative.sub.html
index e277d9e..a9e2b295 100644
--- a/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-image-tentative.sub.html
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-image-tentative.sub.html
@@ -26,7 +26,7 @@
 <body>
   <p>Image inserted further below.</p>
   <div id="image-container">
-    <img id="off" load="eager" src="http://{{hosts[alt][www1]}}:{{ports[http][0]}}/feature-policy/experimental-features/resources/lazyload.png"></img>
+    <img id="off" loading="eager" src="http://{{hosts[alt][www1]}}:{{ports[http][0]}}/feature-policy/experimental-features/resources/lazyload.png"></img>
   </div>
   <script>
     var img = document.querySelector("img");
@@ -35,11 +35,11 @@
       target.load_complete = wait_for_load(target).then(() => target.did_load = true );
     });
 
-    // Sanity-check: Verify that when feature-policy 'lazyload' is enabled, the lazyload attribute
-    // value 'OFF' works as expected (images load immediately).
+    // Sanity-check: Verify that when feature-policy 'lazyload' is enabled, the attribute
+    // loading='eager' works as expected (images load immediately).
     promise_test( async(t) => {
       await window.load_complete;
       assert_true(img.did_load, "Image should have loaded.");
-    }, "When feature is enabled, load=eager works as expected.");
+    }, "When feature is enabled, loading=eager works as expected.");
  </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html b/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html
index ebed07b..3a2f469 100644
--- a/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html
@@ -31,12 +31,12 @@
 
   window.scrollTo(0, 0);
 
-  // Sanity-check: Make sure load='lazy' works as intended.
+  // Sanity-check: Make sure loading='lazy' works as intended.
   promise_test(async(t) => {
-    // Add a frame with load="lazy".
+    // Add a frame with loading="lazy".
     let frame_on = createIframe(document.body, {
         id: "ON",
-        load: "lazy",
+        loading: "lazy",
         src: `${cross_origin_url}?id=ON`
       });
     // Sanity-check: The frame is not visible.
@@ -48,17 +48,17 @@
         await waitForMessageOrTimeout(t, "ON", load_timeout);
     assert_equals(msg_or_timeout_attr_on,
                   expected_timeout_msg,
-                  "With load='lazy', the frame should not load.");
+                  "With loading='lazy', the frame should not load.");
   }, "Sanity-check: Contents do not load immediately (no eager-loading) " +
-     "when the load attribute is 'lazy' and frame is in viewport.");
+     "when the loading attribute is 'lazy' and frame is in viewport.");
 
   // When feature is enabled, a frame can turn off lazy loading by setting the
   // attribute to 'off'.
   promise_test(async(t) => {
-    // Add a frame with load="eager".
+    // Add a frame with loading="eager".
     let frame_off = createIframe(document.body, {
         id: "OFF",
-        load: "eager",
+        loading: "eager",
         src: `${cross_origin_url}?id=OFF`
       });
     // Sanity-check: The frame is not visible.
@@ -71,7 +71,7 @@
 
     assert_equals(msg_or_timeout_attr_off,
                   expected_load_msg,
-                  "With load='eager', the frame should load.");
+                  "With loading='eager', the frame should load.");
   }, "When 'lazyload' feature is enabled, a frame can avoid lazyloading by " +
-     "setting 'load' attribute to 'eager'");
+     "setting 'loading' attribute to 'eager'");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/OWNERS b/third_party/blink/web_tests/external/wpt/geolocation-API/OWNERS
index 61e5876..6d678d86 100644
--- a/third_party/blink/web_tests/external/wpt/geolocation-API/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/geolocation-API/OWNERS
@@ -1,5 +1,3 @@
 # TEAM: device-dev@chromium.org
-# COMPONENT: Blink>Geolocation
-
-# Original (legacy) owner.
+# COMPONENT: Blink>Location
 mcasas@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/html-media-capture/OWNERS b/third_party/blink/web_tests/external/wpt/html-media-capture/OWNERS
index d96b9bf..5db6e74 100644
--- a/third_party/blink/web_tests/external/wpt/html-media-capture/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/html-media-capture/OWNERS
@@ -1,4 +1,4 @@
 # TEAM: media-dev@chromium.org
 # COMPONENT: Blink>ImageCapture
-
 rijubrata.bhaumik@intel.com
+mcasas@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-record/OWNERS b/third_party/blink/web_tests/external/wpt/mediacapture-record/OWNERS
index 9c7779b..681555b 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-record/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-record/OWNERS
@@ -1,5 +1,3 @@
-# TEAM: webrtc-dev@chromium.org
+# TEAM: media-dev@chromium.org
 # COMPONENT: Blink>MediaRecording
-
-# Original (legacy) owner.
 mcasas@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/mixed-content/generic/mixed-content-test-case.js b/third_party/blink/web_tests/external/wpt/mixed-content/generic/mixed-content-test-case.js
index a50b61c7..e7b0baa 100644
--- a/third_party/blink/web_tests/external/wpt/mixed-content/generic/mixed-content-test-case.js
+++ b/third_party/blink/web_tests/external/wpt/mixed-content/generic/mixed-content-test-case.js
@@ -3,11 +3,6 @@
  * @author burnik@google.com (Kristijan Burnik)
  */
 
-function wrapResult(server_data) {
-  // Currently the returned value is not used in mixed-content tests.
-  return null;
-}
-
 /**
  * MixedContentTestCase exercises all the tests for checking browser behavior
  * when resources regarded as mixed-content are requested. A single run covers
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-create-orphaned.html b/third_party/blink/web_tests/external/wpt/portals/portals-create-orphaned.html
new file mode 100644
index 0000000..903186ff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/portals/portals-create-orphaned.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+  <script>
+    promise_test(async () => {
+      let waitForMessage = new Promise((resolve, reject) => {
+        var bc = new BroadcastChannel("portals-create-orphaned");
+        bc.onmessage = e => {
+          bc.close();
+          resolve(e.data);
+        }
+      });
+      window.open("resources/portal-create-orphaned.html");
+      let message = await waitForMessage;
+      assert_equals(message, "portal loaded");
+    }, "creating a portal from an orphaned portal should succeed");
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-create-orphaned.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-create-orphaned.html
new file mode 100644
index 0000000..89b927f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-create-orphaned.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<body>
+  <script>
+    var portal = document.createElement("portal");
+    portal.src = "simple-portal.html";
+    let waitForMessage = new Promise((resolve, reject) => {
+      var bc_portal = new BroadcastChannel("simple-portal");
+      bc_portal.onmessage = e => {
+        bc_portal.close();
+        portal.activate();
+        var portal2 = document.createElement("portal");
+        portal2.src = "simple-portal.html";
+        document.body.appendChild(portal2);
+        var bc2 = new BroadcastChannel("simple-portal");
+        bc2.onmessage = e => {
+          bc2.close();
+          resolve("portal loaded");
+        }
+      }
+    });
+    document.body.appendChild(portal);
+    waitForMessage.then(message => {
+      var bc = new BroadcastChannel("portals-create-orphaned");
+      bc.postMessage(message);
+      bc.close();
+    });
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/referrer-policy-test-case.js b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/referrer-policy-test-case.js
index 6b5ae7f..6d570f1 100644
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/referrer-policy-test-case.js
+++ b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/referrer-policy-test-case.js
@@ -1,10 +1,3 @@
-function wrapResult(server_data) {
-  return {
-    referrer: server_data.headers.referer,
-    headers: server_data.headers
-  }
-}
-
 // NOTE: This method only strips the fragment and is not in accordance to the
 // recommended draft specification:
 // https://w3c.github.io/webappsec/specs/referrer-policy/#null
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-redirect-upgrade.https-expected.txt b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-redirect-upgrade.https-expected.txt
index 0d9e1b9..bc6f2cd3 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-redirect-upgrade.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-redirect-upgrade.https-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 PASS secure/same-origin => secure/same-origin worker
-FAIL insecure/same-origin => secure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=https%3A%2F%2Fweb-platform.test%3A8444%2Fupgrade-insecure-requests%2Fsupport%2Fworker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+FAIL insecure/same-origin => secure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=https%3A%2F%2Fweb-platform.test%3A8444%2Fcommon%2Fsecurity-features%2Fsubresource%2Fworker.py' cannot be accessed from origin 'https://web-platform.test:8444'."
 PASS secure/same-origin => insecure/same-origin worker
-FAIL insecure/same-origin => insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=http%3A%2F%2Fweb-platform.test%3A8444%2Fupgrade-insecure-requests%2Fsupport%2Fworker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+FAIL insecure/same-origin => insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=http%3A%2F%2Fweb-platform.test%3A8444%2Fcommon%2Fsecurity-features%2Fsubresource%2Fworker.py' cannot be accessed from origin 'https://web-platform.test:8444'."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-upgrade.https-expected.txt b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-upgrade.https-expected.txt
index 5132c62..8195596 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-upgrade.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-upgrade.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 PASS secure/same-origin worker
-FAIL insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/worker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+FAIL insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/common/security-features/subresource/worker.py' cannot be accessed from origin 'https://web-platform.test:8444'."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/generate.py b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/generate.py
index 8c8cca21..4fb7078e 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/generate.py
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/generate.py
@@ -33,8 +33,8 @@
   ('layout-worklet', 'WORKLET'), ('paint-worklet', 'WORKLET'),
   ('worker', 'WORKER'),
   ('module-worker', 'WORKER'),
-  ('worker-subresource-xhr', 'IMAGE'),
-  ('worker-subresource-fetch', 'IMAGE')]:
+  ('worker-subresource-xhr', 'FETCH'),
+  ('worker-subresource-fetch', 'FETCH')]:
   sameOriginOnly = 'true' if resourceType == 'WORKER' else 'false'
   types = [('', 'generateTests'), ('-redirect', 'generateRedirectTests')]
   if name == 'module-worker' or resourceType == 'WORKLET':
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/pass.png b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/pass.png
deleted file mode 100644
index 2fa1e0a..0000000
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/pass.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/pass.png.headers b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/pass.png.headers
deleted file mode 100644
index cb762eff..0000000
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/pass.png.headers
+++ /dev/null
@@ -1 +0,0 @@
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/post-origin-to-parent.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/post-origin-to-parent.html
deleted file mode 100644
index 4f596ef..0000000
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/post-origin-to-parent.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<script>
-  parent.postMessage(window.location.origin, '*');
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/testharness-helper.sub.js b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/testharness-helper.sub.js
index 70378ed..f578e898 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/testharness-helper.sub.js
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/testharness-helper.sub.js
@@ -1,9 +1,3 @@
-// Used by common.js.
-function wrapResult(server_data) {
-  // Currently the returned value is not used in mixed-content tests.
-  return null;
-}
-
 const Host = {
   SAME_ORIGIN: "same-origin",
   CROSS_ORIGIN: "cross-origin",
@@ -20,6 +14,7 @@
   WORKER: "worker",
   WORKLET: "worklet",
   WEBSOCKET: "websocket",
+  FETCH: "fetch",
 };
 
 // These tests rely on some unintuitive cleverness due to WPT's test setup:
@@ -27,22 +22,24 @@
 // in the form `http://[domain]:[https-port]`. If the upgrade fails, the load will fail,
 // as we don't serve HTTP over the secure port.
 function generateURL(host, protocol, resourceType) {
-  var url = new URL("http://{{host}}:{{ports[https][0]}}/upgrade-insecure-requests/support/");
+  var url = new URL("http://{{host}}:{{ports[https][0]}}/common/security-features/subresource/");
   url.protocol = protocol == Protocol.INSECURE ? "http" : "https";
   url.hostname = host == Host.SAME_ORIGIN ? "{{host}}" : "{{domains[天気の良い日]}}";
 
   if (resourceType == ResourceType.IMAGE) {
-    url.pathname += "pass.png";
+    url.pathname += "image.py";
   } else if (resourceType == ResourceType.FRAME) {
-    url.pathname += "post-origin-to-parent.html";
+    url.pathname += "document.py";
   } else if (resourceType == ResourceType.WEBSOCKET) {
     url.port = {{ports[wss][0]}};
     url.protocol = protocol == Protocol.INSECURE ? "ws" : "wss";
     url.pathname = "echo";
   } else if (resourceType == ResourceType.WORKER) {
-    url.pathname += "worker.js";
+    url.pathname += "worker.py";
   } else if (resourceType == ResourceType.WORKLET) {
-    url.pathname = "/worklets/resources/empty-worklet-script-with-cors-header.js";
+    url.pathname += "worker.py";
+  } else if (resourceType == ResourceType.FETCH) {
+    url.pathname += "xhr.py";
   }
   return {
     name: protocol + "/" + host + " "  + resourceType,
@@ -110,24 +107,24 @@
   return tests;
 }
 
-function assert_image_loads(test, url, height, width) {
+function assert_image_loads(test, url) {
   var i = document.createElement('img');
   i.onload = test.step_func_done(_ => {
-    assert_equals(i.naturalHeight, height, "Height.");
-    assert_equals(i.naturalWidth, width, "Width.");
+    assert_greater_than(i.naturalHeight, 0, "Height.");
+    assert_greater_than(i.naturalWidth, 0, "Width.");
   });
   i.onerror = test.unreached_func(url + " should load successfully.");
   i.src = url;
 }
 
-function assert_image_loads_in_srcdoc(test, url, height, width) {
+function assert_image_loads_in_srcdoc(test, url) {
   var frame = document.createElement('iframe');
   frame.srcdoc = "yay!";
   frame.onload = _ => {
     var i = frame.contentDocument.createElement('img');
     i.onload = test.step_func_done(_ => {
-      assert_equals(i.naturalHeight, height, "Height.");
-      assert_equals(i.naturalWidth, width, "Width.");
+      assert_greater_than(i.naturalHeight, 0, "Height.");
+      assert_greater_than(i.naturalWidth, 0, "Width.");
       frame.remove();
     });
     i.onerror = test.unreached_func(url + " should load successfully.");
@@ -137,13 +134,13 @@
   document.body.appendChild(frame);
 }
 
-function assert_image_loads_in_blank(test, url, height, width) {
+function assert_image_loads_in_blank(test, url) {
   var frame = document.createElement('iframe');
   frame.onload = _ => {
     var i = frame.contentDocument.createElement('img');
     i.onload = test.step_func_done(_ => {
-      assert_equals(i.naturalHeight, height, "Height.");
-      assert_equals(i.naturalWidth, width, "Width.");
+      assert_greater_than(i.naturalHeight, 0, "Height.");
+      assert_greater_than(i.naturalWidth, 0, "Width.");
       frame.remove();
     });
     i.onerror = test.unreached_func(url + " should load successfully.");
@@ -153,20 +150,6 @@
   document.body.appendChild(frame);
 }
 
-function assert_frame_loads(test, url) {
-  var i = document.createElement('iframe');
-
-  window.addEventListener('message', test.step_func(e => {
-    if (e.source == i.contentWindow) {
-      i.remove();
-      test.done();
-    }
-  }));
-
-  i.src = url;
-  document.body.appendChild(i);
-}
-
 function assert_websocket_loads(test, url) {
   var w = new WebSocket(url, "echo");
   w.onopen = test.step_func(_ => {
@@ -178,12 +161,12 @@
 
 const testMap = {
   "image": test => {
-    async_test(t => assert_image_loads(t, test.url, 64, 168), test.name);
-    async_test(t => assert_image_loads_in_srcdoc(t, test.url, 64, 168), test.name + " in <iframe srcdoc>");
-    async_test(t => assert_image_loads_in_blank(t, test.url, 64, 168), test.name + " in <iframe>");
+    async_test(t => assert_image_loads(t, test.url), test.name);
+    async_test(t => assert_image_loads_in_srcdoc(t, test.url), test.name + " in <iframe srcdoc>");
+    async_test(t => assert_image_loads_in_blank(t, test.url), test.name + " in <iframe>");
   },
   "iframe":
-    test => async_test(t => assert_frame_loads(t, test.url), test.name),
+    test => promise_test(t => requestViaIframe(test.url), test.name),
 
   "worker":
     test => promise_test(
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js
deleted file mode 100644
index 7e2168bc..0000000
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js
+++ /dev/null
@@ -1 +0,0 @@
-postMessage('done');
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js.headers b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js.headers
deleted file mode 100644
index cb762eff..0000000
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js.headers
+++ /dev/null
@@ -1 +0,0 @@
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-redirect-upgrade.https-expected.txt b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-redirect-upgrade.https-expected.txt
index 0d9e1b9..bc6f2cd3 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-redirect-upgrade.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-redirect-upgrade.https-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 PASS secure/same-origin => secure/same-origin worker
-FAIL insecure/same-origin => secure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=https%3A%2F%2Fweb-platform.test%3A8444%2Fupgrade-insecure-requests%2Fsupport%2Fworker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+FAIL insecure/same-origin => secure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=https%3A%2F%2Fweb-platform.test%3A8444%2Fcommon%2Fsecurity-features%2Fsubresource%2Fworker.py' cannot be accessed from origin 'https://web-platform.test:8444'."
 PASS secure/same-origin => insecure/same-origin worker
-FAIL insecure/same-origin => insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=http%3A%2F%2Fweb-platform.test%3A8444%2Fupgrade-insecure-requests%2Fsupport%2Fworker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+FAIL insecure/same-origin => insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=http%3A%2F%2Fweb-platform.test%3A8444%2Fcommon%2Fsecurity-features%2Fsubresource%2Fworker.py' cannot be accessed from origin 'https://web-platform.test:8444'."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-redirect-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-redirect-upgrade.https.html
index b2ce2cf..948dd65 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-redirect-upgrade.https.html
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-redirect-upgrade.https.html
@@ -12,7 +12,7 @@
 </head>
 <body>
 <script>
-const tests = generateRedirectTests(ResourceType.IMAGE, false);
+const tests = generateRedirectTests(ResourceType.FETCH, false);
 tests.forEach(test => testMap['worker-subresource-fetch'](test));
 </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-upgrade.https.html
index 1639363..bc98b9f2 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-upgrade.https.html
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-upgrade.https.html
@@ -12,7 +12,7 @@
 </head>
 <body>
 <script>
-const tests = generateTests(ResourceType.IMAGE, false);
+const tests = generateTests(ResourceType.FETCH, false);
 tests.forEach(test => testMap['worker-subresource-fetch'](test));
 </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-upgrade.https-expected.txt b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-upgrade.https-expected.txt
index 5132c62..8195596 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-upgrade.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-upgrade.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 PASS secure/same-origin worker
-FAIL insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/worker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+FAIL insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/common/security-features/subresource/worker.py' cannot be accessed from origin 'https://web-platform.test:8444'."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/fast/events/popup-blocked-to-post-blank-expected.txt b/third_party/blink/web_tests/fast/events/popup-blocked-to-post-blank-expected.txt
index 5305a4e3..1c6ee54 100644
--- a/third_party/blink/web_tests/fast/events/popup-blocked-to-post-blank-expected.txt
+++ b/third_party/blink/web_tests/fast/events/popup-blocked-to-post-blank-expected.txt
@@ -1 +1,2 @@
+CONSOLE ERROR: line 15: Not allowed to navigate top frame to data URL: data:text/html,<script>alert(window)</script>?
 If the POST pop-up was not blocked then there will be an ALERT containing a Window object. Otherwise, the test passes.
diff --git a/third_party/blink/web_tests/fast/frames/sandboxed-iframe-navigation-targetlink-expected.txt b/third_party/blink/web_tests/fast/frames/sandboxed-iframe-navigation-targetlink-expected.txt
index 06a635cf..cbcb138 100644
--- a/third_party/blink/web_tests/fast/frames/sandboxed-iframe-navigation-targetlink-expected.txt
+++ b/third_party/blink/web_tests/fast/frames/sandboxed-iframe-navigation-targetlink-expected.txt
@@ -1,6 +1,5 @@
 CONSOLE ERROR: line 18: Unsafe JavaScript attempt to initiate navigation for frame with URL 'about:blank' from frame with URL 'sandboxed-iframe-navigation-targetlink.html'. The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors.
 
-CONSOLE ERROR: line 18: Blocked opening 'sandboxed-iframe-navigated.html' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set.
 This test verifies that a sandboxed IFrame cannot open a link in another frame using the target attribute of a link.
 
 This is done by loading ten non-sandboxed IFrames, and a single sandboxed one. In addition each of these frames have a target frame (so, 22 frames in total). Expect ten frames to be able to open a link in their corresponding target frame, but the sandboxed one to not be one of them.
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html
index b61300e..cdcc06b 100644
--- a/third_party/blink/web_tests/fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html
+++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html
@@ -25,6 +25,8 @@
     ["Down", "frameA,1"],
     ["Down", "frameA,1"],
     ["Down", "frameA,1"],
+    ["Down", "frameA,1"],
+    ["Down", "frameA,2"],
     ["Down", "frameA,2"],
     ["Down", "end"],
     ["Up", "frameA,frameAbody"],
@@ -35,6 +37,8 @@
     ["Up", "frameA,2"],
     ["Up", "frameA,2"],
     ["Up", "frameA,2"],
+    ["Up", "frameA,2"],
+    ["Up", "frameA,1"],
     ["Up", "frameA,1"],
     ["Up", "start"],
   ];
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-media-elements.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-media-elements.html
index fb42a2d..4d59037b 100644
--- a/third_party/blink/web_tests/fast/spatial-navigation/snav-media-elements.html
+++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-media-elements.html
@@ -1,3 +1,11 @@
+<style>
+  p {
+    margin: 0;
+  }
+  video {
+    height: 100px;
+  }
+</style>
 <p>This is a link <a id="start" href="a">start of Test</a>.</p>
 <video id="v1" controls tabindex="0" src="../../media/content/test.mp4"></video>
 <p>This is a link <a id="i2" href="a">i2</a>.</p>
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-navigate-visible-elements-only.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-navigate-visible-elements-only.html
new file mode 100644
index 0000000..fafebd8
--- /dev/null
+++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-navigate-visible-elements-only.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/snav-testharness.js"></script>
+
+<style>
+  div {
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    position: absolute;
+  }
+
+  #A {
+    top: 601px;
+  }
+</style>
+
+<div id="start" tabindex="0"></div>
+<div id="A" tabindex="0"></div>
+
+<script>
+  // This test checks that focusless mode allows entering focus into an element
+  // with the enter key and exiting it with the escape key.
+  const A = document.getElementById("A");
+  const start = document.getElementById("start");
+
+  snav.assertSnavEnabledAndTestable();
+  start.focus();
+
+  test(() => {
+    assert_equals(window.scrollY, 0, "Start at 0 scroll offset.")
+    assert_equals(window.internals.interestedElement,
+                  start, "Top DIV starts off focused");
+
+    // Down should scroll the visual viewport, since there's no targets
+    // availabe on screen.
+    snav.triggerMove('Down');
+
+    assert_equals(window.internals.interestedElement,
+                  start,
+                  "First navigation should't move interest");
+    assert_greater_than(window.scrollY, 0,
+                  "First navigation should scroll");
+    assert_greater_than(window.innerHeight,
+                        A.getBoundingClientRect().top,
+                        "A element should now be at least partially visible");
+
+    snav.triggerMove('Down');
+    assert_equals(window.internals.interestedElement,
+                  A,
+                  "Navigate to onscreen element.");
+  }, "Don't navigate to elements that are off screen.");
+</script>
diff --git a/third_party/blink/web_tests/http/tests/lazyload/attribute.html b/third_party/blink/web_tests/http/tests/lazyload/attribute.html
index 07751af..c6181504 100644
--- a/third_party/blink/web_tests/http/tests/lazyload/attribute.html
+++ b/third_party/blink/web_tests/http/tests/lazyload/attribute.html
@@ -6,10 +6,10 @@
 <body>
   <div style="height:10000px;"></div>
   <img id="no_attribute_img" src='../loading/resources/base-image1.png'>
-  <img id="auto_attribute_img" src='../loading/resources/base-image2.png' load="auto">
-  <img id="invalid_attribute_img" src='../loading/resources/base-image3.png' load="invalid-value-default">
-  <img id="lazy_attribute_img" src='../loading/resources/dup-image1.png' load="lazy">
-  <img id="eager_attribute_img" src='../loading/resources/dup-image2.png' load="eager">
+  <img id="auto_attribute_img" src='../loading/resources/base-image2.png' loading="auto">
+  <img id="invalid_attribute_img" src='../loading/resources/base-image3.png' loading="invalid-value-default">
+  <img id="lazy_attribute_img" src='../loading/resources/dup-image1.png' loading="lazy">
+  <img id="eager_attribute_img" src='../loading/resources/dup-image2.png' loading="eager">
 </body>
 
 <script>
@@ -29,48 +29,48 @@
       assert_false(is_image_fully_loaded(no_attribute_img));
     }));
     lazy_attribute_img.addEventListener("load",
-      t.unreached_func("Load event should not be fired for below viewport image with load=lazy"));
+      t.unreached_func("Load event should not be fired for below viewport image with loading=lazy"));
     auto_attribute_img.addEventListener("load",
-      t.unreached_func("Load event should not be fired for below viewport image with load=auto"));
+      t.unreached_func("Load event should not be fired for below viewport image with loading=auto"));
     no_attribute_img.addEventListener("load",
-      t.unreached_func("Load event should not be fired for below viewport image with no load attribute"));
+      t.unreached_func("Load event should not be fired for below viewport image with no loading attribute"));
     invalid_attribute_img.addEventListener("load",
-      t.unreached_func("Load event should not be fired for below viewport image with invalid load attribute"));
-  }, "Test that <img> with load=lazy or auto or no attribute or invalid value are loaded as a placeholder");
+      t.unreached_func("Load event should not be fired for below viewport image with invalid loading attribute"));
+  }, "Test that <img> with loading=lazy or auto or no attribute or invalid value are loaded as a placeholder");
 
   async_test(function(t) {
     eager_attribute_img.addEventListener("load",
       t.step_func_done(function() {
         assert_true(is_image_fully_loaded(eager_attribute_img));
       }));
-  }, "Test that <img> with load=eager is fully loaded, and not a placeholder");
+  }, "Test that <img> with loading=eager is fully loaded, and not a placeholder");
 
   async_test(function(t) {
     var complete = 0;
     var onload_callback = function() {
       if (++complete == 4) {
-        // The four images with load=lazy,auto or default or invalid attribute are loaded.
+        // The four images with loading=lazy,auto or default or invalid attribute are loaded.
         assert_true(is_image_fully_loaded(no_attribute_img));
         assert_true(is_image_fully_loaded(lazy_attribute_img));
         assert_true(is_image_fully_loaded(auto_attribute_img));
         assert_true(is_image_fully_loaded(invalid_attribute_img));
         t.done();
       }
-      assert_equals("eager", this.getAttribute('load'));
+      assert_equals("eager", this.getAttribute('loading'));
     };
     no_attribute_img.addEventListener("load", onload_callback);
     lazy_attribute_img.addEventListener("load", onload_callback);
     auto_attribute_img.addEventListener("load", onload_callback);
     invalid_attribute_img.addEventListener("load", onload_callback);
     window.addEventListener("load", t.step_func(function() {
-      assert_equals(null, no_attribute_img.getAttribute('load'));
-      assert_equals("lazy", lazy_attribute_img.getAttribute('load'));
-      assert_equals("auto", auto_attribute_img.getAttribute('load'));
-      assert_equals("invalid-value-default", invalid_attribute_img.getAttribute('load'));
-      no_attribute_img.setAttribute('load', 'eager');
-      lazy_attribute_img.setAttribute('load', 'eager');
-      auto_attribute_img.setAttribute('load', 'eager');
-      invalid_attribute_img.setAttribute('load', 'eager');
+      assert_equals(null, no_attribute_img.getAttribute('loading'));
+      assert_equals("lazy", lazy_attribute_img.getAttribute('loading'));
+      assert_equals("auto", auto_attribute_img.getAttribute('loading'));
+      assert_equals("invalid-value-default", invalid_attribute_img.getAttribute('loading'));
+      no_attribute_img.setAttribute('loading', 'eager');
+      lazy_attribute_img.setAttribute('loading', 'eager');
+      auto_attribute_img.setAttribute('loading', 'eager');
+      invalid_attribute_img.setAttribute('loading', 'eager');
     }));
   }, "Test that deferred <img> are fully loaded when lazyload is turned off");
 </script>
diff --git a/third_party/blink/web_tests/http/tests/security/sandboxed-iframe-form-top-expected.txt b/third_party/blink/web_tests/http/tests/security/sandboxed-iframe-form-top-expected.txt
index ad4c764..de8060f 100644
--- a/third_party/blink/web_tests/http/tests/security/sandboxed-iframe-form-top-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/sandboxed-iframe-form-top-expected.txt
@@ -1,6 +1,5 @@
 CONSOLE ERROR: line 8: Unsafe JavaScript attempt to initiate navigation for frame with URL 'http://127.0.0.1:8000/security/sandboxed-iframe-form-top.html' from frame with URL 'http://127.0.0.1:8000/security/resources/sandboxed-iframe-form-top.html'. The frame attempting navigation of the top-level window is sandboxed, but the flag of 'allow-top-navigation' or 'allow-top-navigation-by-user-activation' is not set.
 
-CONSOLE ERROR: line 8: Blocked opening 'http://127.0.0.1:8000/security/resources/fail.html?' in a new window because the request was made in a sandboxed frame whose 'allow-popups' permission is not set.
 This tests passes if the sandboxed frame cannot navigate the top frame.
 
 PASS
diff --git a/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt b/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
index e1ae030..a616f48 100644
--- a/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
@@ -152,6 +152,7 @@
   *GenericContainer
     text "Div in list isn't presentational"
   checkbox "Content within label refers to label container"
+  button "aria-hidden false button"
   GenericContainer
   combobox
 {
@@ -337,6 +338,7 @@
   text "List item also presentational"
   GenericContainer
   checkbox "Content within label refers to label container"
+  button "aria-hidden false button"
   GenericContainer
   *combobox
     MenuListPopup
diff --git a/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/popup-blocked-to-post-blank-expected.txt b/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/popup-blocked-to-post-blank-expected.txt
new file mode 100644
index 0000000..1c6ee54
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/popup-blocked-to-post-blank-expected.txt
@@ -0,0 +1,2 @@
+CONSOLE ERROR: line 15: Not allowed to navigate top frame to data URL: data:text/html,<script>alert(window)</script>?
+If the POST pop-up was not blocked then there will be an ALERT containing a Window object. Otherwise, the test passes.
diff --git a/third_party/blink/web_tests/virtual/user-activation-v2/fast/events/popup-blocked-to-post-blank-expected.txt b/third_party/blink/web_tests/virtual/user-activation-v2/fast/events/popup-blocked-to-post-blank-expected.txt
new file mode 100644
index 0000000..1c6ee54
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/user-activation-v2/fast/events/popup-blocked-to-post-blank-expected.txt
@@ -0,0 +1,2 @@
+CONSOLE ERROR: line 15: Not allowed to navigate top frame to data URL: data:text/html,<script>alert(window)</script>?
+If the POST pop-up was not blocked then there will be an ALERT containing a Window object. Otherwise, the test passes.
diff --git a/third_party/libcxx-pretty-printers/.style.yapf b/third_party/libcxx-pretty-printers/.style.yapf
new file mode 100644
index 0000000..557fa7b
--- /dev/null
+++ b/third_party/libcxx-pretty-printers/.style.yapf
@@ -0,0 +1,2 @@
+[style]
+based_on_style = pep8
diff --git a/third_party/libcxx-pretty-printers/README.chromium b/third_party/libcxx-pretty-printers/README.chromium
index f63918a..2edbcb2 100644
--- a/third_party/libcxx-pretty-printers/README.chromium
+++ b/third_party/libcxx-pretty-printers/README.chromium
@@ -1,6 +1,6 @@
 Name: libcxx-pretty-printers
-URL: https://github.com/LeszekSwirski/libcxx-pretty-printers
-Version: dc4eb17426ce62262992d7c52aa1140f9b707c37
+URL: https://github.com/tanderson-google/libcxx-pretty-printers
+Version: unknown
 License: GPL v3
 License File: LICENSE
 Security Critical: no
@@ -9,10 +9,10 @@
 GDB Pretty Printers for libc++ of Clang/LLVM
 
 Local patches:
-None
+This is a fork of [1] which is a fork of [2] which is a fork of [3] which was
+originally a fork of some pretty-printers for libstdc++.  printers.py no longer
+tracks any of these upstreams.
 
-Upgrading:
-$ git clone https://github.com/LeszekSwirski/libcxx-pretty-printers.git
-$ rm -rf .git .gitignore
-* Add README.chromium
-* Add OWNERS
+[1] https://github.com/tanderson-google/libcxx-pretty-printers
+[2] https://github.com/LeszekSwirski/libcxx-pretty-printers
+[3] https://github.com/koutheir/libcxx-pretty-printers
diff --git a/third_party/libcxx-pretty-printers/README.md b/third_party/libcxx-pretty-printers/README.md
deleted file mode 100644
index 5433b0e..0000000
--- a/third_party/libcxx-pretty-printers/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-libcxx-pretty-printers
-======================
-
-GDB Pretty Printers for libc++ of Clang/LLVM
diff --git a/third_party/libcxx-pretty-printers/src/libcxx/v1/printers.py b/third_party/libcxx-pretty-printers/printers.py
similarity index 71%
rename from third_party/libcxx-pretty-printers/src/libcxx/v1/printers.py
rename to third_party/libcxx-pretty-printers/printers.py
index 3c43aaa5..e59493f1 100644
--- a/third_party/libcxx-pretty-printers/src/libcxx/v1/printers.py
+++ b/third_party/libcxx-pretty-printers/printers.py
@@ -63,6 +63,10 @@
     pass
 
 
+def make_type_re(typename):
+    return re.compile('^std::__[a-zA-Z0-9]+::' + typename + '<.*>$')
+
+
 # Starting with the type ORIG, search for the member type NAME.  This
 # handles searching upward through superclasses.  This is needed to
 # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615.
@@ -84,34 +88,33 @@
 
 
 def pair_to_tuple(val):
-    if val.type.name.startswith("std::__1::__compressed_pair"):
+    if make_type_re('__compressed_pair').match(val.type.name):
         t1 = val.type.template_argument(0)
         t2 = val.type.template_argument(1)
 
         base1 = val.type.fields()[0].type
         base2 = val.type.fields()[1].type
 
-        return (
-            (val if base1.template_argument(2)
-             else val.cast(base1)["__value_"]).cast(t1),
-            (val if base2.template_argument(2)
-             else val.cast(base2)["__value_"]).cast(t2)
-        )
+        return ((val if base1.template_argument(2) else
+                 val.cast(base1)["__value_"]).cast(t1),
+                (val if base2.template_argument(2) else
+                 val.cast(base2)["__value_"]).cast(t2))
 
     else:
         return (val['first'], val['second'])
 
+
 void_type = gdb.lookup_type('void')
 
+
 def ptr_to_void_ptr(val):
-  if gdb.types.get_basic_type(val.type).code == gdb.TYPE_CODE_PTR:
-    return val.cast(void_type.pointer())
-  else:
-    return val
-  
+    if gdb.types.get_basic_type(val.type).code == gdb.TYPE_CODE_PTR:
+        return val.cast(void_type.pointer())
+    else:
+        return val
 
 
-class StdStringPrinter:
+class StringPrinter:
     "Print a std::basic_string of some kind"
 
     def __init__(self, typename, val):
@@ -125,9 +128,9 @@
             type = type.target()
 
         ss = pair_to_tuple(self.val['__r_'])[0]['__s']
-        __short_mask = 0x1
+        __short_mask = int(self.val['__short_mask'])
         if (ss['__size_'] & __short_mask) == 0:
-            len = (ss['__size_'] >> 1)
+            len = ss['__size_'] >> 1 if __short_mask == 1 else ss['__size_']
             ptr = ss['__data_']
         else:
             sl = pair_to_tuple(self.val['__r_'])[0]['__l']
@@ -158,7 +161,9 @@
             else:
                 state = 'count %d, weak %d' % (usecount, weakcount)
 
-        return '%s (%s) = %s => %s' % (self.typename, state, self.val['__ptr_'], self.val['__ptr_'].dereference())
+        return '%s (%s) = %s => %s' % (self.typename, state,
+                                       self.val['__ptr_'],
+                                       self.val['__ptr_'].dereference())
 
 
 class UniquePointerPrinter:
@@ -171,11 +176,13 @@
     def to_string(self):
         v = pair_to_tuple(self.val['__ptr_'])[0]
         if v == 0:
-            return '%s<%s> = %s <nullptr>' % (str(self.typename), str(v.type.target()), str(v))
-        return '%s<%s> = %s => %s' % (str(self.typename), str(v.type.target()), str(v), v.dereference())
+            return '%s<%s> = %s <nullptr>' % (str(self.typename),
+                                              str(v.type.target()), str(v))
+        return '%s<%s> = %s => %s' % (str(self.typename), str(v.type.target()),
+                                      str(v), v.dereference())
 
 
-class StdPairPrinter:
+class PairPrinter:
     "Print a std::pair"
 
     def __init__(self, typename, val):
@@ -184,21 +191,20 @@
 
     def children(self):
         vals = pair_to_tuple(self.val)
-        return [('first', vals[0]),
-                ('second', vals[1])]
+        return [('first', vals[0]), ('second', vals[1])]
 
     def to_string(self):
         return 'pair'
 
+
 #    def display_hint(self):
 #        return 'array'
 
 
-class StdTuplePrinter:
+class TuplePrinter:
     "Print a std::tuple"
 
     class _iterator(Iterator):
-
         def __init__(self, head):
             self.head = head['base_']
             self.fields = self.head.type.fields()
@@ -226,15 +232,15 @@
             return 'empty %s' % (self.typename)
         return 'tuple'
 
+
 #    def display_hint(self):
 #        return 'array'
 
 
-class StdListPrinter:
+class ListPrinter:
     "Print a std::list"
 
     class _iterator(Iterator):
-
         def __init__(self, nodetype, head):
             self.nodetype = nodetype
             self.base = head['__next_']
@@ -268,11 +274,12 @@
             return 'empty %s' % (self.typename)
         return '%s' % (self.typename)
 
+
 #    def display_hint(self):
 #        return 'array'
 
 
-class StdListIteratorPrinter:
+class ListIteratorPrinter:
     "Print std::list::iterator"
 
     def __init__(self, typename, val):
@@ -283,11 +290,10 @@
         return self.val['__ptr_']['__value_']
 
 
-class StdForwardListPrinter:
+class ForwardListPrinter:
     "Print a std::forward_list"
 
     class _iterator(Iterator):
-
         def __init__(self, head):
             self.node = head
             self.count = 0
@@ -318,11 +324,10 @@
         return '%s' % (self.typename)
 
 
-class StdVectorPrinter:
+class VectorPrinter:
     "Print a std::vector"
 
     class _iterator(Iterator):
-
         def __init__(self, start, finish_or_size, bits_per_word, bitvec):
             self.bitvec = bitvec
             if bitvec:
@@ -371,24 +376,23 @@
 
     def children(self):
         if self.is_bool:
-            return self._iterator(self.val['__begin_'],
-                                  self.val['__size_'],
-                                  self.val['__bits_per_word'],
-                                  self.is_bool)
+            return self._iterator(self.val['__begin_'], self.val['__size_'],
+                                  self.val['__bits_per_word'], self.is_bool)
         else:
-            return self._iterator(self.val['__begin_'],
-                                  self.val['__end_'],
-                                  0,
+            return self._iterator(self.val['__begin_'], self.val['__end_'], 0,
                                   self.is_bool)
 
     def to_string(self):
         if self.is_bool:
             length = self.val['__size_']
-            capacity = pair_to_tuple(self.val['__cap_alloc_'])[0] * self.val['__bits_per_word']
+            capacity = pair_to_tuple(
+                self.val['__cap_alloc_'])[0] * self.val['__bits_per_word']
             if length == 0:
-                return 'empty %s<bool> (capacity=%d)' % (self.typename, int(capacity))
+                return 'empty %s<bool> (capacity=%d)' % (self.typename,
+                                                         int(capacity))
             else:
-                return '%s<bool> (length=%d, capacity=%d)' % (self.typename, int(length), int(capacity))
+                return '%s<bool> (length=%d, capacity=%d)' % (
+                    self.typename, int(length), int(capacity))
         else:
             start = ptr_to_void_ptr(self.val['__begin_'])
             finish = ptr_to_void_ptr(self.val['__end_'])
@@ -396,15 +400,17 @@
             length = finish - start
             capacity = end - start
             if length == 0:
-                return 'empty %s (capacity=%d)' % (self.typename, int(capacity))
+                return 'empty %s (capacity=%d)' % (self.typename,
+                                                   int(capacity))
             else:
-                return '%s (length=%d, capacity=%d)' % (self.typename, int(length), int(capacity))
+                return '%s (length=%d, capacity=%d)' % (
+                    self.typename, int(length), int(capacity))
 
     def display_hint(self):
         return 'array'
 
 
-class StdVectorIteratorPrinter:
+class VectorIteratorPrinter:
     "Print std::vector::iterator"
 
     def __init__(self, typename, val):
@@ -414,7 +420,7 @@
         return self.val['__i'].dereference()
 
 
-class StdVectorBoolIteratorPrinter:
+class VectorBoolIteratorPrinter:
     "Print std::vector<bool>::iterator"
 
     def __init__(self, typename, val):
@@ -428,11 +434,10 @@
             return 0
 
 
-class StdDequePrinter:
+class DequePrinter:
     "Print a std::deque"
 
     class _iterator(Iterator):
-
         def __init__(self, size, block_size, start, map_begin, map_end):
             self.block_size = block_size
             self.count = 0
@@ -445,7 +450,8 @@
                 self.end_p = 0
             else:
                 self.p = self.mp.dereference() + start % block_size
-                self.end_p = self.end_mp.dereference() + self.end_p % block_size
+                self.end_p = self.end_mp.dereference(
+                ) + self.end_p % block_size
 
         def __iter__(self):
             return self
@@ -459,7 +465,8 @@
                 self.mp += 1
                 self.p = self.mp.dereference()
 
-            if (self.mp > self.end_mp) or ((self.p > self.end_p) and (self.mp == self.end_mp)):
+            if (self.mp > self.end_mp) or ((self.p > self.end_p) and
+                                           (self.mp == self.end_mp)):
                 raise StopIteration
 
             return ('[%d]' % int(self.count - 1), old_p.dereference())
@@ -484,15 +491,15 @@
         if block_size.is_optimized_out:
             # Warning, this is pretty flaky
             block_size = 4096 / size_of_value_type if size_of_value_type < 256 else 16
-        return self._iterator(self.size, block_size,
-                              self.val['__start_'], block_map['__begin_'],
-                              block_map['__end_'])
+        return self._iterator(self.size, block_size, self.val['__start_'],
+                              block_map['__begin_'], block_map['__end_'])
+
 
 #    def display_hint (self):
 #        return 'array'
 
 
-class StdDequeIteratorPrinter:
+class DequeIteratorPrinter:
     "Print std::deque::iterator"
 
     def __init__(self, typename, val):
@@ -502,7 +509,7 @@
         return self.val['__ptr_'].dereference()
 
 
-class StdStackOrQueuePrinter:
+class StackOrQueuePrinter:
     "Print a std::stack or std::queue"
 
     def __init__(self, typename, val):
@@ -521,7 +528,7 @@
         return None
 
 
-class StdBitsetPrinter:
+class BitsetPrinter:
     "Print a std::bitset"
 
     def __init__(self, typename, val):
@@ -553,12 +560,11 @@
         return result
 
 
-class StdSetPrinter:
+class SetPrinter:
     "Print a std::set or std::multiset"
 
     # Turn an RbtreeIterator into a pretty-print iterator.
     class _iterator(Iterator):
-
         def __init__(self, rbiter):
             self.rbiter = rbiter
             self.count = 0
@@ -591,12 +597,12 @@
     def children(self):
         return self._iterator(self.rbiter)
 
+
 #    def display_hint (self):
 #        return 'set'
 
 
 class RbtreeIterator:
-
     def __init__(self, rbtree):
         self.node = rbtree['__begin_node_']
         self.size = pair_to_tuple(rbtree['__pair3_'])[0]
@@ -634,7 +640,7 @@
         return result
 
 
-class StdRbtreeIteratorPrinter:
+class RbtreeIteratorPrinter:
     "Print std::set::iterator"
 
     def __init__(self, typename, val):
@@ -644,12 +650,11 @@
         return self.val['__ptr_']['__value_']
 
 
-class StdMapPrinter:
+class MapPrinter:
     "Print a std::map or std::multimap"
 
     # Turn an RbtreeIterator into a pretty-print iterator.
     class _iterator(Iterator):
-
         def __init__(self, rbiter):
             self.rbiter = rbiter
             self.count = 0
@@ -663,8 +668,8 @@
         def __next__(self):
             item = self.rbiter.__next__()
             item = item.dereference()['__value_']
-            result = ('[%d] %s' % (self.count, str(
-                item['__cc']['first'])), item['__cc']['second'])
+            result = ('[%d] %s' % (self.count, str(item['__cc']['first'])),
+                      item['__cc']['second'])
             self.count += 1
             return result
 
@@ -683,11 +688,12 @@
     def children(self):
         return self._iterator(self.rbiter)
 
+
 #    def display_hint (self):
 #        return 'map'
 
 
-class StdMapIteratorPrinter:
+class MapIteratorPrinter:
     "Print std::map::iterator"
 
     def __init__(self, typename, val):
@@ -700,7 +706,6 @@
 
 
 class HashtableIterator:
-
     def __init__(self, hashtable):
         self.node = pair_to_tuple(hashtable['__p1_'])[0]['__next_']
         self.size = pair_to_tuple(hashtable['__p2_'])[0]
@@ -714,8 +719,8 @@
     def __next__(self):
         if self.node == 0:
             raise StopIteration
-        hash_node_type = gdb.lookup_type(
-            self.node.dereference().type.name + '::__node_pointer')
+        hash_node_type = gdb.lookup_type(self.node.dereference().type.name +
+                                         '::__node_pointer')
         node = self.node.cast(hash_node_type).dereference()
         self.node = node['__next_']
         value = node['__value_']
@@ -727,7 +732,7 @@
         return value
 
 
-class StdHashtableIteratorPrinter:
+class HashtableIteratorPrinter:
     "Print std::unordered_set::iterator"
 
     def __init__(self, typename, val):
@@ -737,7 +742,7 @@
         return self.val['__node_']['__value_']
 
 
-class StdUnorderedMapIteratorPrinter:
+class UnorderedMapIteratorPrinter:
     "Print std::unordered_map::iterator"
 
     def __init__(self, typename, val):
@@ -798,11 +803,12 @@
         result = []
         count = 0
         for elt in self.hashtableiter:
-            result.append(
-                ('[%d] %s' % (count, str(elt['first'])), elt['second']))
+            result.append(('[%d] %s' % (count, str(elt['__cc']['first'])),
+                           elt['__cc']['second']))
             count += 1
         return result
 
+
 #    def display_hint (self):
 #        return 'map'
 
@@ -811,7 +817,6 @@
 
 
 class RxPrinter(object):
-
     def __init__(self, name, function):
         super(RxPrinter, self).__init__()
         self.name = name
@@ -823,39 +828,23 @@
             return None
         return self.function(self.name, value)
 
+
 # A pretty-printer that conforms to the "PrettyPrinter" protocol from
 # gdb.printing.  It can also be used directly as an old-style printer.
 
 
 class Printer(object):
-
     def __init__(self, name):
         super(Printer, self).__init__()
         self.name = name
         self.subprinters = []
-        self.lookup = {}
+        self.lookup = []
         self.enabled = True
-        self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)<.*>$')
 
     def add(self, name, function):
-        # A small sanity check.
-        # FIXME
-        if not self.compiled_rx.match(name + '<>'):
-            raise ValueError(
-                'libstdc++ programming error: "%s" does not match' % name)
-        printer = RxPrinter(name, function)
+        printer = RxPrinter('std::' + name, function)
         self.subprinters.append(printer)
-        self.lookup[name] = printer
-
-    # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION.
-    def add_version(self, base, name, function):
-        self.add(base + name, function)
-        self.add(base + '__1::' + name, function)
-
-    # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
-    def add_container(self, base, name, function):
-        self.add_version(base, name, function)
-        self.add_version(base + '__1::', name, function)
+        self.lookup.append((make_type_re(name), printer))
 
     @staticmethod
     def get_basic_type(type):
@@ -873,31 +862,24 @@
         if not typename:
             return None
 
-        # All the types we match are template types, so we can use a
-        # dictionary.
-        match = self.compiled_rx.match(typename)
-        if not match:
-            return None
-
-        basename = match.group(1)
-        if basename in self.lookup:
-            return self.lookup[basename].invoke(val)
+        for (regexp, printer) in self.lookup:
+            if regexp.match(typename):
+                return printer.invoke(val)
 
         # Cannot find a pretty printer.  Return None.
         return None
 
-libcxx_printer = None
+
+printer = None
 
 
 class FilteringTypePrinter(object):
-
     def __init__(self, match, name):
         self.match = match
         self.name = name
         self.enabled = True
 
     class _recognizer(object):
-
         def __init__(self, match, name):
             self.match = match
             self.name = name
@@ -942,12 +924,9 @@
         add_one_type_printer(obj, 'basic_ostream', pfx + 'ostream')
         add_one_type_printer(obj, 'basic_iostream', pfx + 'iostream')
         add_one_type_printer(obj, 'basic_stringbuf', pfx + 'stringbuf')
-        add_one_type_printer(obj, 'basic_istringstream',
-                             pfx + 'istringstream')
-        add_one_type_printer(obj, 'basic_ostringstream',
-                             pfx + 'ostringstream')
-        add_one_type_printer(obj, 'basic_stringstream',
-                             pfx + 'stringstream')
+        add_one_type_printer(obj, 'basic_istringstream', pfx + 'istringstream')
+        add_one_type_printer(obj, 'basic_ostringstream', pfx + 'ostringstream')
+        add_one_type_printer(obj, 'basic_stringstream', pfx + 'stringstream')
         add_one_type_printer(obj, 'basic_filebuf', pfx + 'filebuf')
         add_one_type_printer(obj, 'basic_ifstream', pfx + 'ifstream')
         add_one_type_printer(obj, 'basic_ofstream', pfx + 'ofstream')
@@ -970,8 +949,8 @@
     add_one_type_printer(obj, 'basic_string', 'u16string')
     add_one_type_printer(obj, 'basic_string', 'u32string')
 
-    for dur in ('nanoseconds', 'microseconds', 'milliseconds',
-                'seconds', 'minutes', 'hours'):
+    for dur in ('nanoseconds', 'microseconds', 'milliseconds', 'seconds',
+                'minutes', 'hours'):
         add_one_type_printer(obj, 'duration', dur)
 
     add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0')
@@ -989,128 +968,70 @@
     "Register libc++ pretty-printers with objfile Obj."
 
     global _use_gdb_pp
-    global libcxx_printer
+    global printer
 
     if _use_gdb_pp:
-        gdb.printing.register_pretty_printer(obj, libcxx_printer)
+        gdb.printing.register_pretty_printer(obj, printer)
     else:
         if obj is None:
             obj = gdb
-        obj.pretty_printers.append(libcxx_printer)
+        obj.pretty_printers.append(printer)
 
     register_type_printers(obj)
 
 
 def build_libcxx_dictionary():
-    global libcxx_printer
+    global printer
 
-    libcxx_printer = Printer("libc++-v1")
+    printer = Printer("libc++")
 
-    # For _GLIBCXX_BEGIN_NAMESPACE_VERSION.
-    vers = '(__1::)?'
-    # For _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
-    container = '(__cxx2011::' + vers + ')?'
-
-    # libstdc++ objects requiring pretty-printing.
-    # In order from:
-    # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
-    libcxx_printer.add_version('std::', 'basic_string', StdStringPrinter)
-    libcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter)
-    libcxx_printer.add_container('std::', 'deque', StdDequePrinter)
-    libcxx_printer.add_container('std::', 'list', StdListPrinter)
-    libcxx_printer.add_container('std::', 'map', StdMapPrinter)
-    libcxx_printer.add_container('std::', 'multimap', StdMapPrinter)
-    libcxx_printer.add_container('std::', 'multiset', StdSetPrinter)
-    libcxx_printer.add_version('std::', 'priority_queue',
-                               StdStackOrQueuePrinter)
-    libcxx_printer.add_version('std::', 'queue', StdStackOrQueuePrinter)
-    libcxx_printer.add_version('std::', 'tuple', StdTuplePrinter)
-    libcxx_printer.add_version('std::', 'pair', StdPairPrinter)
-    libcxx_printer.add_container('std::', 'set', StdSetPrinter)
-    libcxx_printer.add_version('std::', 'stack', StdStackOrQueuePrinter)
-    libcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter)
-    libcxx_printer.add_container('std::', 'vector', StdVectorPrinter)
+    # libc++ objects requiring pretty-printing.
+    printer.add('basic_string', StringPrinter)
+    printer.add('bitset', BitsetPrinter)
+    printer.add('deque', DequePrinter)
+    printer.add('list', ListPrinter)
+    printer.add('map', MapPrinter)
+    printer.add('multimap', MapPrinter)
+    printer.add('multiset', SetPrinter)
+    printer.add('priority_queue', StackOrQueuePrinter)
+    printer.add('queue', StackOrQueuePrinter)
+    printer.add('tuple', TuplePrinter)
+    printer.add('pair', PairPrinter)
+    printer.add('set', SetPrinter)
+    printer.add('stack', StackOrQueuePrinter)
+    printer.add('unique_ptr', UniquePointerPrinter)
+    printer.add('vector', VectorPrinter)
     # vector<bool>
 
-    # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG.
-    libcxx_printer.add('std::__debug::bitset', StdBitsetPrinter)
-    libcxx_printer.add('std::__debug::deque', StdDequePrinter)
-    libcxx_printer.add('std::__debug::list', StdListPrinter)
-    libcxx_printer.add('std::__debug::map', StdMapPrinter)
-    libcxx_printer.add('std::__debug::multimap', StdMapPrinter)
-    libcxx_printer.add('std::__debug::multiset', StdSetPrinter)
-    libcxx_printer.add('std::__debug::priority_queue', StdStackOrQueuePrinter)
-    libcxx_printer.add('std::__debug::queue', StdStackOrQueuePrinter)
-    libcxx_printer.add('std::__debug::set', StdSetPrinter)
-    libcxx_printer.add('std::__debug::stack', StdStackOrQueuePrinter)
-    libcxx_printer.add('std::__debug::unique_ptr', UniquePointerPrinter)
-    libcxx_printer.add('std::__debug::vector', StdVectorPrinter)
-
     # For array - the default GDB pretty-printer seems reasonable.
-    libcxx_printer.add_version('std::', 'shared_ptr', SharedPointerPrinter)
-    libcxx_printer.add_version('std::', 'weak_ptr', SharedPointerPrinter)
-    libcxx_printer.add_container('std::', 'unordered_map', UnorderedMapPrinter)
-    libcxx_printer.add_container('std::', 'unordered_set', UnorderedSetPrinter)
-    libcxx_printer.add_container('std::', 'unordered_multimap',
-                                 UnorderedMapPrinter)
-    libcxx_printer.add_container('std::', 'unordered_multiset',
-                                 UnorderedSetPrinter)
-    libcxx_printer.add_container(
-        'std::', 'forward_list', StdForwardListPrinter)
+    printer.add('shared_ptr', SharedPointerPrinter)
+    printer.add('weak_ptr', SharedPointerPrinter)
+    printer.add('unordered_map', UnorderedMapPrinter)
+    printer.add('unordered_set', UnorderedSetPrinter)
+    printer.add('unordered_multimap', UnorderedMapPrinter)
+    printer.add('unordered_multiset', UnorderedSetPrinter)
+    printer.add('forward_list', ForwardListPrinter)
 
-    libcxx_printer.add_version('std::', 'shared_ptr', SharedPointerPrinter)
-    libcxx_printer.add_version('std::', 'weak_ptr', SharedPointerPrinter)
-    libcxx_printer.add_version('std::', 'unordered_map', UnorderedMapPrinter)
-    libcxx_printer.add_version('std::', 'unordered_set', UnorderedSetPrinter)
-    libcxx_printer.add_version('std::', 'unordered_multimap',
-                               UnorderedMapPrinter)
-    libcxx_printer.add_version('std::', 'unordered_multiset',
-                               UnorderedSetPrinter)
+    printer.add('shared_ptr', SharedPointerPrinter)
+    printer.add('weak_ptr', SharedPointerPrinter)
+    printer.add('unordered_map', UnorderedMapPrinter)
+    printer.add('unordered_set', UnorderedSetPrinter)
+    printer.add('unordered_multimap', UnorderedMapPrinter)
+    printer.add('unordered_multiset', UnorderedSetPrinter)
 
-    # These are the C++0x printer registrations for -D_GLIBCXX_DEBUG cases.
-    libcxx_printer.add('std::__debug::unordered_map', UnorderedMapPrinter)
-    libcxx_printer.add('std::__debug::unordered_set', UnorderedSetPrinter)
-    libcxx_printer.add('std::__debug::unordered_multimap', UnorderedMapPrinter)
-    libcxx_printer.add('std::__debug::unordered_multiset', UnorderedSetPrinter)
-    libcxx_printer.add('std::__debug::forward_list', StdForwardListPrinter)
+    printer.add('__list_iterator', ListIteratorPrinter)
+    printer.add('__list_const_iterator', ListIteratorPrinter)
+    printer.add('__tree_iterator', RbtreeIteratorPrinter)
+    printer.add('__tree_const_iterator', RbtreeIteratorPrinter)
+    printer.add('__hash_iterator', HashtableIteratorPrinter)
+    printer.add('__hash_const_iterator', HashtableIteratorPrinter)
+    printer.add('__hash_map_iterator', UnorderedMapIteratorPrinter)
+    printer.add('__hash_map_const_iterator', UnorderedMapIteratorPrinter)
+    printer.add('__map_iterator', MapIteratorPrinter)
+    printer.add('__map_const_iterator', MapIteratorPrinter)
+    printer.add('__deque_iterator', DequeIteratorPrinter)
+    printer.add('__wrap_iter', VectorIteratorPrinter)
+    printer.add('__bit_iterator', VectorBoolIteratorPrinter)
 
-    libcxx_printer.add_container('std::', '__list_iterator',
-                                 StdListIteratorPrinter)
-    libcxx_printer.add_container('std::', '__list_const_iterator',
-                                 StdListIteratorPrinter)
-    libcxx_printer.add_version('std::', '__tree_iterator',
-                               StdRbtreeIteratorPrinter)
-    libcxx_printer.add_version('std::', '__tree_const_iterator',
-                               StdRbtreeIteratorPrinter)
-    libcxx_printer.add_version('std::', '__hash_iterator',
-                               StdHashtableIteratorPrinter)
-    libcxx_printer.add_version('std::', '__hash_const_iterator',
-                               StdHashtableIteratorPrinter)
-    libcxx_printer.add_version('std::', '__hash_map_iterator',
-                               StdUnorderedMapIteratorPrinter)
-    libcxx_printer.add_version('std::', '__hash_map_const_iterator',
-                               StdUnorderedMapIteratorPrinter)
-    libcxx_printer.add_version('std::', '__map_iterator',
-                               StdMapIteratorPrinter)
-    libcxx_printer.add_version('std::', '__map_const_iterator',
-                               StdMapIteratorPrinter)
-    libcxx_printer.add_container('std::', '__deque_iterator',
-                                 StdDequeIteratorPrinter)
-    libcxx_printer.add_version('std::', '__wrap_iter',
-                               StdVectorIteratorPrinter)
-    libcxx_printer.add_version('std::', '__bit_iterator',
-                               StdVectorBoolIteratorPrinter)
-
-    # Debug (compiled with -D_GLIBCXX_DEBUG) printer
-    # registrations.  The Rb_tree debug iterator when unwrapped
-    # from the encapsulating __gnu_debug::_Safe_iterator does not
-    # have the __norm namespace. Just use the existing printer
-    # registration for that.
-    libcxx_printer.add('std::__norm::__list_iterator',
-                       StdListIteratorPrinter)
-    libcxx_printer.add('std::__norm::__list_const_iterator',
-                       StdListIteratorPrinter)
-    libcxx_printer.add('std::__norm::__deque_iterator',
-                       StdDequeIteratorPrinter)
 
 build_libcxx_dictionary()
diff --git a/third_party/libcxx-pretty-printers/src/gdbinit b/third_party/libcxx-pretty-printers/src/gdbinit
deleted file mode 100644
index c45e420..0000000
--- a/third_party/libcxx-pretty-printers/src/gdbinit
+++ /dev/null
@@ -1,6 +0,0 @@
-python
-import sys 
-sys.path.insert(0, '<path_to_libcxx-pp_src_dir>') 
-from libcxx.v1.printers import register_libcxx_printers 
-register_libcxx_printers (None) 
-end
diff --git a/third_party/libcxx-pretty-printers/src/libcxx/__init__.py b/third_party/libcxx-pretty-printers/src/libcxx/__init__.py
deleted file mode 100644
index 8b13789..0000000
--- a/third_party/libcxx-pretty-printers/src/libcxx/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/third_party/libcxx-pretty-printers/src/libcxx/v1/__init__.py b/third_party/libcxx-pretty-printers/src/libcxx/v1/__init__.py
deleted file mode 100644
index 8b13789..0000000
--- a/third_party/libcxx-pretty-printers/src/libcxx/v1/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/third_party/libwebm/OWNERS b/third_party/libwebm/OWNERS
index ca0fd18a..43542744 100644
--- a/third_party/libwebm/OWNERS
+++ b/third_party/libwebm/OWNERS
@@ -1,12 +1,9 @@
 # The following OWNERS refer to libwebm Chromium integration.
 emircan@chromium.org
+mcasas@chromium.org
 niklase@chromium.org
 
 # The following OWNER refer to libwebm content.
 tomfinegan@chromium.org
 
-# Original (legacy) owner.
-mcasas@chromium.org
-
-# TEAM: webrtc-dev@chromium.org
 # COMPONENT: Blink>MediaRecording
diff --git a/tools/gdb/gdbinit b/tools/gdb/gdbinit
index f85c233e..99143aee 100644
--- a/tools/gdb/gdbinit
+++ b/tools/gdb/gdbinit
@@ -35,11 +35,11 @@
   if git.returncode:
     return
   libcxx_pretty_printers = os.path.join(str(src_dir).rstrip(), 'third_party',
-                                        'libcxx-pretty-printers', 'src')
+                                        'libcxx-pretty-printers')
   if not os.path.isdir(libcxx_pretty_printers):
     return
   sys.path.insert(1, libcxx_pretty_printers)
-  from libcxx.v1.printers import register_libcxx_printers
+  from printers import register_libcxx_printers
   register_libcxx_printers(None)
   libcxx_pretty_printers_loaded = True
 
diff --git a/tools/grit/grit/scons.py b/tools/grit/grit/scons.py
deleted file mode 100644
index 71d45fc..0000000
--- a/tools/grit/grit/scons.py
+++ /dev/null
@@ -1,254 +0,0 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-'''SCons integration for GRIT.
-'''
-
-# NOTE: DO NOT IMPORT ANY GRIT STUFF HERE - we import lazily so that
-# grit and its dependencies aren't imported until actually needed.
-
-import os
-import types
-
-def _IsDebugEnabled():
-  return 'GRIT_DEBUG' in os.environ and os.environ['GRIT_DEBUG'] == '1'
-
-def _SourceToFile(source):
-  '''Return the path to the source file, given the 'source' argument as provided
-  by SCons to the _Builder or _Emitter functions.
-  '''
-  # Get the filename of the source.  The 'source' parameter can be a string,
-  # a "node", or a list of strings or nodes.
-  if isinstance(source, types.ListType):
-    source = str(source[0])
-  else:
-    source = str(source)
-  return source
-
-
-def _ParseRcFlags(flags):
-  """Gets a mapping of defines.
-
-  Args:
-    flags: env['RCFLAGS']; the input defines.
-
-  Returns:
-    A tuple of (defines, res_file):
-      defines: A mapping of {name: val}
-      res_file: None, or the specified res file for static file dependencies.
-  """
-  from grit import util
-
-  defines = {}
-  res_file = None
-  # Get the CPP defines from the environment.
-  res_flag = '--res_file='
-  for flag in flags:
-    if flag.startswith(res_flag):
-      res_file = flag[len(res_flag):]
-      continue
-    if flag.startswith('/D'):
-      flag = flag[2:]
-    name, val = util.ParseDefine(flag)
-    # Only apply to first instance of a given define
-    if name not in defines:
-      defines[name] = val
-  return (defines, res_file)
-
-
-def _Builder(target, source, env):
-  print _SourceToFile(source)
-
-  from grit import grit_runner
-  from grit.tool import build
-  options = grit_runner.Options()
-  # This sets options to default values
-  options.ReadOptions([])
-  options.input = _SourceToFile(source)
-
-  # TODO(joi) Check if we can get the 'verbose' option from the environment.
-
-  builder = build.RcBuilder(defines=_ParseRcFlags(env['RCFLAGS'])[0])
-
-  # To ensure that our output files match what we promised SCons, we
-  # use the list of targets provided by SCons and update the file paths in
-  # our .grd input file with the targets.
-  builder.scons_targets = [str(t) for t in target]
-  builder.Run(options, [])
-  return None  # success
-
-
-def _GetOutputFiles(grd, base_dir):
-  """Processes outputs listed in the grd into rc_headers and rc_alls.
-
-  Note that anything that's not an rc_header is classified as an rc_all.
-
-  Args:
-    grd: An open GRD reader.
-
-  Returns:
-    A tuple of (rc_headers, rc_alls, lang_folders):
-      rc_headers: Outputs marked as rc_header.
-      rc_alls: All other outputs.
-      lang_folders: The output language folders.
-  """
-  rc_headers = []
-  rc_alls = []
-  lang_folders = {}
-
-  # Explicit output files.
-  for output in grd.GetOutputFiles():
-    path = os.path.join(base_dir, output.GetFilename())
-    if (output.GetType() == 'rc_header'):
-      rc_headers.append(path)
-    else:
-      rc_alls.append(path)
-    if _IsDebugEnabled():
-      print 'GRIT: Added target %s' % path
-    if output.attrs['lang'] != '':
-      lang_folders[output.attrs['lang']] = os.path.dirname(path)
-
-  return (rc_headers, rc_alls, lang_folders)
-
-
-def _ProcessNodes(grd, base_dir, lang_folders):
-  """Processes the GRD nodes to figure out file dependencies.
-
-  Args:
-    grd: An open GRD reader.
-    base_dir: The base directory for filenames.
-    lang_folders: THe output language folders.
-
-  Returns:
-    A tuple of (structure_outputs, translated_files, static_files):
-      structure_outputs: Structures marked as sconsdep.
-      translated_files: Files that are structures or skeletons, and get
-        translated by GRIT.
-      static_files: Files that are includes, and are used directly by res files.
-  """
-  structure_outputs = []
-  translated_files = []
-  static_files = []
-
-  # Go through nodes, figuring out resources.  Also output certain resources
-  # as build targets, based on the sconsdep flag.
-  for node in grd.ActiveDescendants():
-    with node:
-      file = node.ToRealPath(node.GetInputPath())
-      if node.name == 'structure':
-        translated_files.append(os.path.abspath(file))
-        # TODO(joi) Should remove the "if sconsdep is true" thing as it is a
-        # hack - see grit/node/structure.py
-        if node.HasFileForLanguage() and node.attrs['sconsdep'] == 'true':
-          for lang in lang_folders:
-            path = node.FileForLanguage(lang, lang_folders[lang],
-                                        create_file=False,
-                                        return_if_not_generated=False)
-            if path:
-              structure_outputs.append(path)
-              if _IsDebugEnabled():
-                print 'GRIT: Added target %s' % path
-      elif (node.name == 'skeleton' or (node.name == 'file' and node.parent and
-                                        node.parent.name == 'translations')):
-        translated_files.append(os.path.abspath(file))
-      elif node.name == 'include':
-        # If it's added by file name and the file isn't easy to find, don't make
-        # it a dependency.  This could add some build flakiness, but it doesn't
-        # work otherwise.
-        if node.attrs['filenameonly'] != 'true' or os.path.exists(file):
-          static_files.append(os.path.abspath(file))
-        # If it's output from mk, look in the output directory.
-        elif node.attrs['mkoutput'] == 'true':
-          static_files.append(os.path.join(base_dir, os.path.basename(file)))
-
-  return (structure_outputs, translated_files, static_files)
-
-
-def _SetDependencies(env, base_dir, res_file, rc_alls, translated_files,
-                     static_files):
-  """Sets dependencies in the environment.
-
-  Args:
-    env: The SCons environment.
-    base_dir: The base directory for filenames.
-    res_file: The res_file specified in the RC flags.
-    rc_alls: All non-rc_header outputs.
-    translated_files: Files that are structures or skeletons, and get
-      translated by GRIT.
-    static_files: Files that are includes, and are used directly by res files.
-  """
-  if res_file:
-    env.Depends(os.path.join(base_dir, res_file), static_files)
-  else:
-    # Make a best effort dependency setup when no res file is specified.
-    translated_files.extend(static_files)
-
-  for rc_all in rc_alls:
-    env.Depends(rc_all, translated_files)
-
-
-def _Emitter(target, source, env):
-  """Modifies the list of targets to include all outputs.
-
-  Note that this also sets up the dependencies, even though it's an emitter
-  rather than a scanner.  This is so that the resource header file doesn't show
-  as having dependencies.
-
-  Args:
-    target: The list of targets to emit for.
-    source: The source or list of sources for the target.
-    env: The SCons environment.
-
-  Returns:
-    A tuple of (targets, sources).
-  """
-  from grit import grd_reader
-  from grit import util
-
-  (defines, res_file) = _ParseRcFlags(env['RCFLAGS'])
-
-  grd = grd_reader.Parse(_SourceToFile(source), debug=_IsDebugEnabled())
-  # TODO(jperkins): This is a hack to get an output context set for the reader.
-  # This should really be smarter about the language.
-  grd.SetOutputLanguage('en')
-  grd.SetDefines(defines)
-
-  base_dir = util.dirname(str(target[0]))
-  (rc_headers, rc_alls, lang_folders) = _GetOutputFiles(grd, base_dir)
-  (structure_outputs, translated_files, static_files) = _ProcessNodes(grd,
-      base_dir, lang_folders)
-
-  rc_alls.extend(structure_outputs)
-  _SetDependencies(env, base_dir, res_file, rc_alls, translated_files,
-                   static_files)
-
-  targets = rc_headers
-  targets.extend(rc_alls)
-
-  # Return target and source lists.
-  return (targets, source)
-
-
-# Function name is mandated by newer versions of SCons.
-def generate(env):
-  # Importing this module should be possible whenever this function is invoked
-  # since it should only be invoked by SCons.
-  import SCons.Builder
-  import SCons.Action
-
-  # The varlist parameter tells SCons that GRIT needs to be invoked again
-  # if RCFLAGS has changed since last compilation.
-  build_action = SCons.Action.FunctionAction(_Builder, varlist=['RCFLAGS'])
-  emit_action = SCons.Action.FunctionAction(_Emitter, varlist=['RCFLAGS'])
-
-  builder = SCons.Builder.Builder(action=build_action, emitter=emit_action,
-                                  src_suffix='.grd')
-
-  # Add our builder and scanner to the environment.
-  env.Append(BUILDERS = {'GRIT': builder})
-
-
-# Function name is mandated by newer versions of SCons.
-def exists(env):
-  return 1
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py
index ecebf7c..46ea4ba 100644
--- a/tools/grit/grit/tool/build.py
+++ b/tools/grit/grit/tool/build.py
@@ -2,8 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-'''The 'grit build' tool along with integration for this tool with the
-SCons build system.
+'''The 'grit build' tool.
 '''
 
 import codecs
@@ -218,12 +217,9 @@
       print 'This tool takes no tool-specific arguments.'
       return 2
     self.SetOptions(opts)
-    if self.scons_targets:
-      self.VerboseOut('Using SCons targets to identify files to output.\n')
-    else:
-      self.VerboseOut('Output directory: %s (absolute path: %s)\n' %
-                      (self.output_directory,
-                       os.path.abspath(self.output_directory)))
+    self.VerboseOut('Output directory: %s (absolute path: %s)\n' %
+                    (self.output_directory,
+                     os.path.abspath(self.output_directory)))
 
     if whitelist_filenames:
       self.whitelist_names = set()
@@ -281,11 +277,6 @@
     # has been called, otherwise None.
     self.res = None
 
-    # Set to a list of filenames for the output nodes that are relative
-    # to the current working directory.  They are in the same order as the
-    # output nodes in the file.
-    self.scons_targets = None
-
     # The set of names that are whitelisted to actually be included in the
     # output.
     self.whitelist_names = None
@@ -351,20 +342,9 @@
     return 'utf_16'
 
   def Process(self):
-    # Update filenames with those provided by SCons if we're being invoked
-    # from SCons.  The list of SCons targets also includes all <structure>
-    # node outputs, but it starts with our output files, in the order they
-    # occur in the .grd
-    if self.scons_targets:
-      assert len(self.scons_targets) >= len(self.res.GetOutputFiles())
-      outfiles = self.res.GetOutputFiles()
-      for ix in range(len(outfiles)):
-        outfiles[ix].output_filename = os.path.abspath(
-          self.scons_targets[ix])
-    else:
-      for output in self.res.GetOutputFiles():
-        output.output_filename = os.path.abspath(os.path.join(
-          self.output_directory, output.GetOutputFilename()))
+    for output in self.res.GetOutputFiles():
+      output.output_filename = os.path.abspath(os.path.join(
+        self.output_directory, output.GetOutputFilename()))
 
     # If there are whitelisted names, tag the tree once up front, this way
     # while looping through the actual output, it is just an attribute check.
@@ -490,7 +470,9 @@
 
     and we run
 
-      grit -i blah.grd -o ../out/gen --depdir ../out --depfile ../out/gen/blah.rd.d
+      grit -i blah.grd -o ../out/gen \
+           --depdir ../out \
+           --depfile ../out/gen/blah.rd.d
 
     from the directory src/ we will generate a depfile ../out/gen/blah.grd.d
     that has the contents
diff --git a/tools/idl_parser/idl_lexer.py b/tools/idl_parser/idl_lexer.py
index e39650175..b7e0674 100755
--- a/tools/idl_parser/idl_lexer.py
+++ b/tools/idl_parser/idl_lexer.py
@@ -71,7 +71,6 @@
     'float' : 'FLOAT',
     'FrozenArray' : 'FROZENARRAY',
     'getter': 'GETTER',
-    'implements' : 'IMPLEMENTS',
     'includes' : 'INCLUDES',
     'Infinity' : 'INFINITY',
     'inherit' : 'INHERIT',
diff --git a/tools/idl_parser/idl_parser.py b/tools/idl_parser/idl_parser.py
index e53489d..17f05c3 100755
--- a/tools/idl_parser/idl_parser.py
+++ b/tools/idl_parser/idl_parser.py
@@ -259,7 +259,6 @@
                   | Dictionary
                   | Enum
                   | Typedef
-                  | ImplementsStatement
                   | IncludesStatement"""
     p[0] = p[1]
 
@@ -497,11 +496,6 @@
     """Typedef : TYPEDEF error ';'"""
     p[0] = self.BuildError(p, 'Typedef')
 
-  def p_ImplementsStatement(self, p):
-    """ImplementsStatement : identifier IMPLEMENTS identifier ';'"""
-    name = self.BuildAttribute('REFERENCE', p[3])
-    p[0] = self.BuildNamed('Implements', p, 1, name)
-
   def p_IncludesStatement(self, p):
     """IncludesStatement : identifier INCLUDES identifier ';'"""
     name = self.BuildAttribute('REFERENCE', p[3])
@@ -825,7 +819,6 @@
                            | DICTIONARY
                            | ENUM
                            | GETTER
-                           | IMPLEMENTS
                            | INCLUDES
                            | INHERIT
                            | LEGACYCALLER
diff --git a/tools/idl_parser/idl_parser_test.py b/tools/idl_parser/idl_parser_test.py
index 4d27abe..d7c8a5d 100755
--- a/tools/idl_parser/idl_parser_test.py
+++ b/tools/idl_parser/idl_parser_test.py
@@ -52,52 +52,52 @@
         self._TestNode(node, filename)
 
 
-class TestImplements(unittest.TestCase):
+class TestIncludes(unittest.TestCase):
 
   def setUp(self):
     self.parser = IDLParser(IDLLexer(), mute_error=True)
 
-  def _ParseImplements(self, idl_text):
+  def _ParseIncludes(self, idl_text):
     filenode = self.parser.ParseText(filename='', data=idl_text)
     self.assertEqual(1, len(filenode.GetChildren()))
     return filenode.GetChildren()[0]
 
-  def testAImplementsB(self):
-    idl_text = 'A implements B;'
-    implements_node = self._ParseImplements(idl_text)
-    self.assertEqual('Implements(A)', str(implements_node))
-    reference_node = implements_node.GetProperty('REFERENCE')
+  def testAIncludesB(self):
+    idl_text = 'A includes B;'
+    includes_node = self._ParseIncludes(idl_text)
+    self.assertEqual('Includes(A)', str(includes_node))
+    reference_node = includes_node.GetProperty('REFERENCE')
     self.assertEqual('B', str(reference_node))
 
-  def testBImplementsC(self):
-    idl_text = 'B implements C;'
-    implements_node = self._ParseImplements(idl_text)
-    self.assertEqual('Implements(B)', str(implements_node))
-    reference_node = implements_node.GetProperty('REFERENCE')
+  def testBIncludesC(self):
+    idl_text = 'B includes C;'
+    includes_node = self._ParseIncludes(idl_text)
+    self.assertEqual('Includes(B)', str(includes_node))
+    reference_node = includes_node.GetProperty('REFERENCE')
     self.assertEqual('C', str(reference_node))
 
   def testUnexpectedSemicolon(self):
-    idl_text = 'A implements;'
-    node = self._ParseImplements(idl_text)
+    idl_text = 'A includes;'
+    node = self._ParseIncludes(idl_text)
     self.assertEqual('Error', node.GetClass())
     error_message = node.GetName()
-    self.assertEqual('Unexpected ";" after keyword "implements".',
+    self.assertEqual('Unexpected ";" after keyword "includes".',
         error_message)
 
-  def testUnexpectedImplements(self):
-    idl_text = 'implements C;'
-    node = self._ParseImplements(idl_text)
+  def testUnexpectedIncludes(self):
+    idl_text = 'includes C;'
+    node = self._ParseIncludes(idl_text)
     self.assertEqual('Error', node.GetClass())
     error_message = node.GetName()
-    self.assertEqual('Unexpected implements.',
+    self.assertEqual('Unexpected includes.',
         error_message)
 
-  def testUnexpectedImplementsAfterBracket(self):
-    idl_text = '[foo] implements B;'
-    node = self._ParseImplements(idl_text)
+  def testUnexpectedIncludesAfterBracket(self):
+    idl_text = '[foo] includes B;'
+    node = self._ParseIncludes(idl_text)
     self.assertEqual('Error', node.GetClass())
     error_message = node.GetName()
-    self.assertEqual('Unexpected keyword "implements" after "]".',
+    self.assertEqual('Unexpected keyword "includes" after "]".',
         error_message)
 
 
diff --git a/tools/idl_parser/test_lexer/keywords.in b/tools/idl_parser/test_lexer/keywords.in
index 612facfd..c175d28 100644
--- a/tools/idl_parser/test_lexer/keywords.in
+++ b/tools/idl_parser/test_lexer/keywords.in
@@ -15,7 +15,6 @@
 FALSE false
 FLOAT float
 GETTER getter
-IMPLEMENTS implements
 INFINITY Infinity
 INHERIT inherit
 INTERFACE interface
diff --git a/tools/idl_parser/test_parser/interface_web.idl b/tools/idl_parser/test_parser/interface_web.idl
index 58e744d..566e27a 100644
--- a/tools/idl_parser/test_parser/interface_web.idl
+++ b/tools/idl_parser/test_parser/interface_web.idl
@@ -617,12 +617,6 @@
 [ Exposed(Window, Worker) ] interface InterfaceExposedError { };
 
 /** TREE
- *Implements(Foo)
- *  REFERENCE: Bar
- */
-Foo implements Bar;
-
-/** TREE
  *Includes(Foo)
  *  REFERENCE: Bar
  */
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 496c60d..5d7a0e9 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -168,6 +168,8 @@
       'Dawn Linux x64 Builder': 'dawn_tests_release_trybot',
       'Dawn Linux x64 DEPS Builder': 'dawn_tests_release_trybot',
 
+      'Dawn Mac x64 Builder': 'dawn_tests_release_trybot',
+
       'Dawn Win10 x86 Builder': 'dawn_tests_release_trybot_x86',
       'Dawn Win10 x64 Builder': 'dawn_tests_release_trybot',
       'Dawn Win10 x86 DEPS Builder': 'dawn_tests_release_trybot_x86',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 86d5826..3553b23 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -34177,6 +34177,7 @@
   <int value="1298981651" label="disable-new-task-manager"/>
   <int value="1300282719" label="OfflinePagesBackgroundLoading:enabled"/>
   <int value="1300753556" label="ManualPasswordGenerationAndroid:disabled"/>
+  <int value="1301902557" label="AutofillCreditCardAuthentication:disabled"/>
   <int value="1302421166" label="NativeNotifications:disabled"/>
   <int value="1304636193" label="ArcEnableUnifiedAudioFocus:enabled"/>
   <int value="1307003774" label="AutofillEnableCompanyName:disabled"/>
@@ -34293,6 +34294,7 @@
   <int value="1479248574" label="disable-voice-input"/>
   <int value="1481562816" label="disable-password-link"/>
   <int value="1482039233" label="SearchSuggestionsOnLocalNtp:disabled"/>
+  <int value="1482839038" label="AutofillCreditCardAuthentication:enabled"/>
   <int value="1486171015" label="disable-fill-on-account-select"/>
   <int value="1487341558" label="MacViewsAutofillPopup:enabled"/>
   <int value="1488193175" label="ChromeOSAssistant:enabled"/>
diff --git a/tools/metrics/histograms/pretty_print.py b/tools/metrics/histograms/pretty_print.py
index dd57976d..a72d2c5 100755
--- a/tools/metrics/histograms/pretty_print.py
+++ b/tools/metrics/histograms/pretty_print.py
@@ -59,24 +59,33 @@
 
 def fixObsoleteOrder(tree):
   """Put obsolete tags at the beginning of histogram tags."""
+  obsoletes = []
+
   for child in tree:
-    obsoletes = []
     if child.tag == 'obsolete':
       obsoletes.append(child)
-    for obsolete in obsoletes:
-      tree.remove(obsolete)
-      tree.insert(0, obsolete)
-    fixObsoleteOrder(child)
+    else:
+      fixObsoleteOrder(child)
+
+  for obsolete in obsoletes:
+    tree.remove(obsolete)
+
+  # Only keep the first obsolete tag.
+  if obsoletes:
+    tree.insert(0, obsoletes[0])
 
 def DropNodesByTagName(tree, tag):
   """Drop all nodes with named tag from the XML tree."""
+  removes = []
+
   for child in tree:
-    removes = []
     if child.tag == tag:
       removes.append(child)
-    for child in removes:
-      tree.remove(child)
-    DropNodesByTagName(child, tag)
+    else:
+      DropNodesByTagName(child, tag)
+
+  for child in removes:
+    tree.remove(child)
 
 def PrettyPrintHistograms(raw_xml):
   """Pretty-print the given histograms XML.
diff --git a/tools/metrics/histograms/pretty_print_test.py b/tools/metrics/histograms/pretty_print_test.py
index e0c1280c..07f91e2 100755
--- a/tools/metrics/histograms/pretty_print_test.py
+++ b/tools/metrics/histograms/pretty_print_test.py
@@ -27,6 +27,9 @@
  </histogram>
  <histogram name="Foo.Bar" units="xxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyzzzz">
   <summary>Foo</summary>
+  <obsolete>Obsolete 1</obsolete>
+  <obsolete>Obsolete 2</obsolete>
+  <enums>This shouldn't be here</enums>
  </histogram>
 </histograms>
 <enums>This shouldn't be here</enums>
@@ -43,6 +46,9 @@
 <histograms>
 
 <histogram name="Foo.Bar" units="xxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyzzzz">
+  <obsolete>
+    Obsolete 1
+  </obsolete>
   <summary>Foo</summary>
 </histogram>
 
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 3bb08260..a2e4927 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -42,6 +42,44 @@
   </metric>
 </event>
 
+<event name="AbusiveExperienceHeuristic.JavaScriptDialog">
+  <owner>yaoxia@chromium.org</owner>
+  <metric name="DismissalCause">
+    <summary>
+      An enum that specifies the dismissal reason for JavaScript popup dialog
+      that can be triggered by window.alert(), window.confirm() or
+      window.prompt(). See JavaScriptDialogTabHelper::DismissalCause for the
+      enum elements.
+    </summary>
+  </metric>
+</event>
+
+<event name="AbusiveExperienceHeuristic.TabUnder">
+  <owner>csharrison@chromium.org</owner>
+  <metric name="DidTabUnder">
+    <summary>
+      True if the page attempted a tab-under navigation.
+    </summary>
+  </metric>
+</event>
+
+<event name="AbusiveExperienceHeuristic.WindowOpen">
+  <owner>yaoxia@chromium.org</owner>
+  <summary>
+    Recorded whenever window.open() is called when AdTagging is enabled.
+  </summary>
+  <metric name="FromAdScript">
+    <summary>
+      True if the page called window.open() with an ad script in the stack.
+    </summary>
+  </metric>
+  <metric name="FromAdSubframe">
+    <summary>
+      True if the page called window.open() from an ad subframe.
+    </summary>
+  </metric>
+</event>
+
 <event name="AdPageLoad">
   <owner>johnidel@chromium.org</owner>
   <owner>jkarlin@chromium.org</owner>
@@ -87,44 +125,6 @@
   </metric>
 </event>
 
-<event name="AbusiveExperienceHeuristic.TabUnder">
-  <owner>csharrison@chromium.org</owner>
-  <metric name="DidTabUnder">
-    <summary>
-      True if the page attempted a tab-under navigation.
-    </summary>
-  </metric>
-</event>
-
-<event name="AbusiveExperienceHeuristic.WindowOpen">
-  <owner>yaoxia@chromium.org</owner>
-  <summary>
-    Recorded whenever window.open() is called when AdTagging is enabled.
-  </summary>
-  <metric name="FromAdScript">
-    <summary>
-      True if the page called window.open() with an ad script in the stack.
-    </summary>
-  </metric>
-  <metric name="FromAdSubframe">
-    <summary>
-      True if the page called window.open() from an ad subframe.
-    </summary>
-  </metric>
-</event>
-
-<event name="AbusiveExperienceHeuristic.JavaScriptDialog">
-  <owner>yaoxia@chromium.org</owner>
-  <metric name="DismissalCause">
-    <summary>
-      An enum that specifies the dismissal reason for JavaScript popup dialog
-      that can be triggered by window.alert(), window.confirm() or
-      window.prompt(). See JavaScriptDialogTabHelper::DismissalCause for the
-      enum elements.
-    </summary>
-  </metric>
-</event>
-
 <event name="AmpPageLoad" singular="True">
   <owner>sullivan@chromium.org</owner>
   <metric name="MainFrameAmpPageLoad">
@@ -185,93 +185,6 @@
   </metric>
 </event>
 
-<event name="Autofill.CardUploadDecision">
-  <owner>sebsg@chromium.org</owner>
-  <metric name="UploadDecision">
-    <summary>
-      Whether the upload was proposed to the user or the reasons why it was not.
-      The value is a bitmask of |CardUploadDecisionMetric|.
-    </summary>
-  </metric>
-</event>
-
-<event name="AppListAppLaunch">
-  <owner>pdyson@chromium.org</owner>
-  <summary>
-    Recorded when an app is launched from the launcher on ChromeOS. This can be
-    from the suggestion chip, or from the grid of apps. The UKM metrics are not
-    keyed by navigational urls. Instead, for Chrome apps the keys are based upon
-    the app id, for Play apps the keys are based upon a hash of the package name
-    and for PWAs the keys are the urls associated with the PWA.
-  </summary>
-  <metric name="AllClicksLast24Hours">
-    <summary>
-      Total number of clicks launching logged apps in the last 24 hours.
-      Accurate to the nearest 15 minutes. Bucketing: values above 20 rounded
-      down to the nearest 10. Maximum value of 200.
-    </summary>
-  </metric>
-  <metric name="AllClicksLastHour">
-    <summary>
-      Total number of clicks launching logged apps in the last hour. Accurate to
-      the nearest minute. Bucketing: values above 20 rounded down to the nearest
-      10. Maximum value of 200.
-    </summary>
-  </metric>
-  <metric name="AppType">
-    <summary>
-      The type of app. 1: CHROME, 2: PLAY, 3: PWA.
-    </summary>
-  </metric>
-  <metric name="ClickMethod">
-    <summary>
-      Click method. 1: MOUSE, 2: TOUCH, 3: SYTLUS, 4: KEYBOARD.
-    </summary>
-  </metric>
-  <metric name="DayOfWeek">
-    <summary>
-      An enum representing the day of the week that the data was logged in the
-      local time zone. Sunday = 0.
-    </summary>
-  </metric>
-  <metric name="DeviceMode">
-    <summary>
-      The mode of the device. 1: CLOSED_LID (Lid is closed), 2: LAPTOP (Lid is
-      open, tablet mode off or unsupported) , 3: TABLET (Lid is open, tablet
-      mode on or no lid at all).
-    </summary>
-  </metric>
-  <metric name="DeviceType">
-    <summary>
-      The type of the device. 1: TABLET, 2: LAPTOP.
-    </summary>
-  </metric>
-  <metric name="HourOfDay">
-    <summary>
-      The hour of the day when the data is logged. Hours since midnight in the
-      local time zone.
-    </summary>
-  </metric>
-  <metric name="LaunchedFrom">
-    <summary>
-      Where the app was launched from. 1: GRID, 2: SUGGESTED, 3: SHELF.
-    </summary>
-  </metric>
-  <metric name="PositionIndex">
-    <summary>
-      The position of the app within the grid/suggested apps/shelf. 0 is the
-      first position.
-    </summary>
-  </metric>
-  <metric name="TotalHours">
-    <summary>
-      Number of hours in the current session up to this event. Bucketing:
-      exponential buckets, increasing in size by 25%, rounded to the nearest
-      integer. i.e. 0, 1, 2, 3, 4, 5, 6, 7, 9, 12, 15, 18, 23, 28, 36, 44...
-    </summary>
-  </metric>
-</event>
-
 <event name="AppListAppClickData">
   <owner>pdyson@chromium.org</owner>
   <summary>
@@ -508,6 +421,93 @@
   </metric>
 </event>
 
+<event name="AppListAppLaunch">
+  <owner>pdyson@chromium.org</owner>
+  <summary>
+    Recorded when an app is launched from the launcher on ChromeOS. This can be
+    from the suggestion chip, or from the grid of apps. The UKM metrics are not
+    keyed by navigational urls. Instead, for Chrome apps the keys are based upon
+    the app id, for Play apps the keys are based upon a hash of the package name
+    and for PWAs the keys are the urls associated with the PWA.
+  </summary>
+  <metric name="AllClicksLast24Hours">
+    <summary>
+      Total number of clicks launching logged apps in the last 24 hours.
+      Accurate to the nearest 15 minutes. Bucketing: values above 20 rounded
+      down to the nearest 10. Maximum value of 200.
+    </summary>
+  </metric>
+  <metric name="AllClicksLastHour">
+    <summary>
+      Total number of clicks launching logged apps in the last hour. Accurate to
+      the nearest minute. Bucketing: values above 20 rounded down to the nearest
+      10. Maximum value of 200.
+    </summary>
+  </metric>
+  <metric name="AppType">
+    <summary>
+      The type of app. 1: CHROME, 2: PLAY, 3: PWA.
+    </summary>
+  </metric>
+  <metric name="ClickMethod">
+    <summary>
+      Click method. 1: MOUSE, 2: TOUCH, 3: SYTLUS, 4: KEYBOARD.
+    </summary>
+  </metric>
+  <metric name="DayOfWeek">
+    <summary>
+      An enum representing the day of the week that the data was logged in the
+      local time zone. Sunday = 0.
+    </summary>
+  </metric>
+  <metric name="DeviceMode">
+    <summary>
+      The mode of the device. 1: CLOSED_LID (Lid is closed), 2: LAPTOP (Lid is
+      open, tablet mode off or unsupported) , 3: TABLET (Lid is open, tablet
+      mode on or no lid at all).
+    </summary>
+  </metric>
+  <metric name="DeviceType">
+    <summary>
+      The type of the device. 1: TABLET, 2: LAPTOP.
+    </summary>
+  </metric>
+  <metric name="HourOfDay">
+    <summary>
+      The hour of the day when the data is logged. Hours since midnight in the
+      local time zone.
+    </summary>
+  </metric>
+  <metric name="LaunchedFrom">
+    <summary>
+      Where the app was launched from. 1: GRID, 2: SUGGESTED, 3: SHELF.
+    </summary>
+  </metric>
+  <metric name="PositionIndex">
+    <summary>
+      The position of the app within the grid/suggested apps/shelf. 0 is the
+      first position.
+    </summary>
+  </metric>
+  <metric name="TotalHours">
+    <summary>
+      Number of hours in the current session up to this event. Bucketing:
+      exponential buckets, increasing in size by 25%, rounded to the nearest
+      integer. i.e. 0, 1, 2, 3, 4, 5, 6, 7, 9, 12, 15, 18, 23, 28, 36, 44...
+    </summary>
+  </metric>
+</event>
+
+<event name="Autofill.CardUploadDecision">
+  <owner>sebsg@chromium.org</owner>
+  <metric name="UploadDecision">
+    <summary>
+      Whether the upload was proposed to the user or the reasons why it was not.
+      The value is a bitmask of |CardUploadDecisionMetric|.
+    </summary>
+  </metric>
+</event>
+
 <event name="Autofill.DeveloperEngagement">
   <owner>jiahuiguo@google.com</owner>
   <summary>
@@ -629,129 +629,6 @@
   </metric>
 </event>
 
-<event name="Autofill.HiddenRepresentationalFieldSkipDecision">
-  <owner>parastoog@chromium.org</owner>
-  <summary>
-    Recorded while trying to fill or preview a hidden or a representational
-    field.
-  </summary>
-  <metric name="FieldOverallType">
-    <summary>
-      Field's overall |ServerFieldType|. See |AutofillField.GetStorableType()|.
-    </summary>
-  </metric>
-  <metric name="FieldSignature">
-    <summary>
-      The signature of the field. This is the hash identifier used to denote
-      this field for query and voting purposes. See
-      components/autofill/core/common/signatures_util.cc for more details.
-    </summary>
-  </metric>
-  <metric name="FieldTypeGroup">
-    <summary>
-      Field's |FieldTypeGroup|. See |AutofillType.group()|.
-    </summary>
-  </metric>
-  <metric name="FormSignature">
-    <summary>
-      The signature of the form. This is the hash identifier used to denote this
-      form for query and voting purposes. See
-      components/autofill/core/common/signatures_util.cc for more details.
-    </summary>
-  </metric>
-  <metric name="HeuristicType">
-    <summary>
-      Field's |ServerFieldType| based on heuristics. See
-      |AutofillField.heuristic_type()|.
-    </summary>
-  </metric>
-  <metric name="HtmlFieldMode">
-    <summary>
-      Whether the field's autocomplete hint specified 'billing' or 'shipping'.
-      See |AutofillField.html_mode()|.
-    </summary>
-  </metric>
-  <metric name="HtmlFieldType">
-    <summary>
-      Field's autocomplete field type hint. See |AutofillField.html_type()|.
-    </summary>
-  </metric>
-  <metric name="IsSkipped">
-    <summary>
-      True if the field was skipped while filling or previewing the form,
-      because it was hidden or representational, but not a 'select' one.
-    </summary>
-  </metric>
-  <metric name="ServerType">
-    <summary>
-      Field's |ServerFieldType| returned by server. See
-      |AutofillField.server_type()|.
-    </summary>
-  </metric>
-</event>
-
-<event name="Autofill.RepeatedServerTypePredictionRationalized">
-  <owner>parastoog@chromium.org</owner>
-  <summary>
-    Recorded when a field type predicted by server is rationalized because of
-    repetition.
-  </summary>
-  <metric name="FieldNewOverallType">
-    <summary>
-      Field's overall |ServerFieldType| after rationalization. See
-      |AutofillField.GetStorableType()|.
-    </summary>
-  </metric>
-  <metric name="FieldOldOverallType">
-    <summary>
-      Field's overall |ServerFieldType| before rationalization. See
-      |AutofillField.GetStorableType()|.
-    </summary>
-  </metric>
-  <metric name="FieldSignature">
-    <summary>
-      The signature of the field. This is the hash identifier used to denote
-      this field for query and voting purposes. See
-      components/autofill/core/common/signatures_util.cc for more details.
-    </summary>
-  </metric>
-  <metric name="FieldTypeGroup">
-    <summary>
-      Field's |FieldTypeGroup|. See |AutofillType.group()|.
-    </summary>
-  </metric>
-  <metric name="FormSignature">
-    <summary>
-      The signature of the form. This is the hash identifier used to denote this
-      form for query and voting purposes. See
-      components/autofill/core/common/signatures_util.cc for more details.
-    </summary>
-  </metric>
-  <metric name="HeuristicType">
-    <summary>
-      Field's |ServerFieldType| based on heuristics. See
-      |AutofillField.heuristic_type()|.
-    </summary>
-  </metric>
-  <metric name="HtmlFieldMode">
-    <summary>
-      Whether the field's autocomplete hint specified 'billing' or 'shipping'.
-      See |AutofillField.html_mode()|.
-    </summary>
-  </metric>
-  <metric name="HtmlFieldType">
-    <summary>
-      Field's autocomplete field type hint. See |AutofillField.html_type()|.
-    </summary>
-  </metric>
-  <metric name="ServerType">
-    <summary>
-      Field's |ServerFieldType| returned by server. See
-      |AutofillField.server_type()|.
-    </summary>
-  </metric>
-</event>
-
 <event name="Autofill.FormEvent">
   <owner>dlkumar@google.com</owner>
   <summary>
@@ -815,6 +692,67 @@
   </metric>
 </event>
 
+<event name="Autofill.HiddenRepresentationalFieldSkipDecision">
+  <owner>parastoog@chromium.org</owner>
+  <summary>
+    Recorded while trying to fill or preview a hidden or a representational
+    field.
+  </summary>
+  <metric name="FieldOverallType">
+    <summary>
+      Field's overall |ServerFieldType|. See |AutofillField.GetStorableType()|.
+    </summary>
+  </metric>
+  <metric name="FieldSignature">
+    <summary>
+      The signature of the field. This is the hash identifier used to denote
+      this field for query and voting purposes. See
+      components/autofill/core/common/signatures_util.cc for more details.
+    </summary>
+  </metric>
+  <metric name="FieldTypeGroup">
+    <summary>
+      Field's |FieldTypeGroup|. See |AutofillType.group()|.
+    </summary>
+  </metric>
+  <metric name="FormSignature">
+    <summary>
+      The signature of the form. This is the hash identifier used to denote this
+      form for query and voting purposes. See
+      components/autofill/core/common/signatures_util.cc for more details.
+    </summary>
+  </metric>
+  <metric name="HeuristicType">
+    <summary>
+      Field's |ServerFieldType| based on heuristics. See
+      |AutofillField.heuristic_type()|.
+    </summary>
+  </metric>
+  <metric name="HtmlFieldMode">
+    <summary>
+      Whether the field's autocomplete hint specified 'billing' or 'shipping'.
+      See |AutofillField.html_mode()|.
+    </summary>
+  </metric>
+  <metric name="HtmlFieldType">
+    <summary>
+      Field's autocomplete field type hint. See |AutofillField.html_type()|.
+    </summary>
+  </metric>
+  <metric name="IsSkipped">
+    <summary>
+      True if the field was skipped while filling or previewing the form,
+      because it was hidden or representational, but not a 'select' one.
+    </summary>
+  </metric>
+  <metric name="ServerType">
+    <summary>
+      Field's |ServerFieldType| returned by server. See
+      |AutofillField.server_type()|.
+    </summary>
+  </metric>
+</event>
+
 <event name="Autofill.InteractedWithForm">
   <owner>jiahuiguo@google.com</owner>
   <summary>
@@ -849,6 +787,68 @@
   </metric>
 </event>
 
+<event name="Autofill.RepeatedServerTypePredictionRationalized">
+  <owner>parastoog@chromium.org</owner>
+  <summary>
+    Recorded when a field type predicted by server is rationalized because of
+    repetition.
+  </summary>
+  <metric name="FieldNewOverallType">
+    <summary>
+      Field's overall |ServerFieldType| after rationalization. See
+      |AutofillField.GetStorableType()|.
+    </summary>
+  </metric>
+  <metric name="FieldOldOverallType">
+    <summary>
+      Field's overall |ServerFieldType| before rationalization. See
+      |AutofillField.GetStorableType()|.
+    </summary>
+  </metric>
+  <metric name="FieldSignature">
+    <summary>
+      The signature of the field. This is the hash identifier used to denote
+      this field for query and voting purposes. See
+      components/autofill/core/common/signatures_util.cc for more details.
+    </summary>
+  </metric>
+  <metric name="FieldTypeGroup">
+    <summary>
+      Field's |FieldTypeGroup|. See |AutofillType.group()|.
+    </summary>
+  </metric>
+  <metric name="FormSignature">
+    <summary>
+      The signature of the form. This is the hash identifier used to denote this
+      form for query and voting purposes. See
+      components/autofill/core/common/signatures_util.cc for more details.
+    </summary>
+  </metric>
+  <metric name="HeuristicType">
+    <summary>
+      Field's |ServerFieldType| based on heuristics. See
+      |AutofillField.heuristic_type()|.
+    </summary>
+  </metric>
+  <metric name="HtmlFieldMode">
+    <summary>
+      Whether the field's autocomplete hint specified 'billing' or 'shipping'.
+      See |AutofillField.html_mode()|.
+    </summary>
+  </metric>
+  <metric name="HtmlFieldType">
+    <summary>
+      Field's autocomplete field type hint. See |AutofillField.html_type()|.
+    </summary>
+  </metric>
+  <metric name="ServerType">
+    <summary>
+      Field's |ServerFieldType| returned by server. See
+      |AutofillField.server_type()|.
+    </summary>
+  </metric>
+</event>
+
 <event name="Autofill.SelectedMaskedServerCard">
   <obsolete>
     Deprecated 2/2019
@@ -997,6 +997,70 @@
   </metric>
 </event>
 
+<event name="BackgroundFetch">
+  <owner>nator@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    A BackgroundFetch event is logged before a background fetch is started from
+    a document context.
+  </summary>
+  <metric name="DeniedDueToPermissions">
+    <summary>
+      Boolean for whether the background fetch was denied due to permission.
+      This includes only the content setting permission.
+    </summary>
+  </metric>
+  <metric name="DownloadTotal">
+    <summary>
+      The value of downloadTotal provided with the background fetch. This is the
+      number of bytes that the developer expects to be downloaded with the
+      background fetch. This number is exponentially bucketed for privacy
+      reasons, and uses the UKM GetExponentialBucketMin method with a value of
+      2.0 for spacing.
+    </summary>
+  </metric>
+  <metric name="HasTitle">
+    <summary>
+      Boolean for whether a title was provided with the background fetch.
+    </summary>
+  </metric>
+  <metric name="NumIcons">
+    <summary>
+      Count of icons provided with the background fetch.
+    </summary>
+  </metric>
+  <metric name="NumRequestsInFetch">
+    <summary>
+      Number of requests in the background fetch. This number is exponentially
+      bucketed for privacy reasons, and uses the UKM GetExponentialBucketMin
+      method with a value of 2.0 for spacing.
+    </summary>
+  </metric>
+  <metric name="RatioOfIdealToChosenIconSize">
+    <summary>
+      Ratio of the ideal icon to the chosen icon size, times hundred. This will
+      be set to -1 if either ideal icon size is 0, or if none of the provided
+      icons are suitable.
+    </summary>
+  </metric>
+</event>
+
+<event name="BackgroundFetchDeletingRegistration">
+  <owner>nator@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    A BackgroundFetchDeletingRegistration event is logged when a background
+    fetch job is being deleted.
+  </summary>
+  <metric name="UserInitiatedAbort">
+    <summary>
+      Boolean for whether the background fetch job was cancelled from the UI.
+    </summary>
+  </metric>
+</event>
+
 <event name="Blink.UpdateTime">
   <owner>schenney@chromium.org</owner>
   <summary>
@@ -1801,6 +1865,18 @@
   </metric>
 </event>
 
+<event name="Compositor.Rendering">
+  <owner>khushalsagar@chromium.org</owner>
+  <summary>
+    Metrics related to rendering in the compositor.
+  </summary>
+  <metric name="CheckerboardedImagesCount">
+    <summary>
+      The number of images checker-imaged and re-rasterized on this page.
+    </summary>
+  </metric>
+</event>
+
 <event name="Compositor.UserInteraction">
   <owner>khushalsagar@chromium.org</owner>
   <summary>
@@ -1836,18 +1912,6 @@
   </metric>
 </event>
 
-<event name="Compositor.Rendering">
-  <owner>khushalsagar@chromium.org</owner>
-  <summary>
-    Metrics related to rendering in the compositor.
-  </summary>
-  <metric name="CheckerboardedImagesCount">
-    <summary>
-      The number of images checker-imaged and re-rasterized on this page.
-    </summary>
-  </metric>
-</event>
-
 <event name="ContextualSearch">
   <owner>donnd@chromium.org</owner>
   <summary>
@@ -2193,6 +2257,24 @@
   </metric>
 </event>
 
+<event name="Document.OutliveTimeAfterShutdown">
+  <owner>hajimehoshi@chromium.org</owner>
+  <owner>keishi@chromium.org</owner>
+  <summary>
+    Recorded when a Document object survives certain number of garbage
+    collections after detached. It is expected that regular Document objects are
+    destroyed soon after detached, and if a document outlives longer, probably
+    this can be leaked.
+  </summary>
+  <metric name="GCCount">
+    <summary>
+      Measures the numbers of garbarge collection after the document is
+      detached. This is recorded when the number reached certain numbers like 5
+      or 10.
+    </summary>
+  </metric>
+</event>
+
 <event name="DocumentCreated">
   <owner>beccahughes@chromium.org</owner>
   <summary>
@@ -2218,62 +2300,6 @@
   </metric>
 </event>
 
-<event name="Document.OutliveTimeAfterShutdown">
-  <owner>hajimehoshi@chromium.org</owner>
-  <owner>keishi@chromium.org</owner>
-  <summary>
-    Recorded when a Document object survives certain number of garbage
-    collections after detached. It is expected that regular Document objects are
-    destroyed soon after detached, and if a document outlives longer, probably
-    this can be leaked.
-  </summary>
-  <metric name="GCCount">
-    <summary>
-      Measures the numbers of garbarge collection after the document is
-      detached. This is recorded when the number reached certain numbers like 5
-      or 10.
-    </summary>
-  </metric>
-</event>
-
-<event name="Download.Started">
-  <owner>jming@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <summary>
-    Metrics taken when a download begins. It has one Download.Ended and none to
-    multiple Download.Interrupted/Download.Resumed events associated with it.
-  </summary>
-  <metric name="DownloadConnectionSecurity">
-    <summary>
-      The state of the security of the final download URL and all the redirects
-      leading to it. Expressed as an enum defined in DownloadConnectionSecurity.
-    </summary>
-  </metric>
-  <metric name="DownloadId">
-    <summary>
-      The id of the download that is used to associate separate events.
-    </summary>
-  </metric>
-  <metric name="DownloadSource">
-    <summary>
-      The source of the download, expressed as an enum defined in DownloadEntry.
-    </summary>
-  </metric>
-  <metric name="FileType">
-    <summary>
-      The type of file that is downloaded, expressed as an enum defined in
-      DownloadContentType.
-    </summary>
-  </metric>
-  <metric name="IsSameHostDownload">
-    <summary>
-      A boolean denoting if the final download URL is the same host as the
-      initiating frame (i.e., whether the initiating site likely controls the
-      download itself).
-    </summary>
-  </metric>
-</event>
-
 <event name="Download.Completed">
   <owner>jming@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -2377,40 +2403,41 @@
   </metric>
 </event>
 
-<event name="Event.ScrollUpdate.Touch">
-  <owner>nzolghadr@chromium.org</owner>
+<event name="Download.Started">
+  <owner>jming@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
   <summary>
-    Metrics related to a scroll action caused by the generated ScrollUpdate
-    gesture event.
+    Metrics taken when a download begins. It has one Download.Ended and none to
+    multiple Download.Interrupted/Download.Resumed events associated with it.
   </summary>
-  <metric name="IsMainThread">
+  <metric name="DownloadConnectionSecurity">
     <summary>
-      Whether the event is handled on the main thread or not.
+      The state of the security of the final download URL and all the redirects
+      leading to it. Expressed as an enum defined in DownloadConnectionSecurity.
     </summary>
   </metric>
-  <metric name="TimeToHandled">
+  <metric name="DownloadId">
     <summary>
-      The time in microseconds between initial creation of a touch event and the
-      generated ScrollUpdate gesture event is handled on main/impl thread. If no
-      swap was induced by the ScrollUpdate gesture event, no recording is made.
+      The id of the download that is used to associate separate events.
     </summary>
   </metric>
-  <metric name="TimeToScrollUpdateSwapBegin">
+  <metric name="DownloadSource">
     <summary>
-      The time in microseconds between the initial creation of a touch event and
-      the start of the frame swap on the GPU service. If no swap was induced by
-      the event, no recording is made. The first GSU of every scrolling sequence
-      is excluded from this metric.
+      The source of the download, expressed as an enum defined in DownloadEntry.
     </summary>
-    <aggregation>
-      <history>
-        <index fields="profile.country"/>
-        <index fields="profile.country,profile.system_ram"/>
-        <statistics>
-          <quantiles type="std-percentiles"/>
-        </statistics>
-      </history>
-    </aggregation>
+  </metric>
+  <metric name="FileType">
+    <summary>
+      The type of file that is downloaded, expressed as an enum defined in
+      DownloadContentType.
+    </summary>
+  </metric>
+  <metric name="IsSameHostDownload">
+    <summary>
+      A boolean denoting if the final download URL is the same host as the
+      initiating frame (i.e., whether the initiating site likely controls the
+      download itself).
+    </summary>
   </metric>
 </event>
 
@@ -2453,6 +2480,73 @@
   </metric>
 </event>
 
+<event name="Event.ScrollBegin.Wheel">
+  <owner>nzolghadr@chromium.org</owner>
+  <summary>
+    Metrics related to first scroll action caused by the generated ScrollUpdate
+    gesture event.
+  </summary>
+  <metric name="IsMainThread">
+    <summary>
+      Whether the event is handled on the main thread or not.
+    </summary>
+  </metric>
+  <metric name="TimeToHandled">
+    <summary>
+      The time in microseconds between initial creation of a wheel event and the
+      first generated ScrollUpdate gesture event in a given scroll gesture event
+      sequence is handled on main/impl thread. If no swap was induced by the
+      ScrollBegin gesture event, no recording is made.
+    </summary>
+  </metric>
+  <metric name="TimeToScrollUpdateSwapBegin">
+    <summary>
+      The time in microseconds between the initial creation of a wheel event and
+      the start of the frame swap on the GPU service caused by the generated
+      ScrollUpdate gesture event if that ScrollUpdate is the first such event in
+      a given scroll gesture event sequence. If no swap was induced by the
+      event, no recording is made.
+    </summary>
+  </metric>
+</event>
+
+<event name="Event.ScrollUpdate.Touch">
+  <owner>nzolghadr@chromium.org</owner>
+  <summary>
+    Metrics related to a scroll action caused by the generated ScrollUpdate
+    gesture event.
+  </summary>
+  <metric name="IsMainThread">
+    <summary>
+      Whether the event is handled on the main thread or not.
+    </summary>
+  </metric>
+  <metric name="TimeToHandled">
+    <summary>
+      The time in microseconds between initial creation of a touch event and the
+      generated ScrollUpdate gesture event is handled on main/impl thread. If no
+      swap was induced by the ScrollUpdate gesture event, no recording is made.
+    </summary>
+  </metric>
+  <metric name="TimeToScrollUpdateSwapBegin">
+    <summary>
+      The time in microseconds between the initial creation of a touch event and
+      the start of the frame swap on the GPU service. If no swap was induced by
+      the event, no recording is made. The first GSU of every scrolling sequence
+      is excluded from this metric.
+    </summary>
+    <aggregation>
+      <history>
+        <index fields="profile.country"/>
+        <index fields="profile.country,profile.system_ram"/>
+        <statistics>
+          <quantiles type="std-percentiles"/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
+</event>
+
 <event name="Event.ScrollUpdate.Wheel">
   <owner>nzolghadr@chromium.org</owner>
   <owner>tdresser@chromium.org</owner>
@@ -2483,46 +2577,50 @@
   </metric>
 </event>
 
-<event name="Event.ScrollBegin.Wheel">
-  <owner>nzolghadr@chromium.org</owner>
+<event name="HistoryManipulationIntervention">
+  <owner>shivanisha@chromium.org</owner>
   <summary>
-    Metrics related to first scroll action caused by the generated ScrollUpdate
-    gesture event.
+    Logged when an entry in the back-forward list is marked to be skipped on
+    subsequent back/forward button clicks as part of the history manipulation
+    intervention. This is logged when the entry is navigated away from.
   </summary>
-  <metric name="IsMainThread">
-    <summary>
-      Whether the event is handled on the main thread or not.
-    </summary>
-  </metric>
-  <metric name="TimeToHandled">
-    <summary>
-      The time in microseconds between initial creation of a wheel event and the
-      first generated ScrollUpdate gesture event in a given scroll gesture event
-      sequence is handled on main/impl thread. If no swap was induced by the
-      ScrollBegin gesture event, no recording is made.
-    </summary>
-  </metric>
-  <metric name="TimeToScrollUpdateSwapBegin">
-    <summary>
-      The time in microseconds between the initial creation of a wheel event and
-      the start of the frame swap on the GPU service caused by the generated
-      ScrollUpdate gesture event if that ScrollUpdate is the first such event in
-      a given scroll gesture event sequence. If no swap was induced by the
-      event, no recording is made.
-    </summary>
-  </metric>
 </event>
 
-<event name="PageForegroundSession">
-  <owner>sullivan@chromium.org</owner>
+<event name="HistoryNavigation" singular="True">
+  <owner>altimin@chromium.org</owner>
+  <owner>arthursonzogni@chromium.org</owner>
   <summary>
-    Total time in foreground in milliseconds, recorded each time the page is
-    backgrounded. May be recorded multiple times for a single page visit.
+    Metrics recorded each time we commit a history navigation, which are needed
+    to estimate benefits of back-forward cache.
   </summary>
-  <metric name="ForegroundDuration">
+  <metric name="LastCommittedSourceIdForTheSameDocument">
     <summary>
-      Total time in foreground in milliseconds, recorded each time the page is
-      backgrounded.
+      For history navigations and reloads, the source id of the previous
+      navigation which loaded the page we're trying to navigate back to.
+    </summary>
+  </metric>
+  <metric name="NavigatedToTheMostRecentEntryForDocument">
+    <summary>
+      Boolean for whether we navigated to the same navigation entry as the one
+      which was last visible.
+
+      It can be false when subframes or same-document navigations are present.
+      For example, after navigating from http://foo to http://foo#bar and then
+      http://bar and then going back by 2 entries will mean we went to
+      http://foo while the last committed entry from this document was
+      http://foo#bar.
+
+      It's expected to be rare, but might be problematic for back-forward cache.
+    </summary>
+  </metric>
+  <metric name="TimeSinceNavigatedAwayFromDocument">
+    <summary>
+      Time in milliseconds from the moment the current navigation stopped being
+      active to the start of the current navigation.
+
+      This is clamped to hours for values greater than 3 hours, to minutes for
+      values greater than 3 minutes, to seconds for values greater than 5
+      seconds.
     </summary>
   </metric>
 </event>
@@ -2555,6 +2653,41 @@
   </metric>
 </event>
 
+<event name="IOS.FindInPageSearchMatches">
+  <owner>thegreenfrog@chromium.org</owner>
+  <owner>michaeldo@chromium.org</owner>
+  <summary>
+    Logged when the FindInPage returns a user search request result.
+  </summary>
+  <metric name="HasMatches">
+    <summary>
+      True if there were matches.
+    </summary>
+  </metric>
+</event>
+
+<event name="IOS.URLMismatchInLegacyAndSlimNavigationManager">
+  <owner>eugenebut@chromium.org</owner>
+  <owner>danyao@chromium.org</owner>
+  <summary>
+    Logged when LegacyNavigationManager and KWKBasedNavigationManager have
+    different last committed URLs. This means that either old or new navigation
+    system has a URL spoofing bug.
+  </summary>
+  <metric name="HasMismatch">
+    <summary>
+      True if there was a mismatch.
+    </summary>
+    <aggregation>
+      <history>
+        <statistics>
+          <enumeration/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
+</event>
+
 <event name="Layout.DisplayCutout.StateChanged">
   <owner>beccahughes@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
@@ -2792,318 +2925,6 @@
   </metric>
 </event>
 
-<event name="Media.EME.RequestMediaKeySystemAccess">
-  <owner>xhwang@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>
-    Event recorded when RequestMediaKeySystemAccess() is called as part of
-    Encrypted Media Extensions (EME) API.
-  </summary>
-  <metric name="KeySystem">
-    <summary>
-      The key system passed in requestMediaKeySystemAccess() call.
-    </summary>
-  </metric>
-  <metric name="VideoCapabilities">
-    <summary>
-      Whether there are any &quot;videoCapabilities&quot;.
-    </summary>
-  </metric>
-  <metric name="VideoCapabilities.HasEmptyRobustness">
-    <summary>
-      Whether there are any &quot;videoCapabilities&quot; with empty robustness.
-    </summary>
-  </metric>
-  <metric name="VideoCapabilities.HasHwSecureAllRobustness">
-    <summary>
-      Whether there are any &quot;videoCapabilities&quot; with robustness being
-      &quot;HW_SECURE_ALL&quot;.
-    </summary>
-  </metric>
-</event>
-
-<event name="Media.Engagement.ShortPlaybackIgnored">
-  <owner>beccahughes@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>
-    The Media Engagement index stores the number of significant media playbacks
-    per origin and the number of audible players. From that we calculate a Media
-    Engagement Score.
-
-    Media with a short playback length is ignored so we are logging any time the
-    player is ignored with the length in msec. This will allow us to identify
-    whether sites are being penalized or there is abuse and allow us to tweak
-    the length considered &quot;short&quot;.
-  </summary>
-  <metric name="Length"/>
-</event>
-
-<event name="Media.Engagement.SessionFinished">
-  <owner>beccahughes@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>
-    The Media Engagement index stores the number of significant media playbacks
-    per origin and the number of visits. From that we calculate a Media
-    Engagement Score.
-
-    To tweak the scoring function we are logging the total number of significant
-    media playbacks, the total number of visits, the calculated engagement score
-    and the new number of significant media playbacks that occured this visit.
-  </summary>
-  <metric name="Engagement.IsHigh">
-    <summary>
-      Whether the Media Engagement Service considers the score to be high (we
-      are using a two threshold approach so there is one threshold to be
-      considered high and another one to lose that status to reduce jitter).
-    </summary>
-  </metric>
-  <metric name="Engagement.IsHigh.Changed">
-    <summary>
-      Whether the IsHigh bit changed during the current session.
-    </summary>
-  </metric>
-  <metric name="Engagement.IsHigh.Changes">
-    <summary>
-      Counts of IsHigh changing (from 0 to 1 or 1 to 0).
-    </summary>
-  </metric>
-  <metric name="Engagement.IsPreloaded">
-    <summary>
-      Whether the origin was preloaded (from the chrome://component) as a high
-      engagement origin.
-    </summary>
-  </metric>
-  <metric name="Engagement.Score">
-    <summary>
-      The calculated Media Engagement score for the current origin. The score is
-      calculated by dividing the number of significant media playbacks by the
-      number of visits. If the number of visits is below 5 then the score will
-      be zero. This score is taken from MediaEngagementService.
-    </summary>
-  </metric>
-  <metric name="Playbacks.AudioContextTotal">
-    <summary>
-      The total number of significant media playbacks on this origin that came
-      from WebAudio / AudioContext.
-    </summary>
-  </metric>
-  <metric name="Playbacks.Delta">
-    <summary>
-      The number of significant media playbacks on this origin during this
-      session (a visit to an origin on the same tab). A playback is determined
-      significant if it meets certain criteria such as a video size of at least
-      200x140px, is not muted, is playing, etc.
-    </summary>
-  </metric>
-  <metric name="Playbacks.MediaElementTotal">
-    <summary>
-      The total number of significant media playbacks on this origin that came
-      from media elements.
-    </summary>
-  </metric>
-  <metric name="Playbacks.SecondsSinceLast">
-    <summary>
-      The number of seconds between significant media playback on the last visit
-      and significant media playback on the current visit. If there was no
-      previous visit or significant media playback this visit it will be 0.
-    </summary>
-  </metric>
-  <metric name="Playbacks.Total">
-    <summary>
-      The total number of significant media playbacks on this origin.
-    </summary>
-  </metric>
-  <metric name="Player.Audible.Delta">
-    <summary>
-      The number of unique audio/video players on a page that was audible (made
-      sound) during a visit.
-    </summary>
-  </metric>
-  <metric name="Player.Audible.Total">
-    <summary>
-      The delta from above but instead of a single visit, the total of all
-      deltas for all visits on this origin.
-    </summary>
-  </metric>
-  <metric name="Player.Significant.Delta">
-    <summary>
-      The number of unique audio/video players on a page that was audible (made
-      sound) and considered significant (played for at least 7 seconds) during a
-      visit.
-    </summary>
-  </metric>
-  <metric name="Player.Significant.Total">
-    <summary>
-      The delta from above but instead of a single visit, the total of all
-      deltas for all visits on this origin.
-    </summary>
-  </metric>
-  <metric name="Visits.Total">
-    <summary>
-      The total number of visits to this origin.
-    </summary>
-  </metric>
-</event>
-
-<event name="Media.SiteMuted" singular="True">
-  <owner>steimel@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>
-    Event recorded when a website tries to play audio but is muted by the sound
-    content setting.
-  </summary>
-  <metric name="MuteReason">
-    <summary>
-      Enum value giving the reason the site was muted. Defined as
-      |SoundContentSettingObserver::MuteReason|.
-    </summary>
-  </metric>
-</event>
-
-<event name="Media.WatchTime">
-  <obsolete>
-    Deprecated 8/2017 in favor Media.BasicPlayback
-  </obsolete>
-  <owner>dalecurtis@chromium.org</owner>
-  <summary>
-    Watch time is defined as the amount of elapsed media time for audio+video
-    media aggregated per player instance. A minimum of 7 seconds of unmuted,
-    foreground media must be watched to start watch time monitoring. Watch time
-    is checked on a regular basis and reported upon one of the stop events
-    mentioned below or at player destruction if none occur prior.
-
-    Any one of paused, hidden, or muted is sufficient to stop watch time metric
-    reports. Each of these has a hysteresis where if the state change is undone
-    within some time, the watch time will be counted as uninterrupted.
-
-    Power events (on/off battery power) have a similar hysteresis, but unlike
-    the aforementioned properties, will not stop metric collection.
-
-    Native controls events have a similar behavior than power events.
-
-    Each seek event will result in a new watch time metric being started and the
-    old metric finalized as accurately as possible.
-  </summary>
-  <metric name="Audio.AC"/>
-  <metric name="Audio.All"/>
-  <metric name="Audio.Battery"/>
-  <metric name="Audio.EME"/>
-  <metric name="Audio.MSE"/>
-  <metric name="Audio.NativeControlsOff"/>
-  <metric name="Audio.NativeControlsOn"/>
-  <metric name="Audio.SRC"/>
-  <metric name="AudioVideo.AC"/>
-  <metric name="AudioVideo.All"/>
-  <metric name="AudioVideo.Background.AC"/>
-  <metric name="AudioVideo.Background.All"/>
-  <metric name="AudioVideo.Background.Battery"/>
-  <metric name="AudioVideo.Background.EME"/>
-  <metric name="AudioVideo.Background.MSE"/>
-  <metric name="AudioVideo.Background.SRC"/>
-  <metric name="AudioVideo.Battery"/>
-  <metric name="AudioVideo.DisplayFullscreen"/>
-  <metric name="AudioVideo.DisplayInline"/>
-  <metric name="AudioVideo.DisplayPictureInPicture"/>
-  <metric name="AudioVideo.EME"/>
-  <metric name="AudioVideo.MSE"/>
-  <metric name="AudioVideo.NativeControlsOff"/>
-  <metric name="AudioVideo.NativeControlsOn"/>
-  <metric name="AudioVideo.SRC"/>
-</event>
-
-<event name="Media.WebAudio.AudioContext.AudibleTime">
-  <owner>hongchan@chromium.org</owner>
-  <owner>rtoy@chromium.org</owner>
-  <owner>webaudio-dev@chromium.org</owner>
-  <summary>
-    Records the AudioContext audible time information.
-  </summary>
-  <metric name="AudibleTime">
-    <summary>
-      Audible time in milliseconds for this event.
-    </summary>
-  </metric>
-  <metric name="IsMainFrame">
-    <summary>
-      Indicates whether the event is fired from main frame.
-    </summary>
-  </metric>
-</event>
-
-<event name="Media.WebMediaPlayerState">
-  <owner>dalecurtis@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>
-    Final state of WebMediaPlayerImpl instance. Records only immutable playback
-    properties. Contains a PlaybackID which links to Media.BasicPlayback events.
-  </summary>
-  <metric name="ContainerName">
-    <summary>
-      media::container_names::MediaContainerName enum value. Only recorded for
-      !IsMSE src=URL playbacks, this is the container of the media being played
-      back; E.g., mp4, avi, mp3, etc.
-    </summary>
-  </metric>
-  <metric name="FinalPipelineStatus">
-    <summary>
-      media::PipelineStatus enum value. Always 0 if the playback succeeded; all
-      other values indicate the playback ended in an error.
-    </summary>
-  </metric>
-  <metric name="IsEME">
-    <summary>
-      Boolean value indicating if this event is for an EME playback. Note: EME
-      can be attached anytime during the lifecycle of a WebMediaPlayerImpl, but
-      once attached can't be removed.
-    </summary>
-  </metric>
-  <metric name="IsMSE">
-    <summary>
-      Boolean value indicating if this event is for an MSE playback. If false it
-      means this was a SRC playback.
-    </summary>
-  </metric>
-  <metric name="IsTopFrame">
-    <summary>
-      Flag indicating whether the report comes from the top frame or some inner
-      frame. For privacy, metrics from inner frames are recorded with the top
-      frame's origin, so this flag helps separate top frame vs. embedded
-      playbacks.
-    </summary>
-  </metric>
-  <metric name="PlayerID">
-    <summary>
-      ID which corresponds to a given WebMediaPlayerImpl instance. May be linked
-      with Media.BasicPlayback events to understand a playback more deeply.
-    </summary>
-  </metric>
-  <metric name="TimeToFirstFrame">
-    <summary>
-      Time in milliseconds from when WebMediaPlayerImpl starts loading until the
-      first video frame has been shown.
-    </summary>
-  </metric>
-  <metric name="TimeToMetadata">
-    <summary>
-      Time in milliseconds from when WebMediaPlayerImpl starts loading until
-      metadata is known.
-    </summary>
-  </metric>
-  <metric name="TimeToPlayReady">
-    <summary>
-      Time in milliseconds from when WebMediaPlayerImpl starts loading until it
-      has buffered enough to start playback.
-    </summary>
-  </metric>
-  <metric name="URLScheme">
-    <summary>
-      media::mojom::MediaURLScheme enum value. Only recorded for !IsMSE src=URL
-      playbacks, this is the scheme of that URL; E.g., http, https, filesystem,
-      etc.
-    </summary>
-  </metric>
-</event>
-
 <event name="Media.BasicPlayback">
   <owner>dalecurtis@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
@@ -3289,6 +3110,174 @@
   </metric>
 </event>
 
+<event name="Media.EME.RequestMediaKeySystemAccess">
+  <owner>xhwang@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Event recorded when RequestMediaKeySystemAccess() is called as part of
+    Encrypted Media Extensions (EME) API.
+  </summary>
+  <metric name="KeySystem">
+    <summary>
+      The key system passed in requestMediaKeySystemAccess() call.
+    </summary>
+  </metric>
+  <metric name="VideoCapabilities">
+    <summary>
+      Whether there are any &quot;videoCapabilities&quot;.
+    </summary>
+  </metric>
+  <metric name="VideoCapabilities.HasEmptyRobustness">
+    <summary>
+      Whether there are any &quot;videoCapabilities&quot; with empty robustness.
+    </summary>
+  </metric>
+  <metric name="VideoCapabilities.HasHwSecureAllRobustness">
+    <summary>
+      Whether there are any &quot;videoCapabilities&quot; with robustness being
+      &quot;HW_SECURE_ALL&quot;.
+    </summary>
+  </metric>
+</event>
+
+<event name="Media.Engagement.SessionFinished">
+  <owner>beccahughes@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    The Media Engagement index stores the number of significant media playbacks
+    per origin and the number of visits. From that we calculate a Media
+    Engagement Score.
+
+    To tweak the scoring function we are logging the total number of significant
+    media playbacks, the total number of visits, the calculated engagement score
+    and the new number of significant media playbacks that occured this visit.
+  </summary>
+  <metric name="Engagement.IsHigh">
+    <summary>
+      Whether the Media Engagement Service considers the score to be high (we
+      are using a two threshold approach so there is one threshold to be
+      considered high and another one to lose that status to reduce jitter).
+    </summary>
+  </metric>
+  <metric name="Engagement.IsHigh.Changed">
+    <summary>
+      Whether the IsHigh bit changed during the current session.
+    </summary>
+  </metric>
+  <metric name="Engagement.IsHigh.Changes">
+    <summary>
+      Counts of IsHigh changing (from 0 to 1 or 1 to 0).
+    </summary>
+  </metric>
+  <metric name="Engagement.IsPreloaded">
+    <summary>
+      Whether the origin was preloaded (from the chrome://component) as a high
+      engagement origin.
+    </summary>
+  </metric>
+  <metric name="Engagement.Score">
+    <summary>
+      The calculated Media Engagement score for the current origin. The score is
+      calculated by dividing the number of significant media playbacks by the
+      number of visits. If the number of visits is below 5 then the score will
+      be zero. This score is taken from MediaEngagementService.
+    </summary>
+  </metric>
+  <metric name="Playbacks.AudioContextTotal">
+    <summary>
+      The total number of significant media playbacks on this origin that came
+      from WebAudio / AudioContext.
+    </summary>
+  </metric>
+  <metric name="Playbacks.Delta">
+    <summary>
+      The number of significant media playbacks on this origin during this
+      session (a visit to an origin on the same tab). A playback is determined
+      significant if it meets certain criteria such as a video size of at least
+      200x140px, is not muted, is playing, etc.
+    </summary>
+  </metric>
+  <metric name="Playbacks.MediaElementTotal">
+    <summary>
+      The total number of significant media playbacks on this origin that came
+      from media elements.
+    </summary>
+  </metric>
+  <metric name="Playbacks.SecondsSinceLast">
+    <summary>
+      The number of seconds between significant media playback on the last visit
+      and significant media playback on the current visit. If there was no
+      previous visit or significant media playback this visit it will be 0.
+    </summary>
+  </metric>
+  <metric name="Playbacks.Total">
+    <summary>
+      The total number of significant media playbacks on this origin.
+    </summary>
+  </metric>
+  <metric name="Player.Audible.Delta">
+    <summary>
+      The number of unique audio/video players on a page that was audible (made
+      sound) during a visit.
+    </summary>
+  </metric>
+  <metric name="Player.Audible.Total">
+    <summary>
+      The delta from above but instead of a single visit, the total of all
+      deltas for all visits on this origin.
+    </summary>
+  </metric>
+  <metric name="Player.Significant.Delta">
+    <summary>
+      The number of unique audio/video players on a page that was audible (made
+      sound) and considered significant (played for at least 7 seconds) during a
+      visit.
+    </summary>
+  </metric>
+  <metric name="Player.Significant.Total">
+    <summary>
+      The delta from above but instead of a single visit, the total of all
+      deltas for all visits on this origin.
+    </summary>
+  </metric>
+  <metric name="Visits.Total">
+    <summary>
+      The total number of visits to this origin.
+    </summary>
+  </metric>
+</event>
+
+<event name="Media.Engagement.ShortPlaybackIgnored">
+  <owner>beccahughes@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    The Media Engagement index stores the number of significant media playbacks
+    per origin and the number of audible players. From that we calculate a Media
+    Engagement Score.
+
+    Media with a short playback length is ignored so we are logging any time the
+    player is ignored with the length in msec. This will allow us to identify
+    whether sites are being penalized or there is abuse and allow us to tweak
+    the length considered &quot;short&quot;.
+  </summary>
+  <metric name="Length"/>
+</event>
+
+<event name="Media.SiteMuted" singular="True">
+  <owner>steimel@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Event recorded when a website tries to play audio but is muted by the sound
+    content setting.
+  </summary>
+  <metric name="MuteReason">
+    <summary>
+      Enum value giving the reason the site was muted. Defined as
+      |SoundContentSettingObserver::MuteReason|.
+    </summary>
+  </metric>
+</event>
+
 <event name="Media.VideoDecodePerfRecord">
   <owner>chcunningham@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
@@ -3411,6 +3400,150 @@
   </metric>
 </event>
 
+<event name="Media.WatchTime">
+  <obsolete>
+    Deprecated 8/2017 in favor Media.BasicPlayback
+  </obsolete>
+  <owner>dalecurtis@chromium.org</owner>
+  <summary>
+    Watch time is defined as the amount of elapsed media time for audio+video
+    media aggregated per player instance. A minimum of 7 seconds of unmuted,
+    foreground media must be watched to start watch time monitoring. Watch time
+    is checked on a regular basis and reported upon one of the stop events
+    mentioned below or at player destruction if none occur prior.
+
+    Any one of paused, hidden, or muted is sufficient to stop watch time metric
+    reports. Each of these has a hysteresis where if the state change is undone
+    within some time, the watch time will be counted as uninterrupted.
+
+    Power events (on/off battery power) have a similar hysteresis, but unlike
+    the aforementioned properties, will not stop metric collection.
+
+    Native controls events have a similar behavior than power events.
+
+    Each seek event will result in a new watch time metric being started and the
+    old metric finalized as accurately as possible.
+  </summary>
+  <metric name="Audio.AC"/>
+  <metric name="Audio.All"/>
+  <metric name="Audio.Battery"/>
+  <metric name="Audio.EME"/>
+  <metric name="Audio.MSE"/>
+  <metric name="Audio.NativeControlsOff"/>
+  <metric name="Audio.NativeControlsOn"/>
+  <metric name="Audio.SRC"/>
+  <metric name="AudioVideo.AC"/>
+  <metric name="AudioVideo.All"/>
+  <metric name="AudioVideo.Background.AC"/>
+  <metric name="AudioVideo.Background.All"/>
+  <metric name="AudioVideo.Background.Battery"/>
+  <metric name="AudioVideo.Background.EME"/>
+  <metric name="AudioVideo.Background.MSE"/>
+  <metric name="AudioVideo.Background.SRC"/>
+  <metric name="AudioVideo.Battery"/>
+  <metric name="AudioVideo.DisplayFullscreen"/>
+  <metric name="AudioVideo.DisplayInline"/>
+  <metric name="AudioVideo.DisplayPictureInPicture"/>
+  <metric name="AudioVideo.EME"/>
+  <metric name="AudioVideo.MSE"/>
+  <metric name="AudioVideo.NativeControlsOff"/>
+  <metric name="AudioVideo.NativeControlsOn"/>
+  <metric name="AudioVideo.SRC"/>
+</event>
+
+<event name="Media.WebAudio.AudioContext.AudibleTime">
+  <owner>hongchan@chromium.org</owner>
+  <owner>rtoy@chromium.org</owner>
+  <owner>webaudio-dev@chromium.org</owner>
+  <summary>
+    Records the AudioContext audible time information.
+  </summary>
+  <metric name="AudibleTime">
+    <summary>
+      Audible time in milliseconds for this event.
+    </summary>
+  </metric>
+  <metric name="IsMainFrame">
+    <summary>
+      Indicates whether the event is fired from main frame.
+    </summary>
+  </metric>
+</event>
+
+<event name="Media.WebMediaPlayerState">
+  <owner>dalecurtis@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Final state of WebMediaPlayerImpl instance. Records only immutable playback
+    properties. Contains a PlaybackID which links to Media.BasicPlayback events.
+  </summary>
+  <metric name="ContainerName">
+    <summary>
+      media::container_names::MediaContainerName enum value. Only recorded for
+      !IsMSE src=URL playbacks, this is the container of the media being played
+      back; E.g., mp4, avi, mp3, etc.
+    </summary>
+  </metric>
+  <metric name="FinalPipelineStatus">
+    <summary>
+      media::PipelineStatus enum value. Always 0 if the playback succeeded; all
+      other values indicate the playback ended in an error.
+    </summary>
+  </metric>
+  <metric name="IsEME">
+    <summary>
+      Boolean value indicating if this event is for an EME playback. Note: EME
+      can be attached anytime during the lifecycle of a WebMediaPlayerImpl, but
+      once attached can't be removed.
+    </summary>
+  </metric>
+  <metric name="IsMSE">
+    <summary>
+      Boolean value indicating if this event is for an MSE playback. If false it
+      means this was a SRC playback.
+    </summary>
+  </metric>
+  <metric name="IsTopFrame">
+    <summary>
+      Flag indicating whether the report comes from the top frame or some inner
+      frame. For privacy, metrics from inner frames are recorded with the top
+      frame's origin, so this flag helps separate top frame vs. embedded
+      playbacks.
+    </summary>
+  </metric>
+  <metric name="PlayerID">
+    <summary>
+      ID which corresponds to a given WebMediaPlayerImpl instance. May be linked
+      with Media.BasicPlayback events to understand a playback more deeply.
+    </summary>
+  </metric>
+  <metric name="TimeToFirstFrame">
+    <summary>
+      Time in milliseconds from when WebMediaPlayerImpl starts loading until the
+      first video frame has been shown.
+    </summary>
+  </metric>
+  <metric name="TimeToMetadata">
+    <summary>
+      Time in milliseconds from when WebMediaPlayerImpl starts loading until
+      metadata is known.
+    </summary>
+  </metric>
+  <metric name="TimeToPlayReady">
+    <summary>
+      Time in milliseconds from when WebMediaPlayerImpl starts loading until it
+      has buffered enough to start playback.
+    </summary>
+  </metric>
+  <metric name="URLScheme">
+    <summary>
+      media::mojom::MediaURLScheme enum value. Only recorded for !IsMSE src=URL
+      playbacks, this is the scheme of that URL; E.g., http, https, filesystem,
+      etc.
+    </summary>
+  </metric>
+</event>
+
 <event name="Memory.Experimental">
   <owner>erikchen@chromium.org</owner>
   <owner>ssid@chromium.org</owner>
@@ -3972,6 +4105,25 @@
   </metric>
 </event>
 
+<event name="MixedContentAutoupgrade.ResourceRequest">
+  <owner>carlosil@chromium.org</owner>
+  <summary>
+    Status and Network error or HTTP response code for a resource request that
+    was autoupgraded to HTTPS as part of the mixed content autoupgrade
+    experiment.
+  </summary>
+  <metric name="Code">
+    <summary>
+      The HTTP response or network error code for an autoupgraded request.
+    </summary>
+  </metric>
+  <metric name="Status">
+    <summary>
+      An enum with 0 representing started, 1 failed, and 2 response received.
+    </summary>
+  </metric>
+</event>
+
 <event name="Net.LegacyTLSVersion">
   <owner>davidben@chromium.org</owner>
   <summary>
@@ -3980,6 +4132,39 @@
   </summary>
 </event>
 
+<event name="NoStatePrefetch" singular="True">
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    Metrics related to NoStatePrefetch that are recorded using the same UKM IDs
+    as PageLoad.
+  </summary>
+  <metric name="PrefetchedRecently.FinalStatus">
+    <summary>
+      Final status of the nostate prefetch if one was recently attempted for
+      either the committed URL of this navigation or for any URL in the redirect
+      chain for the main frame resource for this navigation. page. Recorded as
+      enum PrerenderFinalStatus in //tools/metrics/histograms/enums.xml.
+    </summary>
+  </metric>
+  <metric name="PrefetchedRecently.Origin">
+    <summary>
+      Triggering origin of the nostate prefetch if one was recently attempted
+      for either the committed URL of this navigation or for any URL in the
+      redirect chain for the main frame resource for this navigation. Recorded
+      as enum PrerenderOrigin in //tools/metrics/histograms/enums.xml.
+    </summary>
+  </metric>
+  <metric name="PrefetchedRecently.PrefetchAge">
+    <summary>
+      Records the time (in milliseconds) from the start of the nostate prefetch
+      to the time of commit of this navigation. Metric is recorded down to the
+      nearest power of 2. Recorded only if a nostate prefetch was recently
+      attempted for either the committed URL of this navigation or for any URL
+      in the redirect chain for the main frame resource for this navigation.
+    </summary>
+  </metric>
+</event>
+
 <event name="Notification">
   <owner>peter@chromium.org</owner>
   <summary>
@@ -4079,109 +4264,6 @@
   </metric>
 </event>
 
-<event name="BackgroundFetch">
-  <owner>nator@chromium.org</owner>
-  <owner>rayankans@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    A BackgroundFetch event is logged before a background fetch is started from
-    a document context.
-  </summary>
-  <metric name="DeniedDueToPermissions">
-    <summary>
-      Boolean for whether the background fetch was denied due to permission.
-      This includes only the content setting permission.
-    </summary>
-  </metric>
-  <metric name="DownloadTotal">
-    <summary>
-      The value of downloadTotal provided with the background fetch. This is the
-      number of bytes that the developer expects to be downloaded with the
-      background fetch. This number is exponentially bucketed for privacy
-      reasons, and uses the UKM GetExponentialBucketMin method with a value of
-      2.0 for spacing.
-    </summary>
-  </metric>
-  <metric name="HasTitle">
-    <summary>
-      Boolean for whether a title was provided with the background fetch.
-    </summary>
-  </metric>
-  <metric name="NumIcons">
-    <summary>
-      Count of icons provided with the background fetch.
-    </summary>
-  </metric>
-  <metric name="NumRequestsInFetch">
-    <summary>
-      Number of requests in the background fetch. This number is exponentially
-      bucketed for privacy reasons, and uses the UKM GetExponentialBucketMin
-      method with a value of 2.0 for spacing.
-    </summary>
-  </metric>
-  <metric name="RatioOfIdealToChosenIconSize">
-    <summary>
-      Ratio of the ideal icon to the chosen icon size, times hundred. This will
-      be set to -1 if either ideal icon size is 0, or if none of the provided
-      icons are suitable.
-    </summary>
-  </metric>
-</event>
-
-<event name="BackgroundFetchDeletingRegistration">
-  <owner>nator@chromium.org</owner>
-  <owner>rayankans@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    A BackgroundFetchDeletingRegistration event is logged when a background
-    fetch job is being deleted.
-  </summary>
-  <metric name="UserInitiatedAbort">
-    <summary>
-      Boolean for whether the background fetch job was cancelled from the UI.
-    </summary>
-  </metric>
-</event>
-
-<event name="HistoryNavigation" singular="True">
-  <owner>altimin@chromium.org</owner>
-  <owner>arthursonzogni@chromium.org</owner>
-  <summary>
-    Metrics recorded each time we commit a history navigation, which are needed
-    to estimate benefits of back-forward cache.
-  </summary>
-  <metric name="LastCommittedSourceIdForTheSameDocument">
-    <summary>
-      For history navigations and reloads, the source id of the previous
-      navigation which loaded the page we're trying to navigate back to.
-    </summary>
-  </metric>
-  <metric name="NavigatedToTheMostRecentEntryForDocument">
-    <summary>
-      Boolean for whether we navigated to the same navigation entry as the one
-      which was last visible.
-
-      It can be false when subframes or same-document navigations are present.
-      For example, after navigating from http://foo to http://foo#bar and then
-      http://bar and then going back by 2 entries will mean we went to
-      http://foo while the last committed entry from this document was
-      http://foo#bar.
-
-      It's expected to be rare, but might be problematic for back-forward cache.
-    </summary>
-  </metric>
-  <metric name="TimeSinceNavigatedAwayFromDocument">
-    <summary>
-      Time in milliseconds from the moment the current navigation stopped being
-      active to the start of the current navigation.
-
-      This is clamped to hours for values greater than 3 hours, to minutes for
-      values greater than 3 minutes, to seconds for values greater than 5
-      seconds.
-    </summary>
-  </metric>
-</event>
-
 <event name="OfflinePages.SavePageRequested">
   <obsolete>
     Deprecated 03/2019
@@ -4215,6 +4297,20 @@
   </metric>
 </event>
 
+<event name="PageForegroundSession">
+  <owner>sullivan@chromium.org</owner>
+  <summary>
+    Total time in foreground in milliseconds, recorded each time the page is
+    backgrounded. May be recorded multiple times for a single page visit.
+  </summary>
+  <metric name="ForegroundDuration">
+    <summary>
+      Total time in foreground in milliseconds, recorded each time the page is
+      backgrounded.
+    </summary>
+  </metric>
+</event>
+
 <event name="PageLoad" singular="True">
   <owner>bmcquade@chromium.org</owner>
   <summary>
@@ -4782,37 +4878,20 @@
   </metric>
 </event>
 
-<event name="NoStatePrefetch" singular="True">
-  <owner>tbansal@chromium.org</owner>
+<event name="PageLoad.FromGoogleSearch" singular="True">
+  <owner>bmcquade@chromium.org</owner>
+  <owner>mushan@chromium.org</owner>
   <summary>
-    Metrics related to NoStatePrefetch that are recorded using the same UKM IDs
-    as PageLoad.
+    Recorded for page loads that were navigated to via Google Search.
   </summary>
-  <metric name="PrefetchedRecently.FinalStatus">
-    <summary>
-      Final status of the nostate prefetch if one was recently attempted for
-      either the committed URL of this navigation or for any URL in the redirect
-      chain for the main frame resource for this navigation. page. Recorded as
-      enum PrerenderFinalStatus in //tools/metrics/histograms/enums.xml.
-    </summary>
-  </metric>
-  <metric name="PrefetchedRecently.Origin">
-    <summary>
-      Triggering origin of the nostate prefetch if one was recently attempted
-      for either the committed URL of this navigation or for any URL in the
-      redirect chain for the main frame resource for this navigation. Recorded
-      as enum PrerenderOrigin in //tools/metrics/histograms/enums.xml.
-    </summary>
-  </metric>
-  <metric name="PrefetchedRecently.PrefetchAge">
-    <summary>
-      Records the time (in milliseconds) from the start of the nostate prefetch
-      to the time of commit of this navigation. Metric is recorded down to the
-      nearest power of 2. Recorded only if a nostate prefetch was recently
-      attempted for either the committed URL of this navigation or for any URL
-      in the redirect chain for the main frame resource for this navigation.
-    </summary>
-  </metric>
+</event>
+
+<event name="PageLoad.ServiceWorkerControlled" singular="True">
+  <owner>bmcquade@chromium.org</owner>
+  <owner>falken@chromium.org</owner>
+  <summary>
+    Recorded for page loads controlled by a service worker.
+  </summary>
 </event>
 
 <event name="PageLoadCapping" singular="True">
@@ -4833,20 +4912,43 @@
   </metric>
 </event>
 
-<event name="PageLoad.FromGoogleSearch" singular="True">
-  <owner>bmcquade@chromium.org</owner>
-  <owner>mushan@chromium.org</owner>
+<event name="PageWithPassword">
+  <owner>battre@chromium.org</owner>
   <summary>
-    Recorded for page loads that were navigated to via Google Search.
+    Metrics about websites that contain password forms and the user's
+    interactions with them. No events are created for pages that don't contain
+    password forms.
   </summary>
-</event>
-
-<event name="PageLoad.ServiceWorkerControlled" singular="True">
-  <owner>bmcquade@chromium.org</owner>
-  <owner>falken@chromium.org</owner>
-  <summary>
-    Recorded for page loads controlled by a service worker.
-  </summary>
+  <metric name="FormManagerAvailable">
+    <summary>
+      Records whether Chrome was sufficiently aware of forms during various
+      stages of saving a credential on the site, or whether saving was aborted
+      due to absence of the corresponding form manager. Values correspond to the
+      enum PasswordManagerMetricsRecorder::FormManagerAvailable.
+    </summary>
+  </metric>
+  <metric name="PageLevelUserAction">
+    <summary>
+      Records if the user interacts with the password manager in a way that
+      cannot (reliably) be attributed to a specific PasswordFormManager. Values
+      correspond to the enum
+      PasswordManagerMetricsRecorder::PageLevelUserAction.
+    </summary>
+  </metric>
+  <metric name="ProvisionalSaveFailure">
+    <summary>
+      Records a provisional save failure in case the password manager cannot
+      offer to save a credential. Recorded values correspond to the enum
+      PasswordManagerMetricsRecorder::ProvisionalSaveFailure.
+    </summary>
+  </metric>
+  <metric name="UserModifiedPasswordField">
+    <summary>
+      Records a 1 for every page on which a user has modified a password text
+      field - regardless of how many password fields a page contains or the user
+      modifies.
+    </summary>
+  </metric>
 </event>
 
 <event name="PasswordForm">
@@ -5237,45 +5339,6 @@
   </metric>
 </event>
 
-<event name="PageWithPassword">
-  <owner>battre@chromium.org</owner>
-  <summary>
-    Metrics about websites that contain password forms and the user's
-    interactions with them. No events are created for pages that don't contain
-    password forms.
-  </summary>
-  <metric name="FormManagerAvailable">
-    <summary>
-      Records whether Chrome was sufficiently aware of forms during various
-      stages of saving a credential on the site, or whether saving was aborted
-      due to absence of the corresponding form manager. Values correspond to the
-      enum PasswordManagerMetricsRecorder::FormManagerAvailable.
-    </summary>
-  </metric>
-  <metric name="PageLevelUserAction">
-    <summary>
-      Records if the user interacts with the password manager in a way that
-      cannot (reliably) be attributed to a specific PasswordFormManager. Values
-      correspond to the enum
-      PasswordManagerMetricsRecorder::PageLevelUserAction.
-    </summary>
-  </metric>
-  <metric name="ProvisionalSaveFailure">
-    <summary>
-      Records a provisional save failure in case the password manager cannot
-      offer to save a credential. Recorded values correspond to the enum
-      PasswordManagerMetricsRecorder::ProvisionalSaveFailure.
-    </summary>
-  </metric>
-  <metric name="UserModifiedPasswordField">
-    <summary>
-      Records a 1 for every page on which a user has modified a password text
-      field - regardless of how many password fields a page contains or the user
-      modifies.
-    </summary>
-  </metric>
-</event>
-
 <event name="PaymentRequest.CheckoutEvents">
   <owner>sebsg@chromium.org</owner>
   <metric name="CompletionStatus">
@@ -5293,6 +5356,14 @@
   </metric>
 </event>
 
+<event name="Pepper.Broker" singular="True">
+  <owner>raymes@chromium.org</owner>
+  <summary>
+    Event recorded when a flash instance connects to the broker, resulting in a
+    channel being opened to the broker process.
+  </summary>
+</event>
+
 <event name="Permission">
   <owner>timloh@chromium.org</owner>
   <summary>
@@ -5343,6 +5414,40 @@
   </summary>
 </event>
 
+<event name="Popup.Closed">
+  <owner>csharrison@chromium.org</owner>
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    A popup window was closed.
+  </summary>
+  <metric name="EngagementTime">
+    <summary>
+      The time (in ms, rounded down to the nearest power of 2) a popup
+      WebContents is visible / foregrounded, until it is closed. Keyed by the
+      popup opener's URL (not the URL of the popup).
+    </summary>
+  </metric>
+  <metric name="NumInteractions">
+    <summary>
+      Integer value representing how many user interactions the popup had. This
+      is capped at 100. See IsUserInteractionInputType in web_contents_impl for
+      what an interaction is. Currently it is a mouse, scroll begin, touch
+      start, or raw key down event.
+    </summary>
+  </metric>
+  <metric name="Trusted">
+    <summary>
+      Boolean value representing whether the popup was opened via some trusted
+      event (e.g. context menu, ctrl-click, etc).
+    </summary>
+  </metric>
+  <metric name="UserInitiatedClose">
+    <summary>
+      Boolean value to represent whether the popup was closed by user gesture.
+    </summary>
+  </metric>
+</event>
+
 <event name="Previews" singular="True">
   <owner>ryansturm@chromium.org</owner>
   <summary>
@@ -5468,22 +5573,6 @@
   </metric>
 </event>
 
-<event name="ResponsivenessMeasurement">
-  <owner>npm@chromium.org</owner>
-  <owner>tdresser@chromium.org</owner>
-  <summary>
-    Responsiveness metrics recorded once every 5 seconds.
-  </summary>
-  <metric name="ExpectedTaskQueueingDuration">
-    <summary>
-      Duration in MS for expected task queueing duration. The metric reflects
-      the responsiveness of a tab. A lower value means the tab will respond to
-      inputs faster. This metric is equal to
-      RendererScheduler.ExpectedTaskQueueingDuration of the main frame process.
-    </summary>
-  </metric>
-</event>
-
 <event name="RendererSchedulerTask">
   <owner>altimin@chromium.org</owner>
   <summary>
@@ -5576,44 +5665,18 @@
   </metric>
 </event>
 
-<event name="Pepper.Broker" singular="True">
-  <owner>raymes@chromium.org</owner>
+<event name="ResponsivenessMeasurement">
+  <owner>npm@chromium.org</owner>
+  <owner>tdresser@chromium.org</owner>
   <summary>
-    Event recorded when a flash instance connects to the broker, resulting in a
-    channel being opened to the broker process.
+    Responsiveness metrics recorded once every 5 seconds.
   </summary>
-</event>
-
-<event name="Popup.Closed">
-  <owner>csharrison@chromium.org</owner>
-  <owner>jkarlin@chromium.org</owner>
-  <summary>
-    A popup window was closed.
-  </summary>
-  <metric name="EngagementTime">
+  <metric name="ExpectedTaskQueueingDuration">
     <summary>
-      The time (in ms, rounded down to the nearest power of 2) a popup
-      WebContents is visible / foregrounded, until it is closed. Keyed by the
-      popup opener's URL (not the URL of the popup).
-    </summary>
-  </metric>
-  <metric name="NumInteractions">
-    <summary>
-      Integer value representing how many user interactions the popup had. This
-      is capped at 100. See IsUserInteractionInputType in web_contents_impl for
-      what an interaction is. Currently it is a mouse, scroll begin, touch
-      start, or raw key down event.
-    </summary>
-  </metric>
-  <metric name="Trusted">
-    <summary>
-      Boolean value representing whether the popup was opened via some trusted
-      event (e.g. context menu, ctrl-click, etc).
-    </summary>
-  </metric>
-  <metric name="UserInitiatedClose">
-    <summary>
-      Boolean value to represent whether the popup was closed by user gesture.
+      Duration in MS for expected task queueing duration. The metric reflects
+      the responsiveness of a tab. A lower value means the tab will respond to
+      inputs faster. This metric is equal to
+      RendererScheduler.ExpectedTaskQueueingDuration of the main frame process.
     </summary>
   </metric>
 </event>
@@ -5886,6 +5949,19 @@
   </metric>
 </event>
 
+<event name="SSL.MixedContentShown">
+  <owner>carlosil@chromium.org</owner>
+  <summary>
+    Logged when mixed content is displayed on a site.
+  </summary>
+  <metric name="Type">
+    <summary>
+      A value of the MixedContentType enum, detailing the type of mixed content
+      included on the site.
+    </summary>
+  </metric>
+</event>
+
 <event name="SubframeDownload">
   <obsolete>
     Deprecated as of 03/2019.
@@ -5958,23 +6034,6 @@
   </metric>
 </event>
 
-<event name="Translate">
-  <owner>hamelphi@chromium.org</owner>
-  <summary>
-    Metrics related to a Translate event. These metrics are described in
-    TranslateEventProto.
-  </summary>
-  <metric name="AcceptCount"/>
-  <metric name="Country"/>
-  <metric name="DeclineCount"/>
-  <metric name="EventType"/>
-  <metric name="IgnoreCount"/>
-  <metric name="RankerResponse"/>
-  <metric name="RankerVersion"/>
-  <metric name="SourceLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"/>
-  <metric name="TargetLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"/>
-</event>
-
 <event name="TabManager.Background.FirstAlertFired">
   <owner>chrisha@chromium.org</owner>
   <owner>lpy@chromium.org</owner>
@@ -6168,6 +6227,120 @@
   </metric>
 </event>
 
+<event name="TabManager.Experimental.BackgroundTabOpening.TabSwitchLoadStopped"
+    singular="True">
+  <owner>zhenw@chromium.org</owner>
+  <summary>
+    Collects data when a tab is switched to from another tab and then finishes
+    loading in the foreground during a background tab opening session (the
+    duration of time from when the browser starts to open background tabs until
+    the time the browser has finished loading those tabs or otherwise decided to
+    stop loading them). The event is only recorded when a tab is switched to
+    from another tab within the same tabstrip. As a result, the initial
+    foreground tab is not included in this event since it was not switched to
+    from another tab. The event is not recorded when the session overlaps with
+    session restore.
+  </summary>
+  <metric name="BackgroundTabLoadingCount">
+    <summary>
+      Number of background tabs that are loading.
+    </summary>
+  </metric>
+  <metric name="BackgroundTabOpeningSessionId">
+    <summary>
+      The ID of this background tab opening session.
+    </summary>
+  </metric>
+  <metric name="BackgroundTabPendingCount">
+    <summary>
+      Number of background tabs that are pending.
+    </summary>
+  </metric>
+  <metric name="SequenceId">
+    <summary>
+      The ID of this event's sequence in current background tab opening session.
+    </summary>
+  </metric>
+  <metric name="SystemTabCount">
+    <summary>
+      Number of all tabs of the system, which includes all browser windows.
+    </summary>
+  </metric>
+  <metric name="TabSwitchLoadTime">
+    <summary>
+      Tab switch load time in MS. It is defined as the time between when the
+      user switches to a backround tab, and the time when that tab finishes
+      loading in the foreground. If the user switches away before the tab
+      finishes loading, a metric will not be recorded unless the user switches
+      back, in which case the tab switch load time is measured from that point
+      in time.
+    </summary>
+  </metric>
+</event>
+
+<event name="TabManager.Experimental.SessionRestore.ForegroundTab.PageLoad"
+    singular="True">
+  <owner>zhenw@chromium.org</owner>
+  <summary>
+    Collects the tab counts for the foreground tab page load during session
+    restore. The event is not recorded when the session overlaps with background
+    tab opening. This event should be combined with PageLoad event for analysis.
+  </summary>
+  <metric name="SessionRestoreTabCount">
+    <summary>
+      Number of tabs that are restored.
+    </summary>
+  </metric>
+  <metric name="SystemTabCount">
+    <summary>
+      Number of all tabs of the system, which includes all browser windows.
+    </summary>
+  </metric>
+</event>
+
+<event name="TabManager.Experimental.SessionRestore.TabSwitchLoadStopped"
+    singular="True">
+  <owner>zhenw@chromium.org</owner>
+  <summary>
+    Collects data when a tab is switched to from another tab and then finishes
+    loading in the foreground during session restore The event is only recorded
+    when a tab is switched to from another tab within the same tabstrip. As a
+    result, the initial foreground tab is not included in this event since it
+    was not switched to from another tab. The event is not recorded when the
+    session overlaps with background tab opening.
+  </summary>
+  <metric name="SequenceId">
+    <summary>
+      The ID of this event's sequence in current session restore session.
+    </summary>
+  </metric>
+  <metric name="SessionRestoreSessionId">
+    <summary>
+      The ID of this session restore session.
+    </summary>
+  </metric>
+  <metric name="SessionRestoreTabCount">
+    <summary>
+      Number of tabs that are restored.
+    </summary>
+  </metric>
+  <metric name="SystemTabCount">
+    <summary>
+      Number of all tabs of the system, which includes all browser windows.
+    </summary>
+  </metric>
+  <metric name="TabSwitchLoadTime">
+    <summary>
+      Tab switch load time in MS. It is defined as the time between when the
+      user switches to a background tab, and the time when that tab finishes
+      loading in the foreground. If the user switches away before the tab
+      finishes loading, a metric will not be recorded unless the user switches
+      back, in which case the tab switch load time is measured from that point
+      in time.
+    </summary>
+  </metric>
+</event>
+
 <event name="TabManager.LifecycleStateChange">
   <owner>chrisha@chromium.org</owner>
   <owner>fdoray@chromium.org</owner>
@@ -6373,158 +6546,6 @@
   </metric>
 </event>
 
-<event name="TabManager.WindowMetrics">
-  <owner>michaelpg@chromium.org</owner>
-  <summary>
-    Collects information about a browser or app window to associate with the
-    TabManager.TabMetrics entries for tabs in that window.
-  </summary>
-  <metric name="IsActive">
-    <summary>
-      Whether the window is the active (frontmost) window.
-    </summary>
-  </metric>
-  <metric name="ShowState">
-    <summary>
-      Enumeration of the window show state, such as fullscreen or minimized.
-      Values are enumerated in metrics::WindowMetricsEvent::ShowState.
-    </summary>
-  </metric>
-  <metric name="TabCount">
-    <summary>
-      Number of tabs in the tab strip. Rounded down to the nearest exponential
-      bucket (with a bucket spacing factor of 1.5). Will be 1 for windows with
-      only one top-level WebContents, such as app windows.
-    </summary>
-  </metric>
-  <metric name="Type">
-    <summary>
-      Enumeration for the type of the window. Values are enumerated in
-      metrics::WindowMetricsEvent::Type.
-    </summary>
-  </metric>
-  <metric name="WindowId">
-    <summary>
-      Session ID of the browser or app window this entry represents, unique for
-      the browsing session.
-    </summary>
-  </metric>
-</event>
-
-<event name="TabManager.Experimental.BackgroundTabOpening.TabSwitchLoadStopped"
-    singular="True">
-  <owner>zhenw@chromium.org</owner>
-  <summary>
-    Collects data when a tab is switched to from another tab and then finishes
-    loading in the foreground during a background tab opening session (the
-    duration of time from when the browser starts to open background tabs until
-    the time the browser has finished loading those tabs or otherwise decided to
-    stop loading them). The event is only recorded when a tab is switched to
-    from another tab within the same tabstrip. As a result, the initial
-    foreground tab is not included in this event since it was not switched to
-    from another tab. The event is not recorded when the session overlaps with
-    session restore.
-  </summary>
-  <metric name="BackgroundTabLoadingCount">
-    <summary>
-      Number of background tabs that are loading.
-    </summary>
-  </metric>
-  <metric name="BackgroundTabOpeningSessionId">
-    <summary>
-      The ID of this background tab opening session.
-    </summary>
-  </metric>
-  <metric name="BackgroundTabPendingCount">
-    <summary>
-      Number of background tabs that are pending.
-    </summary>
-  </metric>
-  <metric name="SequenceId">
-    <summary>
-      The ID of this event's sequence in current background tab opening session.
-    </summary>
-  </metric>
-  <metric name="SystemTabCount">
-    <summary>
-      Number of all tabs of the system, which includes all browser windows.
-    </summary>
-  </metric>
-  <metric name="TabSwitchLoadTime">
-    <summary>
-      Tab switch load time in MS. It is defined as the time between when the
-      user switches to a backround tab, and the time when that tab finishes
-      loading in the foreground. If the user switches away before the tab
-      finishes loading, a metric will not be recorded unless the user switches
-      back, in which case the tab switch load time is measured from that point
-      in time.
-    </summary>
-  </metric>
-</event>
-
-<event name="TabManager.Experimental.SessionRestore.ForegroundTab.PageLoad"
-    singular="True">
-  <owner>zhenw@chromium.org</owner>
-  <summary>
-    Collects the tab counts for the foreground tab page load during session
-    restore. The event is not recorded when the session overlaps with background
-    tab opening. This event should be combined with PageLoad event for analysis.
-  </summary>
-  <metric name="SessionRestoreTabCount">
-    <summary>
-      Number of tabs that are restored.
-    </summary>
-  </metric>
-  <metric name="SystemTabCount">
-    <summary>
-      Number of all tabs of the system, which includes all browser windows.
-    </summary>
-  </metric>
-</event>
-
-<event name="TabManager.Experimental.SessionRestore.TabSwitchLoadStopped"
-    singular="True">
-  <owner>zhenw@chromium.org</owner>
-  <summary>
-    Collects data when a tab is switched to from another tab and then finishes
-    loading in the foreground during session restore The event is only recorded
-    when a tab is switched to from another tab within the same tabstrip. As a
-    result, the initial foreground tab is not included in this event since it
-    was not switched to from another tab. The event is not recorded when the
-    session overlaps with background tab opening.
-  </summary>
-  <metric name="SequenceId">
-    <summary>
-      The ID of this event's sequence in current session restore session.
-    </summary>
-  </metric>
-  <metric name="SessionRestoreSessionId">
-    <summary>
-      The ID of this session restore session.
-    </summary>
-  </metric>
-  <metric name="SessionRestoreTabCount">
-    <summary>
-      Number of tabs that are restored.
-    </summary>
-  </metric>
-  <metric name="SystemTabCount">
-    <summary>
-      Number of all tabs of the system, which includes all browser windows.
-    </summary>
-  </metric>
-  <metric name="TabSwitchLoadTime">
-    <summary>
-      Tab switch load time in MS. It is defined as the time between when the
-      user switches to a background tab, and the time when that tab finishes
-      loading in the foreground. If the user switches away before the tab
-      finishes loading, a metric will not be recorded unless the user switches
-      back, in which case the tab switch load time is measured from that point
-      in time.
-    </summary>
-  </metric>
-</event>
-
 <event
     name="TabManager.SessionRestore.ForegroundTab.ExpectedTaskQueueingDurationInfo">
   <owner>zhenw@chromium.org</owner>
@@ -6581,6 +6602,243 @@
   </metric>
 </event>
 
+<event name="TabManager.TabMetrics">
+  <owner>michaelpg@chromium.org</owner>
+  <summary>
+    Collects tab information for a tab after navigations, activations and close
+    events.
+  </summary>
+  <metric name="ContentType">
+    <summary>
+      Obsolete. Enumeration for the MIME type of the page. Values are enumerated
+      in metrics::TabMetricsEvent::ContentType.
+    </summary>
+  </metric>
+  <metric name="DefaultProtocolHandler">
+    <summary>
+      Obsolete. Schemes that a page from this page's origin is the default
+      protocol handler for, meaning the user has chosen to accept (or the
+      handler was preinstalled by Chrome). The metric is repeated, occurring for
+      each such protocol handler, and uses values from
+      metrics::TabMetricsEvent::Scheme.
+    </summary>
+  </metric>
+  <metric name="HasBeforeUnloadHandler">
+    <summary>
+      Boolean value indicating whether the page has a beforeunload JavaScript
+      event handler.
+    </summary>
+  </metric>
+  <metric name="HasFormEntry">
+    <summary>
+      Boolean value indicating whether the page has any user-input text.
+    </summary>
+  </metric>
+  <metric name="IsExtensionProtected">
+    <summary>
+      Obsolete. True if an extension has marked this tab as non-discardable via
+      the chrome.tabs.update() extension API.
+    </summary>
+  </metric>
+  <metric name="IsPinned">
+    <summary>
+      Boolean value indicating whether the tab is pinned in the tabstrip.
+    </summary>
+  </metric>
+  <metric name="KeyEventCount">
+    <summary>
+      Number of key events that were sent to the page.
+    </summary>
+  </metric>
+  <metric name="LabelId">
+    <summary>
+      An int64 random number generated at logging time. The same number will
+      also be logged to the TabManager.Background.ForegroundedOrClosed event, so
+      that feature label can be paired.
+    </summary>
+  </metric>
+  <metric name="MouseEventCount">
+    <summary>
+      Number of mouse events that were sent to the page.
+    </summary>
+  </metric>
+  <metric name="MRUIndex">
+    <summary>
+      Index of the tab in most-recently-used order. A value of N means there are
+      N tabs more recently used than the one that is being foregrounded or
+      closed.
+    </summary>
+  </metric>
+  <metric name="NavigationEntryCount">
+    <summary>
+      Number of navigation entries in the tab's NavigationController.
+      Corresponds to the size of the tab's back/forward list.
+    </summary>
+  </metric>
+  <metric name="NumReactivationBefore">
+    <summary>
+      Number of reactivations that this tab had till now.
+    </summary>
+  </metric>
+  <metric name="PageTransitionCoreType">
+    <summary>
+      Type of the page transition for this navigation. Uses the core values from
+      ui::PageTransition.
+    </summary>
+  </metric>
+  <metric name="PageTransitionFromAddressBar">
+    <summary>
+      True if the page transition came from interacting with the address bar,
+      such as by typing a URL or performing a search.
+    </summary>
+  </metric>
+  <metric name="PageTransitionIsRedirect">
+    <summary>
+      True if the page transition type is a redirect, in which case the
+      PageTransition type may not be accurate.
+    </summary>
+  </metric>
+  <metric name="QueryId">
+    <summary>
+      An int64 random number generated at query time of
+      TabManager::GetSortedLifecycleUnitsFromTabRanker. Tabs with the same
+      QueryId will be later on combined in one full list for further analysis.
+    </summary>
+  </metric>
+  <metric name="SequenceId">
+    <obsolete>
+      Deprecated 11/2018 in favor LabelId.
+    </obsolete>
+    <summary>
+      This metric is obsolete in 11/2018 in favor of LabelId for pairing with
+      Tabmanager.ForegroundedOrClosed event. The sequence of this event and
+      TabManager.ForegroundedOrClosed event in the current session. Incremented
+      by 1 each time one of the two events is logged to provide an ordering of
+      events.
+    </summary>
+  </metric>
+  <metric name="SiteEngagementScore">
+    <summary>
+      Site engagement score in the range [0, 100], rounded down to a multiple of
+      10 to limit granularity.
+    </summary>
+  </metric>
+  <metric name="TimeFromBackgrounded">
+    <summary>
+      Duration in MS from when the tab is backgrounded to when it is brought to
+      foreground or closed.
+    </summary>
+  </metric>
+  <metric name="TotalTabCount">
+    <summary>
+      Total number of tabs open across all non-incognito browser windows. Helps
+      contextualize the MRUIndex value.
+    </summary>
+  </metric>
+  <metric name="TouchEventCount">
+    <summary>
+      Number of touch events that were sent to the page.
+    </summary>
+  </metric>
+  <metric name="WasRecentlyAudible">
+    <summary>
+      Boolean value indicating whether the tab has played audio within the last
+      two seconds.
+    </summary>
+  </metric>
+  <metric name="WindowId">
+    <obsolete>
+      Deprecated 11/2018 in favor of putting window features directly in this
+      event.
+    </obsolete>
+    <summary>
+      WindowId of the WindowMetrics entry corresponding to the browser window
+      containing this tab. This metrics is not populated from 11/2018 because we
+      don't need to join this event with other WindowMetrics any more.
+    </summary>
+  </metric>
+  <metric name="WindowIsActive">
+    <summary>
+      Boolean value indicating whether the window is the active (frontmost)
+      window.
+    </summary>
+  </metric>
+  <metric name="WindowShowState">
+    <summary>
+      Enumeration of the window show state, such as fullscreen or minimized.
+      Values are enumerated in metrics::WindowMetricsEvent::ShowState.
+    </summary>
+  </metric>
+  <metric name="WindowTabCount">
+    <summary>
+      Number of tabs in the tab strip. Rounded down to the nearest exponential
+      bucket (with a bucket spacing factor of 1.5). Will be 1 for windows with
+      only one top-level WebContents, such as app windows.
+    </summary>
+  </metric>
+  <metric name="WindowType">
+    <summary>
+      Enumeration for the type of the window. Values are enumerated in
+      metrics::WindowMetricsEvent::Type.
+    </summary>
+  </metric>
+</event>
+
+<event name="TabManager.WindowMetrics">
+  <owner>michaelpg@chromium.org</owner>
+  <summary>
+    Collects information about a browser or app window to associate with the
+    TabManager.TabMetrics entries for tabs in that window.
+  </summary>
+  <metric name="IsActive">
+    <summary>
+      Whether the window is the active (frontmost) window.
+    </summary>
+  </metric>
+  <metric name="ShowState">
+    <summary>
+      Enumeration of the window show state, such as fullscreen or minimized.
+      Values are enumerated in metrics::WindowMetricsEvent::ShowState.
+    </summary>
+  </metric>
+  <metric name="TabCount">
+    <summary>
+      Number of tabs in the tab strip. Rounded down to the nearest exponential
+      bucket (with a bucket spacing factor of 1.5). Will be 1 for windows with
+      only one top-level WebContents, such as app windows.
+    </summary>
+  </metric>
+  <metric name="Type">
+    <summary>
+      Enumeration for the type of the window. Values are enumerated in
+      metrics::WindowMetricsEvent::Type.
+    </summary>
+  </metric>
+  <metric name="WindowId">
+    <summary>
+      Session ID of the browser or app window this entry represents, unique for
+      the browsing session.
+    </summary>
+  </metric>
+</event>
+
+<event name="Translate">
+  <owner>hamelphi@chromium.org</owner>
+  <summary>
+    Metrics related to a Translate event. These metrics are described in
+    TranslateEventProto.
+  </summary>
+  <metric name="AcceptCount"/>
+  <metric name="Country"/>
+  <metric name="DeclineCount"/>
+  <metric name="EventType"/>
+  <metric name="IgnoreCount"/>
+  <metric name="RankerResponse"/>
+  <metric name="RankerVersion"/>
+  <metric name="SourceLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"/>
+  <metric name="TargetLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"/>
+</event>
+
 <event name="TrustedWebActivity.Open" singular="True">
   <owner>peconn@chromium.org</owner>
   <summary>
@@ -6848,313 +7106,6 @@
   </metric>
 </event>
 
-<event name="TabManager.TabMetrics">
-  <owner>michaelpg@chromium.org</owner>
-  <summary>
-    Collects tab information for a tab after navigations, activations and close
-    events.
-  </summary>
-  <metric name="ContentType">
-    <summary>
-      Obsolete. Enumeration for the MIME type of the page. Values are enumerated
-      in metrics::TabMetricsEvent::ContentType.
-    </summary>
-  </metric>
-  <metric name="DefaultProtocolHandler">
-    <summary>
-      Obsolete. Schemes that a page from this page's origin is the default
-      protocol handler for, meaning the user has chosen to accept (or the
-      handler was preinstalled by Chrome). The metric is repeated, occurring for
-      each such protocol handler, and uses values from
-      metrics::TabMetricsEvent::Scheme.
-    </summary>
-  </metric>
-  <metric name="HasBeforeUnloadHandler">
-    <summary>
-      Boolean value indicating whether the page has a beforeunload JavaScript
-      event handler.
-    </summary>
-  </metric>
-  <metric name="HasFormEntry">
-    <summary>
-      Boolean value indicating whether the page has any user-input text.
-    </summary>
-  </metric>
-  <metric name="IsExtensionProtected">
-    <summary>
-      Obsolete. True if an extension has marked this tab as non-discardable via
-      the chrome.tabs.update() extension API.
-    </summary>
-  </metric>
-  <metric name="IsPinned">
-    <summary>
-      Boolean value indicating whether the tab is pinned in the tabstrip.
-    </summary>
-  </metric>
-  <metric name="KeyEventCount">
-    <summary>
-      Number of key events that were sent to the page.
-    </summary>
-  </metric>
-  <metric name="LabelId">
-    <summary>
-      An int64 random number generated at logging time. The same number will
-      also be logged to the TabManager.Background.ForegroundedOrClosed event, so
-      that feature label can be paired.
-    </summary>
-  </metric>
-  <metric name="MouseEventCount">
-    <summary>
-      Number of mouse events that were sent to the page.
-    </summary>
-  </metric>
-  <metric name="MRUIndex">
-    <summary>
-      Index of the tab in most-recently-used order. A value of N means there are
-      N tabs more recently used than the one that is being foregrounded or
-      closed.
-    </summary>
-  </metric>
-  <metric name="NavigationEntryCount">
-    <summary>
-      Number of navigation entries in the tab's NavigationController.
-      Corresponds to the size of the tab's back/forward list.
-    </summary>
-  </metric>
-  <metric name="NumReactivationBefore">
-    <summary>
-      Number of reactivations that this tab had till now.
-    </summary>
-  </metric>
-  <metric name="PageTransitionCoreType">
-    <summary>
-      Type of the page transition for this navigation. Uses the core values from
-      ui::PageTransition.
-    </summary>
-  </metric>
-  <metric name="PageTransitionFromAddressBar">
-    <summary>
-      True if the page transition came from interacting with the address bar,
-      such as by typing a URL or performing a search.
-    </summary>
-  </metric>
-  <metric name="PageTransitionIsRedirect">
-    <summary>
-      True if the page transition type is a redirect, in which case the
-      PageTransition type may not be accurate.
-    </summary>
-  </metric>
-  <metric name="QueryId">
-    <summary>
-      An int64 random number generated at query time of
-      TabManager::GetSortedLifecycleUnitsFromTabRanker. Tabs with the same
-      QueryId will be later on combined in one full list for further analysis.
-    </summary>
-  </metric>
-  <metric name="SequenceId">
-    <obsolete>
-      Deprecated 11/2018 in favor LabelId.
-    </obsolete>
-    <summary>
-      This metric is obsolete in 11/2018 in favor of LabelId for pairing with
-      Tabmanager.ForegroundedOrClosed event. The sequence of this event and
-      TabManager.ForegroundedOrClosed event in the current session. Incremented
-      by 1 each time one of the two events is logged to provide an ordering of
-      events.
-    </summary>
-  </metric>
-  <metric name="SiteEngagementScore">
-    <summary>
-      Site engagement score in the range [0, 100], rounded down to a multiple of
-      10 to limit granularity.
-    </summary>
-  </metric>
-  <metric name="TimeFromBackgrounded">
-    <summary>
-      Duration in MS from when the tab is backgrounded to when it is brought to
-      foreground or closed.
-    </summary>
-  </metric>
-  <metric name="TotalTabCount">
-    <summary>
-      Total number of tabs open across all non-incognito browser windows. Helps
-      contextualize the MRUIndex value.
-    </summary>
-  </metric>
-  <metric name="TouchEventCount">
-    <summary>
-      Number of touch events that were sent to the page.
-    </summary>
-  </metric>
-  <metric name="WasRecentlyAudible">
-    <summary>
-      Boolean value indicating whether the tab has played audio within the last
-      two seconds.
-    </summary>
-  </metric>
-  <metric name="WindowId">
-    <obsolete>
-      Deprecated 11/2018 in favor of putting window features directly in this
-      event.
-    </obsolete>
-    <summary>
-      WindowId of the WindowMetrics entry corresponding to the browser window
-      containing this tab. This metrics is not populated from 11/2018 because we
-      don't need to join this event with other WindowMetrics any more.
-    </summary>
-  </metric>
-  <metric name="WindowIsActive">
-    <summary>
-      Boolean value indicating whether the window is the active (frontmost)
-      window.
-    </summary>
-  </metric>
-  <metric name="WindowShowState">
-    <summary>
-      Enumeration of the window show state, such as fullscreen or minimized.
-      Values are enumerated in metrics::WindowMetricsEvent::ShowState.
-    </summary>
-  </metric>
-  <metric name="WindowTabCount">
-    <summary>
-      Number of tabs in the tab strip. Rounded down to the nearest exponential
-      bucket (with a bucket spacing factor of 1.5). Will be 1 for windows with
-      only one top-level WebContents, such as app windows.
-    </summary>
-  </metric>
-  <metric name="WindowType">
-    <summary>
-      Enumeration for the type of the window. Values are enumerated in
-      metrics::WindowMetricsEvent::Type.
-    </summary>
-  </metric>
-</event>
-
-<event name="XR.WebXR" singular="True">
-  <owner>billorr@chromium.org</owner>
-  <metric name="DidGetGamepads">
-    <obsolete>
-      Deprecated in M75.
-    </obsolete>
-    <summary>
-      Boolean value that indicates that the Gamepad API was used on a WebXR
-      site.
-    </summary>
-  </metric>
-  <metric name="DidGetXRInputSources">
-    <summary>
-      Boolean value that indicates that the WebXR input API was used.
-    </summary>
-  </metric>
-  <metric name="DidRequestAvailableDevices">
-    <summary>
-      Boolean value that indicates that the API to enumerate devices was called.
-    </summary>
-  </metric>
-  <metric name="DidRequestPose">
-    <summary>
-      Boolean value that indicates that poses were requested.
-    </summary>
-  </metric>
-  <metric name="DidRequestPresentation">
-    <summary>
-      Boolean value that indicates that presentation was requested.
-    </summary>
-  </metric>
-  <metric name="DidUseNavigatorXR">
-    <summary>
-      Boolean value that indicates that the WebXR Device API was used.
-    </summary>
-  </metric>
-  <metric name="ReturnedDevice">
-    <summary>
-      Boolean value that indicates that a device was returned by the API to
-      enumerate devices.
-    </summary>
-  </metric>
-  <metric name="ReturnedPresentationCapableDevice">
-    <summary>
-      Boolean value that indicates that a device was returned by the API to
-      enumerate devices, and that the device supports presentation.
-    </summary>
-  </metric>
-</event>
-
-<event name="XR.PageSession" singular="True">
-  <owner>offenwanger@chromium.org</owner>
-  <summary>
-    Records properties of page use in XR, including VR browsing and WebXR
-    presentation.
-  </summary>
-  <metric name="Duration">
-    <summary>
-      The approximate amount of time the user spends on a page in XR in seconds.
-      Times are reported accurately when low, for example, under a minute, and
-      get rounded to minutes and then hours as they get larger. This is done by
-      SessionTracker::GetRoundedDurationInSeconds.
-    </summary>
-  </metric>
-  <metric name="EnteredFullscreen">
-    <summary>
-      A boolean that is set to 1 if the user requested fullscreen while in XR on
-      some element on the page.
-    </summary>
-  </metric>
-  <metric name="EnteredVROnPageReason">
-    <summary>
-      An enum that indicates that the user entered VR on this page and what
-      triggered the entry into VR, where 1 means VR was entered through headset
-      activation, and 2 means that request presentation triggered the entry into
-      VR.
-    </summary>
-  </metric>
-  <metric name="TimeOnPage">
-    <summary>
-      Deprecated.
-    </summary>
-  </metric>
-  <metric name="WasOmniboxNavigation">
-    <summary>
-      A boolean that is set to 1 if this page was entered into the omnibox,
-      either manually or using autocomplete.
-    </summary>
-  </metric>
-  <metric name="WasVoiceSearchNavigation">
-    <summary>
-      A boolean that is set to 1 if this page was specifically requested and
-      recognized by a voice search.
-    </summary>
-  </metric>
-</event>
-
-<event name="XR.WebXR.PresentationSession">
-  <owner>offenwanger@chromium.org</owner>
-  <summary>
-    Records data for a presentation session, where WebXR is running an exclusive
-    presentation to some device.
-  </summary>
-  <metric name="Duration">
-    <summary>
-      The approximate amount of time the user spends in presentation in seconds.
-      Times are reported accurately when low, for example, under a minute, and
-      get rounded to minutes and then hours as they get larger. This is done by
-      SessionTracker::GetRoundedDurationInSeconds.
-    </summary>
-  </metric>
-  <metric name="StartAction">
-    <summary>
-      A metric to track specifically how the user got into XR presentation. 0:
-      Other, catch all. 1: RequestFrom2DBrowsing, the page requested
-      presentation while Chrome was in 2D mode. 2: RequestFromVRBrowsing, the
-      page requested presentation while Chrome was in VR browsing mode. 3:
-      HeadsetActivation, the user activated the VR headset while in 2D browsing
-      on the page, which listens for headset activations to request
-      presentation. 4: DeepLinkedApp, The page was launched in Chrome from the
-      VR system home (e.g., Daydream Home) and requested presentation.
-    </summary>
-  </metric>
-</event>
-
 <event name="VirtualKeyboard.Open">
   <owner>shend@chromium.org</owner>
   <summary>
@@ -7211,80 +7162,129 @@
   </metric>
 </event>
 
-<event name="IOS.FindInPageSearchMatches">
-  <owner>thegreenfrog@chromium.org</owner>
-  <owner>michaeldo@chromium.org</owner>
+<event name="XR.PageSession" singular="True">
+  <owner>offenwanger@chromium.org</owner>
   <summary>
-    Logged when the FindInPage returns a user search request result.
+    Records properties of page use in XR, including VR browsing and WebXR
+    presentation.
   </summary>
-  <metric name="HasMatches">
+  <metric name="Duration">
     <summary>
-      True if there were matches.
+      The approximate amount of time the user spends on a page in XR in seconds.
+      Times are reported accurately when low, for example, under a minute, and
+      get rounded to minutes and then hours as they get larger. This is done by
+      SessionTracker::GetRoundedDurationInSeconds.
+    </summary>
+  </metric>
+  <metric name="EnteredFullscreen">
+    <summary>
+      A boolean that is set to 1 if the user requested fullscreen while in XR on
+      some element on the page.
+    </summary>
+  </metric>
+  <metric name="EnteredVROnPageReason">
+    <summary>
+      An enum that indicates that the user entered VR on this page and what
+      triggered the entry into VR, where 1 means VR was entered through headset
+      activation, and 2 means that request presentation triggered the entry into
+      VR.
+    </summary>
+  </metric>
+  <metric name="TimeOnPage">
+    <summary>
+      Deprecated.
+    </summary>
+  </metric>
+  <metric name="WasOmniboxNavigation">
+    <summary>
+      A boolean that is set to 1 if this page was entered into the omnibox,
+      either manually or using autocomplete.
+    </summary>
+  </metric>
+  <metric name="WasVoiceSearchNavigation">
+    <summary>
+      A boolean that is set to 1 if this page was specifically requested and
+      recognized by a voice search.
     </summary>
   </metric>
 </event>
 
-<event name="IOS.URLMismatchInLegacyAndSlimNavigationManager">
-  <owner>eugenebut@chromium.org</owner>
-  <owner>danyao@chromium.org</owner>
-  <summary>
-    Logged when LegacyNavigationManager and KWKBasedNavigationManager have
-    different last committed URLs. This means that either old or new navigation
-    system has a URL spoofing bug.
-  </summary>
-  <metric name="HasMismatch">
+<event name="XR.WebXR" singular="True">
+  <owner>billorr@chromium.org</owner>
+  <metric name="DidGetGamepads">
+    <obsolete>
+      Deprecated in M75.
+    </obsolete>
     <summary>
-      True if there was a mismatch.
-    </summary>
-    <aggregation>
-      <history>
-        <statistics>
-          <enumeration/>
-        </statistics>
-      </history>
-    </aggregation>
-  </metric>
-</event>
-
-<event name="MixedContentAutoupgrade.ResourceRequest">
-  <owner>carlosil@chromium.org</owner>
-  <summary>
-    Status and Network error or HTTP response code for a resource request that
-    was autoupgraded to HTTPS as part of the mixed content autoupgrade
-    experiment.
-  </summary>
-  <metric name="Code">
-    <summary>
-      The HTTP response or network error code for an autoupgraded request.
+      Boolean value that indicates that the Gamepad API was used on a WebXR
+      site.
     </summary>
   </metric>
-  <metric name="Status">
+  <metric name="DidGetXRInputSources">
     <summary>
-      An enum with 0 representing started, 1 failed, and 2 response received.
+      Boolean value that indicates that the WebXR input API was used.
+    </summary>
+  </metric>
+  <metric name="DidRequestAvailableDevices">
+    <summary>
+      Boolean value that indicates that the API to enumerate devices was called.
+    </summary>
+  </metric>
+  <metric name="DidRequestPose">
+    <summary>
+      Boolean value that indicates that poses were requested.
+    </summary>
+  </metric>
+  <metric name="DidRequestPresentation">
+    <summary>
+      Boolean value that indicates that presentation was requested.
+    </summary>
+  </metric>
+  <metric name="DidUseNavigatorXR">
+    <summary>
+      Boolean value that indicates that the WebXR Device API was used.
+    </summary>
+  </metric>
+  <metric name="ReturnedDevice">
+    <summary>
+      Boolean value that indicates that a device was returned by the API to
+      enumerate devices.
+    </summary>
+  </metric>
+  <metric name="ReturnedPresentationCapableDevice">
+    <summary>
+      Boolean value that indicates that a device was returned by the API to
+      enumerate devices, and that the device supports presentation.
     </summary>
   </metric>
 </event>
 
-<event name="SSL.MixedContentShown">
-  <owner>carlosil@chromium.org</owner>
+<event name="XR.WebXR.PresentationSession">
+  <owner>offenwanger@chromium.org</owner>
   <summary>
-    Logged when mixed content is displayed on a site.
+    Records data for a presentation session, where WebXR is running an exclusive
+    presentation to some device.
   </summary>
-  <metric name="Type">
+  <metric name="Duration">
     <summary>
-      A value of the MixedContentType enum, detailing the type of mixed content
-      included on the site.
+      The approximate amount of time the user spends in presentation in seconds.
+      Times are reported accurately when low, for example, under a minute, and
+      get rounded to minutes and then hours as they get larger. This is done by
+      SessionTracker::GetRoundedDurationInSeconds.
     </summary>
   </metric>
-</event>
-
-<event name="HistoryManipulationIntervention">
-  <owner>shivanisha@chromium.org</owner>
-  <summary>
-    Logged when an entry in the back-forward list is marked to be skipped on
-    subsequent back/forward button clicks as part of the history manipulation
-    intervention. This is logged when the entry is navigated away from.
-  </summary>
+  <metric name="StartAction">
+    <summary>
+      A metric to track specifically how the user got into XR presentation. 0:
+      Other, catch all. 1: RequestFrom2DBrowsing, the page requested
+      presentation while Chrome was in 2D mode. 2: RequestFromVRBrowsing, the
+      page requested presentation while Chrome was in VR browsing mode. 3:
+      HeadsetActivation, the user activated the VR headset while in 2D browsing
+      on the page, which listens for headset activations to request
+      presentation. 4: DeepLinkedApp, The page was launched in Chrome from the
+      VR system home (e.g., Daydream Home) and requested presentation.
+    </summary>
+  </metric>
 </event>
 
 </ukm-configuration>
diff --git a/tools/metrics/ukm/ukm_model.py b/tools/metrics/ukm/ukm_model.py
index 841257d..f278acca 100644
--- a/tools/metrics/ukm/ukm_model.py
+++ b/tools/metrics/ukm/ukm_model.py
@@ -91,6 +91,7 @@
 
 _UKM_CONFIGURATION_TYPE = models.ObjectNodeType(
     'ukm-configuration',
+    alphabetization=[('event', _LOWERCASE_NAME_FN)],
     extra_newlines=(2, 1, 1),
     indent=False,
     children=[
diff --git a/tools/metrics/ukm/ukm_model_test.py b/tools/metrics/ukm/ukm_model_test.py
index d681a49b..d456e1c 100755
--- a/tools/metrics/ukm/ukm_model_test.py
+++ b/tools/metrics/ukm/ukm_model_test.py
@@ -49,6 +49,29 @@
 </ukm-configuration>
 """.strip()
 
+CONFIG_EVENT_NAMES_SORTED = """
+<ukm-configuration>
+
+<event name="Event1"/>
+
+<event name="Event2"/>
+
+<event name="Event3"/>
+
+</ukm-configuration>
+""".strip()
+
+CONFIG_EVENT_NAMES_UNSORTED = """
+<ukm-configuration>
+
+<event name="Event2"/>
+
+<event name="Event3"/>
+
+<event name="Event1"/>
+
+</ukm-configuration>
+""".strip()
 
 class UkmXmlTest(unittest.TestCase):
 
@@ -70,6 +93,9 @@
     self.assertIn('Metric:1', str(context.exception))
     self.assertIn('does not match regex', str(context.exception))
 
+  def testSortByEventName(self):
+    result = ukm_model.UpdateXML(CONFIG_EVENT_NAMES_UNSORTED)
+    self.assertMultiLineEqual(CONFIG_EVENT_NAMES_SORTED, result.strip())
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index d9e5d022..23a93cc 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -175,10 +175,12 @@
 crbug.com/756119 [ All ] oilpan_gc_times.sync_scroll.key_mobile_sites_smooth/digg [ Skip ]
 
 # Benchmark: rendering.desktop
+crbug.com/950710 [ All ] rendering.desktop/* [ Skip ]
 crbug.com/755556 [ Mac ] rendering.desktop/mix_blend_mode_animation_difference [ Skip ]
 crbug.com/755556 [ Mac ] rendering.desktop/mix_blend_mode_animation_hue [ Skip ]
 
 # Benchmark: rendering.mobile
+crbug.com/950710 [ All ] rendering.mobile/* [ Skip ]
 crbug.com/785485 [ Android_Webview ] rendering.mobile/kevs_3d [ Skip ]
 crbug.com/785286 [ Android_Webview ] rendering.mobile/smash_cat [ Skip ]
 crbug.com/785286 [ Android_Webview ] rendering.mobile/effect_games [ Skip ]
@@ -234,6 +236,9 @@
 # crbug.com/894744 [ Android ] startup.mobile/cct:coldish:bbc [ Skip ]
 crbug.com/948789 [ Nexus_5 ] startup.mobile/maps_pwa:with_http_cache [ Skip ]
 crbug.com/948789 [ Nexus_5X ] startup.mobile/maps_pwa:with_http_cache [ Skip ]
+crbug.com/950754 [ Android_Go ] startup.mobile/cct:coldish:bbc [ Skip ]
+crbug.com/950754 [ Android_Go ] startup.mobile/intent:coldish:bbc [ Skip ]
+crbug.com/950754 [ Android_Go ] startup.mobile/intent:warm:bbc [ Skip ]
 
 # Benchmark: system_health.common_desktop
 crbug.com/773084 [ Mac ] system_health.common_desktop/browse:tools:maps [ Skip ]
@@ -384,6 +389,7 @@
 crbug.com/853212 [ Android_Webview ] v8.browsing_mobile/browse:news:cnn [ Skip ]
 crbug.com/877648 [ Android_Go ] v8.browsing_mobile/browse:news:toi [ Skip ]
 crbug.com/877648 [ Android_Go ] v8.browsing_mobile/browse:news:cnn [ Skip ]
+crbug.com/950757 [ Android_Go ] v8.browsing_mobile/browse:news:cnn:2018 [ Skip ]
 crbug.com/901967 [ Nexus6_Webview ] v8.browsing_mobile/browse:news:toi [ Skip ]
 crbug.com/923116 [ Android ] v8.browsing_mobile/browse:shopping:avito [ Skip ]
 crbug.com/929839 [ Android_Go ] v8.browsing_mobile/browse:chrome:newtab [ Skip ]
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index a8b692a..a252b60 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -39,6 +39,8 @@
     "ax_action_data.h",
     "ax_action_handler.cc",
     "ax_action_handler.h",
+    "ax_clipping_behavior.h",
+    "ax_coordinate_system.h",
     "ax_enum_util.cc",
     "ax_enum_util.h",
     "ax_event.cc",
@@ -58,6 +60,7 @@
     "ax_node_data.h",
     "ax_node_position.cc",
     "ax_node_position.h",
+    "ax_offscreen_result.h",
     "ax_position.h",
     "ax_range.h",
     "ax_relative_bounds.cc",
diff --git a/ui/accessibility/ax_clipping_behavior.h b/ui/accessibility/ax_clipping_behavior.h
new file mode 100644
index 0000000..c4652276
--- /dev/null
+++ b/ui/accessibility/ax_clipping_behavior.h
@@ -0,0 +1,19 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_AX_CLIPPING_BEHAVIOR_H_
+#define UI_ACCESSIBILITY_AX_CLIPPING_BEHAVIOR_H_
+
+namespace ui {
+
+// The clipping behavior to perform on bounds. Clipping limits a node's bounding
+// box to the visible sizes of it's ancestors - which may be hidden or scrolled
+// out of view. For a longer discussion on clipping behavior see the link below.
+// https://chromium.googlesource.com/chromium/src/+/lkgr/docs/accessibility/offscreen.md
+//   kUnclipped: Do not apply clipping to bound results
+//   kClipped:   Apply clipping to bound results
+enum class AXClippingBehavior { kUnclipped, kClipped };
+}  // namespace ui
+
+#endif  // UI_ACCESSIBILITY_AX_CLIPPING_BEHAVIOR_H_
diff --git a/ui/accessibility/ax_coordinate_system.h b/ui/accessibility/ax_coordinate_system.h
new file mode 100644
index 0000000..3cf1f2f6
--- /dev/null
+++ b/ui/accessibility/ax_coordinate_system.h
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_AX_COORDINATE_SYSTEM_H_
+#define UI_ACCESSIBILITY_AX_COORDINATE_SYSTEM_H_
+
+namespace ui {
+
+// The coordinate system of bounds or points. The origin for all coordinate
+// systems is the upper left hand corner of the region. Frame coordinates
+// correspond to the current frame and root frame coordinates are relative to
+// the topmost accessibility tree of the same type. For web content, root frame
+// coordinates are relative to the root frame of the web page. From within an
+// accessibility tree whose root is an iframe, frame coordinates are relative to
+// the region of the iframe. From an iframe leaf accessibility node, frame
+// coordinates are relative to the containing accessibility tree. For native UI,
+// frame coordinates are relative to the current window whereas root frame
+// coordinates are relative to the top-level window. The frame coordinates are
+// equivalent to the root frame coordinates when the current accessibility tree
+// is the root accessibility tree.
+//   kScreen:    Relative to the screen space on the user's device
+//   kRootFrame: Relative to the top-level accessibility tree of the same type
+//   kFrame:     Relative to the current accessibility tree
+enum class AXCoordinateSystem { kScreen, kRootFrame, kFrame };
+}  // namespace ui
+
+#endif  // UI_ACCESSIBILITY_AX_COORDINATE_SYSTEM_H_
diff --git a/ui/accessibility/ax_event_generator.cc b/ui/accessibility/ax_event_generator.cc
index dc904ad..df4c444 100644
--- a/ui/accessibility/ax_event_generator.cc
+++ b/ui/accessibility/ax_event_generator.cc
@@ -369,6 +369,9 @@
   DCHECK_EQ(tree_, tree);
 
   switch (attr) {
+    case ax::mojom::IntListAttribute::kControlsIds:
+      AddEvent(node, Event::CONTROLS_CHANGED);
+      break;
     case ax::mojom::IntListAttribute::kDescribedbyIds:
       AddEvent(node, Event::DESCRIBED_BY_CHANGED);
       break;
diff --git a/ui/accessibility/ax_event_generator.h b/ui/accessibility/ax_event_generator.h
index 640868c0..a70216a 100644
--- a/ui/accessibility/ax_event_generator.h
+++ b/ui/accessibility/ax_event_generator.h
@@ -30,6 +30,7 @@
     CHILDREN_CHANGED,
     CLASS_NAME_CHANGED,
     COLLAPSED,
+    CONTROLS_CHANGED,
     DESCRIBED_BY_CHANGED,
     DESCRIPTION_CHANGED,
     DOCUMENT_SELECTION_CHANGED,
diff --git a/ui/accessibility/ax_event_generator_unittest.cc b/ui/accessibility/ax_event_generator_unittest.cc
index 5cdbdef..d4f8fa1 100644
--- a/ui/accessibility/ax_event_generator_unittest.cc
+++ b/ui/accessibility/ax_event_generator_unittest.cc
@@ -41,6 +41,9 @@
       case AXEventGenerator::Event::COLLAPSED:
         event_name = "COLLAPSED";
         break;
+      case AXEventGenerator::Event::CONTROLS_CHANGED:
+        event_name = "CONTROLS_CHANGED";
+        break;
       case AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
         event_name = "DESCRIBED_BY_CHANGED";
         break;
@@ -764,11 +767,11 @@
                                       ids);
   ASSERT_TRUE(tree.Unserialize(update));
   EXPECT_EQ(
+      "CONTROLS_CHANGED on 6, "
       "LANGUAGE_CHANGED on 2, "
       "OTHER_ATTRIBUTE_CHANGED on 3, "
       "OTHER_ATTRIBUTE_CHANGED on 4, "
       "OTHER_ATTRIBUTE_CHANGED on 5, "
-      "OTHER_ATTRIBUTE_CHANGED on 6, "
       "RELATED_NODE_CHANGED on 6",
       DumpEvents(&event_generator));
 }
@@ -1199,4 +1202,26 @@
       DumpEvents(&event_generator));
 }
 
+TEST(AXEventGeneratorTest, ControlsChanged) {
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(2);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].child_ids.push_back(2);
+  initial_state.nodes[1].id = 2;
+
+  AXTree tree(initial_state);
+  AXEventGenerator event_generator(&tree);
+  AXTreeUpdate update = initial_state;
+
+  std::vector<int> ids = {2};
+  update.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kControlsIds,
+                                      ids);
+  EXPECT_TRUE(tree.Unserialize(update));
+  EXPECT_EQ(
+      "CONTROLS_CHANGED on 1, "
+      "RELATED_NODE_CHANGED on 1",
+      DumpEvents(&event_generator));
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/ax_offscreen_result.h b/ui/accessibility/ax_offscreen_result.h
new file mode 100644
index 0000000..245d5aba
--- /dev/null
+++ b/ui/accessibility/ax_offscreen_result.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_AX_OFFSCREEN_RESULT_H_
+#define UI_ACCESSIBILITY_AX_OFFSCREEN_RESULT_H_
+
+namespace ui {
+
+// The onscreen state of result bounds or points. Any object is offscreen if
+// it is fully clipped or scrolled out of view by any of its ancestors so that
+// it is not rendered on the screen. For a longer discussion on what offscreen
+// means in the context of Chromium see the link below.
+// https://chromium.googlesource.com/chromium/src/+/lkgr/docs/accessibility/offscreen.md
+//   kOnscreen:  The resulting bound or point is onscreen
+//   kOffscreen: The resulting bound or point is offscreen
+enum class AXOffscreenResult { kOnscreen, kOffscreen };
+}  // namespace ui
+
+#endif  // UI_ACCESSIBILITY_AX_OFFSCREEN_RESULT_H_
diff --git a/ui/accessibility/ax_range.h b/ui/accessibility/ax_range.h
index f7af36b..1f2f6269 100644
--- a/ui/accessibility/ax_range.h
+++ b/ui/accessibility/ax_range.h
@@ -192,8 +192,6 @@
         current_line_end = range_end->Clone();
 
       DCHECK(current_line_end->GetAnchor() == current_line_start->GetAnchor());
-      int length_of_current_line =
-          current_line_end->text_offset() - current_line_start->text_offset();
 
       if (current_line_start->GetAnchor()->data().role ==
           ax::mojom::Role::kInlineTextBox) {
@@ -207,13 +205,13 @@
       AXPlatformNodeDelegate* current_anchor_delegate =
           manager->GetDelegate(current_tree_id, current_anchor->id());
 
-      gfx::Rect current_rect = current_anchor_delegate->GetScreenBoundsForRange(
-          current_line_start->text_offset(), length_of_current_line,
-          /*clipped*/ true);
+      gfx::Rect current_rect = current_anchor_delegate->GetRangeBoundsRect(
+          current_line_start->text_offset(), current_line_end->text_offset(),
+          AXCoordinateSystem::kScreen, AXClippingBehavior::kClipped);
 
       // Only add rects that are within the current viewport. The 'clipped'
-      // parameter for GetScreenBoundsForRange will return an empty rect in
-      // that case.
+      // parameter for GetClippedScreenRangeBoundsRect will return an empty rect
+      // in that case.
       if (!current_rect.IsEmpty())
         rectangles.emplace_back(current_rect);
 
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
index 80d0e46..ee24ec5 100644
--- a/ui/accessibility/ax_tree.cc
+++ b/ui/accessibility/ax_tree.cc
@@ -450,6 +450,9 @@
     }
   }
 
+  // Clear list_info_map_
+  ordered_set_info_map_.clear();
+
   std::set<const AXNode*>& new_nodes = update_state.new_nodes;
   std::vector<AXTreeObserver::Change> changes;
   changes.reserve(update.nodes.size());
@@ -492,9 +495,6 @@
     observer.OnAtomicUpdateFinished(this, root_->id() != old_root_id, changes);
   }
 
-  // Clear list_info_map_
-  ordered_set_info_map_.clear();
-
   return true;
 }
 
@@ -980,6 +980,7 @@
       // examined, stop adding to this set.
       if (original_node_index < i)
         break;
+
       // If a decrease in level has been detected before the original node
       // has been examined, then everything previously added to items actually
       // belongs to a different set. Clear items vector.
@@ -1078,11 +1079,20 @@
   // 1. Node role matches ordered set role.
   // 2. The node that calculations were called on is the ordered_set.
   if (node.SetRoleMatchesItemRole(ordered_set) || ordered_set == &node) {
+    auto ordered_set_info_result =
+        ordered_set_info_map_.find(ordered_set->id());
     // If ordered_set is not in the cache, assign it a new set_size.
-    if (ordered_set_info_map_.find(ordered_set->id()) ==
-        ordered_set_info_map_.end()) {
+    if (ordered_set_info_result == ordered_set_info_map_.end()) {
       ordered_set_info_map_[ordered_set->id()] = OrderedSetInfo();
       ordered_set_info_map_[ordered_set->id()].set_size = set_size_value;
+      ordered_set_info_map_[ordered_set->id()].lowest_hierarchical_level =
+          hierarchical_level;
+    } else {
+      OrderedSetInfo ordered_set_info = ordered_set_info_result->second;
+      if (ordered_set_info.lowest_hierarchical_level > hierarchical_level) {
+        ordered_set_info.set_size = set_size_value;
+        ordered_set_info.lowest_hierarchical_level = hierarchical_level;
+      }
     }
   }
 
diff --git a/ui/accessibility/ax_tree.h b/ui/accessibility/ax_tree.h
index 1e8542b..5cc2035 100644
--- a/ui/accessibility/ax_tree.h
+++ b/ui/accessibility/ax_tree.h
@@ -240,6 +240,7 @@
   struct OrderedSetInfo {
     int32_t pos_in_set;
     int32_t set_size;
+    int32_t lowest_hierarchical_level;
     OrderedSetInfo() : pos_in_set(0), set_size(0) {}
     ~OrderedSetInfo() {}
   };
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index 82eec09..89fbad0 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -216,19 +216,21 @@
   SetWeakGPtrToAtkObject(&g_active_top_level_frame, new_top_level_frame);
 }
 
-AXPlatformNodeDelegate::TextRangeBoundsCoordinateSystem
-AtkCoordTypeToTextRangeBoundsCoordinateSystem(AtkCoordType coordinate_type) {
+AXCoordinateSystem AtkCoordTypeToAXCoordinateSystem(
+    AtkCoordType coordinate_type) {
   switch (coordinate_type) {
     case ATK_XY_SCREEN:
-      return AXPlatformNodeDelegate::Screen;
+      return AXCoordinateSystem::kScreen;
     case ATK_XY_WINDOW:
-      return AXPlatformNodeDelegate::Window;
+      return AXCoordinateSystem::kRootFrame;
 #ifdef ATK_230
     case ATK_XY_PARENT:
-      return AXPlatformNodeDelegate::Parent;
+      // AXCoordinateSystem does not support parent coordinates.
+      NOTIMPLEMENTED();
+      return AXCoordinateSystem::kFrame;
 #endif  // ATK_230
     default:
-      return AXPlatformNodeDelegate::Screen;
+      return AXCoordinateSystem::kScreen;
   }
 }
 
@@ -1189,6 +1191,30 @@
 }
 #endif
 
+gfx::Rect GetUnclippedParentRangeBoundsRect(
+    AXPlatformNodeDelegate* ax_platform_node_delegate,
+    const int start_offset,
+    const int end_offset) {
+  const AXPlatformNode* parent_platform_node =
+      AXPlatformNode::FromNativeViewAccessible(
+          ax_platform_node_delegate->GetParent());
+  if (parent_platform_node) {
+    const AXPlatformNodeDelegate* parent_ax_platform_node_delegate =
+        parent_platform_node->GetDelegate();
+    if (parent_ax_platform_node_delegate) {
+      return ax_platform_node_delegate->GetRangeBoundsRect(
+                 start_offset, end_offset, AXCoordinateSystem::kRootFrame,
+                 AXClippingBehavior::kUnclipped) -
+             parent_ax_platform_node_delegate
+                 ->GetBoundsRect(AXCoordinateSystem::kRootFrame,
+                                 AXClippingBehavior::kClipped)
+                 .OffsetFromOrigin();
+    }
+  }
+
+  return gfx::Rect();
+}
+
 void GetCharacterExtents(AtkText* atk_text,
                          int offset,
                          int* x,
@@ -1200,10 +1226,21 @@
   AXPlatformNodeAuraLinux* obj =
       AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
   if (obj) {
-    rect = obj->GetDelegate()->GetTextRangeBoundsRect(
-        obj->UnicodeToUTF16OffsetInText(offset),
-        obj->UnicodeToUTF16OffsetInText(offset + 1),
-        AtkCoordTypeToTextRangeBoundsCoordinateSystem(coordinate_type));
+    switch (coordinate_type) {
+#ifdef ATK_230
+      case ATK_XY_PARENT:
+        rect = GetUnclippedParentRangeBoundsRect(obj->GetDelegate(), offset,
+                                                 offset + 1);
+        break;
+#endif
+      default:
+        rect = obj->GetDelegate()->GetRangeBoundsRect(
+            obj->UnicodeToUTF16OffsetInText(offset),
+            obj->UnicodeToUTF16OffsetInText(offset + 1),
+            AtkCoordTypeToAXCoordinateSystem(coordinate_type),
+            AXClippingBehavior::kUnclipped);
+        break;
+    }
   }
 
   if (x)
@@ -1228,10 +1265,21 @@
   AXPlatformNodeAuraLinux* obj =
       AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
   if (obj) {
-    rect = obj->GetDelegate()->GetTextRangeBoundsRect(
-        obj->UnicodeToUTF16OffsetInText(start_offset),
-        obj->UnicodeToUTF16OffsetInText(end_offset),
-        AtkCoordTypeToTextRangeBoundsCoordinateSystem(coordinate_type));
+    switch (coordinate_type) {
+#ifdef ATK_230
+      case ATK_XY_PARENT:
+        rect = GetUnclippedParentRangeBoundsRect(obj->GetDelegate(),
+                                                 start_offset, end_offset);
+        break;
+#endif
+      default:
+        rect = obj->GetDelegate()->GetRangeBoundsRect(
+            obj->UnicodeToUTF16OffsetInText(start_offset),
+            obj->UnicodeToUTF16OffsetInText(end_offset),
+            AtkCoordTypeToAXCoordinateSystem(coordinate_type),
+            AXClippingBehavior::kUnclipped);
+        break;
+    }
   }
 
   out_rectangle->x = rect.x();
@@ -3339,7 +3387,8 @@
 
 void AXPlatformNodeAuraLinux::SetExtentsRelativeToAtkCoordinateType(
     gint* x, gint* y, gint* width, gint* height, AtkCoordType coord_type) {
-  gfx::Rect extents = delegate_->GetUnclippedScreenBoundsRect();
+  gfx::Rect extents = delegate_->GetBoundsRect(AXCoordinateSystem::kScreen,
+                                               AXClippingBehavior::kUnclipped);
 
   if (x)
     *x = extents.x();
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index a30aabc..6126acfb 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -9,9 +9,12 @@
 #include <utility>
 #include <vector>
 
+#include "ui/accessibility/ax_clipping_behavior.h"
+#include "ui/accessibility/ax_coordinate_system.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_export.h"
 #include "ui/accessibility/ax_node_position.h"
+#include "ui/accessibility/ax_offscreen_result.h"
 #include "ui/accessibility/ax_position.h"
 #include "ui/accessibility/ax_text_utils.h"
 #include "ui/accessibility/platform/ax_unique_id.h"
@@ -78,34 +81,28 @@
   // Get the child of a node given a 0-based index.
   virtual gfx::NativeViewAccessible ChildAtIndex(int index) = 0;
 
-  // Get the bounds of this node in screen coordinates, applying clipping
-  // to all bounding boxes so that the resulting rect is within the window.
-  virtual gfx::Rect GetClippedScreenBoundsRect() const = 0;
+  // Return the bounds of this node in the coordinate system indicated. If the
+  // clipping behavior is set to clipped, clipping is applied. If an offscreen
+  // result address is provided, it will be populated depending on whether the
+  // returned bounding box is onscreen or offscreen.
+  virtual gfx::Rect GetBoundsRect(
+      const AXCoordinateSystem coordinate_system,
+      const AXClippingBehavior clipping_behavior,
+      AXOffscreenResult* offscreen_result = nullptr) const = 0;
 
-  // Get the bounds of this node in screen coordinates without applying
-  // any clipping; it may be outside of the window or offscreen.
-  virtual gfx::Rect GetUnclippedScreenBoundsRect() const = 0;
-
-  // Returns the bounds of the given range in screen coordinates. Only valid
-  // when the role is WebAXRoleStaticText.
-  virtual gfx::Rect GetScreenBoundsForRange(int start,
-                                            int len,
-                                            bool clipped = false) const = 0;
-
-  // Get the bounds of the given text range in the given coordinate system.
-  // Screen gets these boundaries in screen coordinates, Window in coordinates
-  // relative to the parent window, and Parent relative to the parent node. The
-  // offsets refer to offsets within the text returned for this node when
-  // treated as a platform text node.
-  enum TextRangeBoundsCoordinateSystem {
-    Screen,
-    Window,
-    Parent,
-  };
-  virtual gfx::Rect GetTextRangeBoundsRect(
-      int start_offset,
-      int end_offset,
-      TextRangeBoundsCoordinateSystem coordinate_system) const = 0;
+  // Return the bounds of the text range given by text offsets in the coordinate
+  // system indicated. When determining the text offset of a node, the text of
+  // this node is included while descendant text may be accounted for with a
+  // single special character. If the clipping behavior is set to clipped,
+  // clipping is applied. If an offscreen result address is provided, it will be
+  // populated depending on whether the returned bounding box is onscreen or
+  // offscreen.
+  virtual gfx::Rect GetRangeBoundsRect(
+      const int start_offset,
+      const int end_offset,
+      const AXCoordinateSystem coordinate_system,
+      const AXClippingBehavior clipping_behavior,
+      AXOffscreenResult* offscreen_result = nullptr) const = 0;
 
   // Do a *synchronous* hit test of the given location in global screen
   // coordinates, and the node within this node's subtree (inclusive) that's
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
index 6836394d..e5252bf 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -51,27 +51,32 @@
   return nullptr;
 }
 
-gfx::Rect AXPlatformNodeDelegateBase::GetClippedScreenBoundsRect() const {
+gfx::Rect AXPlatformNodeDelegateBase::GetBoundsRect(
+    const AXCoordinateSystem coordinate_system,
+    const AXClippingBehavior clipping_behavior,
+    AXOffscreenResult* offscreen_result) const {
   return gfx::Rect();
 }
 
-gfx::Rect AXPlatformNodeDelegateBase::GetUnclippedScreenBoundsRect() const {
+gfx::Rect AXPlatformNodeDelegateBase::GetRangeBoundsRect(
+    const int start_offset,
+    const int end_offset,
+    const AXCoordinateSystem coordinate_system,
+    const AXClippingBehavior clipping_behavior,
+    AXOffscreenResult* offscreen_result) const {
   return gfx::Rect();
 }
 
-gfx::Rect AXPlatformNodeDelegateBase::GetScreenBoundsForRange(
-    int start,
-    int len,
-    bool clipped) const {
-  return gfx::Rect();
+gfx::Rect AXPlatformNodeDelegateBase::GetClippedScreenBoundsRect(
+    AXOffscreenResult* offscreen_result) const {
+  return GetBoundsRect(AXCoordinateSystem::kScreen,
+                       AXClippingBehavior::kClipped, offscreen_result);
 }
 
-gfx::Rect AXPlatformNodeDelegateBase::GetTextRangeBoundsRect(
-    int start_offset,
-    int end_offset,
-    AXPlatformNodeDelegate::TextRangeBoundsCoordinateSystem coordinate_system)
-    const {
-  return gfx::Rect();
+gfx::Rect AXPlatformNodeDelegateBase::GetUnclippedScreenBoundsRect(
+    AXOffscreenResult* offscreen_result) const {
+  return GetBoundsRect(AXCoordinateSystem::kScreen,
+                       AXClippingBehavior::kUnclipped, offscreen_result);
 }
 
 gfx::NativeViewAccessible AXPlatformNodeDelegateBase::HitTestSync(int x,
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.h b/ui/accessibility/platform/ax_platform_node_delegate_base.h
index d38ba8cc..86ad39f1 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -51,27 +51,22 @@
   // Get the child of a node given a 0-based index.
   gfx::NativeViewAccessible ChildAtIndex(int index) override;
 
-  // Get the bounds of this node in screen coordinates, applying clipping
-  // to all bounding boxes so that the resulting rect is within the window.
-  gfx::Rect GetClippedScreenBoundsRect() const override;
+  gfx::Rect GetBoundsRect(const AXCoordinateSystem coordinate_system,
+                          const AXClippingBehavior clipping_behavior,
+                          AXOffscreenResult* offscreen_result) const override;
 
-  // Get the bounds of this node in screen coordinates without applying
-  // any clipping; it may be outside of the window or offscreen.
-  gfx::Rect GetUnclippedScreenBoundsRect() const override;
+  gfx::Rect GetRangeBoundsRect(
+      const int start_offset,
+      const int end_offset,
+      const AXCoordinateSystem coordinate_system,
+      const AXClippingBehavior clipping_behavior,
+      AXOffscreenResult* offscreen_result) const override;
 
-  // Get the bounds of this node with text offsets in screen coordinates,
-  // optionally applying clipping to all bounding boxes so that the resulting
-  // rect is within the window. Only valid when the role is
-  // ax::mojom::Role::kStaticText.
-  gfx::Rect GetScreenBoundsForRange(int start,
-                                    int len,
-                                    bool clipped = false) const override;
-
-  gfx::Rect GetTextRangeBoundsRect(
-      int start_offset,
-      int end_offset,
-      AXPlatformNodeDelegate::TextRangeBoundsCoordinateSystem coordinate_system)
-      const override;
+  // Derivative utils for AXPlatformNodeDelegate::GetBoundsRect
+  gfx::Rect GetClippedScreenBoundsRect(
+      AXOffscreenResult* offscreen_result = nullptr) const;
+  gfx::Rect GetUnclippedScreenBoundsRect(
+      AXOffscreenResult* offscreen_result = nullptr) const;
 
   // Do a *synchronous* hit test of the given location in global screen
   // coordinates, and the node within this node's subtree (inclusive) that's
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm
index c23d872..f7f0f3e 100644
--- a/ui/accessibility/platform/ax_platform_node_mac.mm
+++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -374,8 +374,8 @@
 - (NSRect)boundsInScreen {
   if (!node_ || !node_->GetDelegate())
     return NSZeroRect;
-  return gfx::ScreenRectToNSRect(
-      node_->GetDelegate()->GetClippedScreenBoundsRect());
+  return gfx::ScreenRectToNSRect(node_->GetDelegate()->GetBoundsRect(
+      ui::AXCoordinateSystem::kScreen, ui::AXClippingBehavior::kClipped));
 }
 
 - (NSString*)getStringAttribute:(ax::mojom::StringAttribute)attribute {
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 17e54a59..bbc7d8a 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -414,8 +414,10 @@
 
 SAFEARRAY* AXPlatformNodeWin::CreateClickablePointArray() {
   SAFEARRAY* clickable_point_array = SafeArrayCreateVector(VT_R8, 0, 2);
-  gfx::Point center =
-      GetDelegate()->GetUnclippedScreenBoundsRect().CenterPoint();
+  gfx::Point center = GetDelegate()
+                          ->GetBoundsRect(AXCoordinateSystem::kScreen,
+                                          AXClippingBehavior::kUnclipped)
+                          .CenterPoint();
 
   double* double_array;
   SafeArrayAccessData(clickable_point_array,
@@ -433,7 +435,8 @@
   if (!GetDelegate() || !IsScrollable())
     return {};
 
-  const gfx::Rect bounds = GetDelegate()->GetClippedScreenBoundsRect();
+  const gfx::Rect bounds = GetDelegate()->GetBoundsRect(
+      AXCoordinateSystem::kScreen, AXClippingBehavior::kClipped);
   const int large_horizontal_change = bounds.width();
   const int large_vertical_change = bounds.height();
 
@@ -591,7 +594,10 @@
   COM_OBJECT_VALIDATE_1_ARG(child);
 
   gfx::Point point(x_left, y_top);
-  if (!GetDelegate()->GetClippedScreenBoundsRect().Contains(point)) {
+  if (!GetDelegate()
+           ->GetBoundsRect(AXCoordinateSystem::kScreen,
+                           AXClippingBehavior::kClipped)
+           .Contains(point)) {
     // Return S_FALSE and VT_EMPTY when outside the object's boundaries.
     child->vt = VT_EMPTY;
     return S_FALSE;
@@ -652,7 +658,8 @@
   COM_OBJECT_VALIDATE_VAR_ID_4_ARGS_AND_GET_TARGET(var_id, x_left, y_top, width,
                                                    height, target);
 
-  gfx::Rect bounds = target->GetDelegate()->GetUnclippedScreenBoundsRect();
+  gfx::Rect bounds = target->GetDelegate()->GetBoundsRect(
+      AXCoordinateSystem::kScreen, AXClippingBehavior::kUnclipped);
   *x_left = bounds.x();
   *y_top = bounds.y();
   *width = bounds.width();
@@ -1372,7 +1379,8 @@
     if (GetParent()) {
       AXPlatformNodeBase* base = FromNativeViewAccessible(GetParent());
       scroll_to += base->GetDelegate()
-                       ->GetUnclippedScreenBoundsRect()
+                       ->GetBoundsRect(AXCoordinateSystem::kScreen,
+                                       AXClippingBehavior::kUnclipped)
                        .OffsetFromOrigin();
     }
   } else if (coordinate_type != IA2_COORDTYPE_SCREEN_RELATIVE) {
@@ -1791,7 +1799,8 @@
     return S_OK;
   }
 
-  gfx::RectF clipped_bounds(GetDelegate()->GetClippedScreenBoundsRect());
+  gfx::RectF clipped_bounds(GetDelegate()->GetBoundsRect(
+      AXCoordinateSystem::kScreen, AXClippingBehavior::kClipped));
   float x_min = GetIntAttribute(ax::mojom::IntAttribute::kScrollXMin);
   float x_max = GetIntAttribute(ax::mojom::IntAttribute::kScrollXMax);
   float total_width = clipped_bounds.width() + x_max - x_min;
@@ -1824,7 +1833,8 @@
     return S_OK;
   }
 
-  gfx::RectF clipped_bounds(GetDelegate()->GetClippedScreenBoundsRect());
+  gfx::RectF clipped_bounds(GetDelegate()->GetBoundsRect(
+      AXCoordinateSystem::kScreen, AXClippingBehavior::kClipped));
   float y_min = GetIntAttribute(ax::mojom::IntAttribute::kScrollYMin);
   float y_max = GetIntAttribute(ax::mojom::IntAttribute::kScrollYMax);
   float total_height = clipped_bounds.height() + y_max - y_min;
@@ -3474,7 +3484,8 @@
   WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_BOUNDINGRECTANGLE);
   UIA_VALIDATE_CALL_1_ARG(bounding_rectangle);
 
-  gfx::Rect bounds = delegate_->GetUnclippedScreenBoundsRect();
+  gfx::Rect bounds = delegate_->GetBoundsRect(AXCoordinateSystem::kScreen,
+                                              AXClippingBehavior::kUnclipped);
   bounding_rectangle->left = bounds.x();
   bounding_rectangle->top = bounds.y();
   bounding_rectangle->width = bounds.width();
@@ -3593,7 +3604,7 @@
       break;
 
     case UIA_ControllerForPropertyId:
-      result->vt = VT_ARRAY;
+      result->vt = VT_ARRAY | VT_UNKNOWN;
       result->parray = CreateUIAElementsArrayForRelation(
           ax::mojom::IntListAttribute::kControlsIds);
       break;
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index 973fb75..aa37e488 100644
--- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -1796,7 +1796,7 @@
   // TODO(dougt): Try adding one more relation.
 }
 
-TEST_F(AXPlatformNodeWinTest, TestRelationTargetsOfType) {
+TEST_F(AXPlatformNodeWinTest, DISABLED_TestRelationTargetsOfType) {
   AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -3357,6 +3357,44 @@
   }
 }
 
+TEST_F(AXPlatformNodeWinTest, TestUIAGetControllerForPropertyId) {
+  AXNodeData root;
+  root.id = 1;
+  root.role = ax::mojom::Role::kRootWebArea;
+  root.child_ids = {2, 3, 4};
+
+  AXNodeData tab;
+  tab.id = 2;
+  tab.role = ax::mojom::Role::kTab;
+  tab.SetName("tab");
+  std::vector<int32_t> controller_ids = {3, 4};
+  tab.AddIntListAttribute(ax::mojom::IntListAttribute::kControlsIds,
+                          controller_ids);
+
+  AXNodeData panel1;
+  panel1.id = 3;
+  panel1.role = ax::mojom::Role::kTabPanel;
+  panel1.SetName("panel1");
+
+  AXNodeData panel2;
+  panel2.id = 4;
+  panel2.role = ax::mojom::Role::kTabPanel;
+  panel2.SetName("panel2");
+
+  Init(root, tab, panel1, panel2);
+  TestAXNodeWrapper* root_wrapper =
+      TestAXNodeWrapper::GetOrCreate(tree_.get(), GetRootNode());
+  root_wrapper->BuildAllWrappers(tree_.get(), GetRootNode());
+
+  ComPtr<IRawElementProviderSimple> tab_node =
+      QueryInterfaceFromNode<IRawElementProviderSimple>(
+          GetRootNode()->children()[0]);
+
+  std::vector<std::wstring> expected_names = {L"panel1", L"panel2"};
+  EXPECT_UIA_ELEMENT_ARRAY_BSTR_EQ(tab_node, UIA_ControllerForPropertyId,
+                                   UIA_NamePropertyId, expected_names);
+}
+
 TEST_F(AXPlatformNodeWinTest, TestUIAGetDescribedByPropertyId) {
   AXNodeData root;
   std::vector<int32_t> describedby_ids = {1, 2, 3};
diff --git a/ui/accessibility/platform/ax_system_caret_win.cc b/ui/accessibility/platform/ax_system_caret_win.cc
index e8f28e71..d7f9511d 100644
--- a/ui/accessibility/platform/ax_system_caret_win.cc
+++ b/ui/accessibility/platform/ax_system_caret_win.cc
@@ -109,13 +109,19 @@
   return nullptr;
 }
 
-gfx::Rect AXSystemCaretWin::GetClippedScreenBoundsRect() const {
-  // We could optionally add clipping here if ever needed.
-  return ToEnclosingRect(data_.relative_bounds.bounds);
-}
-
-gfx::Rect AXSystemCaretWin::GetUnclippedScreenBoundsRect() const {
-  return ToEnclosingRect(data_.relative_bounds.bounds);
+gfx::Rect AXSystemCaretWin::GetBoundsRect(
+    const AXCoordinateSystem coordinate_system,
+    const AXClippingBehavior clipping_behavior,
+    AXOffscreenResult* offscreen_result) const {
+  switch (coordinate_system) {
+    case AXCoordinateSystem::kScreen:
+      // We could optionally add clipping here if ever needed.
+      return ToEnclosingRect(data_.relative_bounds.bounds);
+    case AXCoordinateSystem::kRootFrame:
+    case AXCoordinateSystem::kFrame:
+      NOTIMPLEMENTED();
+      return gfx::Rect();
+  }
 }
 
 gfx::AcceleratedWidget
diff --git a/ui/accessibility/platform/ax_system_caret_win.h b/ui/accessibility/platform/ax_system_caret_win.h
index a4d2392..a18ed98 100644
--- a/ui/accessibility/platform/ax_system_caret_win.h
+++ b/ui/accessibility/platform/ax_system_caret_win.h
@@ -37,8 +37,9 @@
   // |AXPlatformNodeDelegate| members.
   const AXNodeData& GetData() const override;
   gfx::NativeViewAccessible GetParent() override;
-  gfx::Rect GetClippedScreenBoundsRect() const override;
-  gfx::Rect GetUnclippedScreenBoundsRect() const override;
+  gfx::Rect GetBoundsRect(const AXCoordinateSystem coordinate_system,
+                          const AXClippingBehavior clipping_behavior,
+                          AXOffscreenResult* offscreen_result) const override;
   gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
   bool ShouldIgnoreHoveredStateForTesting() override;
   const ui::AXUniqueId& GetUniqueId() const override;
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc
index 4698d0d..cb27fcb 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -126,27 +126,43 @@
       nullptr;
 }
 
-gfx::Rect TestAXNodeWrapper::GetClippedScreenBoundsRect() const {
-  // We could add clipping here if needed.
-  gfx::RectF bounds = GetData().relative_bounds.bounds;
-  bounds.Offset(g_offset);
-  return gfx::ToEnclosingRect(bounds);
+gfx::Rect TestAXNodeWrapper::GetBoundsRect(
+    const AXCoordinateSystem coordinate_system,
+    const AXClippingBehavior clipping_behavior,
+    AXOffscreenResult* offscreen_result) const {
+  switch (coordinate_system) {
+    case AXCoordinateSystem::kScreen: {
+      // We could optionally add clipping here if ever needed.
+      gfx::RectF bounds = GetData().relative_bounds.bounds;
+      bounds.Offset(g_offset);
+      return gfx::ToEnclosingRect(bounds);
+    }
+    case AXCoordinateSystem::kRootFrame:
+    case AXCoordinateSystem::kFrame:
+      NOTIMPLEMENTED();
+      return gfx::Rect();
+  }
 }
 
-gfx::Rect TestAXNodeWrapper::GetUnclippedScreenBoundsRect() const {
-  gfx::RectF bounds = GetData().relative_bounds.bounds;
-  bounds.Offset(g_offset);
-  return gfx::ToEnclosingRect(bounds);
-}
-
-gfx::Rect TestAXNodeWrapper::GetScreenBoundsForRange(int start,
-                                                     int len,
-                                                     bool clipped) const {
-  // Ignoring start, len, and clipped, as there's no clean way to map these
-  // via unit tests.
-  gfx::RectF bounds = GetData().relative_bounds.bounds;
-  bounds.Offset(g_offset);
-  return gfx::ToEnclosingRect(bounds);
+gfx::Rect TestAXNodeWrapper::GetRangeBoundsRect(
+    const int start_offset,
+    const int end_offset,
+    const AXCoordinateSystem coordinate_system,
+    const AXClippingBehavior clipping_behavior,
+    AXOffscreenResult* offscreen_result) const {
+  switch (coordinate_system) {
+    case AXCoordinateSystem::kScreen: {
+      // Ignoring start, len, and clipped, as there's no clean way to map these
+      // via unit tests.
+      gfx::RectF bounds = GetData().relative_bounds.bounds;
+      bounds.Offset(g_offset);
+      return gfx::ToEnclosingRect(bounds);
+    }
+    case AXCoordinateSystem::kRootFrame:
+    case AXCoordinateSystem::kFrame:
+      NOTIMPLEMENTED();
+      return gfx::Rect();
+  }
 }
 
 TestAXNodeWrapper* TestAXNodeWrapper::HitTestSyncInternal(int x, int y) {
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.h b/ui/accessibility/platform/test_ax_node_wrapper.h
index 7c2ccfc..05509b1e 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.h
+++ b/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -55,11 +55,15 @@
   gfx::NativeViewAccessible GetParent() override;
   int GetChildCount() override;
   gfx::NativeViewAccessible ChildAtIndex(int index) override;
-  gfx::Rect GetClippedScreenBoundsRect() const override;
-  gfx::Rect GetUnclippedScreenBoundsRect() const override;
-  gfx::Rect GetScreenBoundsForRange(int start,
-                                    int len,
-                                    bool clipped) const override;
+  gfx::Rect GetBoundsRect(const AXCoordinateSystem coordinate_system,
+                          const AXClippingBehavior clipping_behavior,
+                          AXOffscreenResult* offscreen_result) const override;
+  gfx::Rect GetRangeBoundsRect(
+      const int start_offset,
+      const int end_offset,
+      const AXCoordinateSystem coordinate_system,
+      const AXClippingBehavior clipping_behavior,
+      AXOffscreenResult* offscreen_result) const override;
   gfx::NativeViewAccessible HitTestSync(int x, int y) override;
   gfx::NativeViewAccessible GetFocus() override;
   AXPlatformNode* GetFromNodeID(int32_t id) override;
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 67cfa13..49f1ed3 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -351,6 +351,8 @@
       "accelerators/global_media_keys_listener_win.cc",
       "accelerators/global_media_keys_listener_win.h",
       "accelerators/media_keys_listener_win.cc",
+      "accelerators/system_media_controls_media_keys_listener.cc",
+      "accelerators/system_media_controls_media_keys_listener.h",
     ]
   } else if (use_mpris) {
     sources += [
@@ -445,6 +447,10 @@
     }
   }
 
+  if (is_win) {
+    deps += [ "//ui/base/win/system_media_controls" ]
+  }
+
   if (use_mpris) {
     deps += [
       "//dbus",
@@ -1001,10 +1007,13 @@
 
   if (is_win) {
     sources += [
+      "accelerators/system_media_controls_media_keys_listener_unittest.cc",
       "dragdrop/os_exchange_data_win_unittest.cc",
       "win/hwnd_subclass_unittest.cc",
     ]
 
+    deps += [ "//ui/base/win/system_media_controls:test_support" ]
+
     ldflags = [
       "/DELAYLOAD:d2d1.dll",
       "/DELAYLOAD:d3d10_1.dll",
diff --git a/ui/base/accelerators/media_keys_listener_win.cc b/ui/base/accelerators/media_keys_listener_win.cc
index 5a24b96..c50ea0ca 100644
--- a/ui/base/accelerators/media_keys_listener_win.cc
+++ b/ui/base/accelerators/media_keys_listener_win.cc
@@ -5,6 +5,7 @@
 #include "ui/base/accelerators/media_keys_listener.h"
 
 #include "ui/base/accelerators/global_media_keys_listener_win.h"
+#include "ui/base/accelerators/system_media_controls_media_keys_listener.h"
 
 namespace ui {
 
@@ -14,10 +15,18 @@
   DCHECK(delegate);
 
   if (scope == Scope::kGlobal) {
-    if (!GlobalMediaKeysListenerWin::has_instance())
+    // We should never have more than one global media keys listener.
+    if (!SystemMediaControlsMediaKeysListener::has_instance() &&
+        !GlobalMediaKeysListenerWin::has_instance()) {
+      auto listener =
+          std::make_unique<SystemMediaControlsMediaKeysListener>(delegate);
+      if (listener->Initialize())
+        return listener;
+
+      // If |Initialize()| fails, then we fall back to the
+      // GlobalMediaKeysListenerWin.
       return std::make_unique<GlobalMediaKeysListenerWin>(delegate);
-    // We shouldn't try to create more than one GlobalMediaKeysListenerWin
-    // instance.
+    }
     NOTREACHED();
   }
   return nullptr;
diff --git a/ui/base/accelerators/system_media_controls_media_keys_listener.cc b/ui/base/accelerators/system_media_controls_media_keys_listener.cc
new file mode 100644
index 0000000..a07e0eb
--- /dev/null
+++ b/ui/base/accelerators/system_media_controls_media_keys_listener.cc
@@ -0,0 +1,136 @@
+// 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/base/accelerators/system_media_controls_media_keys_listener.h"
+
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service.h"
+
+namespace ui {
+
+// static
+bool SystemMediaControlsMediaKeysListener::has_instance_ = false;
+
+SystemMediaControlsMediaKeysListener::SystemMediaControlsMediaKeysListener(
+    MediaKeysListener::Delegate* delegate)
+    : delegate_(delegate) {
+  DCHECK(delegate_);
+  DCHECK(!has_instance_);
+  has_instance_ = true;
+}
+
+SystemMediaControlsMediaKeysListener::~SystemMediaControlsMediaKeysListener() {
+  DCHECK(has_instance_);
+  has_instance_ = false;
+}
+
+bool SystemMediaControlsMediaKeysListener::Initialize() {
+  // |service_| can be set for tests.
+  if (!service_)
+    service_ = system_media_controls::SystemMediaControlsService::GetInstance();
+
+  // If we still don't have a service, then that means the
+  // SystemMediaControlsService failed to connect to the
+  // SystemMediaTransportControls. If that's the case, return false.
+  if (!service_)
+    return false;
+
+  service_->AddObserver(this);
+  return true;
+}
+
+bool SystemMediaControlsMediaKeysListener::StartWatchingMediaKey(
+    KeyboardCode key_code) {
+  DCHECK(IsMediaKeycode(key_code));
+
+  // If we're already listening for this key, do nothing.
+  if (key_codes_.contains(key_code))
+    return true;
+
+  key_codes_.insert(key_code);
+
+  DCHECK(service_);
+
+  switch (key_code) {
+    case VKEY_MEDIA_PLAY_PAUSE:
+      service_->SetIsPlayEnabled(true);
+      service_->SetIsPauseEnabled(true);
+      break;
+    case VKEY_MEDIA_NEXT_TRACK:
+      service_->SetIsNextEnabled(true);
+      break;
+    case VKEY_MEDIA_PREV_TRACK:
+      service_->SetIsPreviousEnabled(true);
+      break;
+    case VKEY_MEDIA_STOP:
+      service_->SetIsStopEnabled(true);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  return true;
+}
+
+void SystemMediaControlsMediaKeysListener::StopWatchingMediaKey(
+    KeyboardCode key_code) {
+  DCHECK(IsMediaKeycode(key_code));
+
+  // If we're not currently listening for this key, do nothing.
+  if (!key_codes_.contains(key_code))
+    return;
+
+  key_codes_.erase(key_code);
+
+  DCHECK(service_);
+
+  switch (key_code) {
+    case VKEY_MEDIA_PLAY_PAUSE:
+      service_->SetIsPlayEnabled(false);
+      service_->SetIsPauseEnabled(false);
+      break;
+    case VKEY_MEDIA_NEXT_TRACK:
+      service_->SetIsNextEnabled(false);
+      break;
+    case VKEY_MEDIA_PREV_TRACK:
+      service_->SetIsPreviousEnabled(false);
+      break;
+    case VKEY_MEDIA_STOP:
+      service_->SetIsStopEnabled(false);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void SystemMediaControlsMediaKeysListener::OnNext() {
+  MaybeSendKeyCode(VKEY_MEDIA_NEXT_TRACK);
+}
+
+void SystemMediaControlsMediaKeysListener::OnPrevious() {
+  MaybeSendKeyCode(VKEY_MEDIA_PREV_TRACK);
+}
+
+void SystemMediaControlsMediaKeysListener::OnPause() {
+  MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
+}
+
+void SystemMediaControlsMediaKeysListener::OnStop() {
+  MaybeSendKeyCode(VKEY_MEDIA_STOP);
+}
+
+void SystemMediaControlsMediaKeysListener::OnPlay() {
+  MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
+}
+
+void SystemMediaControlsMediaKeysListener::MaybeSendKeyCode(
+    KeyboardCode key_code) {
+  if (!key_codes_.contains(key_code))
+    return;
+
+  Accelerator accelerator(key_code, /*modifiers=*/0);
+  delegate_->OnMediaKeysAccelerator(accelerator);
+}
+
+}  // namespace ui
diff --git a/ui/base/accelerators/system_media_controls_media_keys_listener.h b/ui/base/accelerators/system_media_controls_media_keys_listener.h
new file mode 100644
index 0000000..c900d841
--- /dev/null
+++ b/ui/base/accelerators/system_media_controls_media_keys_listener.h
@@ -0,0 +1,69 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_ACCELERATORS_SYSTEM_MEDIA_CONTROLS_MEDIA_KEYS_LISTENER_H_
+#define UI_BASE_ACCELERATORS_SYSTEM_MEDIA_CONTROLS_MEDIA_KEYS_LISTENER_H_
+
+#include "base/containers/flat_set.h"
+#include "ui/base/accelerators/media_keys_listener.h"
+#include "ui/base/ui_base_export.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service_observer.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+
+namespace system_media_controls {
+class SystemMediaControlsService;
+}  // namespace system_media_controls
+
+namespace ui {
+
+// Implementation of MediaKeysListener that uses the System Media Transport
+// Controls API to listen for media key presses. It only allows for a single
+// instance to be created in order to prevent conflicts from multiple listeners.
+class UI_BASE_EXPORT SystemMediaControlsMediaKeysListener
+    : public MediaKeysListener,
+      public system_media_controls::SystemMediaControlsServiceObserver {
+ public:
+  explicit SystemMediaControlsMediaKeysListener(
+      MediaKeysListener::Delegate* delegate);
+  ~SystemMediaControlsMediaKeysListener() override;
+
+  static bool has_instance() { return has_instance_; }
+
+  bool Initialize();
+
+  // MediaKeysListener implementation.
+  bool StartWatchingMediaKey(KeyboardCode key_code) override;
+  void StopWatchingMediaKey(KeyboardCode key_code) override;
+
+  // system_media_controls::SystemMediaControlsServiceObserver implementation.
+  void OnNext() override;
+  void OnPrevious() override;
+  void OnPause() override;
+  void OnStop() override;
+  void OnPlay() override;
+
+  void SetSystemMediaControlsServiceForTesting(
+      system_media_controls::SystemMediaControlsService* service) {
+    service_ = service;
+  }
+
+ private:
+  static bool has_instance_;
+
+  // Sends the key code to the delegate if the delegate has asked for it.
+  void MaybeSendKeyCode(KeyboardCode key_code);
+
+  MediaKeysListener::Delegate* delegate_;
+
+  // Set of keys codes that we're currently listening for.
+  base::flat_set<KeyboardCode> key_codes_;
+
+  system_media_controls::SystemMediaControlsService* service_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsMediaKeysListener);
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_ACCELERATORS_SYSTEM_MEDIA_CONTROLS_MEDIA_KEYS_LISTENER_H_
diff --git a/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc b/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc
new file mode 100644
index 0000000..b07c9a59
--- /dev/null
+++ b/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc
@@ -0,0 +1,135 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/accelerators/system_media_controls_media_keys_listener.h"
+
+#include <memory>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/win/system_media_controls/mock_system_media_controls_service.h"
+
+using testing::_;
+using testing::Expectation;
+using testing::WithArg;
+
+namespace ui {
+
+namespace {
+
+class MockMediaKeysListenerDelegate : public MediaKeysListener::Delegate {
+ public:
+  MockMediaKeysListenerDelegate() = default;
+  ~MockMediaKeysListenerDelegate() override = default;
+
+  // MediaKeysListener::Delegate implementation.
+  MOCK_METHOD1(OnMediaKeysAccelerator, void(const Accelerator& accelerator));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockMediaKeysListenerDelegate);
+};
+
+}  // anonymous namespace
+
+class SystemMediaControlsMediaKeysListenerTest : public testing::Test {
+ public:
+  SystemMediaControlsMediaKeysListenerTest() {
+    listener_ =
+        std::make_unique<SystemMediaControlsMediaKeysListener>(&delegate_);
+    listener_->SetSystemMediaControlsServiceForTesting(
+        &mock_system_media_controls_service_);
+  }
+
+  ~SystemMediaControlsMediaKeysListenerTest() override = default;
+
+ protected:
+  system_media_controls::testing::MockSystemMediaControlsService&
+  mock_system_media_controls_service() {
+    return mock_system_media_controls_service_;
+  }
+  MockMediaKeysListenerDelegate& delegate() { return delegate_; }
+  SystemMediaControlsMediaKeysListener* listener() { return listener_.get(); }
+
+ private:
+  system_media_controls::testing::MockSystemMediaControlsService
+      mock_system_media_controls_service_;
+  MockMediaKeysListenerDelegate delegate_;
+  std::unique_ptr<SystemMediaControlsMediaKeysListener> listener_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsMediaKeysListenerTest);
+};
+
+TEST_F(SystemMediaControlsMediaKeysListenerTest,
+       ListensToSystemMediaControlsService) {
+  EXPECT_CALL(mock_system_media_controls_service(), AddObserver(listener()));
+  listener()->Initialize();
+}
+
+TEST_F(SystemMediaControlsMediaKeysListenerTest, SimplePlayPauseTest) {
+  // Should be set to true when we start listening for the key.
+  EXPECT_CALL(mock_system_media_controls_service(), SetIsPlayEnabled(true));
+  EXPECT_CALL(mock_system_media_controls_service(), SetIsPauseEnabled(true));
+
+  EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_))
+      .WillOnce(WithArg<0>([](const Accelerator& accelerator) {
+        EXPECT_EQ(ui::VKEY_MEDIA_PLAY_PAUSE, accelerator.key_code());
+      }));
+
+  ASSERT_TRUE(listener()->Initialize());
+  listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+
+  // Simulate media key press.
+  listener()->OnPlay();
+}
+
+TEST_F(SystemMediaControlsMediaKeysListenerTest, KeyCanBeReRegistered) {
+  Expectation enable_next =
+      EXPECT_CALL(mock_system_media_controls_service(), SetIsNextEnabled(true));
+  Expectation disable_next =
+      EXPECT_CALL(mock_system_media_controls_service(), SetIsNextEnabled(false))
+          .After(enable_next);
+  Expectation reenable_next =
+      EXPECT_CALL(mock_system_media_controls_service(), SetIsNextEnabled(true))
+          .After(disable_next);
+  EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_))
+      .After(reenable_next)
+      .WillOnce(WithArg<0>([](const Accelerator& accelerator) {
+        EXPECT_EQ(ui::VKEY_MEDIA_NEXT_TRACK, accelerator.key_code());
+      }));
+
+  ASSERT_TRUE(listener()->Initialize());
+
+  // Start listening to register the key.
+  listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
+
+  // Stop listening to unregister the key.
+  listener()->StopWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
+
+  // Start listening to re-register the key.
+  listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
+
+  // Simulate media key press.
+  listener()->OnNext();
+}
+
+TEST_F(SystemMediaControlsMediaKeysListenerTest, ListenForMultipleKeys) {
+  // Should be set to true when we start listening for the key.
+  EXPECT_CALL(mock_system_media_controls_service(), SetIsPlayEnabled(true));
+  EXPECT_CALL(mock_system_media_controls_service(), SetIsPauseEnabled(true));
+  EXPECT_CALL(mock_system_media_controls_service(), SetIsPreviousEnabled(true));
+
+  // Should receive the key presses.
+  EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(2);
+
+  ASSERT_TRUE(listener()->Initialize());
+  listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+  listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PREV_TRACK);
+
+  // Simulate media key press.
+  listener()->OnPlay();
+  listener()->OnPrevious();
+}
+
+}  // namespace ui
diff --git a/ui/base/ime/fuchsia/input_method_fuchsia.h b/ui/base/ime/fuchsia/input_method_fuchsia.h
index 4707189c..2863e7d 100644
--- a/ui/base/ime/fuchsia/input_method_fuchsia.h
+++ b/ui/base/ime/fuchsia/input_method_fuchsia.h
@@ -21,7 +21,7 @@
 namespace ui {
 
 // Handles input from physical keyboards and the IME service.
-class COMPONENT_EXPORT(UI_BASE_IME) InputMethodFuchsia
+class COMPONENT_EXPORT(UI_BASE_IME_FUCHSIA) InputMethodFuchsia
     : public InputMethodBase,
       public InputEventDispatcherDelegate,
       public fuchsia::ui::input::InputMethodEditorClient {
diff --git a/ui/base/win/system_media_controls/BUILD.gn b/ui/base/win/system_media_controls/BUILD.gn
new file mode 100644
index 0000000..41ca483
--- /dev/null
+++ b/ui/base/win/system_media_controls/BUILD.gn
@@ -0,0 +1,36 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+component("system_media_controls") {
+  sources = [
+    "system_media_controls_service.cc",
+    "system_media_controls_service.h",
+    "system_media_controls_service_impl.cc",
+    "system_media_controls_service_impl.h",
+    "system_media_controls_service_observer.cc",
+    "system_media_controls_service_observer.h",
+  ]
+
+  defines = [ "IS_SYSTEM_MEDIA_CONTROLS_IMPL" ]
+
+  deps = [
+    "//base",
+    "//ui/gfx",
+  ]
+}
+
+static_library("test_support") {
+  testonly = true
+
+  sources = [
+    "mock_system_media_controls_service.cc",
+    "mock_system_media_controls_service.h",
+  ]
+
+  deps = [
+    ":system_media_controls",
+    "//base",
+    "//testing/gmock",
+  ]
+}
diff --git a/ui/base/win/system_media_controls/OWNERS b/ui/base/win/system_media_controls/OWNERS
new file mode 100644
index 0000000..4152d74
--- /dev/null
+++ b/ui/base/win/system_media_controls/OWNERS
@@ -0,0 +1 @@
+steimel@chromium.org
\ No newline at end of file
diff --git a/ui/base/win/system_media_controls/mock_system_media_controls_service.cc b/ui/base/win/system_media_controls/mock_system_media_controls_service.cc
new file mode 100644
index 0000000..3f3e4bb
--- /dev/null
+++ b/ui/base/win/system_media_controls/mock_system_media_controls_service.cc
@@ -0,0 +1,17 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/win/system_media_controls/mock_system_media_controls_service.h"
+
+namespace system_media_controls {
+
+namespace testing {
+
+MockSystemMediaControlsService::MockSystemMediaControlsService() = default;
+
+MockSystemMediaControlsService::~MockSystemMediaControlsService() = default;
+
+}  // namespace testing
+
+}  // namespace system_media_controls
diff --git a/ui/base/win/system_media_controls/mock_system_media_controls_service.h b/ui/base/win/system_media_controls/mock_system_media_controls_service.h
new file mode 100644
index 0000000..4f5c913
--- /dev/null
+++ b/ui/base/win/system_media_controls/mock_system_media_controls_service.h
@@ -0,0 +1,44 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_MOCK_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
+#define UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_MOCK_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
+
+#include "base/macros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service.h"
+
+namespace system_media_controls {
+
+class SystemMediaControlsServiceObserver;
+
+namespace testing {
+
+// Mock implementation of SystemMediaControlsService for testing.
+class MockSystemMediaControlsService : public SystemMediaControlsService {
+ public:
+  MockSystemMediaControlsService();
+  ~MockSystemMediaControlsService() override;
+
+  // SystemMediaControlsService implementation.
+  MOCK_METHOD1(AddObserver, void(SystemMediaControlsServiceObserver* observer));
+  MOCK_METHOD1(RemoveObserver,
+               void(SystemMediaControlsServiceObserver* observer));
+  MOCK_METHOD1(SetIsNextEnabled, void(bool value));
+  MOCK_METHOD1(SetIsPreviousEnabled, void(bool value));
+  MOCK_METHOD1(SetIsPlayEnabled, void(bool value));
+  MOCK_METHOD1(SetIsPauseEnabled, void(bool value));
+  MOCK_METHOD1(SetIsStopEnabled, void(bool value));
+  MOCK_METHOD1(SetPlaybackStatus,
+               void(ABI::Windows::Media::MediaPlaybackStatus status));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockSystemMediaControlsService);
+};
+
+}  // namespace testing
+
+}  // namespace system_media_controls
+
+#endif  // UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_MOCK_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
diff --git a/ui/base/win/system_media_controls/system_media_controls_service.cc b/ui/base/win/system_media_controls/system_media_controls_service.cc
new file mode 100644
index 0000000..58d5a86
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service.cc
@@ -0,0 +1,22 @@
+// 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/base/win/system_media_controls/system_media_controls_service.h"
+
+#include "ui/base/win/system_media_controls/system_media_controls_service_impl.h"
+
+namespace system_media_controls {
+
+// static
+SystemMediaControlsService* SystemMediaControlsService::GetInstance() {
+  internal::SystemMediaControlsServiceImpl* impl =
+      internal::SystemMediaControlsServiceImpl::GetInstance();
+  if (impl->Initialize())
+    return impl;
+  return nullptr;
+}
+
+SystemMediaControlsService::~SystemMediaControlsService() = default;
+
+}  // namespace system_media_controls
diff --git a/ui/base/win/system_media_controls/system_media_controls_service.h b/ui/base/win/system_media_controls/system_media_controls_service.h
new file mode 100644
index 0000000..fe66681
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service.h
@@ -0,0 +1,50 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
+#define UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
+
+#include <windows.media.control.h>
+
+#include "base/component_export.h"
+
+namespace system_media_controls {
+
+class SystemMediaControlsServiceObserver;
+
+// The SystemMediaControlsService connects with Windows's System Media Transport
+// Controls, receives media key events, and propagates those events to listening
+// SystemMediaControlsServiceObservers. The SystemMediaControlsService tells the
+// System Media Transport Controls which actions are currently available. The
+// SystemMediaControlsService is also used to keep the System Media Transport
+// Controls informed of the current media playback state and metadata.
+class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsService {
+ public:
+  // Returns the singleton instance, creating if necessary. If the
+  // SystemMediaControlsService fails to connect to the
+  // SystemMediaTransportControls, this returns null.
+  static SystemMediaControlsService* GetInstance();
+
+  virtual void AddObserver(SystemMediaControlsServiceObserver* observer) = 0;
+  virtual void RemoveObserver(SystemMediaControlsServiceObserver* observer) = 0;
+
+  // TODO(steimel): Add other controls.
+  // Enable or disable specific controls.
+  virtual void SetIsNextEnabled(bool value) = 0;
+  virtual void SetIsPreviousEnabled(bool value) = 0;
+  virtual void SetIsPlayEnabled(bool value) = 0;
+  virtual void SetIsPauseEnabled(bool value) = 0;
+  virtual void SetIsStopEnabled(bool value) = 0;
+
+  // Setters for metadata.
+  virtual void SetPlaybackStatus(
+      ABI::Windows::Media::MediaPlaybackStatus status) = 0;
+
+ protected:
+  virtual ~SystemMediaControlsService();
+};
+
+}  // namespace system_media_controls
+
+#endif  // UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
diff --git a/ui/base/win/system_media_controls/system_media_controls_service_impl.cc b/ui/base/win/system_media_controls/system_media_controls_service_impl.cc
new file mode 100644
index 0000000..9d7a1a44
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service_impl.cc
@@ -0,0 +1,210 @@
+// 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/base/win/system_media_controls/system_media_controls_service_impl.h"
+
+#include <systemmediatransportcontrolsinterop.h>
+#include <windows.media.control.h>
+#include <wrl/client.h>
+#include <wrl/event.h>
+
+#include "base/strings/string_piece.h"
+#include "base/win/core_winrt_util.h"
+#include "base/win/scoped_hstring.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service_observer.h"
+#include "ui/gfx/win/singleton_hwnd.h"
+
+namespace system_media_controls {
+
+namespace internal {
+
+using ABI::Windows::Media::ISystemMediaTransportControls;
+using ABI::Windows::Media::ISystemMediaTransportControlsButtonPressedEventArgs;
+using ABI::Windows::Media::SystemMediaTransportControls;
+using ABI::Windows::Media::SystemMediaTransportControlsButton;
+using ABI::Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs;
+
+// static
+SystemMediaControlsServiceImpl* SystemMediaControlsServiceImpl::GetInstance() {
+  // We use a base::Singleton here instead of a base::NoDestruct so that we can
+  // clean up external listeners against the Windows platform at exit.
+  return base::Singleton<SystemMediaControlsServiceImpl>::get();
+}
+
+SystemMediaControlsServiceImpl::SystemMediaControlsServiceImpl() = default;
+
+SystemMediaControlsServiceImpl::~SystemMediaControlsServiceImpl() {
+  if (has_valid_registration_token_) {
+    DCHECK(system_media_controls_);
+    system_media_controls_->remove_ButtonPressed(registration_token_);
+    system_media_controls_->put_IsEnabled(false);
+  }
+}
+
+bool SystemMediaControlsServiceImpl::Initialize() {
+  if (attempted_to_initialize_)
+    return initialized_;
+
+  attempted_to_initialize_ = true;
+
+  if (!base::win::ResolveCoreWinRTDelayload() ||
+      !base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) {
+    return false;
+  }
+
+  Microsoft::WRL::ComPtr<ISystemMediaTransportControlsInterop> interop;
+  HRESULT hr = base::win::GetActivationFactory<
+      ISystemMediaTransportControlsInterop,
+      RuntimeClass_Windows_Media_SystemMediaTransportControls>(&interop);
+  if (FAILED(hr))
+    return false;
+
+  hr = interop->GetForWindow(gfx::SingletonHwnd::GetInstance()->hwnd(),
+                             IID_PPV_ARGS(&system_media_controls_));
+  if (FAILED(hr))
+    return false;
+
+  auto handler =
+      Microsoft::WRL::Callback<ABI::Windows::Foundation::ITypedEventHandler<
+          SystemMediaTransportControls*,
+          SystemMediaTransportControlsButtonPressedEventArgs*>>(
+          &SystemMediaControlsServiceImpl::ButtonPressed);
+  hr = system_media_controls_->add_ButtonPressed(handler.Get(),
+                                                 &registration_token_);
+  if (FAILED(hr))
+    return false;
+
+  has_valid_registration_token_ = true;
+
+  hr = system_media_controls_->put_IsEnabled(true);
+  if (FAILED(hr))
+    return false;
+
+  initialized_ = true;
+  return true;
+}
+
+void SystemMediaControlsServiceImpl::AddObserver(
+    SystemMediaControlsServiceObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void SystemMediaControlsServiceImpl::RemoveObserver(
+    SystemMediaControlsServiceObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void SystemMediaControlsServiceImpl::SetIsNextEnabled(bool value) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_IsNextEnabled(value);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetIsPreviousEnabled(bool value) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_IsPreviousEnabled(value);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetIsPlayEnabled(bool value) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_IsPlayEnabled(value);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetIsPauseEnabled(bool value) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_IsPauseEnabled(value);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetIsStopEnabled(bool value) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_IsStopEnabled(value);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetPlaybackStatus(
+    ABI::Windows::Media::MediaPlaybackStatus status) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_PlaybackStatus(status);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::OnPlay() {
+  for (SystemMediaControlsServiceObserver& obs : observers_)
+    obs.OnPlay();
+}
+
+void SystemMediaControlsServiceImpl::OnPause() {
+  for (SystemMediaControlsServiceObserver& obs : observers_)
+    obs.OnPause();
+}
+
+void SystemMediaControlsServiceImpl::OnNext() {
+  for (SystemMediaControlsServiceObserver& obs : observers_)
+    obs.OnNext();
+}
+
+void SystemMediaControlsServiceImpl::OnPrevious() {
+  for (SystemMediaControlsServiceObserver& obs : observers_)
+    obs.OnPrevious();
+}
+
+void SystemMediaControlsServiceImpl::OnStop() {
+  for (SystemMediaControlsServiceObserver& obs : observers_)
+    obs.OnStop();
+}
+
+// static
+HRESULT SystemMediaControlsServiceImpl::ButtonPressed(
+    ISystemMediaTransportControls* sender,
+    ISystemMediaTransportControlsButtonPressedEventArgs* args) {
+  SystemMediaTransportControlsButton button;
+  HRESULT hr = args->get_Button(&button);
+  if (FAILED(hr))
+    return hr;
+
+  SystemMediaControlsServiceImpl* impl = GetInstance();
+
+  switch (button) {
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Play:
+      impl->OnPlay();
+      break;
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Pause:
+      impl->OnPause();
+      break;
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Next:
+      impl->OnNext();
+      break;
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Previous:
+      impl->OnPrevious();
+      break;
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Stop:
+      impl->OnStop();
+      break;
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Record:
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_FastForward:
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Rewind:
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_ChannelUp:
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_ChannelDown:
+      break;
+  }
+
+  return S_OK;
+}
+
+}  // namespace internal
+
+}  // namespace system_media_controls
diff --git a/ui/base/win/system_media_controls/system_media_controls_service_impl.h b/ui/base/win/system_media_controls/system_media_controls_service_impl.h
new file mode 100644
index 0000000..fb10cde
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service_impl.h
@@ -0,0 +1,86 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_IMPL_H_
+#define UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_IMPL_H_
+
+#include <windows.foundation.h>
+#include <windows.media.control.h>
+#include <wrl/client.h>
+
+#include "base/component_export.h"
+#include "base/memory/singleton.h"
+#include "base/observer_list.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service.h"
+
+namespace system_media_controls {
+
+class SystemMediaControlsServiceObserver;
+
+namespace internal {
+
+// Implementation of SystemMediaControlsService that actually connects to the
+// Windows's System Media Transport Controls.
+class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsServiceImpl
+    : public SystemMediaControlsService {
+ public:
+  SystemMediaControlsServiceImpl();
+  ~SystemMediaControlsServiceImpl() override;
+
+  static SystemMediaControlsServiceImpl* GetInstance();
+
+  // Connects to the SystemMediaTransportControls. Returns true if connection
+  // is successful. If already connected, does nothing and returns true.
+  bool Initialize();
+
+  // SystemMediaControlsService implementation.
+  void AddObserver(SystemMediaControlsServiceObserver* observer) override;
+  void RemoveObserver(SystemMediaControlsServiceObserver* observer) override;
+  void SetIsNextEnabled(bool value) override;
+  void SetIsPreviousEnabled(bool value) override;
+  void SetIsPlayEnabled(bool value) override;
+  void SetIsPauseEnabled(bool value) override;
+  void SetIsStopEnabled(bool value) override;
+  void SetPlaybackStatus(
+      ABI::Windows::Media::MediaPlaybackStatus status) override;
+
+ private:
+  friend struct base::DefaultSingletonTraits<SystemMediaControlsServiceImpl>;
+
+  static HRESULT ButtonPressed(
+      ABI::Windows::Media::ISystemMediaTransportControls* sender,
+      ABI::Windows::Media::ISystemMediaTransportControlsButtonPressedEventArgs*
+          args);
+
+  // Called by ButtonPressed when the particular key is pressed.
+  void OnPlay();
+  void OnPause();
+  void OnNext();
+  void OnPrevious();
+  void OnStop();
+
+  Microsoft::WRL::ComPtr<ABI::Windows::Media::ISystemMediaTransportControls>
+      system_media_controls_;
+  EventRegistrationToken registration_token_;
+
+  // True if we've already tried to connect to the SystemMediaTransportControls.
+  bool attempted_to_initialize_ = false;
+
+  // True if we've successfully registered a button handler on the
+  // SystemMediaTransportControls.
+  bool has_valid_registration_token_ = false;
+
+  // True if we've successfully connected to the SystemMediaTransportControls.
+  bool initialized_ = false;
+
+  base::ObserverList<SystemMediaControlsServiceObserver> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsServiceImpl);
+};
+
+}  // namespace internal
+
+}  // namespace system_media_controls
+
+#endif  // UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_IMPL_H_
diff --git a/ui/base/win/system_media_controls/system_media_controls_service_observer.cc b/ui/base/win/system_media_controls/system_media_controls_service_observer.cc
new file mode 100644
index 0000000..cad848d
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service_observer.cc
@@ -0,0 +1,12 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/win/system_media_controls/system_media_controls_service_observer.h"
+
+namespace system_media_controls {
+
+SystemMediaControlsServiceObserver::~SystemMediaControlsServiceObserver() =
+    default;
+
+}  // namespace system_media_controls
diff --git a/ui/base/win/system_media_controls/system_media_controls_service_observer.h b/ui/base/win/system_media_controls/system_media_controls_service_observer.h
new file mode 100644
index 0000000..0f82420a
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service_observer.h
@@ -0,0 +1,29 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_OBSERVER_H_
+#define UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_OBSERVER_H_
+
+#include "base/component_export.h"
+#include "base/observer_list_types.h"
+
+namespace system_media_controls {
+
+// Interface to observe events on the SystemMediaControlsService.
+class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsServiceObserver
+    : public base::CheckedObserver {
+ public:
+  virtual void OnNext() = 0;
+  virtual void OnPrevious() = 0;
+  virtual void OnPause() = 0;
+  virtual void OnStop() = 0;
+  virtual void OnPlay() = 0;
+
+ protected:
+  ~SystemMediaControlsServiceObserver() override;
+};
+
+}  // namespace system_media_controls
+
+#endif  // UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_OBSERVER_H_
diff --git a/ui/display/manager/display_configurator.cc b/ui/display/manager/display_configurator.cc
index bf5b24b..cae3071 100644
--- a/ui/display/manager/display_configurator.cc
+++ b/ui/display/manager/display_configurator.cc
@@ -916,25 +916,23 @@
       std::move(apply_protection_callbacks_.front());
   apply_protection_callbacks_.pop();
 
-  if (!success) {
-    std::move(callback).Run(false);
-    return;
-  }
+  if (success) {
+    if (protection_mask == CONTENT_PROTECTION_METHOD_NONE) {
+      auto it = content_protection_requests_.find(client_id);
+      if (it != content_protection_requests_.end()) {
+        ContentProtections& protections = it->second;
+        protections.erase(display_id);
 
-  if (protection_mask == CONTENT_PROTECTION_METHOD_NONE) {
-    auto it = content_protection_requests_.find(client_id);
-    if (it != content_protection_requests_.end()) {
-      ContentProtections& protections = it->second;
-      protections.erase(display_id);
-
-      if (protections.empty())
-        content_protection_requests_.erase(client_id);
+        if (protections.empty())
+          content_protection_requests_.erase(client_id);
+      }
+    } else {
+      content_protection_requests_[client_id][display_id] = protection_mask;
     }
-  } else {
-    content_protection_requests_[client_id][display_id] = protection_mask;
   }
 
-  std::move(callback).Run(true);
+  std::move(callback).Run(success);
+
   if (!content_protection_tasks_.empty())
     content_protection_tasks_.front().Run();
 }
diff --git a/ui/display/manager/display_configurator_unittest.cc b/ui/display/manager/display_configurator_unittest.cc
index 3fb738a..dd6dbc9 100644
--- a/ui/display/manager/display_configurator_unittest.cc
+++ b/ui/display/manager/display_configurator_unittest.cc
@@ -993,6 +993,84 @@
             log_->GetActionsAndClear());
 }
 
+TEST_F(DisplayConfiguratorTest, ContentProtectionAsync) {
+  Init(false);
+  configurator_.ForceInitialConfigure();
+  EXPECT_NE(kNoActions, log_->GetActionsAndClear());
+
+  auto id = configurator_.RegisterContentProtectionClient();
+  EXPECT_TRUE(id);
+
+  UpdateOutputs(2, true);
+  EXPECT_NE(kNoActions, log_->GetActionsAndClear());
+
+  native_display_delegate_->set_run_async(true);
+
+  // Asynchronous tasks should be pending.
+  constexpr int kTaskCount = 3;
+  for (int i = 0; i < kTaskCount; ++i) {
+    configurator_.ApplyContentProtection(
+        id, outputs_[1]->display_id(), CONTENT_PROTECTION_METHOD_HDCP,
+        base::BindOnce(&DisplayConfiguratorTest::ApplyContentProtectionCallback,
+                       base::Unretained(this)));
+
+    configurator_.QueryContentProtection(
+        id, outputs_[1]->display_id(),
+        base::BindOnce(&DisplayConfiguratorTest::QueryContentProtectionCallback,
+                       base::Unretained(this)));
+  }
+
+  EXPECT_EQ(0, apply_content_protection_call_count_);
+  EXPECT_EQ(0, query_content_protection_call_count_);
+
+  native_display_delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(kTaskCount, apply_content_protection_call_count_);
+  EXPECT_TRUE(apply_content_protection_success_);
+
+  EXPECT_EQ(kTaskCount, query_content_protection_call_count_);
+  EXPECT_TRUE(query_content_protection_success_);
+  EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_HDMI),
+            query_content_protection_connection_mask_);
+  EXPECT_EQ(static_cast<uint32_t>(CONTENT_PROTECTION_METHOD_HDCP),
+            query_content_protection_protection_mask_);
+
+  EXPECT_EQ(GetSetHDCPStateAction(*outputs_[1], HDCP_STATE_DESIRED),
+            log_->GetActionsAndClear());
+
+  // Pending task should run even if previous task fails.
+  native_display_delegate_->set_set_hdcp_state_expectation(false);
+
+  configurator_.ApplyContentProtection(
+      id, outputs_[1]->display_id(), CONTENT_PROTECTION_METHOD_NONE,
+      base::BindOnce(&DisplayConfiguratorTest::ApplyContentProtectionCallback,
+                     base::Unretained(this)));
+
+  configurator_.QueryContentProtection(
+      id, outputs_[1]->display_id(),
+      base::BindOnce(&DisplayConfiguratorTest::QueryContentProtectionCallback,
+                     base::Unretained(this)));
+
+  EXPECT_EQ(kTaskCount, apply_content_protection_call_count_);
+  EXPECT_EQ(kTaskCount, query_content_protection_call_count_);
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(kTaskCount + 1, apply_content_protection_call_count_);
+  EXPECT_FALSE(apply_content_protection_success_);
+
+  EXPECT_EQ(kTaskCount + 1, query_content_protection_call_count_);
+  EXPECT_TRUE(query_content_protection_success_);
+  EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_HDMI),
+            query_content_protection_connection_mask_);
+  EXPECT_EQ(static_cast<uint32_t>(CONTENT_PROTECTION_METHOD_HDCP),
+            query_content_protection_protection_mask_);
+
+  EXPECT_EQ(GetSetHDCPStateAction(*outputs_[1], HDCP_STATE_UNDESIRED),
+            log_->GetActionsAndClear());
+}
+
 TEST_F(DisplayConfiguratorTest, DoNotConfigureWithSuspendedDisplays) {
   InitWithSingleOutput();
 
diff --git a/ui/display/manager/test/test_native_display_delegate.cc b/ui/display/manager/test/test_native_display_delegate.cc
index a90af3fa..ec2490f 100644
--- a/ui/display/manager/test/test_native_display_delegate.cc
+++ b/ui/display/manager/test/test_native_display_delegate.cc
@@ -83,14 +83,26 @@
 
 void TestNativeDisplayDelegate::GetHDCPState(const DisplaySnapshot& output,
                                              GetHDCPStateCallback callback) {
-  std::move(callback).Run(get_hdcp_expectation_, hdcp_state_);
+  if (run_async_) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), get_hdcp_expectation_,
+                                  hdcp_state_));
+  } else {
+    std::move(callback).Run(get_hdcp_expectation_, hdcp_state_);
+  }
 }
 
 void TestNativeDisplayDelegate::SetHDCPState(const DisplaySnapshot& output,
                                              HDCPState state,
                                              SetHDCPStateCallback callback) {
   log_->AppendAction(GetSetHDCPStateAction(output, state));
-  std::move(callback).Run(set_hdcp_expectation_);
+
+  if (run_async_) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), set_hdcp_expectation_));
+  } else {
+    std::move(callback).Run(set_hdcp_expectation_);
+  }
 }
 
 bool TestNativeDisplayDelegate::SetColorMatrix(
diff --git a/ui/file_manager/file_manager/background/js/mock_drive_sync_handler.js b/ui/file_manager/file_manager/background/js/mock_drive_sync_handler.js
index 763ecab4..917123c 100644
--- a/ui/file_manager/file_manager/background/js/mock_drive_sync_handler.js
+++ b/ui/file_manager/file_manager/background/js/mock_drive_sync_handler.js
@@ -6,36 +6,55 @@
 
 /**
  * Mock of DriveSyncHandler.
- *
- * @constructor
- * @struct
  * @implements {DriveSyncHandler}
- * @extends {cr.EventTarget}
  */
-function MockDriveSyncHandler() {
-  /**
-   * @type {boolean} Drive sync suppressed state.
-   * @private
-   */
-  this.syncSuppressed_ = false;
+class MockDriveSyncHandler extends cr.EventTarget {
+  constructor() {
+    super();
+
+    /**
+     * @type {boolean} Drive sync suppressed state.
+     * @private
+     */
+    this.syncSuppressed_ = false;
+
+    /**
+     * @type {boolean} Drive sync disabled on mobile notification state.
+     * @private
+     */
+    this.showingDisabledMobileSyncNotification_ = false;
+  }
 
   /**
-   * @type {boolean} Drive sync disabled on mobile notification state.
-   * @private
+   * Returns the completed event name.
+   * @return {string}
    */
-  this.showingDisabledMobileSyncNotification_ = false;
-}
+  getCompletedEventName() {
+    return MockDriveSyncHandler.DRIVE_SYNC_COMPLETED_EVENT;
+  }
 
-MockDriveSyncHandler.prototype = /** @struct */ {
-  __proto__: cr.EventTarget.prototype,
+  /**
+   * Returns whether the Drive sync is currently suppressed or not.
+   * @return {boolean}
+   */
+  isSyncSuppressed() {
+    return this.syncSuppressed_;
+  }
+
+  /**
+   * Shows a notification that Drive sync is disabled on cellular networks.
+   */
+  showDisabledMobileSyncNotification() {
+    this.showingDisabledMobileSyncNotification_ = true;
+  }
 
   /**
    * @return {boolean} Whether the handler is syncing items or not.
    */
   get syncing() {
     return false;
-  },
-};
+  }
+}
 
 /**
  * Completed event name.
@@ -44,26 +63,3 @@
  * @const
  */
 MockDriveSyncHandler.DRIVE_SYNC_COMPLETED_EVENT = 'completed';
-
-/**
- * Returns the completed event name.
- * @return {string}
- */
-MockDriveSyncHandler.prototype.getCompletedEventName = () => {
-  return MockDriveSyncHandler.DRIVE_SYNC_COMPLETED_EVENT;
-};
-
-/**
- * Returns whether the Drive sync is currently suppressed or not.
- * @return {boolean}
- */
-MockDriveSyncHandler.prototype.isSyncSuppressed = function() {
-  return this.syncSuppressed_;
-};
-
-/**
- * Shows a notification that Drive sync is disabled on cellular networks.
- */
-MockDriveSyncHandler.prototype.showDisabledMobileSyncNotification = function() {
-  this.showingDisabledMobileSyncNotification_ = true;
-};
diff --git a/ui/file_manager/file_manager/background/js/mock_file_operation_manager.js b/ui/file_manager/file_manager/background/js/mock_file_operation_manager.js
index caf9c088..7f2d263 100644
--- a/ui/file_manager/file_manager/background/js/mock_file_operation_manager.js
+++ b/ui/file_manager/file_manager/background/js/mock_file_operation_manager.js
@@ -6,100 +6,93 @@
 
 /**
  * Mock implementation of {FileOperationManager} for tests.
- * @constructor
- * @struct
  * @implements {FileOperationManager}
- * @extends {cr.EventTarget}
  */
-function MockFileOperationManager() {
-  /**
-   * Event to be dispatched when requestTaskCancel is called. Note: the
-   * unittest writes this value before calling requestTaskCancel().
-   * @type {Event}
-   */
-  this.cancelEvent = null;
+class MockFileOperationManager extends cr.EventTarget {
+  constructor() {
+    super();
 
-  /** @type {!Array<string>} */
-  this.generatedTaskIds = [];
+    /**
+     * Event to be dispatched when requestTaskCancel is called. Note: the
+     * unittest writes this value before calling requestTaskCancel().
+     * @type {Event}
+     */
+    this.cancelEvent = null;
 
-  /** @type {Function} */
-  this.pasteResolver = null;
-}
+    /** @type {!Array<string>} */
+    this.generatedTaskIds = [];
 
-MockFileOperationManager.prototype = /** @struct */ {
-  __proto__: cr.EventTarget.prototype,
-};
-
-/**
- * Dispatches a cancel event that has been specified by the unittest.
- */
-MockFileOperationManager.prototype.requestTaskCancel = function() {
-  assert(this.cancelEvent);
-  this.dispatchEvent(this.cancelEvent);
-};
-
-/**
- * Kick off pasting.
- *
- * @param {Array<Entry>} sourceEntries Entries of the source files.
- * @param {DirectoryEntry} targetEntry The destination entry of the target
- *     directory.
- * @param {boolean} isMove True if the operation is "move", otherwise (i.e.
- *     if the operation is "copy") false.
- * @param {string=} opt_taskId If the corresponding item has already created
- *     at another places, we need to specify the ID of the item. If the
- *     item is not created, FileOperationManager generates new ID.
- */
-MockFileOperationManager.prototype.paste = function(
-    sourceEntries, targetEntry, isMove, opt_taskId) {
-  if (this.pasteResolver) {
-    this.pasteResolver.call(this, {
-      sourceEntries: sourceEntries,
-      targetEntry: targetEntry,
-      isMove: isMove,
-      opt_taskId: opt_taskId
-    });
-    // Reset the resolver for the next paste call.
+    /** @type {Function} */
     this.pasteResolver = null;
   }
-};
 
-/**
- * @return {Promise<Object>} A promise that is resolved the next time #paste is
- * called.  The Object contains the arguments that #paste was called with.
- */
-MockFileOperationManager.prototype.whenPasteCalled = function() {
-  if (this.pasteResolver) {
-    throw new Error('Only one paste call can be waited on at a time.');
+  /**
+   * Dispatches a cancel event that has been specified by the unittest.
+   */
+  requestTaskCancel() {
+    assert(this.cancelEvent);
+    this.dispatchEvent(this.cancelEvent);
   }
 
-  return new Promise((resolve, reject) => {
-    this.pasteResolver = resolve;
-  });
-};
+  /**
+   * Kick off pasting.
+   *
+   * @param {Array<Entry>} sourceEntries Entries of the source files.
+   * @param {DirectoryEntry} targetEntry The destination entry of the target
+   *     directory.
+   * @param {boolean} isMove True if the operation is "move", otherwise (i.e.
+   *     if the operation is "copy") false.
+   * @param {string=} opt_taskId If the corresponding item has already created
+   *     at another places, we need to specify the ID of the item. If the
+   *     item is not created, FileOperationManager generates new ID.
+   */
+  paste(sourceEntries, targetEntry, isMove, opt_taskId) {
+    if (this.pasteResolver) {
+      this.pasteResolver.call(this, {
+        sourceEntries: sourceEntries,
+        targetEntry: targetEntry,
+        isMove: isMove,
+        opt_taskId: opt_taskId
+      });
+      // Reset the resolver for the next paste call.
+      this.pasteResolver = null;
+    }
+  }
 
-/**
- * Generates a unique task Id.
- * @return {string}
- */
-MockFileOperationManager.prototype.generateTaskId = function() {
-  const newTaskId = 'task' + this.generatedTaskIds.length;
-  this.generatedTaskIds.push(newTaskId);
-  return newTaskId;
-};
+  /**
+   * @return {Promise<Object>} A promise that is resolved the next time #paste
+   * is called.  The Object contains the arguments that #paste was called with.
+   */
+  whenPasteCalled() {
+    if (this.pasteResolver) {
+      throw new Error('Only one paste call can be waited on at a time.');
+    }
 
-/**
- * @return {boolean} Whether or not the given task ID belongs to a task
- *     generated by this manager.
- */
-MockFileOperationManager.prototype.isKnownTaskId = function(id) {
-  return this.generatedTaskIds.indexOf(id) !== -1;
-};
+    return new Promise((resolve, reject) => {
+      this.pasteResolver = resolve;
+    });
+  }
 
-MockFileOperationManager.prototype.hasQueuedTasks = () => {};
+  /**
+   * Generates a unique task Id.
+   * @return {string}
+   */
+  generateTaskId() {
+    const newTaskId = 'task' + this.generatedTaskIds.length;
+    this.generatedTaskIds.push(newTaskId);
+    return newTaskId;
+  }
 
-MockFileOperationManager.prototype.filterSameDirectoryEntry = () => {};
+  /**
+   * @return {boolean} Whether or not the given task ID belongs to a task
+   *     generated by this manager.
+   */
+  isKnownTaskId(id) {
+    return this.generatedTaskIds.indexOf(id) !== -1;
+  }
 
-MockFileOperationManager.prototype.deleteEntries = () => {};
-
-MockFileOperationManager.prototype.zipSelection = () => {};
+  hasQueuedTasks() {}
+  filterSameDirectoryEntry() {}
+  deleteEntries() {}
+  zipSelection() {}
+}
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index 4209133..6e998bd0 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -682,9 +682,6 @@
 }
 
 js_library("spinner_controller") {
-  deps = [
-    "//ui/webui/resources/js/cr:event_target",
-  ]
 }
 
 js_unittest("spinner_controller_unittest") {
diff --git a/ui/file_manager/file_manager/foreground/js/spinner_controller.js b/ui/file_manager/file_manager/foreground/js/spinner_controller.js
index e5ec81f6..4d92c44 100644
--- a/ui/file_manager/file_manager/foreground/js/spinner_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/spinner_controller.js
@@ -6,96 +6,95 @@
  * Controller for spinners. Spinner requests can be stacked. Eg. if show()
  * is called 3 times, the hide callback has to be called 3 times to make the
  * spinner invisible.
- *
- * @param {!Element} element
- * @constructor
- * @extends {cr.EventTarget}
  */
-function SpinnerController(element) {
-  /**
-   * The container element of the file list.
-   * @type {!Element}
-   * @const
-   * @private
-   */
-  this.element_ = element;
+class SpinnerController {
+  /** @param {!Element} element */
+  constructor(element) {
+    /**
+     * The container element of the file list.
+     * @type {!Element}
+     * @const
+     * @private
+     */
+    this.element_ = element;
+
+    /**
+     * @type {number}
+     * @private
+     */
+    this.activeSpinners_ = 0;
+
+    /**
+     * @type {!Object<number, boolean>}
+     * @private
+     */
+    this.pendingSpinnerTimerIds_ = {};
+
+    /**
+     * @type {number}
+     * @private
+     */
+    this.blinkDuration_ = 1000;  // In milliseconds.
+  }
 
   /**
-   * @type {number}
-   * @private
+   * Blinks the spinner for a short period of time. Hides automatically.
    */
-  this.activeSpinners_ = 0;
+  blink() {
+    const hideCallback = this.show();
+    setTimeout(hideCallback, this.blinkDuration_);
+  }
 
   /**
-   * @type {!Object<number, boolean>}
-   * @private
+   * Shows the spinner immediately until the returned callback is called.
+   * @return {function()} Hide callback.
    */
-  this.pendingSpinnerTimerIds_ = {};
+  show() {
+    return this.showWithDelay(0, () => {});
+  }
 
   /**
-   * @type {number}
+   * Shows the spinner until hide is called. The returned callback must be
+   * called when the spinner is not necessary anymore.
+   * @param {number} delay Delay in milliseconds.
+   * @param {function()} callback Show callback.
+   * @return {function()} Hide callback.
+   */
+  showWithDelay(delay, callback) {
+    const timerId = setTimeout(() => {
+      this.activeSpinners_++;
+      if (this.activeSpinners_ === 1) {
+        this.element_.hidden = false;
+      }
+      delete this.pendingSpinnerTimerIds_[timerId];
+      callback();
+    }, delay);
+
+    this.pendingSpinnerTimerIds_[timerId] = true;
+    return this.maybeHide_.bind(this, timerId);
+  }
+
+  /**
+   * @param {number} duration Duration in milliseconds.
+   */
+  setBlinkDurationForTesting(duration) {
+    this.blinkDuration_ = duration;
+  }
+
+  /**
+   * @param {number} timerId
    * @private
    */
-  this.blinkDuration_ = 1000;  // In milliseconds.
-}
-
-/**
- * Blinks the spinner for a short period of time. Hides automatically.
- */
-SpinnerController.prototype.blink = function() {
-  const hideCallback = this.show();
-  setTimeout(hideCallback, this.blinkDuration_);
-};
-
-/**
- * Shows the spinner immediately until the returned callback is called.
- * @return {function()} Hide callback.
- */
-SpinnerController.prototype.show = function() {
-  return this.showWithDelay(0, () => {});
-};
-
-/**
- * Shows the spinner until hide is called. The returned callback must be called
- * when the spinner is not necessary anymore.
- * @param {number} delay Delay in milliseconds.
- * @param {function()} callback Show callback.
- * @return {function()} Hide callback.
- */
-SpinnerController.prototype.showWithDelay = function(delay, callback) {
-  const timerId = setTimeout(() => {
-    this.activeSpinners_++;
-    if (this.activeSpinners_ === 1) {
-      this.element_.hidden = false;
+  maybeHide_(timerId) {
+    if (timerId in this.pendingSpinnerTimerIds_) {
+      clearTimeout(timerId);
+      delete this.pendingSpinnerTimerIds_[timerId];
+      return;
     }
-    delete this.pendingSpinnerTimerIds_[timerId];
-    callback();
-  }, delay);
 
-  this.pendingSpinnerTimerIds_[timerId] = true;
-  return this.maybeHide_.bind(this, timerId);
-};
-
-/**
- * @param {number} duration Duration in milliseconds.
- */
-SpinnerController.prototype.setBlinkDurationForTesting = function(duration) {
-  this.blinkDuration_ = duration;
-};
-
-/**
- * @param {number} timerId
- * @private
- */
-SpinnerController.prototype.maybeHide_ = function(timerId) {
-  if (timerId in this.pendingSpinnerTimerIds_) {
-    clearTimeout(timerId);
-    delete this.pendingSpinnerTimerIds_[timerId];
-    return;
+    this.activeSpinners_--;
+    if (this.activeSpinners_ === 0) {
+      this.element_.hidden = true;
+    }
   }
-
-  this.activeSpinners_--;
-  if (this.activeSpinners_ === 0) {
-    this.element_.hidden = true;
-  }
-};
+}
diff --git a/ui/file_manager/image_loader/piex/tests.js b/ui/file_manager/image_loader/piex/tests.js
index a072483..18ed115a 100644
--- a/ui/file_manager/image_loader/piex/tests.js
+++ b/ui/file_manager/image_loader/piex/tests.js
@@ -72,18 +72,18 @@
   };
 
   const images = [
-    "images/SONY_A500_01.ARW",
-    "images/EOS_XS_REBEL.CR2",
-    "images/RAW_CANON_1DM2.CR2",
-    "images/L100_4220.DNG",
-    "images/RAW_LEICA_M8.DNG",
-    "images/FUJI_E550_RAW.RAF",
-    "images/NIKON_UB20_O35.NEF",
-    "images/NIKON_GDN0447.NEF",
-    "images/OLYMPUS_SC877.ORF",
-    "images/NIKON_CPIX78.NRW",
-    "images/PANASONIC_DMC.RW2",
-    "images/UNKNOWN_FORMAT.JPG",
+    'images/SONY_A500_01.ARW',
+    'images/EOS_XS_REBEL.CR2',
+    'images/RAW_CANON_1DM2.CR2',
+    'images/L100_4220.DNG',
+    'images/RAW_LEICA_M8.DNG',
+    'images/FUJI_E550_RAW.RAF',
+    'images/NIKON_UB20_O35.NEF',
+    'images/NIKON_GDN0447.NEF',
+    'images/OLYMPUS_SC877.ORF',
+    'images/NIKON_CPIX78.NRW',
+    'images/PANASONIC_DMC.RW2',
+    'images/UNKNOWN_FORMAT.JPG',
   ];
 
   await page.evaluate(() => {
diff --git a/ui/native_theme/common_theme.cc b/ui/native_theme/common_theme.cc
index 8d7e0fa..d0f6ba7 100644
--- a/ui/native_theme/common_theme.cc
+++ b/ui/native_theme/common_theme.cc
@@ -61,6 +61,8 @@
       case NativeTheme::kColorId_DialogBackground:
         return color_utils::AlphaBlend(SK_ColorWHITE, gfx::kGoogleGrey900,
                                        0.04f);
+      case NativeTheme::kColorId_BubbleFooterBackground:
+        return SkColorSetRGB(0x32, 0x36, 0x39);
       case NativeTheme::kColorId_ProminentButtonColor:
         return gfx::kGoogleBlue300;
       case NativeTheme::kColorId_TextOnProminentButtonColor:
@@ -159,6 +161,8 @@
     case NativeTheme::kColorId_DialogBackground:
     case NativeTheme::kColorId_BubbleBackground:
       return SK_ColorWHITE;
+    case NativeTheme::kColorId_BubbleFooterBackground:
+      return gfx::kGoogleGrey050;
 
     // Buttons
     case NativeTheme::kColorId_ButtonEnabledColor:
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
index ebbb9cc7..cf93b2c 100644
--- a/ui/native_theme/native_theme.h
+++ b/ui/native_theme/native_theme.h
@@ -296,6 +296,7 @@
     // Dialogs
     kColorId_DialogBackground,
     kColorId_BubbleBackground,
+    kColorId_BubbleFooterBackground,
     // FocusableBorder
     kColorId_FocusedBorderColor,
     kColorId_UnfocusedBorderColor,
diff --git a/ui/native_theme/native_theme_dark_aura.cc b/ui/native_theme/native_theme_dark_aura.cc
index 17b216ec..ba8aeac 100644
--- a/ui/native_theme/native_theme_dark_aura.cc
+++ b/ui/native_theme/native_theme_dark_aura.cc
@@ -22,6 +22,7 @@
     case kColorId_WindowBackground:
     case kColorId_DialogBackground:
     case kColorId_BubbleBackground:
+    case kColorId_BubbleFooterBackground:
       return SK_ColorBLACK;
 
     // Button
diff --git a/ui/views/accessibility/ax_virtual_view.cc b/ui/views/accessibility/ax_virtual_view.cc
index c10ca2be..ec7296e 100644
--- a/ui/views/accessibility/ax_virtual_view.cc
+++ b/ui/views/accessibility/ax_virtual_view.cc
@@ -266,15 +266,20 @@
   return nullptr;
 }
 
-gfx::Rect AXVirtualView::GetClippedScreenBoundsRect() const {
-  // We could optionally add clipping here if ever needed.
-  // TODO(nektar): Implement bounds that are relative to the parent.
-  return gfx::ToEnclosingRect(custom_data_.relative_bounds.bounds);
-}
-
-gfx::Rect AXVirtualView::GetUnclippedScreenBoundsRect() const {
-  // TODO(nektar): Implement bounds that are relative to the parent.
-  return gfx::ToEnclosingRect(custom_data_.relative_bounds.bounds);
+gfx::Rect AXVirtualView::GetBoundsRect(
+    const ui::AXCoordinateSystem coordinate_system,
+    const ui::AXClippingBehavior clipping_behavior,
+    ui::AXOffscreenResult* offscreen_result) const {
+  switch (coordinate_system) {
+    case ui::AXCoordinateSystem::kScreen:
+      // We could optionally add clipping here if ever needed.
+      // TODO(nektar): Implement bounds that are relative to the parent.
+      return gfx::ToEnclosingRect(custom_data_.relative_bounds.bounds);
+    case ui::AXCoordinateSystem::kRootFrame:
+    case ui::AXCoordinateSystem::kFrame:
+      NOTIMPLEMENTED();
+      return gfx::Rect();
+  }
 }
 
 gfx::NativeViewAccessible AXVirtualView::HitTestSync(int x, int y) {
diff --git a/ui/views/accessibility/ax_virtual_view.h b/ui/views/accessibility/ax_virtual_view.h
index 66fd2f79..e807edc9 100644
--- a/ui/views/accessibility/ax_virtual_view.h
+++ b/ui/views/accessibility/ax_virtual_view.h
@@ -128,8 +128,10 @@
   gfx::NativeViewAccessible ChildAtIndex(int index) override;
   gfx::NativeViewAccessible GetNSWindow() override;
   gfx::NativeViewAccessible GetParent() override;
-  gfx::Rect GetClippedScreenBoundsRect() const override;
-  gfx::Rect GetUnclippedScreenBoundsRect() const override;
+  gfx::Rect GetBoundsRect(
+      const ui::AXCoordinateSystem coordinate_system,
+      const ui::AXClippingBehavior clipping_behavior,
+      ui::AXOffscreenResult* offscreen_result) const override;
   gfx::NativeViewAccessible HitTestSync(int x, int y) override;
   gfx::NativeViewAccessible GetFocus() override;
   ui::AXPlatformNode* GetFromNodeID(int32_t id) override;
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.cc b/ui/views/accessibility/view_ax_platform_node_delegate.cc
index 2c4392a..b6ac0c5 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -296,13 +296,19 @@
   return nullptr;
 }
 
-gfx::Rect ViewAXPlatformNodeDelegate::GetClippedScreenBoundsRect() const {
-  // We could optionally add clipping here if ever needed.
-  return view()->GetBoundsInScreen();
-}
-
-gfx::Rect ViewAXPlatformNodeDelegate::GetUnclippedScreenBoundsRect() const {
-  return view()->GetBoundsInScreen();
+gfx::Rect ViewAXPlatformNodeDelegate::GetBoundsRect(
+    const ui::AXCoordinateSystem coordinate_system,
+    const ui::AXClippingBehavior clipping_behavior,
+    ui::AXOffscreenResult* offscreen_result) const {
+  switch (coordinate_system) {
+    case ui::AXCoordinateSystem::kScreen:
+      // We could optionally add clipping here if ever needed.
+      return view()->GetBoundsInScreen();
+    case ui::AXCoordinateSystem::kRootFrame:
+    case ui::AXCoordinateSystem::kFrame:
+      NOTIMPLEMENTED();
+      return gfx::Rect();
+  }
 }
 
 gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::HitTestSync(int x,
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.h b/ui/views/accessibility/view_ax_platform_node_delegate.h
index 2021a2a..455052d 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate.h
+++ b/ui/views/accessibility/view_ax_platform_node_delegate.h
@@ -51,8 +51,10 @@
   gfx::NativeViewAccessible ChildAtIndex(int index) override;
   gfx::NativeViewAccessible GetNSWindow() override;
   gfx::NativeViewAccessible GetParent() override;
-  gfx::Rect GetClippedScreenBoundsRect() const override;
-  gfx::Rect GetUnclippedScreenBoundsRect() const override;
+  gfx::Rect GetBoundsRect(
+      const ui::AXCoordinateSystem coordinate_system,
+      const ui::AXClippingBehavior clipping_behavior,
+      ui::AXOffscreenResult* offscreen_result) const override;
   gfx::NativeViewAccessible HitTestSync(int x, int y) override;
   gfx::NativeViewAccessible GetFocus() override;
   ui::AXPlatformNode* GetFromNodeID(int32_t id) override;
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_win.cc b/ui/views/accessibility/view_ax_platform_node_delegate_win.cc
index a1e7b940..457a4fc 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_win.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_win.cc
@@ -110,14 +110,19 @@
   return HWNDForView(view());
 }
 
-gfx::Rect ViewAXPlatformNodeDelegateWin::GetClippedScreenBoundsRect() const {
-  // We could optionally add clipping here if ever needed.
-  return GetUnclippedScreenBoundsRect();
+gfx::Rect ViewAXPlatformNodeDelegateWin::GetBoundsRect(
+    const ui::AXCoordinateSystem coordinate_system,
+    const ui::AXClippingBehavior clipping_behavior,
+    ui::AXOffscreenResult* offscreen_result) const {
+  switch (coordinate_system) {
+    case ui::AXCoordinateSystem::kScreen:
+      // We could optionally add clipping here if ever needed.
+      return display::win::ScreenWin::DIPToScreenRect(
+          HWNDForView(view()), view()->GetBoundsInScreen());
+    case ui::AXCoordinateSystem::kRootFrame:
+    case ui::AXCoordinateSystem::kFrame:
+      NOTIMPLEMENTED();
+      return gfx::Rect();
+  }
 }
-
-gfx::Rect ViewAXPlatformNodeDelegateWin::GetUnclippedScreenBoundsRect() const {
-  gfx::Rect bounds = view()->GetBoundsInScreen();
-  return display::win::ScreenWin::DIPToScreenRect(HWNDForView(view()), bounds);
-}
-
 }  // namespace views
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_win.h b/ui/views/accessibility/view_ax_platform_node_delegate_win.h
index 2715eae7..30fc304 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_win.h
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_win.h
@@ -20,8 +20,10 @@
   // |ViewAXPlatformNodeDelegate| overrides:
   gfx::NativeViewAccessible GetParent() override;
   gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
-  gfx::Rect GetClippedScreenBoundsRect() const override;
-  gfx::Rect GetUnclippedScreenBoundsRect() const override;
+  gfx::Rect GetBoundsRect(
+      const ui::AXCoordinateSystem coordinate_system,
+      const ui::AXClippingBehavior clipping_behavior,
+      ui::AXOffscreenResult* offscreen_result) const override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ViewAXPlatformNodeDelegateWin);
diff --git a/ui/views/bubble/footnote_container_view.cc b/ui/views/bubble/footnote_container_view.cc
index 6929a19..4fb844f 100644
--- a/ui/views/bubble/footnote_container_view.cc
+++ b/ui/views/bubble/footnote_container_view.cc
@@ -65,9 +65,8 @@
 FootnoteContainerView::~FootnoteContainerView() = default;
 
 void FootnoteContainerView::SetCornerRadius(float corner_radius) {
-  SkColor background_color = GetNativeTheme()->SystemDarkModeEnabled()
-                                 ? SkColorSetRGB(0x32, 0x36, 0x39)
-                                 : gfx::kGoogleGrey050;
+  SkColor background_color = GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_BubbleFooterBackground);
   SetBackground(std::make_unique<HalfRoundedRectBackground>(background_color,
                                                             corner_radius));
 }
diff --git a/ui/views/controls/button/button.cc b/ui/views/controls/button/button.cc
index 3adb1a5..1b5ba78 100644
--- a/ui/views/controls/button/button.cc
+++ b/ui/views/controls/button/button.cc
@@ -484,6 +484,9 @@
     return button()->GetDragOperations(press_pt);
   }
   bool InDrag() override { return button()->InDrag(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DefaultButtonControllerDelegate);
 };
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -501,7 +504,7 @@
   hover_animation_.SetSlideDuration(kHoverFadeDurationMs);
   SetInstallFocusRingOnFocus(PlatformStyle::kPreferFocusRings);
   button_controller_ = std::make_unique<ButtonController>(
-      this, std::make_unique<DefaultButtonControllerDelegate>(this));
+      this, CreateButtonControllerDelegate());
 }
 
 Button::KeyClickAction Button::GetKeyClickActionForEvent(
@@ -553,8 +556,9 @@
   return button_controller_->IsTriggerableEvent(event);
 }
 
-void Button::SetButtonController(std::unique_ptr<ButtonController> handler) {
-  button_controller_ = std::move(handler);
+void Button::SetButtonController(
+    std::unique_ptr<ButtonController> button_controller) {
+  button_controller_ = std::move(button_controller);
 }
 
 bool Button::ShouldUpdateInkDropOnClickCanceled() const {
diff --git a/ui/views/controls/button/button.h b/ui/views/controls/button/button.h
index d1103fb6..7211006c 100644
--- a/ui/views/controls/button/button.h
+++ b/ui/views/controls/button/button.h
@@ -281,7 +281,7 @@
 
   FocusRing* focus_ring() { return focus_ring_.get(); }
 
-  void SetButtonController(std::unique_ptr<ButtonController> handler);
+  void SetButtonController(std::unique_ptr<ButtonController> button_controller);
 
   // The button's listener. Notified when clicked.
   ButtonListener* listener_;
diff --git a/ui/views/controls/button/button_controller.cc b/ui/views/controls/button/button_controller.cc
index 4afbc100..17d0a12 100644
--- a/ui/views/controls/button/button_controller.cc
+++ b/ui/views/controls/button/button_controller.cc
@@ -17,10 +17,6 @@
 
 ButtonController::~ButtonController() = default;
 
-MenuButtonController* ButtonController::AsMenuButtonController() {
-  return nullptr;
-}
-
 bool ButtonController::OnMousePressed(const ui::MouseEvent& event) {
   if (button_->state() == Button::STATE_DISABLED)
     return true;
diff --git a/ui/views/controls/button/button_controller.h b/ui/views/controls/button/button_controller.h
index 0688f45b..242b6fe4 100644
--- a/ui/views/controls/button/button_controller.h
+++ b/ui/views/controls/button/button_controller.h
@@ -11,8 +11,6 @@
 
 namespace views {
 
-class MenuButtonController;
-
 // Handles logic not related to the visual aspects of a Button such as event
 // handling and state changes.
 class VIEWS_EXPORT ButtonController {
@@ -21,12 +19,6 @@
                    std::unique_ptr<ButtonControllerDelegate> delegate);
   virtual ~ButtonController();
 
-  // Convenience method for downcasting; the ButtonController implementation
-  // returns null.
-  // TODO(cyan): Remove this method and have MenuButton store a data member of
-  // concrete type MenuButtonController*.
-  virtual MenuButtonController* AsMenuButtonController();
-
   // Methods that parallel View::On<Event> handlers:
   virtual bool OnMousePressed(const ui::MouseEvent& event);
   virtual void OnMouseReleased(const ui::MouseEvent& event);
diff --git a/ui/views/controls/button/button_controller_delegate.h b/ui/views/controls/button/button_controller_delegate.h
index dab98c3..8c32a47 100644
--- a/ui/views/controls/button/button_controller_delegate.h
+++ b/ui/views/controls/button/button_controller_delegate.h
@@ -28,7 +28,7 @@
   // Parallels method views::InkDropEventHandler::GetInkDrop:
   virtual InkDrop* GetInkDrop() = 0;
 
-  // Parallels method views::View:
+  // Parallels methods in views::View:
   virtual int GetDragOperations(const gfx::Point& press_pt) = 0;
   virtual bool InDrag() = 0;
 
@@ -37,6 +37,8 @@
 
  private:
   Button* button_;
+
+  DISALLOW_COPY_AND_ASSIGN(ButtonControllerDelegate);
 };
 
 }  // namespace views
diff --git a/ui/views/controls/button/menu_button.cc b/ui/views/controls/button/menu_button.cc
index 927f64d..2b2a7b8 100644
--- a/ui/views/controls/button/menu_button.cc
+++ b/ui/views/controls/button/menu_button.cc
@@ -19,15 +19,14 @@
                        int button_context)
     : LabelButton(nullptr, text, button_context) {
   SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  SetButtonController(std::make_unique<MenuButtonController>(
-      this, menu_button_listener, CreateButtonControllerDelegate()));
+  std::unique_ptr<MenuButtonController> menu_button_controller =
+      std::make_unique<MenuButtonController>(this, menu_button_listener,
+                                             CreateButtonControllerDelegate());
+  menu_button_controller_ = menu_button_controller.get();
+  SetButtonController(std::move(menu_button_controller));
 }
 MenuButton::~MenuButton() = default;
 
-MenuButtonController* MenuButton::button_controller() const {
-  return Button::button_controller()->AsMenuButtonController();
-}
-
 bool MenuButton::Activate(const ui::Event* event) {
   return button_controller()->Activate(event);
 }
diff --git a/ui/views/controls/button/menu_button.h b/ui/views/controls/button/menu_button.h
index d225527f..fcc74fa 100644
--- a/ui/views/controls/button/menu_button.h
+++ b/ui/views/controls/button/menu_button.h
@@ -35,7 +35,9 @@
              int button_context = style::CONTEXT_BUTTON);
   ~MenuButton() override;
 
-  MenuButtonController* button_controller() const;
+  MenuButtonController* button_controller() const {
+    return menu_button_controller_;
+  }
 
   bool Activate(const ui::Event* event);
 
@@ -53,6 +55,8 @@
   void NotifyClick(const ui::Event& event) final;
 
  private:
+  MenuButtonController* menu_button_controller_;
+
   DISALLOW_COPY_AND_ASSIGN(MenuButton);
 };
 
diff --git a/ui/views/controls/button/menu_button_controller.cc b/ui/views/controls/button/menu_button_controller.cc
index 0699575..fdda1a16 100644
--- a/ui/views/controls/button/menu_button_controller.cc
+++ b/ui/views/controls/button/menu_button_controller.cc
@@ -70,10 +70,6 @@
 
 MenuButtonController::~MenuButtonController() = default;
 
-MenuButtonController* MenuButtonController::AsMenuButtonController() {
-  return this;
-}
-
 bool MenuButtonController::OnMousePressed(const ui::MouseEvent& event) {
   if (button()->request_focus_on_press())
     button()->RequestFocus();
diff --git a/ui/views/controls/button/menu_button_controller.h b/ui/views/controls/button/menu_button_controller.h
index 7932afb..9afcbb8 100644
--- a/ui/views/controls/button/menu_button_controller.h
+++ b/ui/views/controls/button/menu_button_controller.h
@@ -46,7 +46,6 @@
   ~MenuButtonController() override;
 
   // view::ButtonController
-  MenuButtonController* AsMenuButtonController() override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
   void OnMouseMoved(const ui::MouseEvent& event) override;
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index 5ca281f..21379b8d 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -19,6 +19,8 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/menu_model.h"
 #include "ui/base/ui_base_features.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/gfx/animation/animation.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
@@ -216,7 +218,16 @@
 bool MenuItemView::HandleAccessibleAction(const ui::AXActionData& action_data) {
   if (action_data.action != ax::mojom::Action::kDoDefault)
     return View::HandleAccessibleAction(action_data);
-  GetMenuController()->Accept(this, ui::EF_NONE);
+
+  // kDoDefault in View would simulate a mouse click in the center of this
+  // MenuItemView. However, mouse events for menus are dispatched via
+  // Widget::SetCapture() to the MenuController rather than to MenuItemView, so
+  // there is no effect. VKEY_RETURN provides a better UX anyway, since it will
+  // move focus to a submenu.
+  ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, ui::DomCode::ENTER,
+                     ui::EF_NONE, ui::DomKey::ENTER, ui::EventTimeForNow());
+  GetMenuController()->SetSelection(this, MenuController::SELECTION_DEFAULT);
+  GetMenuController()->OnWillDispatchKeyEvent(&event);
   return true;
 }
 
diff --git a/ui/views/controls/scrollbar/scroll_bar.cc b/ui/views/controls/scrollbar/scroll_bar.cc
index 0b66dc8e..2679f2ad 100644
--- a/ui/views/controls/scrollbar/scroll_bar.cc
+++ b/ui/views/controls/scrollbar/scroll_bar.cc
@@ -405,7 +405,7 @@
     thumb_position = thumb_position - (thumb_size / 2);
   float result = (thumb_position * (contents_size_ - viewport_size_)) /
                  (track_size - thumb_size);
-  return gfx::ToFlooredInt(result);
+  return gfx::ToRoundedInt(result);
 }
 
 void ScrollBar::SetContentsScrollOffset(int contents_scroll_offset) {
diff --git a/ui/views/controls/slider.cc b/ui/views/controls/slider.cc
index 5c82cb6..ebb9cb4 100644
--- a/ui/views/controls/slider.cc
+++ b/ui/views/controls/slider.cc
@@ -26,14 +26,6 @@
 
 namespace {
 constexpr int kSlideValueChangeDurationMs = 150;
-
-// The image chunks.
-enum BorderElements {
-  LEFT,
-  CENTER_LEFT,
-  CENTER_RIGHT,
-  RIGHT,
-};
 }  // namespace
 
 namespace views {
diff --git a/ui/views/controls/textfield/textfield_model.cc b/ui/views/controls/textfield/textfield_model.cc
index e50e979..4c3328e4 100644
--- a/ui/views/controls/textfield/textfield_model.cc
+++ b/ui/views/controls/textfield/textfield_model.cc
@@ -27,10 +27,10 @@
 // Commit() marks an edit as an independent operation that shouldn't be merged.
 class Edit {
  public:
-  enum Type {
-    INSERT_EDIT,
-    DELETE_EDIT,
-    REPLACE_EDIT,
+  enum class Type {
+    kInsert,
+    kDelete,
+    kReplace,
   };
 
   virtual ~Edit() = default;
@@ -55,7 +55,7 @@
     // user deletes characters then hits return. In this case, the
     // delete should be treated as separate edit that can be undone
     // and should not be merged with the replace edit.
-    if (type_ != DELETE_EDIT && edit->force_merge()) {
+    if (type_ != Type::kDelete && edit->force_merge()) {
       MergeReplace(edit);
       return true;
     }
@@ -109,7 +109,7 @@
   // Merge the replace edit into the current edit. This handles the special case
   // where an omnibox autocomplete string is set after a new character is typed.
   void MergeReplace(const Edit* edit) {
-    CHECK_EQ(REPLACE_EDIT, edit->type_);
+    CHECK_EQ(Type::kReplace, edit->type_);
     CHECK_EQ(0U, edit->old_text_start_);
     CHECK_EQ(0U, edit->new_text_start_);
     base::string16 old_text = edit->old_text_;
@@ -151,7 +151,7 @@
 class InsertEdit : public Edit {
  public:
   InsertEdit(bool mergeable, const base::string16& new_text, size_t at)
-      : Edit(INSERT_EDIT,
+      : Edit(Type::kInsert,
              mergeable ? MergeType::kMergeable : MergeType::kDoNotMerge,
              base::string16(),
              at,
@@ -163,7 +163,8 @@
 
   // Edit implementation.
   bool DoMerge(const Edit* edit) override {
-    if (edit->type() != INSERT_EDIT || new_text_end() != edit->new_text_start_)
+    if (edit->type() != Type::kInsert ||
+        new_text_end() != edit->new_text_start_)
       return false;
     // If continuous edit, merge it.
     // TODO(oshima): gtk splits edits between whitespace. Find out what
@@ -184,7 +185,7 @@
               size_t new_cursor_pos,
               const base::string16& new_text,
               size_t new_text_start)
-      : Edit(REPLACE_EDIT,
+      : Edit(Type::kReplace,
              merge_type,
              old_text,
              old_text_start,
@@ -196,7 +197,7 @@
 
   // Edit implementation.
   bool DoMerge(const Edit* edit) override {
-    if (edit->type() == DELETE_EDIT ||
+    if (edit->type() == Type::kDelete ||
         new_text_end() != edit->old_text_start_ ||
         edit->old_text_start_ != edit->new_text_start_)
       return false;
@@ -214,7 +215,7 @@
              size_t text_start,
              bool backward,
              gfx::Range old_selection)
-      : Edit(DELETE_EDIT,
+      : Edit(Type::kDelete,
              mergeable ? MergeType::kMergeable : MergeType::kDoNotMerge,
              text,
              text_start,
@@ -226,7 +227,7 @@
 
   // Edit implementation.
   bool DoMerge(const Edit* edit) override {
-    if (edit->type() != DELETE_EDIT)
+    if (edit->type() != Type::kDelete)
       return false;
 
     if (delete_backward_) {
@@ -299,11 +300,6 @@
 
 }  // namespace
 
-using internal::Edit;
-using internal::DeleteEdit;
-using internal::InsertEdit;
-using internal::ReplaceEdit;
-
 /////////////////////////////////////////////////////////////////
 // TextfieldModel: public
 
@@ -679,7 +675,7 @@
       composition_range_.start(), composition_range_.length());
   // TODO(oshima): current behavior on ChromeOS is a bit weird and not
   // sure exactly how this should work. Find out and fix if necessary.
-  AddOrMergeEditHistory(std::make_unique<InsertEdit>(
+  AddOrMergeEditHistory(std::make_unique<internal::InsertEdit>(
       false, composition, composition_range_.start()));
   render_text_->SetCursorPosition(composition_range_.end());
   ClearComposition();
@@ -770,8 +766,8 @@
   const base::string16 old_text = text().substr(old_text_start, range.length());
   bool backward = range.is_reversed();
   gfx::Range curr_selection = render_text_->selection();
-  auto edit = std::make_unique<DeleteEdit>(mergeable, old_text, old_text_start,
-                                           backward, curr_selection);
+  auto edit = std::make_unique<internal::DeleteEdit>(
+      mergeable, old_text, old_text_start, backward, curr_selection);
   edit->Redo(this);
   AddOrMergeEditHistory(std::move(edit));
 }
@@ -792,7 +788,7 @@
                                              size_t new_text_start) {
   size_t old_text_start = replacement_range.GetMin();
   bool backward = replacement_range.is_reversed();
-  auto edit = std::make_unique<ReplaceEdit>(
+  auto edit = std::make_unique<internal::ReplaceEdit>(
       merge_type, GetTextFromRange(replacement_range), old_text_start,
       render_text_->selection(), backward, new_cursor_pos, new_text,
       new_text_start);
@@ -802,13 +798,14 @@
 
 void TextfieldModel::ExecuteAndRecordInsert(const base::string16& new_text,
                                             bool mergeable) {
-  auto edit =
-      std::make_unique<InsertEdit>(mergeable, new_text, GetCursorPosition());
+  auto edit = std::make_unique<internal::InsertEdit>(mergeable, new_text,
+                                                     GetCursorPosition());
   edit->Redo(this);
   AddOrMergeEditHistory(std::move(edit));
 }
 
-void TextfieldModel::AddOrMergeEditHistory(std::unique_ptr<Edit> edit) {
+void TextfieldModel::AddOrMergeEditHistory(
+    std::unique_ptr<internal::Edit> edit) {
   ClearRedoHistory();
 
   if (current_edit_ != edit_history_.end() &&
diff --git a/ui/webui/resources/cr_components/chromeos/BUILD.gn b/ui/webui/resources/cr_components/chromeos/BUILD.gn
index 3c7e363..895487a 100644
--- a/ui/webui/resources/cr_components/chromeos/BUILD.gn
+++ b/ui/webui/resources/cr_components/chromeos/BUILD.gn
@@ -9,6 +9,7 @@
 group("closure_compile") {
   deps = [
     ":chromeos_resources",
+    "cellular_setup:closure_compile",
     "multidevice_setup:closure_compile",
     "network:closure_compile",
     "quick_unlock:closure_compile",
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn b/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn
new file mode 100644
index 0000000..98f14a7
--- /dev/null
+++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+assert(is_chromeos, "MultiDevice UI is Chrome OS only.")
+
+js_type_check("closure_compile") {
+  deps = [
+    ":cellular_setup",
+  ]
+}
+
+js_library("cellular_setup") {
+  deps = [
+    "//ui/webui/resources/js:i18n_behavior",
+  ]
+}
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/OWNERS b/ui/webui/resources/cr_components/chromeos/cellular_setup/OWNERS
new file mode 100644
index 0000000..75e2f312
--- /dev/null
+++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/OWNERS
@@ -0,0 +1,2 @@
+azeemarshad@chromium.org
+khorimoto@chromium.org
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html
new file mode 100644
index 0000000..11c88bf3
--- /dev/null
+++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html
@@ -0,0 +1,12 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+
+<dom-module id="cellular-setup">
+  <template>
+    <!-- TODO(azeemarshad): Replace button with actual content.-->
+    <button>[[i18n('cancel')]]</button>
+  </template>
+  <script src="cellular_setup.js">
+  </script>
+</dom-module>
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js
new file mode 100644
index 0000000..b4e2344
--- /dev/null
+++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js
@@ -0,0 +1,10 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// TODO(azeemarshad): Implement cellular setup UI.
+Polymer({
+  is: 'cellular-setup',
+
+  behaviors: [I18nBehavior],
+});
diff --git a/ui/webui/resources/cr_components/cr_components_resources.grdp b/ui/webui/resources/cr_components/cr_components_resources.grdp
index 8c5d906e..6248ce7 100644
--- a/ui/webui/resources/cr_components/cr_components_resources.grdp
+++ b/ui/webui/resources/cr_components/cr_components_resources.grdp
@@ -259,6 +259,16 @@
                type="chrome_html"
                compress="gzip" />
 
+    <!-- Shared between cellular setup flow and OOBE. -->
+    <structure name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_CELLULAR_SETUP_BROWSER_HTML"
+               file="cr_components/chromeos/cellular_setup/cellular_setup.html"
+               type="chrome_html"
+               compress="gzip" />
+    <structure name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_CELLULAR_SETUP_BROWSER_JS"
+               file="cr_components/chromeos/cellular_setup/cellular_setup.js"
+               type="chrome_html"
+               compress="gzip" />
+
     <!-- Shared between MultiDevice setup flow and OOBE. -->
     <structure name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_MULTIDEVICE_SETUP_BROWSER_PROXY_HTML"
                file="cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html"