diff --git a/DEPS b/DEPS
index 6b8be416..d7a4df9d 100644
--- a/DEPS
+++ b/DEPS
@@ -121,7 +121,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'd41c1876d8341e3486939b93d266975e81950147',
+  'skia_revision': 'fad5c773f7b60d2528dae4ccefef7bb5501f0f7b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -133,7 +133,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': '5904ee3f58e31185d588c9568aad065a59f72b1e',
+  'angle_revision': 'd51fbe347e70b1d3c338a215743fab079d1079e0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -145,7 +145,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': '578e24839231b120681cb75dde5d47917b592c20',
+  'pdfium_revision': 'b600f15d3895afac7e6a39b309d59c4229b177f3',
   # 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.
@@ -679,7 +679,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '19ec8ef577ff3efc893b14058a8d7b4a0f068aee',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '33625e18d47e2f6c47ca540c15bb40c745230fbb',
       'condition': 'checkout_linux',
   },
 
@@ -704,7 +704,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'db34d87aff442e9676506dda26535c7fecee3a02',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'eb2767b2eb245bb54b1738ebb7bf4655ba390b44',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1036,7 +1036,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '11455bfdc0c5473e750a28f98bd24dff5a1fbe35',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '71b05185eb636b7325e42376892a6b4ce6e63b98',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1240,7 +1240,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@bfb698e79191c48a05d487152ef07d573a994ebc',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@debfdbae2ec3dee739aeb1b186217f9511e6f02d',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index adf15ef8..20785e6a 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -29,7 +29,6 @@
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/multi_profile_uma.h"
 #include "ash/new_window_controller.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/notification_utils.h"
 #include "ash/public/interfaces/accessibility_controller.mojom.h"
@@ -649,8 +648,7 @@
 }
 
 bool CanHandleStartVoiceInteraction() {
-  return chromeos::switches::IsVoiceInteractionFlagsEnabled() ||
-         chromeos::switches::IsAssistantEnabled();
+  return chromeos::switches::IsAssistantEnabled();
 }
 
 void HandleToggleVoiceInteraction(const ui::Accelerator& accelerator) {
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index 99990ca..2a0d2ae 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "ash/app_list/app_list_metrics.h"
 #include "ash/app_list/app_list_view_delegate.h"
 #include "ash/app_list/model/app_list_model.h"
 #include "ash/app_list/model/app_list_model_observer.h"
@@ -17,7 +18,6 @@
 #include "ash/app_list/presenter/app_list_presenter_impl.h"
 #include "ash/ash_export.h"
 #include "ash/display/window_tree_host_manager.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/assistant/default_voice_interaction_observer.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/interfaces/app_list.mojom.h"
diff --git a/ash/app_list/app_list_metrics.h b/ash/app_list/app_list_metrics.h
index a758b54..ada3395 100644
--- a/ash/app_list/app_list_metrics.h
+++ b/ash/app_list/app_list_metrics.h
@@ -23,6 +23,72 @@
 constexpr char kAppListHideInputLatencyHistogram[] =
     "Apps.AppListHide.InputLatency";
 
+// The UMA histogram that logs usage of suggested and regular apps.
+constexpr char kAppListAppLaunched[] = "Apps.AppListAppLaunched";
+
+// The UMA histogram that logs usage of suggested and regular apps while the
+// fullscreen launcher is enabled.
+constexpr char kAppListAppLaunchedFullscreen[] =
+    "Apps.AppListAppLaunchedFullscreen";
+
+// The UMA histogram that logs different ways to move an app in app list's apps
+// grid.
+constexpr char kAppListAppMovingType[] = "Apps.AppListAppMovingType";
+
+// The UMA histogram that logs the creation time of the AppListView.
+constexpr char kAppListCreationTimeHistogram[] = "Apps.AppListCreationTime";
+
+// The UMA histogram that logs usage of state transitions in the new
+// app list UI.
+constexpr char kAppListStateTransitionSourceHistogram[] =
+    "Apps.AppListStateTransitionSource";
+
+// The UMA histogram that logs the source of vertical page switcher usage in the
+// app list.
+constexpr char kAppListPageSwitcherSourceHistogram[] =
+    "Apps.AppListPageSwitcherSource";
+
+// The UMA histogram that logs usage of the original and redesigned folders.
+constexpr char kAppListFolderOpenedHistogram[] = "Apps.AppListFolderOpened";
+
+// The UMA histogram that logs how the app list transitions from peeking to
+// fullscreen.
+constexpr char kAppListPeekingToFullscreenHistogram[] =
+    "Apps.AppListPeekingToFullscreenSource";
+
+// The UMA histogram that logs how the app list is shown.
+constexpr char kAppListToggleMethodHistogram[] = "Apps.AppListShowSource";
+
+// The UMA histogram that logs which page gets opened by the user.
+constexpr char kPageOpenedHistogram[] = "Apps.AppListPageOpened";
+
+// The UMA histogram that logs how many apps users have in folders.
+constexpr char kNumberOfAppsInFoldersHistogram[] =
+    "Apps.AppsInFolders.FullscreenAppListEnabled";
+
+// The UMA histogram that logs how many folders users have.
+constexpr char kNumberOfFoldersHistogram[] = "Apps.NumberOfFolders";
+
+// The UMA histogram that logs how many pages users have in top level apps grid.
+constexpr char kNumberOfPagesHistogram[] = "Apps.NumberOfPages";
+
+// The UMA histogram that logs how many pages with empty slots users have in top
+// level apps grid.
+constexpr char kNumberOfPagesNotFullHistogram[] = "Apps.NumberOfPagesNotFull";
+
+// The UMA histogram that logs the type of search result opened.
+constexpr char kSearchResultOpenDisplayTypeHistogram[] =
+    "Apps.AppListSearchResultOpenDisplayType";
+
+// The UMA histogram that logs how long the search query was when a result was
+// opened.
+constexpr char kSearchQueryLength[] = "Apps.AppListSearchQueryLength";
+
+// The UMA histogram that logs the Manhattan distance from the origin of the
+// search results to the selected result.
+constexpr char kSearchResultDistanceFromOrigin[] =
+    "Apps.AppListSearchResultDistanceFromOrigin";
+
 // These are used in histograms, do not remove/renumber entries. If you're
 // adding to this enum with the intention that it will be logged, update the
 // AppListZeroStateSearchResultUserActionType enum listing in
@@ -43,6 +109,83 @@
   kMaxValue = kRemovalCanceled,
 };
 
+// The different ways that the app list can transition from PEEKING to
+// FULLSCREEN_ALL_APPS. These values are written to logs.  New enum
+// values can be added, but existing enums must never be renumbered or deleted
+// and reused.
+enum AppListPeekingToFullscreenSource {
+  kSwipe = 0,
+  kExpandArrow = 1,
+  kMousepadScroll = 2,
+  kMousewheelScroll = 3,
+  kMaxPeekingToFullscreen = 4,
+};
+
+// The different ways the app list can be shown. These values are written to
+// logs.  New enum values can be added, but existing enums must never be
+// renumbered or deleted and reused.
+enum AppListShowSource {
+  kSearchKey = 0,
+  kShelfButton = 1,
+  kSwipeFromShelf = 2,
+  kTabletMode = 3,
+  kMaxAppListToggleMethod = 4,
+};
+
+// The two versions of folders. These values are written to logs.  New enum
+// values can be added, but existing enums must never be renumbered or deleted
+// and reused.
+enum AppListFolderOpened {
+  kOldFolders = 0,
+  kFullscreenAppListFolders = 1,
+  kMaxFolderOpened = 2,
+};
+
+// The valid AppListState transitions. These values are written to logs.  New
+// enum values can be added, but existing enums must never be renumbered or
+// deleted and reused. If adding a state transition, add it to the switch
+// statement in AppListView::GetAppListStateTransitionSource.
+enum AppListStateTransitionSource {
+  kFullscreenAllAppsToClosed = 0,
+  kFullscreenAllAppsToFullscreenSearch = 1,
+  kFullscreenAllAppsToPeeking = 2,
+  kFullscreenSearchToClosed = 3,
+  kFullscreenSearchToFullscreenAllApps = 4,
+  kHalfToClosed = 5,
+  KHalfToFullscreenSearch = 6,
+  kHalfToPeeking = 7,
+  kPeekingToClosed = 8,
+  kPeekingToFullscreenAllApps = 9,
+  kPeekingToHalf = 10,
+  kMaxAppListStateTransition = 11,
+};
+
+// The different ways to change pages in the app list's app grid. These values
+// are written to logs.  New enum values can be added, but existing enums must
+// never be renumbered or deleted and reused.
+enum AppListPageSwitcherSource {
+  kTouchPageIndicator = 0,
+  kClickPageIndicator = 1,
+  kSwipeAppGrid = 2,
+  kFlingAppGrid = 3,
+  kMouseWheelScroll = 4,
+  kMousePadScroll = 5,
+  kDragAppToBorder = 6,
+  kMaxAppListPageSwitcherSource = 7,
+};
+
+// The different ways to move an app in app list's apps grid. These values are
+// written to logs. New enum values can be added, but existing enums must never
+// be renumbered or deleted and reused.
+enum AppListAppMovingType {
+  kMoveIntoFolder = 0,
+  kMoveOutOfFolder = 1,
+  kMoveIntoAnotherFolder = 2,
+  kReorderInFolder = 3,
+  kReorderInTopLevel = 4,
+  kMaxAppListAppMovingType = 5,
+};
+
 void RecordFolderShowHideAnimationSmoothness(int actual_frames,
                                              int ideal_duration_ms,
                                              float refresh_rate);
diff --git a/ash/app_list/app_list_presenter_delegate_impl.cc b/ash/app_list/app_list_presenter_delegate_impl.cc
index 4709e2e4..1bc721e 100644
--- a/ash/app_list/app_list_presenter_delegate_impl.cc
+++ b/ash/app_list/app_list_presenter_delegate_impl.cc
@@ -7,7 +7,6 @@
 #include "ash/app_list/app_list_controller_impl.h"
 #include "ash/app_list/presenter/app_list_presenter_impl.h"
 #include "ash/app_list/views/app_list_view.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/shelf_types.h"
diff --git a/ash/app_list/app_list_util.cc b/ash/app_list/app_list_util.cc
index fad545a..c8e2401 100644
--- a/ash/app_list/app_list_util.cc
+++ b/ash/app_list/app_list_util.cc
@@ -4,41 +4,48 @@
 
 #include "ash/app_list/app_list_util.h"
 
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/focus/focus_manager.h"
 
 namespace app_list {
 
-bool CanProcessLeftRightKeyTraversal(const ui::KeyEvent& event) {
+bool IsUnhandledUnmodifiedEvent(const ui::KeyEvent& event) {
   if (event.handled() || event.type() != ui::ET_KEY_PRESSED)
     return false;
 
-  if (event.key_code() != ui::VKEY_LEFT && event.key_code() != ui::VKEY_RIGHT)
-    return false;
-
   if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown())
     return false;
 
   return true;
 }
 
-bool CanProcessUpDownKeyTraversal(const ui::KeyEvent& event) {
-  if (event.handled() || event.type() != ui::ET_KEY_PRESSED)
+bool IsUnhandledLeftRightKeyEvent(const ui::KeyEvent& event) {
+  if (!IsUnhandledUnmodifiedEvent(event))
     return false;
 
-  if (event.key_code() != ui::VKEY_UP && event.key_code() != ui::VKEY_DOWN)
+  return event.key_code() == ui::VKEY_LEFT ||
+         event.key_code() == ui::VKEY_RIGHT;
+}
+
+bool IsUnhandledUpDownKeyEvent(const ui::KeyEvent& event) {
+  if (!IsUnhandledUnmodifiedEvent(event))
     return false;
 
-  if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown())
+  return event.key_code() == ui::VKEY_UP || event.key_code() == ui::VKEY_DOWN;
+}
+
+bool IsUnhandledArrowKeyEvent(const ui::KeyEvent& event) {
+  if (!IsUnhandledUnmodifiedEvent(event))
     return false;
 
-  return true;
+  return event.key_code() == ui::VKEY_DOWN ||
+         event.key_code() == ui::VKEY_RIGHT ||
+         event.key_code() == ui::VKEY_LEFT || event.key_code() == ui::VKEY_UP;
 }
 
 bool ProcessLeftRightKeyTraversalForTextfield(views::Textfield* textfield,
                                               const ui::KeyEvent& key_event) {
-  DCHECK(CanProcessLeftRightKeyTraversal(key_event));
+  DCHECK(IsUnhandledLeftRightKeyEvent(key_event));
 
   const bool move_focus_reverse = base::i18n::IsRTL()
                                       ? key_event.key_code() == ui::VKEY_RIGHT
diff --git a/ash/app_list/app_list_util.h b/ash/app_list/app_list_util.h
index 9a1cfa47..dc951058 100644
--- a/ash/app_list/app_list_util.h
+++ b/ash/app_list/app_list_util.h
@@ -14,13 +14,17 @@
 
 namespace app_list {
 
-// Returns true if the key event can be handled to do left or right focus
-// traversal.
-APP_LIST_EXPORT bool CanProcessLeftRightKeyTraversal(const ui::KeyEvent& event);
+// Returns true if the key event is an unhandled left or right arrow (unmodified
+// by ctrl, shift, or alt)
+APP_LIST_EXPORT bool IsUnhandledLeftRightKeyEvent(const ui::KeyEvent& event);
 
-// Returns true if the key event can be handled to do up or down focus
-// traversal.
-APP_LIST_EXPORT bool CanProcessUpDownKeyTraversal(const ui::KeyEvent& event);
+// Returns true if the key event is an unhandled up or down arrow (unmodified by
+// ctrl, shift, or alt)
+APP_LIST_EXPORT bool IsUnhandledUpDownKeyEvent(const ui::KeyEvent& event);
+
+// Returns true if the key event is an unhandled arrow key event of any type
+// (unmodified by ctrl, shift, or alt)
+APP_LIST_EXPORT bool IsUnhandledArrowKeyEvent(const ui::KeyEvent& event);
 
 // Processes left/right key traversal for the given Textfield. Returns true
 // if focus is moved.
diff --git a/ash/app_list/model/folder_image.cc b/ash/app_list/model/folder_image.cc
index fc385e482..fb3d95ff 100644
--- a/ash/app_list/model/folder_image.cc
+++ b/ash/app_list/model/folder_image.cc
@@ -10,7 +10,6 @@
 #include "ash/app_list/model/app_list_item.h"
 #include "ash/app_list/model/app_list_item_list.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/ash/app_list/pagination_controller.cc b/ash/app_list/pagination_controller.cc
index 595183e0..73a6743 100644
--- a/ash/app_list/pagination_controller.cc
+++ b/ash/app_list/pagination_controller.cc
@@ -4,8 +4,8 @@
 
 #include "ash/app_list/pagination_controller.h"
 
+#include "ash/app_list/app_list_metrics.h"
 #include "ash/app_list/pagination_model.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/metrics/histogram_macros.h"
 #include "ui/events/event.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/ash/app_list/pagination_model.cc b/ash/app_list/pagination_model.cc
index c47cba7..320e278 100644
--- a/ash/app_list/pagination_model.cc
+++ b/ash/app_list/pagination_model.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 
 #include "ash/app_list/pagination_model_observer.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ui/gfx/animation/slide_animation.h"
 
 namespace app_list {
diff --git a/ash/app_list/presenter/app_list_presenter_impl.cc b/ash/app_list/presenter/app_list_presenter_impl.cc
index 675351d..193d21f 100644
--- a/ash/app_list/presenter/app_list_presenter_impl.cc
+++ b/ash/app_list/presenter/app_list_presenter_impl.cc
@@ -12,7 +12,6 @@
 #include "ash/app_list/views/app_list_main_view.h"
 #include "ash/app_list/views/app_list_view.h"
 #include "ash/app_list/views/contents_view.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "base/bind.h"
diff --git a/ash/app_list/test/app_list_test_helper.h b/ash/app_list/test/app_list_test_helper.h
index 965f8156..43b1506 100644
--- a/ash/app_list/test/app_list_test_helper.h
+++ b/ash/app_list/test/app_list_test_helper.h
@@ -7,9 +7,9 @@
 
 #include <memory>
 
+#include "ash/app_list/app_list_metrics.h"
 #include "ash/app_list/model/app_list_view_state.h"
 #include "ash/app_list/test/test_app_list_client.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 
 namespace app_list {
 class AppListView;
diff --git a/ash/app_list/test/app_list_test_model.cc b/ash/app_list/test/app_list_test_model.cc
index 40fd4e0a..21941f1 100644
--- a/ash/app_list/test/app_list_test_model.cc
+++ b/ash/app_list/test/app_list_test_model.cc
@@ -10,7 +10,6 @@
 #include <utility>
 
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc
index e20f9b9..02284f1 100644
--- a/ash/app_list/views/app_list_folder_view.cc
+++ b/ash/app_list/views/app_list_folder_view.cc
@@ -23,7 +23,6 @@
 #include "ash/app_list/views/search_box_view.h"
 #include "ash/app_list/views/top_icon_animation_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_node_data.h"
@@ -544,7 +543,7 @@
 
 bool AppListFolderView::OnKeyPressed(const ui::KeyEvent& event) {
   // Let the FocusManager handle Left/Right keys.
-  if (!CanProcessUpDownKeyTraversal(event))
+  if (!IsUnhandledUpDownKeyEvent(event))
     return false;
 
   if (folder_header_view_->HasTextFocus() && event.key_code() == ui::VKEY_UP) {
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc
index 75a312c..d55bc644 100644
--- a/ash/app_list/views/app_list_item_view.cc
+++ b/ash/app_list/views/app_list_item_view.cc
@@ -13,7 +13,6 @@
 #include "ash/app_list/model/app_list_item.h"
 #include "ash/app_list/views/apps_grid_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/app_list/views/app_list_main_view.cc b/ash/app_list/views/app_list_main_view.cc
index f773433..4fa8a5b 100644
--- a/ash/app_list/views/app_list_main_view.cc
+++ b/ash/app_list/views/app_list_main_view.cc
@@ -20,7 +20,6 @@
 #include "ash/app_list/views/search_box_view.h"
 #include "ash/app_list/views/search_result_base_view.h"
 #include "ash/app_list/views/search_result_page_view.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/bind.h"
 #include "base/callback.h"
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 3e51858..e955127 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -16,7 +16,6 @@
 #include "ash/app_list/views/contents_view.h"
 #include "ash/app_list/views/search_box_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/wallpaper_types.h"
@@ -1492,17 +1491,15 @@
                                                  ->app_list_folder_view()
                                                  ->folder_header_view()
                                                  ->HasTextFocus();
-  if (is_search_box_focused || is_folder_header_view_focused) {
-    // Do not redirect the key event to the |search_box_| when focus is on a
-    // text field.
-    return;
-  }
 
-  if (CanProcessLeftRightKeyTraversal(*event) ||
-      CanProcessUpDownKeyTraversal(*event)) {
-    // Do not redirect the arrow keys that are used to do focus traversal.
+  // Do not redirect the key event to the |search_box_| when focus is on a
+  // text field.
+  if (is_search_box_focused || is_folder_header_view_focused)
     return;
-  }
+
+  // Do not redirect the arrow keys as they are are used for focus traversal.
+  if (IsUnhandledArrowKeyEvent(*event))
+    return;
 
   // Redirect key event to |search_box_|.
   search_box->OnKeyEvent(event);
@@ -1511,11 +1508,11 @@
     search_box->RequestFocus();
     return;
   }
-  if (event->type() == ui::ET_KEY_PRESSED) {
-    // Insert it into search box if the key event is a character. Released
-    // key should not be handled to prevent inserting duplicate character.
+
+  // Insert it into search box if the key event is a character. Released
+  // key should not be handled to prevent inserting duplicate character.
+  if (event->type() == ui::ET_KEY_PRESSED)
     search_box->InsertChar(*event);
-  }
 }
 
 void AppListView::OnScreenKeyboardShown(bool shown) {
diff --git a/ash/app_list/views/app_list_view.h b/ash/app_list/views/app_list_view.h
index 219b7358..d1c93aa 100644
--- a/ash/app_list/views/app_list_view.h
+++ b/ash/app_list/views/app_list_view.h
@@ -9,9 +9,9 @@
 #include <vector>
 
 #include "ash/app_list/app_list_export.h"
+#include "ash/app_list/app_list_metrics.h"
 #include "ash/app_list/app_list_view_delegate.h"
 #include "ash/app_list/model/app_list_view_state.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/callback.h"
 #include "base/macros.h"
 #include "build/build_config.h"
diff --git a/ash/app_list/views/app_list_view_unittest.cc b/ash/app_list/views/app_list_view_unittest.cc
index b561c28..a148dd9 100644
--- a/ash/app_list/views/app_list_view_unittest.cc
+++ b/ash/app_list/views/app_list_view_unittest.cc
@@ -37,7 +37,6 @@
 #include "ash/app_list/views/suggestion_chip_view.h"
 #include "ash/app_list/views/test/apps_grid_view_test_api.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index 301bc2e..0531c6e 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -27,7 +27,6 @@
 #include "ash/app_list/views/search_result_tile_item_view.h"
 #include "ash/app_list/views/top_icon_animation_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "base/guid.h"
@@ -906,7 +905,7 @@
 
 bool AppsGridView::OnKeyPressed(const ui::KeyEvent& event) {
   // Let the FocusManager handle Left/Right keys.
-  if (!CanProcessUpDownKeyTraversal(event))
+  if (!IsUnhandledUpDownKeyEvent(event))
     return false;
 
   return HandleVerticalFocusMovement(event.key_code() ==
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc
index 171d5a5..6997a716 100644
--- a/ash/app_list/views/apps_grid_view_unittest.cc
+++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -30,7 +30,6 @@
 #include "ash/app_list/views/suggestion_chip_container_view.h"
 #include "ash/app_list/views/test/apps_grid_view_test_api.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "base/command_line.h"
diff --git a/ash/app_list/views/contents_view.cc b/ash/app_list/views/contents_view.cc
index 3d64d1d..6f13854 100644
--- a/ash/app_list/views/contents_view.cc
+++ b/ash/app_list/views/contents_view.cc
@@ -21,7 +21,6 @@
 #include "ash/app_list/views/search_result_page_view.h"
 #include "ash/app_list/views/search_result_tile_item_list_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "base/logging.h"
diff --git a/ash/app_list/views/expand_arrow_view.cc b/ash/app_list/views/expand_arrow_view.cc
index 63c603d5d..17225269 100644
--- a/ash/app_list/views/expand_arrow_view.cc
+++ b/ash/app_list/views/expand_arrow_view.cc
@@ -11,7 +11,6 @@
 #include "ash/app_list/views/apps_container_view.h"
 #include "ash/app_list/views/contents_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/vector_icons/vector_icons.h"
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
diff --git a/ash/app_list/views/folder_header_view.cc b/ash/app_list/views/folder_header_view.cc
index e5dfa40..7816fe7c 100644
--- a/ash/app_list/views/folder_header_view.cc
+++ b/ash/app_list/views/folder_header_view.cc
@@ -10,7 +10,6 @@
 #include "ash/app_list/model/app_list_folder_item.h"
 #include "ash/app_list/views/app_list_folder_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "base/macros.h"
@@ -269,7 +268,7 @@
     delegate_->NavigateBack(folder_item_, key_event);
     return true;
   }
-  if (!CanProcessLeftRightKeyTraversal(key_event))
+  if (!IsUnhandledLeftRightKeyEvent(key_event))
     return false;
   return ProcessLeftRightKeyTraversalForTextfield(folder_name_view_, key_event);
 }
diff --git a/ash/app_list/views/folder_header_view_unittest.cc b/ash/app_list/views/folder_header_view_unittest.cc
index acb32856..9f30c30 100644
--- a/ash/app_list/views/folder_header_view_unittest.cc
+++ b/ash/app_list/views/folder_header_view_unittest.cc
@@ -15,7 +15,6 @@
 #include "ash/app_list/test/app_list_test_model.h"
 #include "ash/app_list/views/folder_header_view_delegate.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
diff --git a/ash/app_list/views/page_switcher.cc b/ash/app_list/views/page_switcher.cc
index 04f5aec3..c77a41a1 100644
--- a/ash/app_list/views/page_switcher.cc
+++ b/ash/app_list/views/page_switcher.cc
@@ -8,8 +8,8 @@
 #include <memory>
 #include <utility>
 
+#include "ash/app_list/app_list_metrics.h"
 #include "ash/app_list/pagination_model.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/i18n/number_formatting.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index 5ec9b8c..b5eaf8e8 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -20,7 +20,6 @@
 #include "ash/app_list/views/search_result_base_view.h"
 #include "ash/app_list/views/search_result_page_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/vector_icons/vector_icons.h"
 #include "ash/public/cpp/vector_icons/vector_icons.h"
@@ -245,7 +244,7 @@
 void SearchBoxView::OnKeyEvent(ui::KeyEvent* event) {
   app_list_view_->RedirectKeyEventToSearchBox(event);
 
-  if (!CanProcessUpDownKeyTraversal(*event))
+  if (!IsUnhandledUpDownKeyEvent(*event))
     return;
 
   // If focus is in search box view, up key moves focus to the last element of
@@ -558,7 +557,7 @@
     return false;
   }
 
-  if (CanProcessLeftRightKeyTraversal(key_event))
+  if (IsUnhandledLeftRightKeyEvent(key_event))
     return ProcessLeftRightKeyTraversalForTextfield(search_box(), key_event);
   return false;
 }
diff --git a/ash/app_list/views/search_result_answer_card_view.cc b/ash/app_list/views/search_result_answer_card_view.cc
index d10f070..9145802 100644
--- a/ash/app_list/views/search_result_answer_card_view.cc
+++ b/ash/app_list/views/search_result_answer_card_view.cc
@@ -12,7 +12,6 @@
 #include "ash/app_list/app_list_view_delegate.h"
 #include "ash/app_list/views/app_list_view.h"
 #include "ash/app_list/views/search_result_base_view.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
diff --git a/ash/app_list/views/search_result_answer_card_view_unittest.cc b/ash/app_list/views/search_result_answer_card_view_unittest.cc
index 2d09eb81..a1caad1a 100644
--- a/ash/app_list/views/search_result_answer_card_view_unittest.cc
+++ b/ash/app_list/views/search_result_answer_card_view_unittest.cc
@@ -10,7 +10,6 @@
 #include "ash/app_list/test/app_list_test_view_delegate.h"
 #include "ash/app_list/test/test_search_result.h"
 #include "ash/app_list/views/search_result_view.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "mojo/public/cpp/bindings/binding.h"
diff --git a/ash/app_list/views/search_result_page_view.cc b/ash/app_list/views/search_result_page_view.cc
index a65f74f..c44abbc 100644
--- a/ash/app_list/views/search_result_page_view.cc
+++ b/ash/app_list/views/search_result_page_view.cc
@@ -205,7 +205,7 @@
 
 bool SearchResultPageView::OnKeyPressed(const ui::KeyEvent& event) {
   // Let the FocusManager handle Left/Right keys.
-  if (!CanProcessUpDownKeyTraversal(event))
+  if (!IsUnhandledUpDownKeyEvent(event))
     return false;
 
   views::View* next_focusable_view = nullptr;
diff --git a/ash/app_list/views/search_result_suggestion_chip_view.cc b/ash/app_list/views/search_result_suggestion_chip_view.cc
index 67bd643..c42cff1 100644
--- a/ash/app_list/views/search_result_suggestion_chip_view.cc
+++ b/ash/app_list/views/search_result_suggestion_chip_view.cc
@@ -9,7 +9,6 @@
 #include "ash/app_list/app_list_metrics.h"
 #include "ash/app_list/app_list_view_delegate.h"
 #include "ash/app_list/model/search/search_result.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/internal_app_id_constants.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
diff --git a/ash/app_list/views/search_result_tile_item_list_view.cc b/ash/app_list/views/search_result_tile_item_list_view.cc
index ea09492..5127752 100644
--- a/ash/app_list/views/search_result_tile_item_list_view.cc
+++ b/ash/app_list/views/search_result_tile_item_list_view.cc
@@ -14,7 +14,6 @@
 #include "ash/app_list/views/search_result_page_view.h"
 #include "ash/app_list/views/search_result_tile_item_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/internal_app_id_constants.h"
 #include "base/i18n/rtl.h"
@@ -62,7 +61,8 @@
       separator->SetVisible(false);
       separator->SetBorder(views::CreateEmptyBorder(
           kSeparatorTopPadding, kSeparatorLeftRightPadding,
-          kSearchTileHeight - kSeparatorHeight, kSeparatorLeftRightPadding));
+          AppListConfig::instance().search_tile_height() - kSeparatorHeight,
+          kSeparatorLeftRightPadding));
       separator->SetColor(kSeparatorColor);
 
       separator_views_.push_back(separator);
@@ -149,7 +149,7 @@
 
 bool SearchResultTileItemListView::OnKeyPressed(const ui::KeyEvent& event) {
   // Let the FocusManager handle Left/Right keys.
-  if (!CanProcessUpDownKeyTraversal(event))
+  if (!IsUnhandledUpDownKeyEvent(event))
     return false;
 
   views::View* next_focusable_view = nullptr;
diff --git a/ash/app_list/views/search_result_tile_item_view.cc b/ash/app_list/views/search_result_tile_item_view.cc
index 615bb61..7cb925f 100644
--- a/ash/app_list/views/search_result_tile_item_view.cc
+++ b/ash/app_list/views/search_result_tile_item_view.cc
@@ -14,7 +14,6 @@
 #include "ash/app_list/pagination_model.h"
 #include "ash/app_list/views/app_list_item_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/vector_icons/vector_icons.h"
 #include "base/bind.h"
@@ -567,7 +566,8 @@
                      AppListConfig::instance().grid_tile_height());
   }
 
-  return gfx::Size(kSearchTileWidth, kSearchTileHeight);
+  return gfx::Size(kSearchTileWidth,
+                   AppListConfig::instance().search_tile_height());
 }
 
 bool SearchResultTileItemView::GetTooltipText(const gfx::Point& p,
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc
index ba54a49..9fc2d7a 100644
--- a/ash/app_list/views/search_result_view.cc
+++ b/ash/app_list/views/search_result_view.cc
@@ -16,7 +16,6 @@
 #include "ash/app_list/views/search_result_actions_view.h"
 #include "ash/app_list/views/search_result_list_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/app_list/views/suggestion_chip_container_view.cc b/ash/app_list/views/suggestion_chip_container_view.cc
index 6901809..5e2e044e 100644
--- a/ash/app_list/views/suggestion_chip_container_view.cc
+++ b/ash/app_list/views/suggestion_chip_container_view.cc
@@ -12,7 +12,6 @@
 #include "ash/app_list/views/search_box_view.h"
 #include "ash/app_list/views/search_result_suggestion_chip_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/controls/textfield/textfield.h"
@@ -110,7 +109,7 @@
 
 bool SuggestionChipContainerView::OnKeyPressed(const ui::KeyEvent& event) {
   // Let the FocusManager handle Left/Right keys.
-  if (!CanProcessUpDownKeyTraversal(event))
+  if (!IsUnhandledUpDownKeyEvent(event))
     return false;
 
   // Up key moves focus to the search box. Down key moves focus to the first
diff --git a/ash/app_list/views/top_icon_animation_view.cc b/ash/app_list/views/top_icon_animation_view.cc
index f232a92..f0a4a90f 100644
--- a/ash/app_list/views/top_icon_animation_view.cc
+++ b/ash/app_list/views/top_icon_animation_view.cc
@@ -6,7 +6,6 @@
 
 #include "ash/app_list/views/app_list_item_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/gfx/image/image_skia_operations.h"
diff --git a/ash/assistant/assistant_ui_controller.cc b/ash/assistant/assistant_ui_controller.cc
index ed84ab9e..9ffac793 100644
--- a/ash/assistant/assistant_ui_controller.cc
+++ b/ash/assistant/assistant_ui_controller.cc
@@ -11,6 +11,8 @@
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/util/deep_link_util.h"
 #include "ash/assistant/util/histogram_util.h"
+#include "ash/multi_user/multi_user_window_manager.h"
+#include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/toast/toast_data.h"
@@ -278,6 +280,20 @@
       event_monitor_ = views::EventMonitor::CreateWindowMonitor(
           this, root_window, {ui::ET_MOUSE_PRESSED, ui::ET_TOUCH_PRESSED});
 
+      // We also want to associate the window for Assistant UI with the active
+      // user so that we don't leak across user sessions.
+      auto* window_manager = MultiUserWindowManager::Get();
+      if (window_manager) {
+        const mojom::UserSession* user_session =
+            Shell::Get()->session_controller()->GetUserSession(0);
+        if (user_session) {
+          window_manager->SetWindowOwner(
+              container_view_->GetWidget()->GetNativeWindow(),
+              user_session->user_info->account_id,
+              /*show_for_current_user=*/true);
+        }
+      }
+
       // Only record the entry point when Assistant UI becomes visible.
       assistant::util::RecordAssistantEntryPoint(entry_point.value());
       break;
diff --git a/ash/display/display_prefs.cc b/ash/display/display_prefs.cc
index 442a490e..f8eb2afe 100644
--- a/ash/display/display_prefs.cc
+++ b/ash/display/display_prefs.cc
@@ -654,6 +654,8 @@
 
   DictionaryPrefUpdate update(pref_service, prefs::kDisplayTouchAssociations);
   base::DictionaryValue* pref_data = update.Get();
+  pref_data->Clear();
+
   const display::TouchDeviceManager::TouchAssociationMap& touch_associations =
       touch_device_manager->touch_associations();
 
@@ -703,6 +705,8 @@
   DictionaryPrefUpdate update_port(pref_service,
                                    prefs::kDisplayTouchPortAssociations);
   pref_data = update_port.Get();
+  update_port->Clear();
+
   const display::TouchDeviceManager::PortAssociationMap& port_associations =
       touch_device_manager->port_associations();
 
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index d2291e9..39409e5 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -32,6 +32,7 @@
 #include "components/user_manager/user.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/callback_layer_animation_observer.h"
 #include "ui/compositor/layer_animation_sequence.h"
 #include "ui/compositor/layer_animator.h"
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 7d5e4860..735660b5 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -11,8 +11,6 @@
     "accelerators.h",
     "app_list/app_list_config.cc",
     "app_list/app_list_config.h",
-    "app_list/app_list_constants.cc",
-    "app_list/app_list_constants.h",
     "app_list/app_list_features.cc",
     "app_list/app_list_features.h",
     "app_list/app_list_switches.cc",
diff --git a/ash/public/cpp/app_list/app_list_config.cc b/ash/public/cpp/app_list/app_list_config.cc
index c8e200e8..9f94cb9d 100644
--- a/ash/public/cpp/app_list/app_list_config.cc
+++ b/ash/public/cpp/app_list/app_list_config.cc
@@ -72,7 +72,8 @@
       max_folder_name_chars_(28),
       all_apps_opacity_start_px_(8.0f),
       all_apps_opacity_end_px_(144.0f),
-      search_result_title_font_style_(ui::ResourceBundle::BaseFont) {}
+      search_result_title_font_style_(ui::ResourceBundle::BaseFont),
+      search_tile_height_(90) {}
 
 AppListConfig::~AppListConfig() = default;
 
diff --git a/ash/public/cpp/app_list/app_list_config.h b/ash/public/cpp/app_list/app_list_config.h
index 6e1d74e..07ec9e4 100644
--- a/ash/public/cpp/app_list/app_list_config.h
+++ b/ash/public/cpp/app_list/app_list_config.h
@@ -120,6 +120,7 @@
   ui::ResourceBundle::FontStyle search_result_title_font_style() const {
     return search_result_title_font_style_;
   }
+  int search_tile_height() const { return search_tile_height_; }
 
   gfx::Size grid_icon_size() const {
     return gfx::Size(grid_icon_dimension_, grid_icon_dimension_);
@@ -340,6 +341,9 @@
   // Font style for AppListSearchResultTileItemViews that are not suggested
   // apps.
   const ui::ResourceBundle::FontStyle search_result_title_font_style_;
+
+  // The height of tiles in search result.
+  const int search_tile_height_ = 90;
 };
 
 }  // namespace app_list
diff --git a/ash/public/cpp/app_list/app_list_constants.cc b/ash/public/cpp/app_list/app_list_constants.cc
deleted file mode 100644
index 49c950c..0000000
--- a/ash/public/cpp/app_list/app_list_constants.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/public/cpp/app_list/app_list_constants.h"
-
-#include "build/build_config.h"
-#include "ui/gfx/color_palette.h"
-
-namespace app_list {
-
-// The UMA histogram that logs usage of suggested and regular apps.
-const char kAppListAppLaunched[] = "Apps.AppListAppLaunched";
-
-// The UMA histogram that logs usage of suggested and regular apps while the
-// fullscreen launcher is enabled.
-const char kAppListAppLaunchedFullscreen[] =
-    "Apps.AppListAppLaunchedFullscreen";
-
-// The UMA histogram that logs different ways to move an app in app list's apps
-// grid.
-const char kAppListAppMovingType[] = "Apps.AppListAppMovingType";
-
-// The UMA histogram that logs the creation time of the AppListView.
-const char kAppListCreationTimeHistogram[] = "Apps.AppListCreationTime";
-
-// The UMA histogram that logs usage of state transitions in the new
-// app list UI.
-const char kAppListStateTransitionSourceHistogram[] =
-    "Apps.AppListStateTransitionSource";
-
-// The UMA histogram that logs the source of vertical page switcher usage in the
-// app list.
-const char kAppListPageSwitcherSourceHistogram[] =
-    "Apps.AppListPageSwitcherSource";
-
-// The UMA histogram that logs usage of the original and redesigned folders.
-const char kAppListFolderOpenedHistogram[] = "Apps.AppListFolderOpened";
-
-// The UMA histogram that logs how the app list transitions from peeking to
-// fullscreen.
-const char kAppListPeekingToFullscreenHistogram[] =
-    "Apps.AppListPeekingToFullscreenSource";
-
-// The UMA histogram that logs how the app list is shown.
-const char kAppListToggleMethodHistogram[] = "Apps.AppListShowSource";
-
-// The UMA histogram that logs which page gets opened by the user.
-const char kPageOpenedHistogram[] = "Apps.AppListPageOpened";
-
-// The UMA histogram that logs how many apps users have in folders.
-const char kNumberOfAppsInFoldersHistogram[] =
-    "Apps.AppsInFolders.FullscreenAppListEnabled";
-
-// The UMA histogram that logs how many folders users have.
-const char kNumberOfFoldersHistogram[] = "Apps.NumberOfFolders";
-
-// The UMA histogram that logs how many pages users have in top level apps grid.
-const char kNumberOfPagesHistogram[] = "Apps.NumberOfPages";
-
-// The UMA histogram that logs how many pages with empty slots users have in top
-// level apps grid.
-const char kNumberOfPagesNotFullHistogram[] = "Apps.NumberOfPagesNotFull";
-
-// The UMA histogram that logs the type of search result opened.
-const char kSearchResultOpenDisplayTypeHistogram[] =
-    "Apps.AppListSearchResultOpenDisplayType";
-
-// The UMA histogram that logs how long the search query was when a result was
-// opened.
-const char kSearchQueryLength[] = "Apps.AppListSearchQueryLength";
-
-// The UMA histogram that logs the Manhattan distance from the origin of the
-// search results to the selected result.
-const char kSearchResultDistanceFromOrigin[] =
-    "Apps.AppListSearchResultDistanceFromOrigin";
-
-// The height of tiles in search result.
-const int kSearchTileHeight = 90;
-
-gfx::ShadowValue GetShadowForZHeight(int z_height) {
-  if (z_height <= 0)
-    return gfx::ShadowValue();
-
-  switch (z_height) {
-    case 1:
-      return gfx::ShadowValue(gfx::Vector2d(0, 1), 4,
-                              SkColorSetARGB(0x4C, 0, 0, 0));
-    case 2:
-      return gfx::ShadowValue(gfx::Vector2d(0, 2), 8,
-                              SkColorSetARGB(0x33, 0, 0, 0));
-    default:
-      return gfx::ShadowValue(gfx::Vector2d(0, 8), 24,
-                              SkColorSetARGB(0x3F, 0, 0, 0));
-  }
-}
-
-}  // namespace app_list
diff --git a/ash/public/cpp/app_list/app_list_constants.h b/ash/public/cpp/app_list/app_list_constants.h
deleted file mode 100644
index 144d0d79..0000000
--- a/ash/public/cpp/app_list/app_list_constants.h
+++ /dev/null
@@ -1,125 +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.
-
-#ifndef ASH_PUBLIC_CPP_APP_LIST_APP_LIST_CONSTANTS_H_
-#define ASH_PUBLIC_CPP_APP_LIST_APP_LIST_CONSTANTS_H_
-
-#include <stddef.h>
-
-#include "ash/public/cpp/app_list/app_list_types.h"
-#include "ash/public/cpp/ash_public_export.h"
-#include "build/build_config.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/animation/tween.h"
-#include "ui/gfx/shadow_value.h"
-
-namespace app_list {
-
-// TODO(crbug.com/854836): Move everything here to app_list_config.h.
-
-// The different ways that the app list can transition from PEEKING to
-// FULLSCREEN_ALL_APPS. These values are written to logs.  New enum
-// values can be added, but existing enums must never be renumbered or deleted
-// and reused.
-enum AppListPeekingToFullscreenSource {
-  kSwipe = 0,
-  kExpandArrow = 1,
-  kMousepadScroll = 2,
-  kMousewheelScroll = 3,
-  kMaxPeekingToFullscreen = 4,
-};
-
-// The different ways the app list can be shown. These values are written to
-// logs.  New enum values can be added, but existing enums must never be
-// renumbered or deleted and reused.
-enum AppListShowSource {
-  kSearchKey = 0,
-  kShelfButton = 1,
-  kSwipeFromShelf = 2,
-  kTabletMode = 3,
-  kMaxAppListToggleMethod = 4,
-};
-
-// The two versions of folders. These values are written to logs.  New enum
-// values can be added, but existing enums must never be renumbered or deleted
-// and reused.
-enum AppListFolderOpened {
-  kOldFolders = 0,
-  kFullscreenAppListFolders = 1,
-  kMaxFolderOpened = 2,
-};
-
-// The valid AppListState transitions. These values are written to logs.  New
-// enum values can be added, but existing enums must never be renumbered or
-// deleted and reused. If adding a state transition, add it to the switch
-// statement in AppListView::GetAppListStateTransitionSource.
-enum AppListStateTransitionSource {
-  kFullscreenAllAppsToClosed = 0,
-  kFullscreenAllAppsToFullscreenSearch = 1,
-  kFullscreenAllAppsToPeeking = 2,
-  kFullscreenSearchToClosed = 3,
-  kFullscreenSearchToFullscreenAllApps = 4,
-  kHalfToClosed = 5,
-  KHalfToFullscreenSearch = 6,
-  kHalfToPeeking = 7,
-  kPeekingToClosed = 8,
-  kPeekingToFullscreenAllApps = 9,
-  kPeekingToHalf = 10,
-  kMaxAppListStateTransition = 11,
-};
-
-// The different ways to change pages in the app list's app grid. These values
-// are written to logs.  New enum values can be added, but existing enums must
-// never be renumbered or deleted and reused.
-enum AppListPageSwitcherSource {
-  kTouchPageIndicator = 0,
-  kClickPageIndicator = 1,
-  kSwipeAppGrid = 2,
-  kFlingAppGrid = 3,
-  kMouseWheelScroll = 4,
-  kMousePadScroll = 5,
-  kDragAppToBorder = 6,
-  kMaxAppListPageSwitcherSource = 7,
-};
-
-// The different ways to move an app in app list's apps grid. These values are
-// written to logs. New enum values can be added, but existing enums must never
-// be renumbered or deleted and reused.
-enum AppListAppMovingType {
-  kMoveIntoFolder = 0,
-  kMoveOutOfFolder = 1,
-  kMoveIntoAnotherFolder = 2,
-  kReorderInFolder = 3,
-  kReorderInTopLevel = 4,
-  kMaxAppListAppMovingType = 5,
-};
-
-ASH_PUBLIC_EXPORT extern const char kAppListAppLaunched[];
-ASH_PUBLIC_EXPORT extern const char kAppListAppLaunchedFullscreen[];
-ASH_PUBLIC_EXPORT extern const char kAppListAppMovingType[];
-ASH_PUBLIC_EXPORT extern const char kAppListCreationTimeHistogram[];
-ASH_PUBLIC_EXPORT extern const char kAppListStateTransitionSourceHistogram[];
-ASH_PUBLIC_EXPORT extern const char kAppListPageSwitcherSourceHistogram[];
-ASH_PUBLIC_EXPORT extern const char kAppListFolderOpenedHistogram[];
-ASH_PUBLIC_EXPORT extern const char kAppListPeekingToFullscreenHistogram[];
-ASH_PUBLIC_EXPORT extern const char kAppListToggleMethodHistogram[];
-ASH_PUBLIC_EXPORT extern const char kPageOpenedHistogram[];
-ASH_PUBLIC_EXPORT extern const char kNumberOfAppsInFoldersHistogram[];
-ASH_PUBLIC_EXPORT extern const char kNumberOfFoldersHistogram[];
-ASH_PUBLIC_EXPORT extern const char kNumberOfPagesHistogram[];
-ASH_PUBLIC_EXPORT extern const char kNumberOfPagesNotFullHistogram[];
-
-ASH_PUBLIC_EXPORT extern const char kSearchResultOpenDisplayTypeHistogram[];
-ASH_PUBLIC_EXPORT extern const char kSearchQueryLength[];
-ASH_PUBLIC_EXPORT extern const char kSearchResultDistanceFromOrigin[];
-
-ASH_PUBLIC_EXPORT extern const int kSearchTileHeight;
-
-// Returns the shadow values for a view at |z_height|.
-ASH_PUBLIC_EXPORT gfx::ShadowValue GetShadowForZHeight(int z_height);
-
-}  // namespace app_list
-
-#endif  // ASH_PUBLIC_CPP_APP_LIST_APP_LIST_CONSTANTS_H_
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 9e2adee..f2a7305 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -10,10 +10,10 @@
 
 #include "ash/animation/animation_change_type.h"
 #include "ash/app_list/app_list_controller_impl.h"
+#include "ash/app_list/app_list_metrics.h"
 #include "ash/app_list/home_launcher_gesture_handler.h"
 #include "ash/app_list/model/app_list_view_state.h"
 #include "ash/app_list/views/app_list_view.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
diff --git a/ash/shell.h b/ash/shell.h
index af0db52..2625c1d 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -11,7 +11,6 @@
 
 #include "ash/ash_export.h"
 #include "ash/metrics/user_metrics_recorder.h"
-#include "ash/public/cpp/app_list/app_list_constants.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/session/session_observer.h"
 #include "ash/wm/system_modal_container_event_filter_delegate.h"
@@ -49,7 +48,7 @@
 namespace gfx {
 class Insets;
 class Point;
-}
+}  // namespace gfx
 
 namespace keyboard {
 class KeyboardUIFactory;
diff --git a/base/android/android_image_reader_abi.h b/base/android/android_image_reader_abi.h
index 2c24d86..3b0ba9b 100644
--- a/base/android/android_image_reader_abi.h
+++ b/base/android/android_image_reader_abi.h
@@ -84,6 +84,9 @@
 using pAImageReader_getWindow = media_status_t (*)(AImageReader* reader,
                                                    ANativeWindow** window);
 
+using pAImageReader_getFormat = media_status_t (*)(const AImageReader* reader,
+                                                   int32_t* format);
+
 using pAImageReader_acquireLatestImageAsync =
     media_status_t (*)(AImageReader* reader,
                        AImage** image,
diff --git a/base/android/android_image_reader_compat.cc b/base/android/android_image_reader_compat.cc
index abbf1f23..8db28ef7 100644
--- a/base/android/android_image_reader_compat.cc
+++ b/base/android/android_image_reader_compat.cc
@@ -70,6 +70,7 @@
   LOAD_FUNCTION(libmediandk, AImageReader_newWithUsage);
   LOAD_FUNCTION(libmediandk, AImageReader_setImageListener);
   LOAD_FUNCTION(libmediandk, AImageReader_delete);
+  LOAD_FUNCTION(libmediandk, AImageReader_getFormat);
   LOAD_FUNCTION(libmediandk, AImageReader_getWindow);
   LOAD_FUNCTION(libmediandk, AImageReader_acquireLatestImageAsync);
 
@@ -129,6 +130,12 @@
   AImageReader_delete_(reader);
 }
 
+media_status_t AndroidImageReader::AImageReader_getFormat(
+    const AImageReader* reader,
+    int32_t* format) {
+  return AImageReader_getFormat_(reader, format);
+}
+
 media_status_t AndroidImageReader::AImageReader_getWindow(
     AImageReader* reader,
     ANativeWindow** window) {
diff --git a/base/android/android_image_reader_compat.h b/base/android/android_image_reader_compat.h
index 07311891..b259175 100644
--- a/base/android/android_image_reader_compat.h
+++ b/base/android/android_image_reader_compat.h
@@ -48,6 +48,8 @@
       AImageReader* reader,
       AImageReader_ImageListener* listener);
   void AImageReader_delete(AImageReader* reader);
+  media_status_t AImageReader_getFormat(const AImageReader* reader,
+                                        int32_t* format);
   media_status_t AImageReader_getWindow(AImageReader* reader,
                                         ANativeWindow** window);
   media_status_t AImageReader_acquireLatestImageAsync(AImageReader* reader,
@@ -71,6 +73,7 @@
   pAImageReader_newWithUsage AImageReader_newWithUsage_;
   pAImageReader_setImageListener AImageReader_setImageListener_;
   pAImageReader_delete AImageReader_delete_;
+  pAImageReader_getFormat AImageReader_getFormat_;
   pAImageReader_getWindow AImageReader_getWindow_;
   pAImageReader_acquireLatestImageAsync AImageReader_acquireLatestImageAsync_;
   pANativeWindow_toSurface ANativeWindow_toSurface_;
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java
index 5c81b403..4d248d7 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java
@@ -295,6 +295,7 @@
             Log.i(TAG, "Scanning loaded dex files for test classes.");
             // Mirror TestRequestBuilder.getClassNamesFromClassPath().
             TestLoader loader = new TestLoader();
+            loader.setClassLoader(new ForgivingClassLoader());
             for (DexFile dexFile : mDexFiles) {
                 Enumeration<String> classNames = dexFile.entries();
                 while (classNames.hasMoreElements()) {
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py
index c957bf7..153bb42 100755
--- a/build/android/gyp/compile_resources.py
+++ b/build/android/gyp/compile_resources.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-#
+# encoding: utf-8
 # 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.
@@ -276,6 +276,11 @@
     * Modern ISO 639-1 codes will be renamed to their obsolete variant
       for Indonesian, Hebrew and Yiddish (e.g. 'values-in/ -> values-id/).
 
+    * Norwegian macrolanguage strings will be renamed to Bokmål (main
+      Norway language). See http://crbug.com/920960. In practice this
+      means that 'values-no/ -> values-nb/' unless 'values-nb/' already
+      exists.
+
     * BCP 47 langauge tags will be renamed to an equivalent ISO 639-1
       locale qualifier if possible (e.g. 'values-b+en+US/ -> values-en-rUS').
       Though this is not necessary at the moment, because no third-party
@@ -305,8 +310,8 @@
           raise Exception('Could not substitute locale %s for %s in %s' %
                           (locale, locale2, path))
         if os.path.exists(path2):
-          # This happens sometimes, e.g. the Android support library comes
-          # with both values-sr/ and values-b+sr+Latn/.
+          # This happens sometimes, e.g. some libraries provide both
+          # values-nb/ and values-no/ with the same content.
           continue
         build_utils.MakeDirectory(os.path.dirname(path2))
         shutil.move(path, path2)
diff --git a/build/android/gyp/util/resource_utils.py b/build/android/gyp/util/resource_utils.py
index c6fbebe5..17d67ae 100644
--- a/build/android/gyp/util/resource_utils.py
+++ b/build/android/gyp/util/resource_utils.py
@@ -40,6 +40,7 @@
     'iw': 'he',
     'in': 'id',
     'ji': 'yi',
+    'no': 'nb',  # 'no' is not a real language. http://crbug.com/920960
 }
 
 
diff --git a/build/android/gyp/util/resource_utils_test.py b/build/android/gyp/util/resource_utils_test.py
index c68502a..7fa418e9 100755
--- a/build/android/gyp/util/resource_utils_test.py
+++ b/build/android/gyp/util/resource_utils_test.py
@@ -25,6 +25,7 @@
     'copy_to_clipboard_failure_message': 'Lõikelauale kopeerimine ebaõnnestus'
 }
 
+# pylint: disable=line-too-long
 _EXPECTED_XML_1 = '''<?xml version="1.0" encoding="utf-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 <string name="copy_to_clipboard_failure_message">"Lõikelauale kopeerimine ebaõnnestus"</string>
@@ -32,6 +33,7 @@
 <string name="opening_file_error">"Valit. faili avamine ebaõnnestus"</string>
 </resources>
 '''
+# pylint: enable=line-too-long
 
 _XML_RESOURCES_PREFIX = r'''<?xml version="1.0" encoding="utf-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
@@ -148,6 +150,7 @@
         'he-IL': 'iw-rIL',
         'id': 'in',
         'id-BAR': 'in-rBAR',
+        'nb': 'nb',
         'yi': 'ji'
     }
     for chromium_locale, android_locale in \
@@ -178,6 +181,8 @@
         'in': 'id',
         'in-rBAR': 'id-BAR',
         'id-rBAR': 'id-BAR',
+        'nb': 'nb',
+        'no': 'nb',  # http://crbug.com/920960
     }
     for android_locale, chromium_locale in \
         _TEST_ANDROID_TO_CHROMIUM_LOCALE_MAP.iteritems():
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 22954478..d156f84 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-34369b5e7f0761d645deffe9da5b468f982a3592
\ No newline at end of file
+cebc87ed4b101622e4d556cbfc065d0ecf62351a
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 39698eac..5f29f45b 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-bcbbb02ab5fbf764d103ac937271d4adf9adda17
\ No newline at end of file
+2261dee6accd2cce5bb144be16f42a1f944888fd
\ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION
index 38c1718..6776622f 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=74
 MINOR=0
-BUILD=3684
+BUILD=3685
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java
index d4410cf..3aa3f00 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java
@@ -36,6 +36,9 @@
 import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder;
 import org.chromium.chrome.browser.notifications.NotificationBuilderFactory;
 import org.chromium.chrome.browser.notifications.NotificationConstants;
+import org.chromium.chrome.browser.notifications.NotificationMetadata;
+import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
+import org.chromium.chrome.browser.notifications.PendingIntentProvider;
 import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
 import org.chromium.chrome.browser.util.UrlUtilities;
 import org.chromium.components.offline_items_collection.ContentId;
@@ -63,15 +66,22 @@
      * @param downloadStatus (in progress, paused, successful, failed, deleted, or summary).
      * @param downloadUpdate information about the download (ie. contentId, fileName, icon,
      * isOffTheRecord, etc).
+     * @param notificationId The notification id passed to {@link
+     *         android.app.NotificationManager#notify(String, int, Notification)}.
      * @return Notification that is built based on these parameters.
      */
     public static Notification buildNotification(Context context,
             @DownloadNotificationService.DownloadStatus int downloadStatus,
-            DownloadUpdate downloadUpdate) {
+            DownloadUpdate downloadUpdate, int notificationId) {
         ChromeNotificationBuilder builder =
                 NotificationBuilderFactory
-                        .createChromeNotificationBuilder(
-                                true /* preferCompat */, ChannelDefinitions.ChannelId.DOWNLOADS)
+                        .createChromeNotificationBuilder(true /* preferCompat */,
+                                ChannelDefinitions.ChannelId.DOWNLOADS,
+                                null /* remoteAppPackageName */,
+                                new NotificationMetadata(
+                                        NotificationUmaTracker.SystemNotificationType
+                                                .DOWNLOAD_FILES,
+                                        null /* tag */, notificationId))
                         .setLocalOnly(true)
                         .setGroup(NotificationConstants.GROUP_DOWNLOADS)
                         .setAutoCancel(true);
@@ -126,13 +136,15 @@
                         .addAction(R.drawable.ic_pause_white_24dp,
                                 context.getResources().getString(
                                         R.string.download_notification_pause_button),
-                                buildPendingIntent(
-                                        context, pauseIntent, downloadUpdate.getNotificationId()))
+                                buildPendingIntentProvider(
+                                        context, pauseIntent, downloadUpdate.getNotificationId()),
+                                NotificationUmaTracker.ActionType.DOWNLOAD_PAUSE)
                         .addAction(R.drawable.btn_close_white,
                                 context.getResources().getString(
                                         R.string.download_notification_cancel_button),
-                                buildPendingIntent(
-                                        context, cancelIntent, downloadUpdate.getNotificationId()));
+                                buildPendingIntentProvider(
+                                        context, cancelIntent, downloadUpdate.getNotificationId()),
+                                NotificationUmaTracker.ActionType.DOWNLOAD_CANCEL);
 
                 if (!downloadUpdate.getIsOffTheRecord())
                     builder.setLargeIcon(downloadUpdate.getIcon());
@@ -177,19 +189,21 @@
                         .addAction(R.drawable.ic_file_download_white_24dp,
                                 context.getResources().getString(
                                         R.string.download_notification_resume_button),
-                                buildPendingIntent(
-                                        context, resumeIntent, downloadUpdate.getNotificationId()))
+                                buildPendingIntentProvider(
+                                        context, resumeIntent, downloadUpdate.getNotificationId()),
+                                NotificationUmaTracker.ActionType.DOWNLOAD_RESUME)
                         .addAction(R.drawable.btn_close_white,
                                 context.getResources().getString(
                                         R.string.download_notification_cancel_button),
-                                buildPendingIntent(
-                                        context, cancelIntent, downloadUpdate.getNotificationId()));
+                                buildPendingIntentProvider(
+                                        context, cancelIntent, downloadUpdate.getNotificationId()),
+                                NotificationUmaTracker.ActionType.DOWNLOAD_CANCEL);
 
                 if (!downloadUpdate.getIsOffTheRecord())
                     builder.setLargeIcon(downloadUpdate.getIcon());
 
                 if (downloadUpdate.getIsTransient()) {
-                    builder.setDeleteIntent(buildPendingIntent(
+                    builder.setDeleteIntent(buildPendingIntentProvider(
                             context, cancelIntent, downloadUpdate.getNotificationId()));
                 }
 
@@ -240,9 +254,9 @@
                     ComponentName component = new ComponentName(
                             context.getPackageName(), DownloadBroadcastManager.class.getName());
                     intent.setComponent(component);
-                    builder.setContentIntent(
-                            PendingIntent.getService(context, downloadUpdate.getNotificationId(),
-                                    intent, PendingIntent.FLAG_UPDATE_CURRENT));
+                    builder.setContentIntent(PendingIntentProvider.getService(context,
+                            downloadUpdate.getNotificationId(), intent,
+                            PendingIntent.FLAG_UPDATE_CURRENT));
                 }
 
                 // It's the job of the service to ensure that the default icon is provided when
@@ -284,7 +298,7 @@
             Intent downloadHomeIntent = buildActionIntent(
                     context, ACTION_NOTIFICATION_CLICKED, null, downloadUpdate.getIsOffTheRecord());
             builder.setContentIntent(
-                    PendingIntent.getService(context, downloadUpdate.getNotificationId(),
+                    PendingIntentProvider.getService(context, downloadUpdate.getNotificationId(),
                             downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
         }
 
@@ -315,9 +329,9 @@
      * @param intent Intent to broadcast.
      * @param notificationId ID of the notification.
      */
-    private static PendingIntent buildPendingIntent(
+    private static PendingIntentProvider buildPendingIntentProvider(
             Context context, Intent intent, int notificationId) {
-        return PendingIntent.getService(
+        return PendingIntentProvider.getService(
                 context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
index 599f93f7..691ea3bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -243,7 +243,7 @@
                                                 .setPendingState(pendingState)
                                                 .build();
         Notification notification = DownloadNotificationFactory.buildNotification(
-                context, DownloadStatus.IN_PROGRESS, downloadUpdate);
+                context, DownloadStatus.IN_PROGRESS, downloadUpdate, notificationId);
         updateNotification(notificationId, notification, id,
                 new DownloadSharedPreferenceEntry(id, notificationId, isOffTheRecord,
                         canDownloadWhileMetered, fileName, true, isTransient));
@@ -344,7 +344,7 @@
                                                 .build();
 
         Notification notification = DownloadNotificationFactory.buildNotification(
-                context, DownloadStatus.PAUSED, downloadUpdate);
+                context, DownloadStatus.PAUSED, downloadUpdate, notificationId);
         updateNotification(notificationId, notification, id,
                 new DownloadSharedPreferenceEntry(id, notificationId, isOffTheRecord,
                         canDownloadWhileMetered, fileName, isAutoResumable, isTransient));
@@ -402,7 +402,7 @@
                                                 .setTotalBytes(totalBytes)
                                                 .build();
         Notification notification = DownloadNotificationFactory.buildNotification(
-                context, DownloadStatus.COMPLETED, downloadUpdate);
+                context, DownloadStatus.COMPLETED, downloadUpdate, notificationId);
 
         updateNotification(notificationId, notification, id, null);
         mDownloadForegroundServiceManager.updateDownloadStatus(
@@ -446,7 +446,7 @@
                                                 .setFailState(failState)
                                                 .build();
         Notification notification = DownloadNotificationFactory.buildNotification(
-                context, DownloadStatus.FAILED, downloadUpdate);
+                context, DownloadStatus.FAILED, downloadUpdate, notificationId);
 
         updateNotification(notificationId, notification, id, null);
         mDownloadForegroundServiceManager.updateDownloadStatus(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
index df6833f..fd8ac96 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
@@ -74,15 +74,19 @@
      * sure to keep this list in sync.  Additions should be treated as APPEND ONLY to keep the UMA
      * metric semantics the same over time.
      */
-    @IntDef({ActionType.UNKNOWN})
+    @IntDef({ActionType.UNKNOWN, ActionType.DOWNLOAD_PAUSE, ActionType.DOWNLOAD_RESUME,
+            ActionType.DOWNLOAD_CANCEL})
     @Retention(RetentionPolicy.SOURCE)
     public @interface ActionType {
         int UNKNOWN = -1;
-        // Pause button when an user download is in progress.
-        int DOWNLOAD_FILES_IN_PROGRESS_PAUSE = 0;
-        // Resume button when an user download is in progress.
-        int DOWNLOAD_FILES_IN_PROGRESS_RESUME = 1;
-        int NUM_ENTRIES = 2;
+        // Pause button on user download notification.
+        int DOWNLOAD_PAUSE = 0;
+        // Resume button on user download notification.
+        int DOWNLOAD_RESUME = 1;
+        // Cancel button on user download notification.
+        int DOWNLOAD_CANCEL = 2;
+
+        int NUM_ENTRIES = 3;
     }
 
     private static final String LAST_SHOWN_NOTIFICATION_TYPE_KEY =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 22b1e99..feab79bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -633,7 +633,7 @@
                     params.getReferrer() != null ? params.getReferrer().getPolicy() : 0,
                     params.getIsRendererInitiated(), params.getShouldReplaceCurrentEntry(),
                     params.getHasUserGesture(), params.getShouldClearHistoryList(),
-                    params.getInputStartTimestamp());
+                    params.getInputStartTimestamp(), params.getIntentReceivedTimestamp());
 
             for (TabObserver observer : mObservers) {
                 observer.onLoadUrl(this, params, loadType);
@@ -2952,7 +2952,8 @@
     private native int nativeLoadUrl(long nativeTabAndroid, String url, String initiatorOrigin,
             String extraHeaders, ResourceRequestBody postData, int transition, String referrerUrl,
             int referrerPolicy, boolean isRendererInitiated, boolean shoulReplaceCurrentEntry,
-            boolean hasUserGesture, boolean shouldClearHistoryList, long inputStartTimestamp);
+            boolean hasUserGesture, boolean shouldClearHistoryList, long inputStartTimestamp,
+            long intentReceivedTimestamp);
     private native void nativeSetActiveNavigationEntryTitleForUrl(long nativeTabAndroid, String url,
             String title);
     private native boolean nativePrint(
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index a4252b80..d4d59d6 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-73.0.3683.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-74.0.3684.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 2901130d..c76352f 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -528,7 +528,8 @@
     jboolean should_replace_current_entry,
     jboolean has_user_gesture,
     jboolean should_clear_history_list,
-    jlong input_start_timestamp) {
+    jlong input_start_timestamp,
+    jlong intent_received_timestamp) {
   if (!web_contents())
     return PAGE_LOAD_FAILED;
 
@@ -598,6 +599,9 @@
     if (input_start_timestamp != 0) {
       load_params.input_start =
           base::TimeTicks::FromUptimeMillis(input_start_timestamp);
+    } else if (intent_received_timestamp != 0) {
+      load_params.input_start =
+          base::TimeTicks::FromUptimeMillis(intent_received_timestamp);
     }
     web_contents()->GetController().LoadURLWithParams(load_params);
   }
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index df27cfa..394a0f2 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -173,7 +173,8 @@
       jboolean should_replace_current_entry,
       jboolean has_user_gesture,
       jboolean should_clear_history_list,
-      jlong omnibox_input_received_timestamp);
+      jlong omnibox_input_received_timestamp,
+      jlong intent_received_timestamp);
   void SetActiveNavigationEntryTitleForUrl(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index cc95626..900b10fa 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -319,12 +319,14 @@
     "android_sms/android_sms_urls.cc",
     "android_sms/android_sms_urls.h",
     "android_sms/connection_establisher.h",
-    "android_sms/connection_establisher_impl.cc",
-    "android_sms/connection_establisher_impl.h",
     "android_sms/connection_manager.cc",
     "android_sms/connection_manager.h",
+    "android_sms/fcm_connection_establisher.cc",
+    "android_sms/fcm_connection_establisher.h",
     "android_sms/pairing_lost_notifier.cc",
     "android_sms/pairing_lost_notifier.h",
+    "android_sms/streaming_connection_establisher.cc",
+    "android_sms/streaming_connection_establisher.h",
     "app_mode/app_launch_utils.cc",
     "app_mode/app_launch_utils.h",
     "app_mode/app_session.cc",
@@ -2132,9 +2134,10 @@
     "account_manager/account_migration_runner_unittest.cc",
     "android_sms/android_sms_app_manager_impl_unittest.cc",
     "android_sms/android_sms_app_setup_controller_impl_unittest.cc",
-    "android_sms/connection_establisher_impl_unittest.cc",
     "android_sms/connection_manager_unittest.cc",
+    "android_sms/fcm_connection_establisher_unittest.cc",
     "android_sms/pairing_lost_notifier_unittest.cc",
+    "android_sms/streaming_connection_establisher_unittest.cc",
     "app_mode/startup_app_launcher_unittest.cc",
     "apps/apk_web_app_installer_unittest.cc",
     "apps/intent_helper/apps_navigation_throttle_unittest.cc",
diff --git a/chrome/browser/chromeos/android_sms/android_sms_service.cc b/chrome/browser/chromeos/android_sms/android_sms_service.cc
index 968e451..8634823 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_service.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_service.cc
@@ -5,14 +5,17 @@
 #include "chrome/browser/chromeos/android_sms/android_sms_service.h"
 
 #include "base/time/default_clock.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.h"
 #include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
-#include "chrome/browser/chromeos/android_sms/connection_establisher_impl.h"
 #include "chrome/browser/chromeos/android_sms/connection_manager.h"
+#include "chrome/browser/chromeos/android_sms/fcm_connection_establisher.h"
 #include "chrome/browser/chromeos/android_sms/pairing_lost_notifier.h"
+#include "chrome/browser/chromeos/android_sms/streaming_connection_establisher.h"
 #include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
 #include "components/session_manager/core/session_manager.h"
 #include "content/public/browser/storage_partition.h"
@@ -71,10 +74,18 @@
   if (session_manager::SessionManager::Get()->IsUserSessionBlocked())
     return;
 
+  std::unique_ptr<ConnectionEstablisher> connection_establisher;
+  if (base::FeatureList::IsEnabled(features::kEnableMessagesWebPush)) {
+    connection_establisher = std::make_unique<FcmConnectionEstablisher>(
+        std::make_unique<base::OneShotTimer>());
+  } else {
+    connection_establisher = std::make_unique<StreamingConnectionEstablisher>(
+        base::DefaultClock::GetInstance());
+  }
+
   connection_manager_ = std::make_unique<ConnectionManager>(
-      std::make_unique<ConnectionEstablisherImpl>(
-          base::DefaultClock::GetInstance()),
-      profile_, android_sms_app_manager_.get(), multidevice_setup_client_);
+      std::move(connection_establisher), profile_,
+      android_sms_app_manager_.get(), multidevice_setup_client_);
 }
 
 }  // namespace android_sms
diff --git a/chrome/browser/chromeos/android_sms/connection_establisher.h b/chrome/browser/chromeos/android_sms/connection_establisher.h
index 441d9f0..0f8f929 100644
--- a/chrome/browser/chromeos/android_sms/connection_establisher.h
+++ b/chrome/browser/chromeos/android_sms/connection_establisher.h
@@ -26,6 +26,10 @@
       ConnectionMode connection_mode,
       content::ServiceWorkerContext* service_worker_context) = 0;
 
+  virtual void TearDownConnection(
+      const GURL& url,
+      content::ServiceWorkerContext* service_worker_context) = 0;
+
  protected:
   ConnectionEstablisher() = default;
 
diff --git a/chrome/browser/chromeos/android_sms/connection_manager.cc b/chrome/browser/chromeos/android_sms/connection_manager.cc
index 46aff50..d7e4357b 100644
--- a/chrome/browser/chromeos/android_sms/connection_manager.cc
+++ b/chrome/browser/chromeos/android_sms/connection_manager.cc
@@ -135,8 +135,8 @@
   if (enabled_pwa_url_) {
     PA_LOG(INFO) << "ConnectionManager::UpdateConnectionStatus(): Stopping "
                  << "connection to PWA at " << *enabled_pwa_url_ << ".";
-    GetCurrentServiceWorkerContext()->StopAllServiceWorkersForOrigin(
-        *enabled_pwa_url_);
+    connection_establisher_->TearDownConnection(
+        *enabled_pwa_url_, GetCurrentServiceWorkerContext());
     GetCurrentServiceWorkerContext()->RemoveObserver(this);
   }
 
diff --git a/chrome/browser/chromeos/android_sms/connection_manager_unittest.cc b/chrome/browser/chromeos/android_sms/connection_manager_unittest.cc
index 1a8e787..eefa7149 100644
--- a/chrome/browser/chromeos/android_sms/connection_manager_unittest.cc
+++ b/chrome/browser/chromeos/android_sms/connection_manager_unittest.cc
@@ -118,6 +118,29 @@
     }
   }
 
+  void VerifyTearDownConnectionCalls(
+      size_t expected_count,
+      bool is_last_call_expected_to_be_new_url = true) {
+    const auto& tear_down_connection_calls =
+        fake_connection_establisher_->tear_down_connection_calls();
+    EXPECT_EQ(expected_count, tear_down_connection_calls.size());
+
+    if (expected_count == 0u)
+      return;
+
+    if (is_last_call_expected_to_be_new_url) {
+      EXPECT_EQ(GetAndroidMessagesURL(),
+                std::get<0>(tear_down_connection_calls.back()));
+      EXPECT_EQ(fake_new_service_worker_context_.get(),
+                std::get<1>(tear_down_connection_calls.back()));
+    } else {
+      EXPECT_EQ(GetAndroidMessagesURLOld(),
+                std::get<0>(tear_down_connection_calls.back()));
+      EXPECT_EQ(fake_old_service_worker_context_.get(),
+                std::get<1>(tear_down_connection_calls.back()));
+    }
+  }
+
   void SetPwaState(PwaState pwa_state) {
     if (pwa_state == PwaState::kDisabled) {
       fake_android_sms_app_manager_->SetInstalledAppUrl(base::nullopt);
@@ -267,10 +290,7 @@
   // Verify that disabling feature stops the service worker.
   SetPwaState(PwaState::kDisabled);
   VerifyEstablishConnectionCalls(2u /* expected_count */);
-  const auto& stop_calls = fake_new_service_worker_context()
-                               ->stop_all_service_workers_for_origin_calls();
-  ASSERT_EQ(1u, stop_calls.size());
-  EXPECT_EQ(GetAndroidMessagesURL(), stop_calls[0]);
+  VerifyTearDownConnectionCalls(1u /* expected_count */);
 
   // Verify that subsequent service worker events do not trigger connection.
   fake_new_service_worker_context()->NotifyObserversOnNoControllees(
@@ -293,11 +313,8 @@
   SetPwaState(PwaState::kEnabledWithNewUrl);
 
   // The ServiceWorker for the old URL should have stopped.
-  const auto& stop_old_calls =
-      fake_old_service_worker_context()
-          ->stop_all_service_workers_for_origin_calls();
-  ASSERT_EQ(1u, stop_old_calls.size());
-  EXPECT_EQ(GetAndroidMessagesURLOld(), stop_old_calls[0]);
+  VerifyTearDownConnectionCalls(
+      1u /* expected_count*/, false /* is_last_call_expected_to_be_new_url */);
 
   // A connection to the new URL should have occurred.
   VerifyEstablishConnectionCalls(
diff --git a/chrome/browser/chromeos/android_sms/fake_connection_establisher.cc b/chrome/browser/chromeos/android_sms/fake_connection_establisher.cc
index a373b5a..de93d91 100644
--- a/chrome/browser/chromeos/android_sms/fake_connection_establisher.cc
+++ b/chrome/browser/chromeos/android_sms/fake_connection_establisher.cc
@@ -19,6 +19,12 @@
                                            service_worker_context_);
 }
 
+void FakeConnectionEstablisher::TearDownConnection(
+    const GURL& url,
+    content::ServiceWorkerContext* service_worker_context_) {
+  tear_down_connection_calls_.emplace_back(url, service_worker_context_);
+}
+
 }  // namespace android_sms
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/android_sms/fake_connection_establisher.h b/chrome/browser/chromeos/android_sms/fake_connection_establisher.h
index 96aac836..cd8fa8da 100644
--- a/chrome/browser/chromeos/android_sms/fake_connection_establisher.h
+++ b/chrome/browser/chromeos/android_sms/fake_connection_establisher.h
@@ -26,6 +26,11 @@
     return establish_connection_calls_;
   }
 
+  const std::vector<std::tuple<GURL, content::ServiceWorkerContext*>>&
+  tear_down_connection_calls() const {
+    return tear_down_connection_calls_;
+  }
+
  private:
   // ConnectionEstablisher:
   void EstablishConnection(
@@ -33,8 +38,14 @@
       ConnectionMode connection_mode,
       content::ServiceWorkerContext* service_worker_context) override;
 
+  void TearDownConnection(
+      const GURL& url,
+      content::ServiceWorkerContext* service_worker_context) override;
+
   std::vector<std::tuple<GURL, ConnectionMode, content::ServiceWorkerContext*>>
       establish_connection_calls_;
+  std::vector<std::tuple<GURL, content::ServiceWorkerContext*>>
+      tear_down_connection_calls_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeConnectionEstablisher);
 };
diff --git a/chrome/browser/chromeos/android_sms/fcm_connection_establisher.cc b/chrome/browser/chromeos/android_sms/fcm_connection_establisher.cc
new file mode 100644
index 0000000..ba560bef
--- /dev/null
+++ b/chrome/browser/chromeos/android_sms/fcm_connection_establisher.cc
@@ -0,0 +1,161 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/android_sms/fcm_connection_establisher.h"
+
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "chromeos/components/multidevice/logging/logging.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/blink/public/common/messaging/string_message_codec.h"
+
+namespace chromeos {
+
+namespace android_sms {
+
+const int FcmConnectionEstablisher::kMaxRetryCount = 7;
+
+constexpr base::TimeDelta FcmConnectionEstablisher::kRetryDelay =
+    base::TimeDelta::FromSeconds(5);
+
+// Start message is sent when establishing a connection for the first time on
+// log-in. This allows the service worker to freshly subscribe to push
+// notifications.
+const char FcmConnectionEstablisher::kStartFcmMessage[] =
+    "start_fcm_connection";
+
+// Resume message is sent to notify the service worker to resume handling
+// background notifications after all "Messages for Web" web pages have
+// been closed.
+const char FcmConnectionEstablisher::kResumeFcmMessage[] =
+    "resume_fcm_connection";
+
+// Stop message is sent to notify the service worker to unsubscribe from
+// push messages when the messages feature is disabled.
+const char FcmConnectionEstablisher::kStopFcmMessage[] = "stop_fcm_connection";
+
+FcmConnectionEstablisher::PendingServiceWorkerMessage::
+    PendingServiceWorkerMessage(
+        GURL service_worker_scope,
+        std::string message_content,
+        content::ServiceWorkerContext* service_worker_context)
+    : service_worker_scope(service_worker_scope),
+      message_content(message_content),
+      service_worker_context(service_worker_context) {}
+
+FcmConnectionEstablisher::InFlightMessage::InFlightMessage(
+    PendingServiceWorkerMessage message)
+    : message(message) {}
+
+FcmConnectionEstablisher::FcmConnectionEstablisher(
+    std::unique_ptr<base::OneShotTimer> retry_timer)
+    : retry_timer_(std::move(retry_timer)), weak_ptr_factory_(this) {}
+FcmConnectionEstablisher::~FcmConnectionEstablisher() = default;
+
+void FcmConnectionEstablisher::EstablishConnection(
+    const GURL& url,
+    ConnectionMode connection_mode,
+    content::ServiceWorkerContext* service_worker_context) {
+  base::PostTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::IO},
+      base::BindOnce(
+          &FcmConnectionEstablisher::SendMessageToServiceWorkerWithRetries,
+          weak_ptr_factory_.GetWeakPtr(), url,
+          GetMessageForConnectionMode(connection_mode),
+          service_worker_context));
+}
+
+void FcmConnectionEstablisher::TearDownConnection(
+    const GURL& url,
+    content::ServiceWorkerContext* service_worker_context) {
+  base::PostTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::IO},
+      base::BindOnce(
+          &FcmConnectionEstablisher::SendMessageToServiceWorkerWithRetries,
+          weak_ptr_factory_.GetWeakPtr(), url, kStopFcmMessage,
+          service_worker_context));
+}
+
+// static
+std::string FcmConnectionEstablisher::GetMessageForConnectionMode(
+    ConnectionMode connection_mode) {
+  switch (connection_mode) {
+    case ConnectionMode::kStartConnection:
+      return kStartFcmMessage;
+    case ConnectionMode::kResumeExistingConnection:
+      return kResumeFcmMessage;
+  }
+  NOTREACHED();
+  return "";
+}
+
+void FcmConnectionEstablisher::SendMessageToServiceWorkerWithRetries(
+    const GURL& url,
+    std::string message_string,
+    content::ServiceWorkerContext* service_worker_context) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  message_queue_.emplace(url, message_string, service_worker_context);
+  ProcessMessageQueue();
+}
+
+void FcmConnectionEstablisher::ProcessMessageQueue() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  if (in_flight_message_)
+    return;
+
+  if (message_queue_.empty())
+    return;
+
+  in_flight_message_.emplace(message_queue_.front());
+  message_queue_.pop();
+  SendInFlightMessage();
+}
+
+void FcmConnectionEstablisher::SendInFlightMessage() {
+  const PendingServiceWorkerMessage& message = in_flight_message_->message;
+  blink::TransferableMessage msg;
+  msg.owned_encoded_message =
+      blink::EncodeStringMessage(base::UTF8ToUTF16(message.message_content));
+  msg.encoded_message = msg.owned_encoded_message;
+
+  PA_LOG(VERBOSE) << "Dispatching message " << message.message_content;
+  message.service_worker_context->StartServiceWorkerAndDispatchMessage(
+      message.service_worker_scope, std::move(msg),
+      base::BindOnce(&FcmConnectionEstablisher::OnMessageDispatchResult,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void FcmConnectionEstablisher::OnMessageDispatchResult(bool status) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK(in_flight_message_);
+  PA_LOG(VERBOSE) << "Service worker message returned status: " << status;
+
+  if (!status && in_flight_message_->retry_count < kMaxRetryCount) {
+    base::TimeDelta retry_delay =
+        kRetryDelay * (1 << in_flight_message_->retry_count);
+    in_flight_message_->retry_count++;
+    PA_LOG(VERBOSE) << "Scheduling retry with delay " << retry_delay;
+    retry_timer_->Start(
+        FROM_HERE, retry_delay,
+        base::BindOnce(&FcmConnectionEstablisher::SendInFlightMessage,
+                       weak_ptr_factory_.GetWeakPtr()));
+    return;
+  }
+
+  if (in_flight_message_->retry_count >= kMaxRetryCount) {
+    PA_LOG(WARNING) << "Max retries attempted when dispatching message "
+                    << in_flight_message_->message.message_content;
+  }
+
+  in_flight_message_.reset();
+  ProcessMessageQueue();
+}
+
+}  // namespace android_sms
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/android_sms/fcm_connection_establisher.h b/chrome/browser/chromeos/android_sms/fcm_connection_establisher.h
new file mode 100644
index 0000000..70905ee
--- /dev/null
+++ b/chrome/browser/chromeos/android_sms/fcm_connection_establisher.h
@@ -0,0 +1,96 @@
+// 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_ANDROID_SMS_FCM_CONNECTION_ESTABLISHER_H_
+#define CHROME_BROWSER_CHROMEOS_ANDROID_SMS_FCM_CONNECTION_ESTABLISHER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/chromeos/android_sms/connection_establisher.h"
+
+namespace chromeos {
+
+namespace android_sms {
+
+// ConnectionEstablisher implementation that initiates an FCM web push
+// suscription frin the Android Messages for Web service worker and the
+// Tachyon server by dispatching a known message string to it.
+class FcmConnectionEstablisher : public ConnectionEstablisher {
+ public:
+  explicit FcmConnectionEstablisher(
+      std::unique_ptr<base::OneShotTimer> retry_timer);
+  ~FcmConnectionEstablisher() override;
+
+  // ConnectionEstablisher:
+  void EstablishConnection(
+      const GURL& url,
+      ConnectionMode connection_mode,
+      content::ServiceWorkerContext* service_worker_context) override;
+
+  void TearDownConnection(
+      const GURL& url,
+      content::ServiceWorkerContext* service_worker_context) override;
+
+ private:
+  struct PendingServiceWorkerMessage {
+    PendingServiceWorkerMessage(
+        GURL service_worker_scope,
+        std::string message_content,
+        content::ServiceWorkerContext* service_worker_context);
+    GURL service_worker_scope;
+    std::string message_content;
+    content::ServiceWorkerContext* service_worker_context;
+  };
+
+  struct InFlightMessage {
+    explicit InFlightMessage(PendingServiceWorkerMessage message);
+    PendingServiceWorkerMessage message;
+    size_t retry_count = 0u;
+  };
+
+  FRIEND_TEST_ALL_PREFIXES(FcmConnectionEstablisherTest,
+                           TestEstablishConnection);
+  FRIEND_TEST_ALL_PREFIXES(FcmConnectionEstablisherTest,
+                           TestTearDownConnection);
+
+  static std::string GetMessageForConnectionMode(
+      ConnectionMode connection_mode);
+
+  void SendMessageToServiceWorkerWithRetries(
+      const GURL& url,
+      std::string message_string,
+      content::ServiceWorkerContext* service_worker_context);
+
+  void ProcessMessageQueue();
+
+  void SendInFlightMessage();
+
+  void OnMessageDispatchResult(bool status);
+
+  std::unique_ptr<base::OneShotTimer> retry_timer_;
+  base::Optional<InFlightMessage> in_flight_message_;
+
+  // A queue of messages to be dispatched. Messages are dispatched and retried
+  // one at a time from this queue.
+  base::queue<PendingServiceWorkerMessage> message_queue_;
+
+  static const char kStartFcmMessage[];
+  static const char kResumeFcmMessage[];
+  static const char kStopFcmMessage[];
+  static const int kMaxRetryCount;
+  static const base::TimeDelta kRetryDelay;
+
+  base::WeakPtrFactory<FcmConnectionEstablisher> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FcmConnectionEstablisher);
+};
+
+}  // namespace android_sms
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_ANDROID_SMS_FCM_CONNECTION_ESTABLISHER_H_
diff --git a/chrome/browser/chromeos/android_sms/fcm_connection_establisher_unittest.cc b/chrome/browser/chromeos/android_sms/fcm_connection_establisher_unittest.cc
new file mode 100644
index 0000000..bb382db
--- /dev/null
+++ b/chrome/browser/chromeos/android_sms/fcm_connection_establisher_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/android_sms/fcm_connection_establisher.h"
+
+#include <utility>
+
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/timer/mock_timer.h"
+#include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
+#include "content/public/test/fake_service_worker_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/messaging/string_message_codec.h"
+
+namespace chromeos {
+
+namespace android_sms {
+
+class FcmConnectionEstablisherTest : public testing::Test {
+ protected:
+  FcmConnectionEstablisherTest()
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
+  ~FcmConnectionEstablisherTest() override = default;
+
+  void VerifyTransferrableMessage(
+      const char* expected,
+      const content::FakeServiceWorkerContext::
+          StartServiceWorkerAndDispatchMessageArgs& call_args) {
+    base::string16 message_string;
+    blink::DecodeStringMessage(
+        std::get<blink::TransferableMessage>(call_args).owned_encoded_message,
+        &message_string);
+    EXPECT_EQ(base::UTF8ToUTF16(expected), message_string);
+  }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+  DISALLOW_COPY_AND_ASSIGN(FcmConnectionEstablisherTest);
+};
+
+TEST_F(FcmConnectionEstablisherTest, TestEstablishConnection) {
+  auto mock_retry_timer = std::make_unique<base::MockOneShotTimer>();
+  base::MockOneShotTimer* mock_retry_timer_ptr = mock_retry_timer.get();
+
+  content::FakeServiceWorkerContext fake_service_worker_context;
+  FcmConnectionEstablisher fcm_connection_establisher(
+      std::move(mock_retry_timer));
+  auto& message_dispatch_calls =
+      fake_service_worker_context
+          .start_service_worker_and_dispatch_message_calls();
+
+  // Verify that message is dispatch to service worker.
+  fcm_connection_establisher.EstablishConnection(
+      GetAndroidMessagesURL(),
+      ConnectionEstablisher::ConnectionMode::kStartConnection,
+      &fake_service_worker_context);
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(1u, message_dispatch_calls.size());
+  EXPECT_EQ(GetAndroidMessagesURL(), std::get<GURL>(message_dispatch_calls[0]));
+  VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage,
+                             message_dispatch_calls[0]);
+
+  // Return success to result callback and verify that no retries are attempted
+  std::move(std::get<content::ServiceWorkerContext::ResultCallback>(
+                message_dispatch_calls[0]))
+      .Run(true /* status */);
+  ASSERT_EQ(1u, message_dispatch_calls.size());
+  EXPECT_FALSE(mock_retry_timer_ptr->IsRunning());
+
+  // Verify that when multiple requests are sent only the first one is
+  // dispatched while the others are queued.
+  fcm_connection_establisher.EstablishConnection(
+      GetAndroidMessagesURL(),
+      ConnectionEstablisher::ConnectionMode::kStartConnection,
+      &fake_service_worker_context);
+  fcm_connection_establisher.EstablishConnection(
+      GetAndroidMessagesURL(),
+      ConnectionEstablisher::ConnectionMode::kResumeExistingConnection,
+      &fake_service_worker_context);
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(2u, message_dispatch_calls.size());
+  VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage,
+                             message_dispatch_calls[1]);
+
+  // Verify that if the first request fails then it's retried
+  std::move(std::get<content::ServiceWorkerContext::ResultCallback>(
+                message_dispatch_calls[1]))
+      .Run(false /* status */);
+  ASSERT_EQ(2u, message_dispatch_calls.size());
+  EXPECT_TRUE(mock_retry_timer_ptr->IsRunning());
+  mock_retry_timer_ptr->Fire();
+  ASSERT_EQ(3u, message_dispatch_calls.size());
+  VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage,
+                             message_dispatch_calls[2]);
+
+  // Verify that if the first request succeeds then the next message is
+  // dispatched
+  std::move(std::get<content::ServiceWorkerContext::ResultCallback>(
+                message_dispatch_calls[2]))
+      .Run(true /* status */);
+  ASSERT_EQ(4u, message_dispatch_calls.size());
+  EXPECT_FALSE(mock_retry_timer_ptr->IsRunning());
+  VerifyTransferrableMessage(FcmConnectionEstablisher::kResumeFcmMessage,
+                             message_dispatch_calls[3]);
+
+  // Complete second request and verify that no more retries are scheduled.
+  std::move(std::get<content::ServiceWorkerContext::ResultCallback>(
+                message_dispatch_calls[3]))
+      .Run(true /* status */);
+  EXPECT_FALSE(mock_retry_timer_ptr->IsRunning());
+
+  // Verify that max retries are attempted before abandoning request
+  fcm_connection_establisher.EstablishConnection(
+      GetAndroidMessagesURL(),
+      ConnectionEstablisher::ConnectionMode::kStartConnection,
+      &fake_service_worker_context);
+  base::RunLoop().RunUntilIdle();
+
+  int retry_count = 0;
+  while (true) {
+    ASSERT_EQ(5u + retry_count, message_dispatch_calls.size());
+    std::move(std::get<content::ServiceWorkerContext::ResultCallback>(
+                  message_dispatch_calls[4 + retry_count]))
+        .Run(false /* status */);
+    if (mock_retry_timer_ptr->IsRunning()) {
+      mock_retry_timer_ptr->Fire();
+      retry_count++;
+    } else {
+      break;
+    }
+  }
+
+  EXPECT_EQ(FcmConnectionEstablisher::kMaxRetryCount, retry_count);
+}
+
+TEST_F(FcmConnectionEstablisherTest, TestTearDownConnection) {
+  content::FakeServiceWorkerContext fake_service_worker_context;
+  FcmConnectionEstablisher fcm_connection_establisher(
+      std::make_unique<base::MockOneShotTimer>());
+  auto& message_dispatch_calls =
+      fake_service_worker_context
+          .start_service_worker_and_dispatch_message_calls();
+
+  // Verify that message is dispatch to service worker.
+  fcm_connection_establisher.TearDownConnection(GetAndroidMessagesURL(),
+                                                &fake_service_worker_context);
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(1u, message_dispatch_calls.size());
+  EXPECT_EQ(GetAndroidMessagesURL(), std::get<GURL>(message_dispatch_calls[0]));
+  VerifyTransferrableMessage(FcmConnectionEstablisher::kStopFcmMessage,
+                             message_dispatch_calls[0]);
+}
+
+}  // namespace android_sms
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/android_sms/connection_establisher_impl.cc b/chrome/browser/chromeos/android_sms/streaming_connection_establisher.cc
similarity index 74%
rename from chrome/browser/chromeos/android_sms/connection_establisher_impl.cc
rename to chrome/browser/chromeos/android_sms/streaming_connection_establisher.cc
index 4c00f54..13ab0b2 100644
--- a/chrome/browser/chromeos/android_sms/connection_establisher_impl.cc
+++ b/chrome/browser/chromeos/android_sms/streaming_connection_establisher.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 "chrome/browser/chromeos/android_sms/connection_establisher_impl.h"
+#include "chrome/browser/chromeos/android_sms/streaming_connection_establisher.h"
 
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
@@ -18,29 +18,36 @@
 
 namespace android_sms {
 
-const char ConnectionEstablisherImpl::kStartStreamingMessage[] =
+const char StreamingConnectionEstablisher::kStartStreamingMessage[] =
     "start_streaming_connection";
 
-const char ConnectionEstablisherImpl::kResumeStreamingMessage[] =
+const char StreamingConnectionEstablisher::kResumeStreamingMessage[] =
     "resume_streaming_connection";
 
-ConnectionEstablisherImpl::ConnectionEstablisherImpl(base::Clock* clock)
+StreamingConnectionEstablisher::StreamingConnectionEstablisher(
+    base::Clock* clock)
     : clock_(clock) {}
-ConnectionEstablisherImpl::~ConnectionEstablisherImpl() = default;
+StreamingConnectionEstablisher::~StreamingConnectionEstablisher() = default;
 
-void ConnectionEstablisherImpl::EstablishConnection(
+void StreamingConnectionEstablisher::EstablishConnection(
     const GURL& url,
     ConnectionMode connection_mode,
     content::ServiceWorkerContext* service_worker_context) {
   base::PostTaskWithTraits(
       FROM_HERE, {content::BrowserThread::IO},
-      base::BindOnce(
-          &ConnectionEstablisherImpl::SendStartStreamingMessageIfNotConnected,
-          base::Unretained(this), url, connection_mode,
-          service_worker_context));
+      base::BindOnce(&StreamingConnectionEstablisher::
+                         SendStartStreamingMessageIfNotConnected,
+                     base::Unretained(this), url, connection_mode,
+                     service_worker_context));
 }
 
-void ConnectionEstablisherImpl::SendStartStreamingMessageIfNotConnected(
+void StreamingConnectionEstablisher::TearDownConnection(
+    const GURL& url,
+    content::ServiceWorkerContext* service_worker_context) {
+  service_worker_context->StopAllServiceWorkersForOrigin(url);
+}
+
+void StreamingConnectionEstablisher::SendStartStreamingMessageIfNotConnected(
     const GURL& url,
     ConnectionMode connection_mode,
     content::ServiceWorkerContext* service_worker_context) {
@@ -69,11 +76,11 @@
   start_connection_message_time_ = clock_->Now();
   service_worker_context->StartServiceWorkerAndDispatchLongRunningMessage(
       url, std::move(msg),
-      base::BindOnce(&ConnectionEstablisherImpl::OnMessageDispatchResult,
+      base::BindOnce(&StreamingConnectionEstablisher::OnMessageDispatchResult,
                      base::Unretained(this)));
 }
 
-void ConnectionEstablisherImpl::OnMessageDispatchResult(bool status) {
+void StreamingConnectionEstablisher::OnMessageDispatchResult(bool status) {
   // When message dispatch result callback is called, it means that the service
   // worker resolved it's message handler promise and is not holding a
   // background connection.
diff --git a/chrome/browser/chromeos/android_sms/connection_establisher_impl.h b/chrome/browser/chromeos/android_sms/streaming_connection_establisher.h
similarity index 64%
rename from chrome/browser/chromeos/android_sms/connection_establisher_impl.h
rename to chrome/browser/chromeos/android_sms/streaming_connection_establisher.h
index cc8a691..a5917b9 100644
--- a/chrome/browser/chromeos/android_sms/connection_establisher_impl.h
+++ b/chrome/browser/chromeos/android_sms/streaming_connection_establisher.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 CHROME_BROWSER_CHROMEOS_ANDROID_SMS_CONNECTION_ESTABLISHER_IMPL_H_
-#define CHROME_BROWSER_CHROMEOS_ANDROID_SMS_CONNECTION_ESTABLISHER_IMPL_H_
+#ifndef CHROME_BROWSER_CHROMEOS_ANDROID_SMS_STREAMING_CONNECTION_ESTABLISHER_H_
+#define CHROME_BROWSER_CHROMEOS_ANDROID_SMS_STREAMING_CONNECTION_ESTABLISHER_H_
 
 #include "base/time/clock.h"
 #include "chrome/browser/chromeos/android_sms/connection_establisher.h"
@@ -18,18 +18,23 @@
 //
 // To allow the service worker to continue running past it's default timeout
 // this message is sent using a special long-running dispatch.
-class ConnectionEstablisherImpl : public ConnectionEstablisher {
+class StreamingConnectionEstablisher : public ConnectionEstablisher {
  public:
-  explicit ConnectionEstablisherImpl(base::Clock* clock);
-  ~ConnectionEstablisherImpl() override;
+  explicit StreamingConnectionEstablisher(base::Clock* clock);
+  ~StreamingConnectionEstablisher() override;
 
   void EstablishConnection(
       const GURL& url,
       ConnectionMode connection_mode,
       content::ServiceWorkerContext* service_worker_context) override;
 
+  void TearDownConnection(
+      const GURL& url,
+      content::ServiceWorkerContext* service_worker_context) override;
+
  private:
-  FRIEND_TEST_ALL_PREFIXES(ConnectionEstablisherImplTest, EstablishConnection);
+  FRIEND_TEST_ALL_PREFIXES(StreamingConnectionEstablisherTest,
+                           EstablishConnection);
 
   void SendStartStreamingMessageIfNotConnected(
       const GURL& url,
@@ -43,11 +48,11 @@
   base::Clock* clock_;
   bool is_connected_ = false;
   base::Time start_connection_message_time_;
-  DISALLOW_COPY_AND_ASSIGN(ConnectionEstablisherImpl);
+  DISALLOW_COPY_AND_ASSIGN(StreamingConnectionEstablisher);
 };
 
 }  // namespace android_sms
 
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_CHROMEOS_ANDROID_SMS_CONNECTION_ESTABLISHER_IMPL_H_
+#endif  // CHROME_BROWSER_CHROMEOS_ANDROID_SMS_STREAMING_CONNECTION_ESTABLISHER_H_
diff --git a/chrome/browser/chromeos/android_sms/connection_establisher_impl_unittest.cc b/chrome/browser/chromeos/android_sms/streaming_connection_establisher_unittest.cc
similarity index 74%
rename from chrome/browser/chromeos/android_sms/connection_establisher_impl_unittest.cc
rename to chrome/browser/chromeos/android_sms/streaming_connection_establisher_unittest.cc
index 66130aa9..326be53 100644
--- a/chrome/browser/chromeos/android_sms/connection_establisher_impl_unittest.cc
+++ b/chrome/browser/chromeos/android_sms/streaming_connection_establisher_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 "chrome/browser/chromeos/android_sms/connection_establisher_impl.h"
+#include "chrome/browser/chromeos/android_sms/streaming_connection_establisher.h"
 
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
@@ -18,22 +18,22 @@
 
 namespace android_sms {
 
-class ConnectionEstablisherImplTest : public testing::Test {
+class StreamingConnectionEstablisherTest : public testing::Test {
  protected:
-  ConnectionEstablisherImplTest()
+  StreamingConnectionEstablisherTest()
       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
-  ~ConnectionEstablisherImplTest() override = default;
+  ~StreamingConnectionEstablisherTest() override = default;
 
  private:
   content::TestBrowserThreadBundle thread_bundle_;
-  DISALLOW_COPY_AND_ASSIGN(ConnectionEstablisherImplTest);
+  DISALLOW_COPY_AND_ASSIGN(StreamingConnectionEstablisherTest);
 };
 
-TEST_F(ConnectionEstablisherImplTest, EstablishConnection) {
+TEST_F(StreamingConnectionEstablisherTest, EstablishConnection) {
   base::HistogramTester histogram_tester;
   content::FakeServiceWorkerContext fake_service_worker_context;
   base::SimpleTestClock test_clock;
-  ConnectionEstablisherImpl connection_establisher(&test_clock);
+  StreamingConnectionEstablisher connection_establisher(&test_clock);
   auto& message_dispatch_calls =
       fake_service_worker_context
           .start_service_worker_and_dispatch_long_running_message_calls();
@@ -52,7 +52,7 @@
           .owned_encoded_message,
       &message_string);
   EXPECT_EQ(
-      base::UTF8ToUTF16(ConnectionEstablisherImpl::kStartStreamingMessage),
+      base::UTF8ToUTF16(StreamingConnectionEstablisher::kStartStreamingMessage),
       message_string);
 
   // Verify that message is not dispatched again if previous result callback has
@@ -100,9 +100,23 @@
       std::get<blink::TransferableMessage>(message_dispatch_calls[2])
           .owned_encoded_message,
       &resume_message_string);
-  EXPECT_EQ(
-      base::UTF8ToUTF16(ConnectionEstablisherImpl::kResumeStreamingMessage),
-      resume_message_string);
+  EXPECT_EQ(base::UTF8ToUTF16(
+                StreamingConnectionEstablisher::kResumeStreamingMessage),
+            resume_message_string);
+}
+
+TEST_F(StreamingConnectionEstablisherTest, TearDownConnection) {
+  content::FakeServiceWorkerContext fake_service_worker_context;
+  base::SimpleTestClock test_clock;
+  StreamingConnectionEstablisher connection_establisher(&test_clock);
+
+  // Verify that tear down stops all service worker.
+  connection_establisher.TearDownConnection(GetAndroidMessagesURL(),
+                                            &fake_service_worker_context);
+  const auto& stop_calls =
+      fake_service_worker_context.stop_all_service_workers_for_origin_calls();
+  ASSERT_EQ(1u, stop_calls.size());
+  EXPECT_EQ(GetAndroidMessagesURL(), stop_calls[0]);
 }
 
 }  // namespace android_sms
diff --git a/chrome/browser/chromeos/arc/arc_util.cc b/chrome/browser/chromeos/arc/arc_util.cc
index b3cd275..0b9eee37 100644
--- a/chrome/browser/chromeos/arc/arc_util.cc
+++ b/chrome/browser/chromeos/arc/arc_util.cc
@@ -615,12 +615,8 @@
     base::ReplaceChars(pref_locale, "-", "_", &pref_locale);
     bool disallowed = !base::ContainsValue(kAllowedLocales, pref_locale);
 
-    if (disallowed && base::CommandLine::ForCurrentProcess()
-                              ->GetSwitchValueASCII(
-                                  chromeos::switches::kVoiceInteractionLocales)
-                              .find(pref_locale) == std::string::npos) {
+    if (disallowed)
       return ash::mojom::AssistantAllowedState::DISALLOWED_BY_LOCALE;
-    }
   }
 
   return ash::mojom::AssistantAllowedState::ALLOWED;
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
index 8bdc5e7..7a06431 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
@@ -169,7 +169,10 @@
           profile->GetPrefs());
 #if defined(OS_CHROMEOS)
   // Do not create DevTools if it's disabled for primary profile.
-  if (Profile* primary_profile = ProfileManager::GetPrimaryUserProfile()) {
+  Profile* primary_profile = ProfileManager::GetPrimaryUserProfile();
+  if (primary_profile &&
+      policy::DeveloperToolsPolicyHandler::IsDevToolsAvailabilitySetByPolicy(
+          primary_profile->GetPrefs())) {
     availability =
         policy::DeveloperToolsPolicyHandler::GetMostRestrictiveAvailability(
             availability,
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 39c7e3b0..d00ff627 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -743,9 +743,13 @@
   ]
   defines = []
 
-  # TODO(loyso): Remove this circular dependency. http://crbug.com/876576.
-  allow_circular_includes_from =
-      [ "//chrome/browser/web_applications/extensions" ]
+  allow_circular_includes_from = [
+    # TODO(loyso): Remove this circular dependency. http://crbug.com/876576.
+    "//chrome/browser/web_applications/extensions",
+
+    # TODO(crbug/925153): Remove this circular dependency.
+    "//chrome/browser/safe_browsing",
+  ]
 
   # Since browser and browser_extensions actually depend on each other,
   # we must omit the dependency from browser_extensions to browser.
diff --git a/chrome/browser/policy/developer_tools_policy_handler.cc b/chrome/browser/policy/developer_tools_policy_handler.cc
index 5743f884..1c33dfb 100644
--- a/chrome/browser/policy/developer_tools_policy_handler.cc
+++ b/chrome/browser/policy/developer_tools_policy_handler.cc
@@ -218,6 +218,12 @@
 }
 
 // static
+bool DeveloperToolsPolicyHandler::IsDevToolsAvailabilitySetByPolicy(
+    const PrefService* pref_service) {
+  return pref_service->IsManagedPreference(prefs::kDevToolsAvailability);
+}
+
+// static
 DeveloperToolsPolicyHandler::Availability
 DeveloperToolsPolicyHandler::GetMostRestrictiveAvailability(
     Availability availability_1,
diff --git a/chrome/browser/policy/developer_tools_policy_handler.h b/chrome/browser/policy/developer_tools_policy_handler.h
index e8bc0589..6ea42a4a 100644
--- a/chrome/browser/policy/developer_tools_policy_handler.h
+++ b/chrome/browser/policy/developer_tools_policy_handler.h
@@ -54,6 +54,11 @@
   // |Availability::kDisallowedForForceInstalledExtensions|.
   static Availability GetDevToolsAvailability(const PrefService* pref_service);
 
+  // Returns true if developer tools availability is set by an active policy in
+  // |pref_service|.
+  static bool IsDevToolsAvailabilitySetByPolicy(
+      const PrefService* pref_service);
+
   // Returns the most restrictive availability within [|availability_1|,
   // |availability_2|].
   static Availability GetMostRestrictiveAvailability(
diff --git a/chrome/browser/resources/chromeos/chromevox/braille/bluetooth_braille_display_manager.js b/chrome/browser/resources/chromeos/chromevox/braille/bluetooth_braille_display_manager.js
index 3cab81d..953913e 100644
--- a/chrome/browser/resources/chromeos/chromevox/braille/bluetooth_braille_display_manager.js
+++ b/chrome/browser/resources/chromeos/chromevox/braille/bluetooth_braille_display_manager.js
@@ -176,7 +176,12 @@
    */
   finishPairing: function(display, pincode) {
     chrome.bluetoothPrivate.setPairingResponse(
-        {response: 'confirm', device: display, pincode: pincode}, () => {});
+        {
+          response: chrome.bluetoothPrivate.PairingResponse.CONFIRM,
+          device: display,
+          pincode: pincode
+        },
+        () => {});
   },
 
   /**
diff --git a/chrome/browser/resources/chromeos/chromevox/common/command_store.js b/chrome/browser/resources/chromeos/chromevox/common/command_store.js
index 119495a..0d262ae 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/command_store.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/command_store.js
@@ -138,13 +138,6 @@
     'disallowOOBE': true,
     category: 'modifier_keys'
   },
-  'toggleKeyPrefix': {
-    announce: false,
-    skipInput: true,
-    msgId: 'prefix_key',
-    'disallowOOBE': true,
-    category: 'modifier_keys'
-  },
   'passThroughMode': {
     announce: false,
     msgId: 'pass_through_key_description',
@@ -161,15 +154,9 @@
   'toggleChromeVox': {
     announce: false,
     platformFilter: cvox.PlatformFilter.WML,
-    msgId: 'toggle_chromevox_active',
-    category: 'modifier_keys'
+    msgId: 'toggle_chromevox_active'
   },
   'toggleChromeVoxVersion': {announce: false},
-  'showNextUpdatePage': {
-    msgId: 'show_next_update_description',
-    announce: false,
-    'category': 'help_commands'
-  },
   'openChromeVoxMenus': {announce: false, msgId: 'menus_title'},
   'decreaseTtsRate': {
     announce: false,
@@ -413,7 +400,6 @@
   'help': {
     announce: false,
     msgId: 'help',
-    'disallowOOBE': true,
     disallowContinuation: true,
     category: 'help_commands'
   },
@@ -438,12 +424,17 @@
     'disallowOOBE': true,
     category: 'help_commands'
   },
-  'showTtsSettings':
-      {announce: false, msgId: 'show_tts_settings', category: 'help_commands'},
+  'showTtsSettings': {
+    announce: false,
+    msgId: 'show_tts_settings',
+    category: 'help_commands',
+    disallowOOBE: true
+  },
   'toggleBrailleCaptions':
       {announce: false, msgId: 'braille_captions', category: 'help_commands'},
   'reportIssue': {
     announce: false,
+    disallowOOBE: true,
     msgId: 'panel_menu_item_report_issue',
     category: 'help_commands'
   },
diff --git a/chrome/browser/resources/chromeos/chromevox/common/command_store_test.unitjs b/chrome/browser/resources/chromeos/chromevox/common/command_store_test.unitjs
index 0d8ffef..758397f 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/command_store_test.unitjs
+++ b/chrome/browser/resources/chromeos/chromevox/common/command_store_test.unitjs
@@ -27,10 +27,10 @@
   assertEquals(11, categories.length);
   assertEquals('modifier_keys', categories[0]);
   assertEquals('controlling_speech', categories[1]);
-  assertEquals('help_commands', categories[2]);
-  assertEquals('navigation', categories[3]);
-  assertEquals('actions', categories[4]);
-  assertEquals('information', categories[5]);
+  assertEquals('navigation', categories[2]);
+  assertEquals('actions', categories[3]);
+  assertEquals('information', categories[4]);
+  assertEquals('help_commands', categories[5]);
   assertEquals('overview', categories[6]);
   assertEquals('jump_commands', categories[7]);
   assertEquals('tables', categories[8]);
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
index 7cfb8a3c..8b472e9 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
@@ -14,8 +14,9 @@
 goog.require('Output');
 goog.require('TreeDumper');
 goog.require('cvox.ChromeVoxBackground');
-goog.require('cvox.ChromeVoxPrefs');
 goog.require('cvox.ChromeVoxKbHandler');
+goog.require('cvox.ChromeVoxPrefs');
+goog.require('cvox.CommandStore');
 
 goog.scope(function() {
 var AutomationEvent = chrome.automation.AutomationEvent;
@@ -25,12 +26,20 @@
 var RoleType = chrome.automation.RoleType;
 var StateType = chrome.automation.StateType;
 
+/** @private {boolean} */
+CommandHandler.incognito_ = !!chrome.runtime.getManifest()['incognito'];
+
 /**
  * Handles ChromeVox Next commands.
  * @param {string} command
  * @return {boolean} True if the command should propagate.
  */
 CommandHandler.onCommand = function(command) {
+  // Check for a command disallowed in OOBE/login.
+  if (CommandHandler.incognito_ && cvox.CommandStore.CMD_WHITELIST[command] &&
+      cvox.CommandStore.CMD_WHITELIST[command].disallowOOBE)
+    return true;
+
   // Check for loss of focus which results in us invalidating our current
   // range. Note this call is synchronis.
   chrome.automation.getFocus(function(focusedNode) {
diff --git a/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py b/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py
index 0dab9310..c7d2d80 100755
--- a/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py
+++ b/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py
@@ -54,6 +54,10 @@
 _AUTOMATION_EXTERNS = (
     ChromeRootPath('third_party/closure_compiler/externs/automation.js'))
 
+# BluetoothPrivate externs file.
+_BLUETOOTH_PRIVATE_EXTERNS = (
+    ChromeRootPath('third_party/closure_compiler/externs/bluetooth_private.js'))
+
 # MetricsPrivate externs file.
 _METRICS_PRIVATE_EXTERNS = (
     ChromeRootPath('third_party/closure_compiler/externs/metrics_private.js'))
@@ -85,6 +89,7 @@
     _ACCESSIBILITY_PRIVATE_EXTERNS,
     _AUDIO_EXTERNS,
     _AUTOMATION_EXTERNS,
+    _BLUETOOTH_PRIVATE_EXTERNS,
     _CHROME_EXTERNS,
     _CHROME_EXTENSIONS_EXTERNS,
     _COMMANDLINE_PRIVATE_EXTERNS,
diff --git a/chrome/browser/resources/chromeos/first_run/app_list_step.html b/chrome/browser/resources/chromeos/first_run/app_list_step.html
index a02df59d..c2e8560 100644
--- a/chrome/browser/resources/chromeos/first_run/app_list_step.html
+++ b/chrome/browser/resources/chromeos/first_run/app_list_step.html
@@ -2,7 +2,7 @@
   <h1 i18n-content="appListHeader"></h1>
   <p>
     <span i18n-content="appListText1"></span><br>
-    <span id="voice-interaction-text" i18n-content="appListText2" hidden></span>
+    <span id="google-assistant-text" i18n-content="appListText2" hidden></span>
   </p>
   <div class="controls">
     <button i18n-content="nextButton"
diff --git a/chrome/browser/resources/chromeos/first_run/first_run.js b/chrome/browser/resources/chromeos/first_run/first_run.js
index bd82d036..8fc04739 100644
--- a/chrome/browser/resources/chromeos/first_run/first_run.js
+++ b/chrome/browser/resources/chromeos/first_run/first_run.js
@@ -229,8 +229,8 @@
      * |pointWithOffset|: Optional parameter for positioning bubble. Contains
      *     [x, y, offset], where (x, y) - point to which bubble points,
      *     offset - distance between arrow and point.
-     * |voiceInteractionEnabled|: Optional boolean value to indicate if voice
-     *     interaction is enabled by the device.
+     * |assistantEnabled|: Optional boolean value to indicate if Google
+     *     Assistant is enabled.
      */
     showStep: function(stepParams) {
       assert(!this.currentStep_);
@@ -244,8 +244,8 @@
             stepParams.pointWithOffset.slice(0, 2),
             stepParams.pointWithOffset[2]);
       }
-      if (stepParams.voiceInteractionEnabled)
-        step.setVoiceInteractionEnabled();
+      if (stepParams.assistantEnabled)
+        step.setAssistantEnabled();
       step.show(true, function(step) {
         step.focusDefaultControl();
         this.currentStep_ = step;
diff --git a/chrome/browser/resources/chromeos/first_run/step.js b/chrome/browser/resources/chromeos/first_run/step.js
index f17e29af..f479959 100644
--- a/chrome/browser/resources/chromeos/first_run/step.js
+++ b/chrome/browser/resources/chromeos/first_run/step.js
@@ -101,11 +101,11 @@
     },
 
     /**
-     * Updates UI when voice interaction is enabled by the device.
+     * Updates UI when Google Assistant is enabled.
      */
-    setVoiceInteractionEnabled: function() {
+    setAssistantEnabled: function() {
       if (this.name_ == 'app-list')
-        $('voice-interaction-text').hidden = false;
+        $('google-assistant-text').hidden = false;
     },
   };
 
diff --git a/chrome/browser/resources/md_extensions/item_list.js b/chrome/browser/resources/md_extensions/item_list.js
index 481cd4c..04f8df0 100644
--- a/chrome/browser/resources/md_extensions/item_list.js
+++ b/chrome/browser/resources/md_extensions/item_list.js
@@ -52,7 +52,8 @@
      * @return {?Element}
      */
     getDetailsButton: function(id) {
-      return this.$$(`#${id}`).getDetailsButton();
+      const item = this.$$(`#${id}`);
+      return item && item.getDetailsButton();
     },
 
     /**
@@ -60,7 +61,8 @@
      * @return {?Element}
      */
     getErrorsButton: function(id) {
-      return this.$$(`#${id}`).getErrorsButton();
+      const item = this.$$(`#${id}`);
+      return item && item.getErrorsButton();
     },
 
     /**
diff --git a/chrome/browser/resources/md_user_manager/user_manager.html b/chrome/browser/resources/md_user_manager/user_manager.html
index 606774f..3401148 100644
--- a/chrome/browser/resources/md_user_manager/user_manager.html
+++ b/chrome/browser/resources/md_user_manager/user_manager.html
@@ -2,7 +2,8 @@
 <html build="$i18n{buildType}"
     dir="$i18n{textdirection}"
     lang="$i18n{language}"
-    screen="$i18n{screenType}">
+    screen="$i18n{screenType}"
+    $i18n{dark}>
 <head>
   <meta charset="utf-8">
   <meta name="google" value="notranslate">
@@ -361,5 +362,6 @@
     <include src="../../../../ui/login/account_picker/user_pod_template.html">
   </user-manager-pages>
   <script src="user_manager.js"></script>
+  <link rel="import" href="chrome://resources/html/dark_mode.html">
 </body>
 </html>
diff --git a/chrome/browser/resources/print_preview/print_preview_new.html b/chrome/browser/resources/print_preview/print_preview_new.html
index 2917106..e85a24c1 100644
--- a/chrome/browser/resources/print_preview/print_preview_new.html
+++ b/chrome/browser/resources/print_preview/print_preview_new.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<html dir="$i18n{textdirection}" lang="$i18n{language}" $i18n{dark}>
 <head>
   <meta charset="utf-8">
   <style>
@@ -22,5 +22,6 @@
   <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
   <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
   <link rel="import" href="new/app.html">
+  <link rel="import" href="chrome://resources/html/dark_mode.html">
 </body>
 </html>
diff --git a/chrome/browser/resources/settings/autofill_page/autofill_page.html b/chrome/browser/resources/settings/autofill_page/autofill_page.html
index 7943505..7222b6e1 100644
--- a/chrome/browser/resources/settings/autofill_page/autofill_page.html
+++ b/chrome/browser/resources/settings/autofill_page/autofill_page.html
@@ -16,8 +16,10 @@
 <dom-module id="settings-autofill-page">
   <template>
     <style include="settings-shared">
-      cr-link-row:not([hidden]) + cr-link-row {
+      cr-link-row {
         --cr-icon-button-margin-start: 20px;
+      }
+      cr-link-row:not([hidden]) + cr-link-row {
         border-top: var(--settings-separator-line);
       }
     </style>
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
index 57fe166..2a44cd9a 100644
--- a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
+++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.html
@@ -59,25 +59,26 @@
             </template>
           </select>
         </div>
-        <div class="settings-box two-line" hidden=
-            "[[!prefs.settings.voice_interaction.hotword.enabled.value]]">
-          <div class="start text-area">
-            <div class="label">
-              $i18n{googleAssistantVoiceSettings}
+        <template is="dom-if" if="[[voiceMatchEnabled_]]">
+          <div class="settings-box two-line">
+            <div class="start text-area">
+              <div class="label">
+                $i18n{googleAssistantVoiceSettings}
+              </div>
+              <div class="secondary label">
+                $i18n{googleAssistantVoiceSettingsDescription}
+              </div>
             </div>
-            <div class="secondary label">
-              $i18n{googleAssistantVoiceSettingsDescription}
-            </div>
+            <paper-button id="button" class="secondary-button"
+                on-click="onRetrainVoiceModelTapped_">
+              $i18n{googleAssistantVoiceSettingsRetrainButton}
+            </paper-button>
+            <paper-button id="button" class="secondary-button"
+                on-click="onDeleteVoiceModelTapped_">
+              $i18n{googleAssistantVoiceSettingsDeleteButton}
+            </paper-button>
           </div>
-          <paper-button id="button" class="secondary-button"
-              on-click="onRetrainVoiceModelTapped_">
-            $i18n{googleAssistantVoiceSettingsRetrainButton}
-          </paper-button>
-          <paper-button id="button" class="secondary-button"
-              on-click="onDeleteVoiceModelTapped_">
-            $i18n{googleAssistantVoiceSettingsDeleteButton}
-          </paper-button>
-        </div>
+        </template>
         <settings-toggle-button id="googleAssistantNotificationEnable"
             pref="{{prefs.settings.voice_interaction.notification.enabled}}"
             label="$i18n{googleAssistantEnableNotification}"
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js
index 7aaa74f..8205b12 100644
--- a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js
+++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js
@@ -31,6 +31,12 @@
     },
 
     /** @private */
+    voiceMatchEnabled_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /** @private */
     hotwordDspAvailable_: {
       type: Boolean,
       value: function() {
@@ -148,6 +154,9 @@
   /** @private */
   onPrefsChanged_: function() {
     this.refreshDspHotwordState_();
+
+    this.voiceMatchEnabled_ = loadTimeData.getBoolean('voiceMatchEnabled') &&
+        this.getPref('settings.voice_interaction.hotword.enabled.value');
   },
 
   /** @private */
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js b/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js
index 43d7827..c988dbd 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js
+++ b/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js
@@ -131,9 +131,20 @@
         ])
         .then(args => {
           const canSetDefault = args[0];
-          if (!canSetDefault) {
-            modules = modules.filter(module => module != 'nux-set-as-default');
-          }
+
+          modules = modules.filter(module => {
+            if (module == 'nux-set-as-default') {
+              return canSetDefault;
+            }
+
+            if (module == 'nux-email') {
+              // Show email module in en-US only until email recommendations
+              // for other locales is figured out.
+              return navigator.language == 'en-US';
+            }
+
+            return true;
+          });
 
           const indicatorElementCount = modules.reduce((count, module) => {
             return count += MODULES_NEEDING_INDICATOR.has(module) ? 1 : 0;
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index 33d7acf..e7f5dfe 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/safe_browsing/test_extension_event_observer.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "chrome/browser/signin/account_fetcher_service_factory.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/fake_account_fetcher_service_builder.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
@@ -33,7 +32,6 @@
 #include "components/safe_browsing/password_protection/password_protection_navigation_throttle.h"
 #include "components/safe_browsing/password_protection/password_protection_request.h"
 #include "components/signin/core/browser/account_info.h"
-#include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/fake_account_fetcher_service.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/sync/user_events/fake_user_event_service.h"
@@ -255,13 +253,9 @@
     FakeAccountFetcherService* account_fetcher_service =
         static_cast<FakeAccountFetcherService*>(
             AccountFetcherServiceFactory::GetForProfile(profile()));
-    AccountTrackerService* account_tracker_service =
-        AccountTrackerServiceFactory::GetForProfile(profile());
-    std::string gaia_id = account_info.gaia;
-    std::string email = account_info.email;
     account_fetcher_service->FakeUserInfoFetchSuccess(
-        account_tracker_service->PickAccountIdForAccount(gaia_id, email), email,
-        gaia_id, hosted_domain, "full_name", "given_name", "locale",
+        account_info.account_id, account_info.email, account_info.gaia,
+        hosted_domain, "full_name", "given_name", "locale",
         "http://picture.example.com/picture.jpg");
   }
 
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc
index 30bd9c1..a9e340d 100644
--- a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc
+++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task/post_task.h"
@@ -19,6 +20,7 @@
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
+#include "components/safe_browsing/db/database_manager.h"
 #include "components/safe_browsing/features.h"
 #include "components/safe_browsing/ping_manager.h"
 #include "components/safe_browsing/web_ui/safe_browsing_ui.h"
@@ -91,7 +93,10 @@
 AndroidTelemetryService::AndroidTelemetryService(
     SafeBrowsingService* sb_service,
     Profile* profile)
-    : TelemetryService(), profile_(profile), sb_service_(sb_service) {
+    : TelemetryService(),
+      profile_(profile),
+      sb_service_(sb_service),
+      weak_ptr_factory_(this) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(profile_);
   DCHECK(sb_service_);
@@ -126,6 +131,10 @@
     return;
   }
 
+  // The report can be sent. Try capturing the safety net ID. This should
+  // complete before the download completes, but is not guaranteed, That's OK.
+  MaybeCaptureSafetyNetId();
+
   item->AddObserver(this);
 }
 
@@ -225,6 +234,21 @@
       recent_navigations_to_collect, report->mutable_referrer_chain());
 }
 
+void AndroidTelemetryService::MaybeCaptureSafetyNetId() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(sb_service_->database_manager());
+  if (!safety_net_id_on_ui_thread_.empty()) {
+    return;
+  }
+
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, {content::BrowserThread::IO},
+      base::BindOnce(&SafeBrowsingDatabaseManager::GetSafetyNetId,
+                     sb_service_->database_manager()),
+      base::BindOnce(&AndroidTelemetryService::SetSafetyNetIdOnUIThread,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
 void AndroidTelemetryService::MaybeSendApkDownloadReport(
     download::DownloadItem* item) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -249,7 +273,6 @@
   mutable_download_item_info->set_length(item->GetReceivedBytes());
   mutable_download_item_info->set_file_basename(
       item->GetTargetFilePath().BaseName().value());
-  // TODO(vakh): Capture |safety_net_id_on_ui_thread_|. It is unset currently.
   report->set_safety_net_id(safety_net_id_on_ui_thread_);
 
   std::string serialized;
@@ -270,4 +293,9 @@
   RecordApkDownloadTelemetryOutcome(ApkDownloadTelemetryOutcome::SENT);
 }
 
+void AndroidTelemetryService::SetSafetyNetIdOnUIThread(const std::string& sid) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  safety_net_id_on_ui_thread_ = sid;
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h
index 0b17ac2..682813b 100644
--- a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h
+++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/safe_browsing/telemetry/telemetry_service.h"
 #include "components/download/public/common/download_item.h"
 #include "components/safe_browsing/proto/csd.pb.h"
@@ -59,11 +60,20 @@
   void FillReferrerChain(content::WebContents* web_contents,
                          ClientSafeBrowsingReportRequest* report);
 
+  // If |safety_net_id_on_ui_thread_| isn't already set, post a task on the IO
+  // thread to get the safety net ID of the device and then store that value on
+  // the UI thread in |safety_net_id_on_ui_thread_|.
+  void MaybeCaptureSafetyNetId();
+
   // Sets the relevant fields in an instance of
   // |ClientSafeBrowsingReportRequest| and sends it to the Safe Browsing
   // backend. The report may not be sent if the proto fails to serialize.
   void MaybeSendApkDownloadReport(download::DownloadItem* item);
 
+  // Gets called on the UI thread when the |safety_net_id| of the device has
+  // been captured. Sets |safety_net_id_on_ui_thread_| to the captured value.
+  void SetSafetyNetIdOnUIThread(const std::string& safety_net_id);
+
   // Helper method to get prefs from |profile_|.
   const PrefService* GetPrefs();
 
@@ -78,6 +88,8 @@
   // Unowned.
   SafeBrowsingService* sb_service_;
 
+  base::WeakPtrFactory<AndroidTelemetryService> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(AndroidTelemetryService);
 };
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 4430a22e..7ab4785 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -337,7 +337,8 @@
     ]
   }
 
-  allow_circular_includes_from = []
+  # TODO(crbug/925153): Remove this circular dependency.
+  allow_circular_includes_from = [ "//chrome/browser/safe_browsing" ]
   defines = []
   libs = []
 
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
index 7567a66..e814193 100644
--- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
+++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
@@ -412,18 +412,10 @@
       "http://site1.com", "http://www.site2.com", "http://sité3.com",
       "http://www.sité4.com"};
 
-  // Set high engagement scores in the main profile and low engagement scores
-  // in incognito. Main profile should record metrics, incognito shouldn't.
-  Browser* incognito = CreateIncognitoBrowser();
-  LookalikeUrlService::Get(incognito->profile())
-      ->SetClockForTesting(test_clock());
-
   for (const char* const kSite : kEngagedSites) {
     SetEngagementScore(browser(), GURL(kSite), kHighEngagement);
-    SetEngagementScore(incognito, GURL(kSite), kLowEngagement);
   }
 
-  // Main profile should record metrics because there are engaged sites.
   std::vector<GURL> ukm_urls;
   for (const auto& test_case : kSiteEngagementTestCases) {
     base::HistogramTester histograms;
@@ -445,11 +437,43 @@
     CheckUkm(ukm_urls,
              LookalikeUrlNavigationObserver::MatchType::kSiteEngagement);
   }
+}
+
+// Similar to Idn_SiteEngagement_Match, but tests a single domain. Also checks
+// that the list of engaged sites in incognito and the main profile don't affect
+// each other.
+IN_PROC_BROWSER_TEST_P(LookalikeUrlNavigationObserverBrowserTest,
+                       Idn_SiteEngagement_Match_Incognito) {
+  const GURL kNavigatedUrl = GetURL("sité1.com");
+  const GURL kEngagedUrl = GetURL("site1.com");
+
+  // Set high engagement scores in the main profile and low engagement scores
+  // in incognito. Main profile should record metrics, incognito shouldn't.
+  Browser* incognito = CreateIncognitoBrowser();
+  LookalikeUrlService::Get(incognito->profile())
+      ->SetClockForTesting(test_clock());
+  SetEngagementScore(browser(), kEngagedUrl, kHighEngagement);
+  SetEngagementScore(incognito, kEngagedUrl, kLowEngagement);
+
+  std::vector<GURL> ukm_urls;
+  // Main profile should record metrics because there are engaged sites.
+  {
+    base::HistogramTester histograms;
+    // Advance the clock to force LookalikeUrlService to fetch a new engaged
+    // site list.
+    test_clock()->Advance(base::TimeDelta::FromHours(1));
+    TestHistogramEventsRecordedAndInfobarVisibility(
+        browser(), &histograms, kNavigatedUrl, kEngagedUrl,
+        NavigationSuggestionEvent::kMatchSiteEngagement);
+
+    ukm_urls.push_back(kNavigatedUrl);
+    CheckUkm(ukm_urls,
+             LookalikeUrlNavigationObserver::MatchType::kSiteEngagement);
+  }
 
   // Incognito shouldn't record metrics because there are no engaged sites.
-  for (const auto& test_case : kSiteEngagementTestCases) {
+  {
     base::HistogramTester histograms;
-    const GURL kNavigatedUrl = GetURL(test_case.navigated);
     test_clock()->Advance(base::TimeDelta::FromHours(1));
     TestInfobarNotShown(incognito, kNavigatedUrl);
     histograms.ExpectTotalCount(LookalikeUrlNavigationObserver::kHistogramName,
@@ -458,35 +482,25 @@
 
   // Now reverse the scores: Set low engagement in the main profile and high
   // engagement in incognito.
-  for (const char* const kSite : kEngagedSites) {
-    SetEngagementScore(browser(), GURL(kSite), kLowEngagement);
-    SetEngagementScore(incognito, GURL(kSite), kHighEngagement);
-  }
+  SetEngagementScore(browser(), kEngagedUrl, kLowEngagement);
+  SetEngagementScore(incognito, kEngagedUrl, kHighEngagement);
 
   // Incognito should start recording metrics and main profile should stop.
-  for (const auto& test_case : kSiteEngagementTestCases) {
+  {
     base::HistogramTester histograms;
-    const GURL kNavigatedUrl = GetURL(test_case.navigated);
-    const GURL kExpectedSuggestedUrl = GetURL(test_case.suggested);
-
-    // Even if the navigated site has a low engagement score, it should be
-    // considered for lookalike suggestions.
-    SetEngagementScore(incognito, kNavigatedUrl, kLowEngagement);
-    // Advance the clock to force LookalikeUrlService to fetch a new engaged
-    // site list.
     test_clock()->Advance(base::TimeDelta::FromHours(1));
 
     TestHistogramEventsRecordedAndInfobarVisibility(
-        incognito, &histograms, kNavigatedUrl, kExpectedSuggestedUrl,
+        incognito, &histograms, kNavigatedUrl, kEngagedUrl,
         NavigationSuggestionEvent::kMatchSiteEngagement);
     ukm_urls.push_back(kNavigatedUrl);
     CheckUkm(ukm_urls,
              LookalikeUrlNavigationObserver::MatchType::kSiteEngagement);
   }
+
   // Main profile shouldn't record metrics because there are no engaged sites.
-  for (const auto& test_case : kSiteEngagementTestCases) {
+  {
     base::HistogramTester histograms;
-    const GURL kNavigatedUrl = GetURL(test_case.navigated);
     test_clock()->Advance(base::TimeDelta::FromHours(1));
     TestInfobarNotShown(browser(), kNavigatedUrl);
     histograms.ExpectTotalCount(LookalikeUrlNavigationObserver::kHistogramName,
diff --git a/chrome/browser/ui/signin_view_controller.cc b/chrome/browser/ui/signin_view_controller.cc
index f5c1c01..bc8d3d6 100644
--- a/chrome/browser/ui/signin_view_controller.cc
+++ b/chrome/browser/ui/signin_view_controller.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/dice_tab_helper.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_promo.h"
@@ -81,12 +80,12 @@
 
 // Returns the promo action to be used when signing with a new account.
 signin_metrics::PromoAction GetPromoActionForNewAccount(
-    AccountTrackerService* account_tracker,
+    identity::IdentityManager* identity_manager,
     signin::AccountConsistencyMethod account_consistency) {
   if (account_consistency != signin::AccountConsistencyMethod::kDice)
     return signin_metrics::PromoAction::PROMO_ACTION_NEW_ACCOUNT_PRE_DICE;
 
-  return account_tracker->GetAccounts().size() > 0
+  return identity_manager->GetAccountsWithRefreshTokens().size() > 0
              ? signin_metrics::PromoAction::
                    PROMO_ACTION_NEW_ACCOUNT_EXISTING_ACCOUNT
              : signin_metrics::PromoAction::
@@ -125,8 +124,7 @@
     email = manager->GetPrimaryAccountInfo().email;
   }
   signin_metrics::PromoAction promo_action = GetPromoActionForNewAccount(
-      AccountTrackerServiceFactory::GetForProfile(profile),
-      account_consistency);
+      IdentityManagerFactory::GetForProfile(profile), account_consistency);
   ShowDiceSigninTab(browser, signin_reason, access_point, promo_action, email,
                     redirect_url);
 }
diff --git a/chrome/browser/ui/webui/chromeos/first_run/first_run_handler.cc b/chrome/browser/ui/webui/chromeos/first_run/first_run_handler.cc
index f20a4561..523bbed 100644
--- a/chrome/browser/ui/webui/chromeos/first_run/first_run_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/first_run/first_run_handler.cc
@@ -4,11 +4,26 @@
 
 #include "chrome/browser/ui/webui/chromeos/first_run/first_run_handler.h"
 
+#include <utility>
+
+#include "ash/public/interfaces/voice_interaction_controller.mojom.h"
 #include "base/bind.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/arc/arc_util.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "content/public/browser/web_ui.h"
 
+namespace {
+
+bool IsAssistantAllowed() {
+  return ash::mojom::AssistantAllowedState::ALLOWED ==
+         arc::IsAssistantAllowedForProfile(
+             ProfileManager::GetActiveUserProfile());
+}
+
+}  // namespace
+
 namespace chromeos {
 
 FirstRunHandler::FirstRunHandler()
@@ -47,9 +62,7 @@
   step_params.SetKey("name", base::Value(name));
   step_params.SetKey("position", position.AsValue());
   step_params.SetKey("pointWithOffset", base::Value(base::Value::Type::LIST));
-  step_params.SetKey(
-      "voiceInteractionEnabled",
-      base::Value(chromeos::switches::IsVoiceInteractionEnabled()));
+  step_params.SetKey("assistantEnabled", base::Value(IsAssistantAllowed()));
 
   web_ui()->CallJavascriptFunctionUnsafe("cr.FirstRun.showStep", step_params);
 }
@@ -66,9 +79,7 @@
   point_with_offset.AppendInteger(y);
   point_with_offset.AppendInteger(offset);
   step_params.SetKey("pointWithOffset", std::move(point_with_offset));
-  step_params.SetKey(
-      "voiceInteractionEnabled",
-      base::Value(chromeos::switches::IsVoiceInteractionEnabled()));
+  step_params.SetKey("assistantEnabled", base::Value(IsAssistantAllowed()));
 
   web_ui()->CallJavascriptFunctionUnsafe("cr.FirstRun.showStep", step_params);
 }
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 15cccc58..b42f338 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/printing/print_preview_data_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/webui/dark_mode_handler.h"
 #include "chrome/browser/ui/webui/localized_string.h"
 #include "chrome/browser/ui/webui/metrics_handler.h"
 #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
@@ -468,6 +469,7 @@
   // Set up the chrome://print/ data source.
   Profile* profile = Profile::FromWebUI(web_ui);
   content::WebUIDataSource* source = CreatePrintPreviewUISource(profile);
+  DarkModeHandler::Initialize(web_ui, source);
   content::WebUIDataSource::Add(profile, source);
 
   // Set up the chrome://theme/ source.
diff --git a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
index 95320dd..adf20e0 100644
--- a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
@@ -59,14 +59,13 @@
     AccountTrackerService* account_tracker_service,
     identity::IdentityManager* identity_manager)
     : account_manager_(account_manager),
-      account_tracker_service_(account_tracker_service),
       identity_manager_(identity_manager),
-      account_mapper_util_(account_tracker_service_),
+      account_mapper_util_(account_tracker_service),
       account_manager_observer_(this),
-      account_tracker_service_observer_(this),
+      identity_manager_observer_(this),
       weak_factory_(this) {
   DCHECK(account_manager_);
-  DCHECK(account_tracker_service_);
+  DCHECK(identity_manager_);
 }
 
 AccountManagerUIHandler::~AccountManagerUIHandler() = default;
@@ -123,9 +122,6 @@
         account_manager::AccountType::ACCOUNT_TYPE_GAIA) {
       continue;
     }
-    AccountInfo account_info =
-        account_tracker_service_->FindAccountInfoByGaiaId(account_key.id);
-    DCHECK(!account_info.IsEmpty());
 
     base::DictionaryValue account;
     account.SetString("id", account_key.id);
@@ -140,11 +136,18 @@
             !identity_manager_
                  ->HasAccountWithRefreshTokenInPersistentErrorState(
                      oauth_account_id));
-    account.SetString("fullName", account_info.full_name);
-    account.SetString("email", account_info.email);
-    if (!account_info.account_image.IsEmpty()) {
-      account.SetString("pic", webui::GetBitmapDataUrl(
-                                   account_info.account_image.AsBitmap()));
+
+    base::Optional<AccountInfo> maybe_account_info =
+        identity_manager_->FindAccountInfoForAccountWithRefreshTokenByGaiaId(
+            account_key.id);
+    DCHECK(maybe_account_info.has_value());
+
+    account.SetString("fullName", maybe_account_info->full_name);
+    account.SetString("email", maybe_account_info->email);
+    if (!maybe_account_info->account_image.IsEmpty()) {
+      account.SetString("pic",
+                        webui::GetBitmapDataUrl(
+                            maybe_account_info->account_image.AsBitmap()));
     } else {
       gfx::ImageSkia default_icon =
           *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
@@ -214,19 +217,19 @@
 
 void AccountManagerUIHandler::OnJavascriptAllowed() {
   account_manager_observer_.Add(account_manager_);
-  account_tracker_service_observer_.Add(account_tracker_service_);
+  identity_manager_observer_.Add(identity_manager_);
 }
 
 void AccountManagerUIHandler::OnJavascriptDisallowed() {
   account_manager_observer_.RemoveAll();
-  account_tracker_service_observer_.RemoveAll();
+  identity_manager_observer_.RemoveAll();
 }
 
-// |AccountManager::Observer| overrides.
-// Note: We need to listen on |AccountManager| in addition to
-// |AccountTrackerService| because there is no guarantee that |AccountManager|
-// (our source of truth) will have a newly added account by the time
-// |AccountTrackerService| has it.
+// |AccountManager::Observer| overrides. Note: We need to listen on
+// |AccountManager| in addition to |IdentityManager| because there is no
+// guarantee that |AccountManager| (our source of truth) will have a newly added
+// account by the time the underlying |AccountTrackerService| managed by the
+// |IdentityManager| has it.
 void AccountManagerUIHandler::OnTokenUpserted(
     const AccountManager::AccountKey& account_key) {
   RefreshUI();
@@ -237,18 +240,18 @@
   RefreshUI();
 }
 
-// |AccountTrackerService::Observer| overrides.
-// For newly added accounts, |AccountTrackerService| may take some time to
-// fetch user's full name and account image. Whenever that is completed, we
-// may need to update the UI with this new set of information.
-// Note that we may be listening to |AccountTrackerService| but we still
-// consider |AccountManager| to be the source of truth for account list.
+// |identity::IdentityManager::Observer| overrides. For newly added accounts,
+// |identity::IdentityManager| may take some time to fetch user's full name and
+// account image. Whenever that is completed, we may need to update the UI with
+// this new set of information. Note that we may be listening to
+// |identity::IdentityManager| but we still consider |AccountManager| to be the
+// source of truth for account list.
 void AccountManagerUIHandler::OnAccountUpdated(const AccountInfo& info) {
   RefreshUI();
 }
 
-void AccountManagerUIHandler::OnAccountRemoved(const AccountInfo& account_key) {
-}
+void AccountManagerUIHandler::OnAccountRemovedWithInfo(
+    const AccountInfo& account_key) {}
 
 void AccountManagerUIHandler::RefreshUI() {
   FireWebUIListener("accounts-changed");
diff --git a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h
index e97cfdb9..0eb1750a 100644
--- a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h
@@ -14,18 +14,19 @@
 #include "chrome/browser/chromeos/account_mapper_util.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "chromeos/account_manager/account_manager.h"
-#include "components/signin/core/browser/account_tracker_service.h"
 #include "services/identity/public/cpp/identity_manager.h"
 
+class AccountTrackerService;
+
 namespace chromeos {
 namespace settings {
 
 class AccountManagerUIHandler : public ::settings::SettingsPageUIHandler,
                                 public AccountManager::Observer,
-                                public AccountTrackerService::Observer {
+                                public identity::IdentityManager::Observer {
  public:
-  // Accepts non-owning pointers to |AccountManager| and
-  // |AccountTrackerService|. Both of these must outlive |this| instance.
+  // Accepts non-owning pointers to |AccountManager|, |AccountTrackerService|
+  // and |IdentityManager|. Both of these must outlive |this| instance.
   AccountManagerUIHandler(AccountManager* account_manager,
                           AccountTrackerService* account_tracker_service,
                           identity::IdentityManager* identity_manager);
@@ -42,9 +43,9 @@
   void OnTokenUpserted(const AccountManager::AccountKey& account_key) override;
   void OnAccountRemoved(const AccountManager::AccountKey& account_key) override;
 
-  // |AccountTrackerService::Observer| overrides.
+  // |identity::IdentityManager::Observer| overrides.
   void OnAccountUpdated(const AccountInfo& info) override;
-  void OnAccountRemoved(const AccountInfo& account_key) override;
+  void OnAccountRemovedWithInfo(const AccountInfo& account_key) override;
 
  private:
   // WebUI "getAccounts" message callback.
@@ -73,9 +74,6 @@
   // A non-owning pointer to |AccountManager|.
   AccountManager* const account_manager_;
 
-  // A non-owning pointer to |AccountTrackerService|.
-  AccountTrackerService* const account_tracker_service_;
-
   // A non-owning pointer to |IdentityManager|.
   identity::IdentityManager* const identity_manager_;
 
@@ -86,10 +84,10 @@
   ScopedObserver<AccountManager, AccountManager::Observer>
       account_manager_observer_;
 
-  // An observer for |AccountTrackerService|. Automatically deregisters when
+  // An observer for |identity::IdentityManager|. Automatically deregisters when
   // |this| is destructed.
-  ScopedObserver<AccountTrackerService, AccountTrackerService::Observer>
-      account_tracker_service_observer_;
+  ScopedObserver<identity::IdentityManager, identity::IdentityManager::Observer>
+      identity_manager_observer_;
 
   base::WeakPtrFactory<AccountManagerUIHandler> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(AccountManagerUIHandler);
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 6e713e6..9bc0e9c 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -2263,6 +2263,11 @@
 
   html_source->AddBoolean("hotwordDspAvailable",
                           chromeos::IsHotwordDspAvailable());
+
+  html_source->AddBoolean(
+      "voiceMatchEnabled",
+      base::FeatureList::IsEnabled(
+          chromeos::assistant::features::kAssistantVoiceMatch));
 }
 #endif
 
diff --git a/chrome/browser/ui/webui/signin/md_user_manager_ui.cc b/chrome/browser/ui/webui/signin/md_user_manager_ui.cc
index c012745..7c65f834 100644
--- a/chrome/browser/ui/webui/signin/md_user_manager_ui.cc
+++ b/chrome/browser/ui/webui/signin/md_user_manager_ui.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_shortcut_manager.h"
 #include "chrome/browser/signin/signin_util.h"
+#include "chrome/browser/ui/webui/dark_mode_handler.h"
 #include "chrome/browser/ui/webui/signin/signin_create_profile_handler.h"
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
 #include "chrome/browser/ui/webui/signin/user_manager_screen_handler.h"
@@ -44,6 +45,7 @@
 
   // Set up the chrome://md-user-manager/ source.
   auto* md_user_source = CreateUIDataSource(localized_strings);
+  DarkModeHandler::Initialize(web_ui, md_user_source);
   content::WebUIDataSource::Add(profile, md_user_source);
 
   // Set up the chrome://theme/ source
diff --git a/chrome/test/chromedriver/chrome/version.cc b/chrome/test/chromedriver/chrome/version.cc
index 93c492fb..54c3592a 100644
--- a/chrome/test/chromedriver/chrome/version.cc
+++ b/chrome/test/chromedriver/chrome/version.cc
@@ -9,7 +9,7 @@
 namespace {
 
 // This variable must be able to be found and parsed by the upload script.
-const int kMinimumSupportedChromeVersion[] = {70, 0, 3538, 0};
+const int kMinimumSupportedChromeVersion[] = {71, 0, 3578, 0};
 
 }  // namespace
 
diff --git a/chrome/test/chromedriver/test/run_all_tests.py b/chrome/test/chromedriver/test/run_all_tests.py
index 033a90b..9e712007 100755
--- a/chrome/test/chromedriver/test/run_all_tests.py
+++ b/chrome/test/chromedriver/test/run_all_tests.py
@@ -217,21 +217,21 @@
     versions = {'HEAD': archive.GetLatestRevision()}
     # Linux64 build numbers
     if util.IsLinux():
+      versions['73'] = '625894'
       versions['72'] = '612434'
       versions['71'] = '599034'
-      versions['70'] = '587811'
 
     # Mac build numbers
     elif util.IsMac():
+      versions['73'] = '625897'
       versions['72'] = '612451'
       versions['71'] = '599028'
-      versions['70'] = '587811'
 
     # Windows build numbers
     elif util.IsWindows():
+      versions['73'] = '625885'
       versions['72'] = '612432'
       versions['71'] = '598927'
-      versions['70'] = '587814'
 
     code = 0
     for version, revision in versions.iteritems():
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 378e4ce4..9791a7af 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -98,6 +98,11 @@
     'ChromeDriverPageLoadTimeoutTest.testRefreshWithPageLoadTimeout',
 ]
 
+_VERSION_SPECIFIC_FILTER['73'] = [
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2532
+    'ChromeDriverPageLoadTimeoutTest.testRefreshWithPageLoadTimeout',
+]
+
 _VERSION_SPECIFIC_FILTER['72'] = [
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2532
     'ChromeDriverPageLoadTimeoutTest.testRefreshWithPageLoadTimeout',
@@ -108,12 +113,6 @@
     'ChromeDriverPageLoadTimeoutTest.testRefreshWithPageLoadTimeout',
 ]
 
-_VERSION_SPECIFIC_FILTER['70'] = [
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2532
-    'ChromeDriverPageLoadTimeoutTest.testRefreshWithPageLoadTimeout',
-    # Feature not yet supported in this version
-    'ChromeDriverTest.testGenerateTestReport',
-]
 
 
 _OS_SPECIFIC_FILTER = {}
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index a820b964..f9320612 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-11644.0.0
\ No newline at end of file
+11651.0.0
\ No newline at end of file
diff --git a/chromeos/constants/chromeos_switches.cc b/chromeos/constants/chromeos_switches.cc
index 500a9e0..7f5833f 100644
--- a/chromeos/constants/chromeos_switches.cc
+++ b/chromeos/constants/chromeos_switches.cc
@@ -27,14 +27,6 @@
 // all stored user keys will be converted to GaiaId)
 const char kTestCrosGaiaIdMigrationStarted[] = "started";
 
-// Controls whether to enable assistant for locale.
-const base::Feature kAssistantFeatureForLocale{
-    "ChromeOSAssistantForLocale", base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Controls whether to enable voice interaction feature.
-const base::Feature kVoiceInteractionFeature{"ChromeOSVoiceInteraction",
-                                             base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Controls whether Instant Tethering supports hosts which use the background
 // advertisement model.
 const base::Feature kInstantTetheringBackgroundAdvertisementSupport{
@@ -360,9 +352,6 @@
 const char kEnableVideoPlayerChromecastSupport[] =
     "enable-video-player-chromecast-support";
 
-// Enables the VoiceInteraction support.
-const char kEnableVoiceInteraction[] = "enable-voice-interaction";
-
 // Disables ARC for managed accounts.
 const char kEnterpriseDisableArc[] = "enterprise-disable-arc";
 
@@ -551,9 +540,6 @@
 const char kTetherHostScansIgnoreWiredConnections[] =
     "tether-host-scans-ignore-wired-connections";
 
-// List of locales supported by voice interaction.
-const char kVoiceInteractionLocales[] = "voice-interaction-supported-locales";
-
 // Used to tell the policy infrastructure to not let profile initialization
 // complete until policy is manually set by a test. This is used to provide
 // backward compatibility with a few tests that incorrectly use the
@@ -625,40 +611,6 @@
   return base::CommandLine::ForCurrentProcess()->HasSwitch(kCellularFirst);
 }
 
-bool IsVoiceInteractionLocalesSupported() {
-  // We use Chromium variations to control locales for which assistant should
-  // be enabled. But we still keep checking the previously hard-coded locales
-  // for compatibility.
-  if (base::FeatureList::IsEnabled(kAssistantFeatureForLocale))
-    return true;
-
-  // TODO(updowndota): Add DCHECK here to make sure the value never changes
-  // after all the use case for this method has been moved into user session.
-
-  // Disable voice interaction for non-supported locales.
-  std::string kLocale = icu::Locale::getDefault().getName();
-  if (kLocale != ULOC_US && kLocale != ULOC_UK && kLocale != ULOC_CANADA &&
-      base::CommandLine::ForCurrentProcess()
-              ->GetSwitchValueASCII(
-                  chromeos::switches::kVoiceInteractionLocales)
-              .find(kLocale) == std::string::npos) {
-    return false;
-  }
-  return true;
-}
-
-bool IsVoiceInteractionFlagsEnabled() {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  return !IsAssistantFlagsEnabled() &&
-         (command_line->HasSwitch(kEnableVoiceInteraction) ||
-          base::FeatureList::IsEnabled(kVoiceInteractionFeature));
-}
-
-bool IsVoiceInteractionEnabled() {
-  return IsVoiceInteractionLocalesSupported() &&
-         IsVoiceInteractionFlagsEnabled();
-}
-
 bool IsAccountManagerEnabled() {
   return base::FeatureList::IsEnabled(kAccountManager);
 }
diff --git a/chromeos/constants/chromeos_switches.h b/chromeos/constants/chromeos_switches.h
index b3782b3..2a90cb1 100644
--- a/chromeos/constants/chromeos_switches.h
+++ b/chromeos/constants/chromeos_switches.h
@@ -103,7 +103,6 @@
 CHROMEOS_EXPORT extern const char kEnableTouchCalibrationSetting[];
 CHROMEOS_EXPORT extern const char kEnableTouchpadThreeFingerClick[];
 CHROMEOS_EXPORT extern const char kEnableVideoPlayerChromecastSupport[];
-CHROMEOS_EXPORT extern const char kEnableVoiceInteraction[];
 CHROMEOS_EXPORT extern const char kEnterpriseDisableArc[];
 CHROMEOS_EXPORT extern const char kEnterpriseDisableLicenseTypeSelection[];
 CHROMEOS_EXPORT extern const char kEnterpriseEnableForcedReEnrollment[];
@@ -150,7 +149,6 @@
 CHROMEOS_EXPORT extern const char kTestWallpaperServer[];
 CHROMEOS_EXPORT extern const char kTetherStub[];
 CHROMEOS_EXPORT extern const char kTetherHostScansIgnoreWiredConnections[];
-CHROMEOS_EXPORT extern const char kVoiceInteractionLocales[];
 CHROMEOS_EXPORT extern const char kWaitForInitialPolicyFetchForTest[];
 CHROMEOS_EXPORT extern const char kWakeOnWifiPacket[];
 
@@ -183,15 +181,6 @@
 // Returns true if this is a Cellular First device.
 CHROMEOS_EXPORT bool IsCellularFirstDevice();
 
-// Returns true if the locale is supported by voice interaction.
-CHROMEOS_EXPORT bool IsVoiceInteractionLocalesSupported();
-
-// Returns true if voice interaction flags are enabled.
-CHROMEOS_EXPORT bool IsVoiceInteractionFlagsEnabled();
-
-// Returns true if voice interaction is enabled.
-CHROMEOS_EXPORT bool IsVoiceInteractionEnabled();
-
 // Returns true if Chrome OS Account Manager is enabled.
 CHROMEOS_EXPORT bool IsAccountManagerEnabled();
 
diff --git a/chromeos/dbus/shill_manager_client_unittest.cc b/chromeos/dbus/shill_manager_client_unittest.cc
index d854dbe5..4867622 100644
--- a/chromeos/dbus/shill_manager_client_unittest.cc
+++ b/chromeos/dbus/shill_manager_client_unittest.cc
@@ -144,7 +144,7 @@
   property_dict_writer.CloseContainer(&property_entry_writer);
   wap_list_writer.CloseContainer(&property_dict_writer);
   variant_writer.CloseContainer(&wap_list_writer);
-  type_entry_writer.CloseContainer(&wap_list_writer);
+  type_entry_writer.CloseContainer(&variant_writer);
   type_dict_writer.CloseContainer(&type_entry_writer);
   writer.CloseContainer(&type_dict_writer);
 
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index c446763f..bc09293 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1415,6 +1415,11 @@
     FormData* form,
     FormFieldData* field) {
   form->origin = GetCanonicalOriginForDocument(document);
+  if (!document.Body().IsNull()) {
+    SCOPED_UMA_HISTOGRAM_TIMER(
+        "PasswordManager.ButtonTitlePerformance.NoFormTag");
+    form->button_titles = InferButtonTitlesForForm(document.Body());
+  }
   if (document.GetFrame() && document.GetFrame()->Top()) {
     form->main_frame_origin = document.GetFrame()->Top()->GetSecurityOrigin();
   } else {
@@ -1791,6 +1796,11 @@
   form->unique_renderer_id = form_element.UniqueRendererFormId();
   form->origin = GetCanonicalOriginForDocument(frame->GetDocument());
   form->action = GetCanonicalActionForForm(form_element);
+  {
+    SCOPED_UMA_HISTOGRAM_TIMER(
+        "PasswordManager.ButtonTitlePerformance.HasFormTag");
+    form->button_titles = InferButtonTitlesForForm(form_element);
+  }
   if (frame->Top()) {
     form->main_frame_origin = frame->Top()->GetSecurityOrigin();
   } else {
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 46afe629..6f71f1eb 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -368,6 +368,8 @@
     "test_autofill_manager.h",
     "test_autofill_profile_validator.cc",
     "test_autofill_profile_validator.h",
+    "test_autofill_profile_validator_delayed.cc",
+    "test_autofill_profile_validator_delayed.h",
     "test_autofill_provider.cc",
     "test_autofill_provider.h",
     "test_credit_card_save_manager.cc",
diff --git a/components/autofill/core/browser/autofill_profile_validator.cc b/components/autofill/core/browser/autofill_profile_validator.cc
index 35d0a46..6a2744f 100644
--- a/components/autofill/core/browser/autofill_profile_validator.cc
+++ b/components/autofill/core/browser/autofill_profile_validator.cc
@@ -14,7 +14,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
-#include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_profile_validation_util.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h"
@@ -39,14 +38,13 @@
     base::WeakPtr<const AutofillProfile> profile,
     autofill::AddressValidator* validator,
     AutofillProfileValidatorCallback on_validated)
-    : profile_(profile),
+    : profile_(*profile),
       validator_(validator),
       on_validated_(std::move(on_validated)),
       has_responded_(false),
       weak_factory_(this) {
   on_timeout_.Reset(base::BindOnce(&ValidationRequest::OnRulesLoaded,
                              weak_factory_.GetWeakPtr()));
-  DCHECK(profile_);
   base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, on_timeout_.callback(),
       base::TimeDelta::FromSeconds(kRulesLoadingTimeoutSeconds));
@@ -63,12 +61,8 @@
     return;
   has_responded_ = true;
 
-  if (!profile_)
-    return;
-
-  profile_validation_util::ValidateProfile(profile_.get(), validator_);
-
-  std::move(on_validated_).Run(profile_.get());
+  profile_validation_util::ValidateProfile(&profile_, validator_);
+  std::move(on_validated_).Run(&profile_);
 }
 
 AutofillProfileValidator::AutofillProfileValidator(
@@ -102,7 +96,7 @@
 
     // Start loading the rules for the region. If the rules were already in the
     // process of being loaded, this call will do nothing.
-    address_validator_.LoadRules(region_code);
+    LoadRulesForRegion(region_code);
   }
 }
 
diff --git a/components/autofill/core/browser/autofill_profile_validator.h b/components/autofill/core/browser/autofill_profile_validator.h
index 52d88a8..2253b4d4 100644
--- a/components/autofill/core/browser/autofill_profile_validator.h
+++ b/components/autofill/core/browser/autofill_profile_validator.h
@@ -14,14 +14,13 @@
 
 #include "base/cancelable_callback.h"
 #include "base/macros.h"
+#include "components/autofill/core/browser/autofill_profile.h"
 #include "third_party/libaddressinput/chromium/chrome_address_validator.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
 
 namespace autofill {
 
-class AutofillProfile;
-
 using AutofillProfileValidatorCallback =
     base::OnceCallback<void(const AutofillProfile*)>;
 
@@ -45,6 +44,13 @@
   void StartProfileValidation(const AutofillProfile* profile,
                               AutofillProfileValidatorCallback cb);
 
+ protected:
+  // Starts loading the rules for the specified |region_code|.
+  virtual void LoadRulesForRegion(const std::string& region_code);
+
+  // The address validator used to load rules.
+  AddressValidator address_validator_;
+
  private:
   // ValidationRequest loads Rules from the server and validates various fields
   // in an autofill profile.
@@ -60,7 +66,7 @@
     void OnRulesLoaded();
 
    private:
-    base::WeakPtr<const AutofillProfile> profile_;
+    AutofillProfile profile_;
 
     // Not owned. Outlives this object.
     AddressValidator* validator_;
@@ -78,9 +84,6 @@
   // Returns whether the rules for the specified |region_code| is loaded.
   bool AreRulesLoadedForRegion(const std::string& region_code);
 
-  // Starts loading the rules for the specified |region_code|.
-  void LoadRulesForRegion(const std::string& region_code);
-
   // Implementation of the LoadRulesListener interface. Called when the address
   // rules for the |region_code| have finished loading.
   void OnAddressValidationRulesLoaded(const std::string& region_code,
@@ -90,9 +93,6 @@
   std::map<std::string, std::vector<std::unique_ptr<ValidationRequest>>>
       pending_requests_;
 
-  // The address validator used to load rules.
-  AddressValidator address_validator_;
-
   DISALLOW_COPY_AND_ASSIGN(AutofillProfileValidator);
 };
 
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 437e16a..119f18e 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -632,11 +632,8 @@
   AutofillProfile* profile = GetProfileByGUID(data_model.guid());
   if (profile) {
     if (profile->record_type() == AutofillProfile::LOCAL_PROFILE) {
-      // We can't make the change directly on the web_profiles_, the update
-      // should happen in the database first.
-      AutofillProfile updated_profile(*profile);
-      updated_profile.RecordAndLogUse();
-      UpdateProfileInDB(updated_profile);
+      profile->RecordAndLogUse();
+      UpdateProfileInDB(*profile, /*enforced=*/true);
     } else if (profile->record_type() == AutofillProfile::SERVER_PROFILE) {
       profile->RecordAndLogUse();
       // TODO(crbug.com/864519): Update this once addresses support account
@@ -1009,17 +1006,38 @@
       CHROME_VERSION_MAJOR;
   for (const auto* profile : profiles) {
     if (!profile->is_client_validity_states_updated() || update_validation) {
+      profile->set_is_client_validity_states_updated(false);
+      ongoing_profile_changes_[profile->guid()].push_back(
+          AutofillProfileDeepChange(AutofillProfileChange::UPDATE, *profile));
+      ongoing_profile_changes_[profile->guid()].back().set_enforce_update();
       client_profile_validator_->StartProfileValidation(
           profile, base::BindOnce(&PersonalDataManager::OnValidated,
                                   weak_factory_.GetWeakPtr()));
     }
   }
+
   // Set the pref to the current major version if already not set.
   if (update_validation)
     pref_service_->SetInteger(prefs::kAutofillLastVersionValidated,
                               CHROME_VERSION_MAJOR);
 }
 
+bool PersonalDataManager::UpdateClientValidityStates(
+    const AutofillProfile& profile) {
+  if (!base::FeatureList::IsEnabled(
+          autofill::features::kAutofillProfileClientValidation) ||
+      !client_profile_validator_ ||
+      profile.is_client_validity_states_updated()) {
+    OnValidated(&profile);
+    return false;
+  }
+
+  client_profile_validator_->StartProfileValidation(
+      &profile, base::BindOnce(&PersonalDataManager::OnValidated,
+                               weak_factory_.GetWeakPtr()));
+  return true;
+}
+
 std::vector<AutofillProfile*> PersonalDataManager::GetServerProfiles() const {
   std::vector<AutofillProfile*> result;
   if (!IsAutofillProfileEnabled())
@@ -1343,7 +1361,7 @@
   for (AutofillProfile* profile : GetProfiles()) {
     if (profile->origin() != kSettingsOrigin && !profile->origin().empty()) {
       profile->set_origin(std::string());
-      UpdateProfileInDB(*profile);
+      UpdateProfileInDB(*profile, /*enforced=*/true);
     }
   }
 
@@ -1387,9 +1405,7 @@
                            : street_address + line_separator + city;
       profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, street_address);
       profile->SetRawInfo(ADDRESS_HOME_CITY, base::string16());
-
-      // Make the update.
-      UpdateProfileInDB(*profile);
+      UpdateProfileInDB(*profile, /*enforced=*/true);
     }
   }
 
@@ -1398,17 +1414,36 @@
 }
 
 void PersonalDataManager::OnValidated(const AutofillProfile* profile) {
-  // We always set a value for country validity state.
-  DCHECK(profile->GetValidityState(ServerFieldType::ADDRESS_HOME_COUNTRY,
-                                   AutofillProfile::CLIENT) !=
-         AutofillProfile::UNVALIDATED);
+  if (!profile)
+    return;
+
+  if (!ProfileChangesAreOnGoing(profile->guid()))
+    return;
 
   // Set the validity states updated, only when the validation has occurred. If
   // the rules were not loaded for any reason, don't set the flag.
-  if (profile->GetValidityState(ServerFieldType::ADDRESS_HOME_COUNTRY,
-                                AutofillProfile::CLIENT) !=
-      AutofillProfile::UNVALIDATED)
-    profile->set_is_client_validity_states_updated(true);
+  bool validity_updated =
+      (profile->GetValidityState(ServerFieldType::ADDRESS_HOME_COUNTRY,
+                                 AutofillProfile::CLIENT) !=
+       AutofillProfile::UNVALIDATED);
+
+  // For every relevant profile change on the ongoing_profile_changes_, mark the
+  // change to show that the validation is done, and set the validity of the
+  // profile if the validity was updated.
+  for (const auto& change : ongoing_profile_changes_[profile->guid()]) {
+    if (!profile->EqualsForClientValidationPurpose(*(change.profile())))
+      continue;
+
+    change.validation_effort_made();
+
+    if (validity_updated) {
+      change.profile()->set_is_client_validity_states_updated(true);
+      change.profile()->SetClientValidityFromBitfieldValue(
+          profile->GetClientValidityBitfieldValue());
+    }
+  }
+
+  HandleNextProfileChange(profile->guid());
 }
 
 const ProfileValidityMap& PersonalDataManager::GetProfileValidityByGUID(
@@ -1955,10 +1990,8 @@
     const AutofillProfileDeepChange& change) {
   const auto& guid = change.key();
   const auto& change_type = change.type();
-  const auto& profile = change.profile();
-
+  const auto& profile = *(change.profile());
   DCHECK(guid == profile.guid());
-
   // Happens only in tests.
   if (!ProfileChangesAreOnGoing(guid)) {
     DVLOG(1) << "Received an unexpected response from database.";
@@ -1977,7 +2010,8 @@
     case AutofillProfileChange::UPDATE:
       profiles_server_validities_need_update_ = true;
       if (profile_exists &&
-          !existing_profile->EqualsForUpdatePurposes(profile)) {
+          (change.enforce_update() ||
+           !existing_profile->EqualsForUpdatePurposes(profile))) {
         web_profiles_.erase(
             FindElementByGUID<AutofillProfile>(web_profiles_, guid));
         web_profiles_.push_back(std::make_unique<AutofillProfile>(profile));
@@ -2580,7 +2614,6 @@
 }
 
 void PersonalDataManager::AddProfileToDB(const AutofillProfile& profile) {
-  // Add the new profile to the web database.
   if (profile.IsEmpty(app_locale_)) {
     NotifyPersonalDataChanged();
     return;
@@ -2592,26 +2625,30 @@
       NotifyPersonalDataChanged();
       return;
     }
-    database_helper_->GetLocalDatabase()->AddAutofillProfile(profile);
   }
-  ongoing_profile_changes_[profile.guid()].push(
+  ongoing_profile_changes_[profile.guid()].push_back(
       AutofillProfileDeepChange(AutofillProfileChange::ADD, profile));
+  UpdateClientValidityStates(profile);
 }
 
-void PersonalDataManager::UpdateProfileInDB(const AutofillProfile& profile) {
-  if (!ProfileChangesAreOnGoing(profile.guid())) {
+void PersonalDataManager::UpdateProfileInDB(const AutofillProfile& profile,
+                                            bool enforced) {
+  // if the update is enforced, don't check if a similar profile already exists
+  // or not. Otherwise, check if updating the profile makes sense.
+  if (!enforced && !ProfileChangesAreOnGoing(profile.guid())) {
     const auto* existing_profile = GetProfileByGUID(profile.guid());
     bool profile_exists = (existing_profile != nullptr);
-    if (profile_exists && !existing_profile->EqualsForUpdatePurposes(profile)) {
-      database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile);
-    } else {
+    if (!profile_exists || existing_profile->EqualsForUpdatePurposes(profile)) {
       NotifyPersonalDataChanged();
       return;
     }
   }
 
-  ongoing_profile_changes_[profile.guid()].push(
+  ongoing_profile_changes_[profile.guid()].push_back(
       AutofillProfileDeepChange(AutofillProfileChange::UPDATE, profile));
+  if (enforced)
+    ongoing_profile_changes_[profile.guid()].back().set_enforce_update();
+  UpdateClientValidityStates(profile);
 }
 
 void PersonalDataManager::RemoveProfileFromDB(const std::string& guid) {
@@ -2620,11 +2657,12 @@
     NotifyPersonalDataChanged();
     return;
   }
-
-  if (!ProfileChangesAreOnGoing(guid))
+  AutofillProfileDeepChange change(AutofillProfileChange::REMOVE, guid);
+  if (!ProfileChangesAreOnGoing(guid)) {
     database_helper_->GetLocalDatabase()->RemoveAutofillProfile(guid);
-  ongoing_profile_changes_[guid].push(
-      AutofillProfileDeepChange(AutofillProfileChange::REMOVE, guid));
+    change.set_is_ongoing_on_background();
+  }
+  ongoing_profile_changes_[guid].push_back(std::move(change));
 }
 
 void PersonalDataManager::HandleNextProfileChange(const std::string& guid) {
@@ -2632,10 +2670,13 @@
     return;
 
   const auto& change = ongoing_profile_changes_[guid].front();
+  if (change.is_ongoing_on_background())
+    return;
+
   const auto& change_type = change.type();
   const auto* existing_profile = GetProfileByGUID(guid);
   const bool profile_exists = (existing_profile != nullptr);
-  const auto& profile = ongoing_profile_changes_[guid].front().profile();
+  const auto& profile = *(ongoing_profile_changes_[guid].front().profile());
 
   DCHECK(guid == profile.guid());
 
@@ -2645,23 +2686,30 @@
       return;
     }
     database_helper_->GetLocalDatabase()->RemoveAutofillProfile(guid);
+    change.set_is_ongoing_on_background();
     return;
   }
 
+  if (!change.has_validation_effort_made())
+    return;
+
   if (change_type == AutofillProfileChange::ADD) {
     if (profile_exists || FindByContents(web_profiles_, profile)) {
       OnProfileChangeDone(guid);
       return;
     }
     database_helper_->GetLocalDatabase()->AddAutofillProfile(profile);
+    change.set_is_ongoing_on_background();
     return;
   }
 
-  if (!profile_exists || existing_profile->EqualsForUpdatePurposes(profile)) {
+  if (profile_exists && (change.enforce_update() ||
+                         !existing_profile->EqualsForUpdatePurposes(profile))) {
+    database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile);
+    change.set_is_ongoing_on_background();
+  } else {
     OnProfileChangeDone(guid);
-    return;
   }
-  database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile);
 }
 
 bool PersonalDataManager::ProfileChangesAreOnGoing(const std::string& guid) {
@@ -2680,7 +2728,7 @@
 }
 
 void PersonalDataManager::OnProfileChangeDone(const std::string& guid) {
-  ongoing_profile_changes_[guid].pop();
+  ongoing_profile_changes_[guid].pop_front();
 
   if (!ProfileChangesAreOnGoing()) {
     Refresh();
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 754305d..2f36e65 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PERSONAL_DATA_MANAGER_H_
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_PERSONAL_DATA_MANAGER_H_
 
+#include <deque>
 #include <list>
 #include <memory>
 #include <set>
@@ -255,11 +256,16 @@
   void UpdateProfilesServerValidityMapsIfNeeded(
       const std::vector<AutofillProfile*>& profiles);
 
-  // Updates the validity states of |profiles| according to client side
-  // validation API: |client_profile_validator_|.
+  // Requests an update for the validity states of the |profiles| according to
+  // client side validation API: |client_profile_validator_|.
   void UpdateClientValidityStates(
       const std::vector<AutofillProfile*>& profiles);
 
+  // Requests an update for the validity states of the |profile| according to
+  // the client side validation API: |client_profile_validator_|. Returns true
+  // if the validation was requested.
+  bool UpdateClientValidityStates(const AutofillProfile& profile);
+
   // Returns the profiles to suggest to the user, ordered by frecency.
   std::vector<AutofillProfile*> GetProfilesToSuggest() const;
 
@@ -388,6 +394,11 @@
   // Triggered when a profile is added/updated/removed on db.
   void OnAutofillProfileChanged(const AutofillProfileDeepChange& change);
 
+  void set_client_profile_validator_for_test(
+      AutofillProfileValidator* validator) {
+    client_profile_validator_ = validator;
+  }
+
  protected:
   // Only PersonalDataManagerFactory and certain tests can create instances of
   // PersonalDataManager.
@@ -467,9 +478,16 @@
                            ClearCreditCardNonSettingsOrigins);
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
                            MoveJapanCityToStreetAddress);
-  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, RequestProfileValidity);
+  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
+                           RequestProfileServerValidity);
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
                            GetProfileSuggestions_InvalidDataBasedOnServer);
+  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerMockTest,
+                           UpdateProfilesValidityStates_MoveToJapan);
+  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerMockTest,
+                           UpdateProfilesValidityStates_AddUpdateSet);
+  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerMockTest,
+                           UpdateProfilesValidityStates_Dedupe);
 
   friend class autofill::AutofillInteractiveTest;
   friend class autofill::PersonalDataManagerFactory;
@@ -477,6 +495,8 @@
   friend class FormDataImporterTest;
   friend class PersonalDataManagerTest;
   friend class PersonalDataManagerTestBase;
+  friend class PersonalDataManagerHelper;
+  friend class PersonalDataManagerMockTest;
   friend class SaveImportedProfileTest;
   friend class ProfileSyncServiceAutofillTest;
   friend class ::RemoveAutofillTester;
@@ -561,7 +581,8 @@
   // https://crbug.com/871301
   void MoveJapanCityToStreetAddress();
 
-  // Called when the |profile| is validated by the AutofillProfileValidator.
+  // Called when the |profile| is validated by the AutofillProfileValidator,
+  // updates the profiles on the |ongoing_profile_changes_| and the DB.
   virtual void OnValidated(const AutofillProfile* profile);
 
   // Get the profiles fields validity map by |guid|.
@@ -722,9 +743,11 @@
   // Resets |synced_profile_validity_|.
   void ResetProfileValidity();
 
-  // Add/Update/Remove profiles on DB.
+  // Add/Update/Remove |profile| on DB.
   void AddProfileToDB(const AutofillProfile& profile);
-  void UpdateProfileInDB(const AutofillProfile& profile);
+  // |enforced| is true when the update should happen regardless of an equal
+  // profile. (equal in the sense of AutofillProfile::EqualForUpdate)
+  void UpdateProfileInDB(const AutofillProfile& profile, bool enforced = false);
   void RemoveProfileFromDB(const std::string& guid);
 
   // Look at the next profile change for profile with guid = |guid|, and handle
@@ -764,11 +787,11 @@
 
   // Profiles validity read from the prefs. They are kept updated by
   // observing changes in pref_services. We need to set the
-  // |profile_validities_need_update| whenever this is changed.
+  // |profile_validities_need_update_| whenever this is changed.
   std::unique_ptr<UserProfileValidityMap> synced_profile_validity_;
 
   // A timely ordered list of on going changes for each profile.
-  std::unordered_map<std::string, std::queue<AutofillProfileDeepChange>>
+  std::unordered_map<std::string, std::deque<AutofillProfileDeepChange>>
       ongoing_profile_changes_;
 
   // The client side profile validator.
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index f06c16f..f2230dc 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -176,13 +176,6 @@
     account_database_service_->Init();
 
     test::DisableSystemServices(prefs_.get());
-    ResetPersonalDataManager(USER_MODE_NORMAL);
-
-    // Reset the deduping and profile validation prefs to their default value.
-    personal_data_->pref_service_->SetInteger(
-        prefs::kAutofillLastVersionDeduped, 0);
-    personal_data_->pref_service_->SetInteger(
-        prefs::kAutofillLastVersionValidated, CHROME_VERSION_MAJOR);
   }
 
   void TearDownTest() {
@@ -193,10 +186,10 @@
   }
 
   void ResetPersonalDataManager(UserMode user_mode,
-                                bool use_sync_transport_mode) {
+                                bool use_sync_transport_mode,
+                                PersonalDataManager* personal_data_) {
     bool is_incognito = (user_mode == USER_MODE_INCOGNITO);
 
-    personal_data_.reset(new PersonalDataManagerMock("en"));
     personal_data_->Init(
         scoped_refptr<AutofillWebDataService>(profile_database_service_),
         base::FeatureList::IsEnabled(
@@ -219,8 +212,113 @@
     WaitForOnPersonalDataChangedRepeatedly();
   }
 
-  void ResetPersonalDataManager(UserMode user_mode) {
-    ResetPersonalDataManager(user_mode, /*use_sync_transport_mode=*/false);
+  bool TurnOnSyncFeature(PersonalDataManager* personal_data_)
+      WARN_UNUSED_RESULT {
+    sync_service_.SetIsAuthenticatedAccountPrimary(true);
+    if (!sync_service_.IsSyncFeatureEnabled())
+      return false;
+    personal_data_->OnStateChanged(&sync_service_);
+
+    return personal_data_->IsSyncFeatureEnabled();
+  }
+
+  void EnableWalletCardImport() {
+    identity_test_env_.MakePrimaryAccountAvailable("syncuser@example.com");
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kEnableOfferStoreUnmaskedWalletCards);
+  }
+
+  void RemoveByGUIDFromPersonalDataManager(
+      const std::string& guid,
+      PersonalDataManager* personal_data_) {
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillOnce(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
+
+    personal_data_->RemoveByGUID(guid);
+    run_loop.Run();
+  }
+
+  void SetServerCards(std::vector<CreditCard> server_cards) {
+    test::SetServerCreditCards(account_autofill_table_, server_cards);
+  }
+
+  // Verify that the web database has been updated and the notification sent.
+  void WaitOnceForOnPersonalDataChanged() {
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillOnce(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+    run_loop.Run();
+  }
+
+  // Verifies that the web database has been updated and the notification sent.
+  void WaitForOnPersonalDataChanged() {
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillOnce(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
+    run_loop.Run();
+  }
+
+  // Verifies that the web database has been updated and the notification sent.
+  void WaitForOnPersonalDataChangedRepeatedly() {
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillRepeatedly(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
+    run_loop.Run();
+  }
+
+  AccountInfo SetActiveSecondaryAccount() {
+    AccountInfo account_info;
+    account_info.email = "signed_in_account@email.com";
+    account_info.account_id = "account_id";
+    sync_service_.SetAuthenticatedAccountInfo(account_info);
+    sync_service_.SetIsAuthenticatedAccountPrimary(false);
+    return account_info;
+  }
+
+  void MoveJapanCityToStreetAddress(PersonalDataManager* personal_data_,
+                                    int move_times) {
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillRepeatedly(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(move_times);
+    personal_data_->MoveJapanCityToStreetAddress();
+    run_loop.Run();
+  }
+
+  // The temporary directory should be deleted at the end to ensure that
+  // files are not used anymore and deletion succeeds.
+  base::ScopedTempDir temp_dir_;
+  base::test::ScopedTaskEnvironment task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::UI};
+  std::unique_ptr<PrefService> prefs_;
+  identity::IdentityTestEnvironment identity_test_env_;
+  syncer::TestSyncService sync_service_;
+  scoped_refptr<AutofillWebDataService> profile_database_service_;
+  scoped_refptr<AutofillWebDataService> account_database_service_;
+  scoped_refptr<WebDatabaseService> profile_web_database_;
+  scoped_refptr<WebDatabaseService> account_web_database_;
+  AutofillTable* profile_autofill_table_;  // weak ref
+  AutofillTable* account_autofill_table_;  // weak ref
+  PersonalDataLoadedObserverMock personal_data_observer_;
+  base::test::ScopedFeatureList scoped_features_;
+};
+
+class PersonalDataManagerHelper : public PersonalDataManagerTestBase {
+ protected:
+  void ResetPersonalDataManager(UserMode user_mode,
+                                bool use_account_server_storage = false) {
+    personal_data_.reset(new PersonalDataManager("en"));
+    PersonalDataManagerTestBase::ResetPersonalDataManager(
+        user_mode, use_account_server_storage, personal_data_.get());
   }
 
   void ResetProfiles() {
@@ -229,12 +327,8 @@
     WaitForOnPersonalDataChanged();
   }
 
-  bool TurnOnSyncFeature() WARN_UNUSED_RESULT {
-    sync_service_.SetIsAuthenticatedAccountPrimary(true);
-    if (!sync_service_.IsSyncFeatureEnabled())
-      return false;
-    personal_data_->OnStateChanged(&sync_service_);
-    return personal_data_->IsSyncFeatureEnabled();
+  bool TurnOnSyncFeature() {
+    return PersonalDataManagerTestBase::TurnOnSyncFeature(personal_data_.get());
   }
 
   void EnableWalletCardImport() {
@@ -400,14 +494,8 @@
   }
 
   void RemoveByGUIDFromPersonalDataManager(const std::string& guid) {
-    base::RunLoop run_loop;
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
-        .WillOnce(QuitMessageLoop(&run_loop));
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .Times(testing::AnyNumber());
-
-    personal_data_->RemoveByGUID(guid);
-    run_loop.Run();
+    PersonalDataManagerTestBase::RemoveByGUIDFromPersonalDataManager(
+        guid, personal_data_.get());
   }
 
   void SetServerCards(const std::vector<CreditCard>& server_cards) {
@@ -423,7 +511,8 @@
     base::RunLoop run_loop;
     EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
         .WillOnce(QuitMessageLoop(&run_loop));
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
 
     personal_data_->SaveImportedProfile(profile);
     run_loop.Run();
@@ -433,45 +522,56 @@
     base::RunLoop run_loop;
     EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
         .WillOnce(QuitMessageLoop(&run_loop));
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
 
     personal_data_->ConvertWalletAddressesAndUpdateWalletCards();
     run_loop.Run();
   }
 
-  // Verifies that the web database has been updated and the notification sent.
-  void WaitForOnPersonalDataChanged() {
-    base::RunLoop run_loop;
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
-        .WillOnce(QuitMessageLoop(&run_loop));
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .Times(testing::AnyNumber());
-    run_loop.Run();
+  std::unique_ptr<PersonalDataManager> personal_data_;
+};
+
+class PersonalDataManagerTest : public PersonalDataManagerHelper,
+                                public testing::Test {
+ protected:
+  void SetUp() override {
+    SetUpTest();
+    ResetPersonalDataManager(USER_MODE_NORMAL);
+  }
+  void TearDown() override { TearDownTest(); }
+};
+
+class PersonalDataManagerMockTest : public PersonalDataManagerTestBase,
+                                    public testing::Test {
+ protected:
+  void SetUp() override {
+    SetUpTest();
+    ResetPersonalDataManager(USER_MODE_NORMAL);
+    // Reset the deduping and profile validation prefs to their default value.
+    personal_data_->pref_service_->SetInteger(
+        prefs::kAutofillLastVersionDeduped, 0);
+    personal_data_->pref_service_->SetInteger(
+        prefs::kAutofillLastVersionValidated,
+        atoi(version_info::GetVersionNumber().c_str()));
+    personal_data_->is_autofill_profile_cleanup_pending_ = true;
+  }
+  void TearDown() override { TearDownTest(); }
+
+  void ResetPersonalDataManager(UserMode user_mode) {
+    personal_data_.reset(new PersonalDataManagerMock("en"));
+    PersonalDataManagerTestBase::ResetPersonalDataManager(
+        user_mode, /*use_account_server_storage=*/true, personal_data_.get());
   }
 
-  void WaitOnceForOnPersonalDataChanged() {
-    base::RunLoop run_loop;
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
-        .WillOnce(QuitMessageLoop(&run_loop));
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
-    run_loop.Run();
+  bool TurnOnSyncFeature() {
+    return PersonalDataManagerTestBase::TurnOnSyncFeature(personal_data_.get());
   }
 
-  // Verifies that the web database has been updated and the notification sent.
-  void WaitForOnPersonalDataChangedRepeatedly() {
-    base::RunLoop run_loop;
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
-        .WillRepeatedly(QuitMessageLoop(&run_loop));
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .Times(testing::AnyNumber());
-    run_loop.Run();
-  }
-
-  void ExpectOnValidated(AutofillProfile* profile) {
-    EXPECT_CALL(*personal_data_, OnValidated(profile)).Times(1);
-    ON_CALL(*personal_data_, OnValidated(profile))
-        .WillByDefault(testing::Invoke(
-            personal_data_.get(), &PersonalDataManagerMock::OnValidatedPDM));
+  void StopTheDedupeProcess() {
+    personal_data_->pref_service_->SetInteger(
+        prefs::kAutofillLastVersionDeduped,
+        atoi(version_info::GetVersionNumber().c_str()));
   }
 
   void ResetAutofillLastVersionValidated() {
@@ -480,44 +580,81 @@
         prefs::kAutofillLastVersionValidated, 0);
   }
 
+  void AddProfileToPersonalDataManager(const AutofillProfile& profile) {
+    base::RunLoop run_loop;
+
+    EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(1);
+    ON_CALL(*personal_data_, OnValidated(testing::_))
+        .WillByDefault(testing::Invoke(
+            personal_data_.get(), &PersonalDataManagerMock::OnValidatedPDM));
+
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillOnce(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
+
+    personal_data_->AddProfile(profile);
+
+    run_loop.Run();
+  }
+
+  void UpdateProfileOnPersonalDataManager(const AutofillProfile& profile) {
+    base::RunLoop run_loop;
+
+    EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(1);
+    ON_CALL(*personal_data_, OnValidated(testing::_))
+        .WillByDefault(testing::Invoke(
+            personal_data_.get(), &PersonalDataManagerMock::OnValidatedPDM));
+
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillOnce(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
+
+    personal_data_->UpdateProfile(profile);
+
+    run_loop.Run();
+  }
+
+  void RemoveByGUIDFromPersonalDataManager(const std::string& guid) {
+    PersonalDataManagerTestBase::RemoveByGUIDFromPersonalDataManager(
+        guid, personal_data_.get());
+  }
+
+  void UpdateClientValidityStatesOnPersonalDataManager(
+      const std::vector<AutofillProfile*>& profiles) {
+    int num_updates = 0;
+    if (GetLastVersionValidatedUpdate() < CHROME_VERSION_MAJOR) {
+      num_updates = profiles.size();
+    } else {
+      for (auto* profile : profiles) {
+        if (!profile->is_client_validity_states_updated())
+          num_updates++;
+      }
+    }
+
+    base::RunLoop run_loop;
+
+    EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(num_updates);
+    ON_CALL(*personal_data_, OnValidated(testing::_))
+        .WillByDefault(testing::Invoke(
+            personal_data_.get(), &PersonalDataManagerMock::OnValidatedPDM));
+
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillRepeatedly(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
+    // Validate the profiles through the client validation API.
+    personal_data_->UpdateClientValidityStates(profiles);
+    run_loop.Run();
+  }
+
   int GetLastVersionValidatedUpdate() {
     return personal_data_->pref_service_->GetInteger(
         prefs::kAutofillLastVersionValidated);
   }
 
-  AccountInfo SetActiveSecondaryAccount() {
-    AccountInfo account_info;
-    account_info.email = "signed_in_account@email.com";
-    account_info.account_id = "account_id";
-    sync_service_.SetAuthenticatedAccountInfo(account_info);
-    sync_service_.SetIsAuthenticatedAccountPrimary(false);
-    return account_info;
-  }
-
-  // The temporary directory should be deleted at the end to ensure that
-  // files are not used anymore and deletion succeeds.
-  base::ScopedTempDir temp_dir_;
-  base::test::ScopedTaskEnvironment task_environment_{
-      base::test::ScopedTaskEnvironment::MainThreadType::UI};
-  std::unique_ptr<PrefService> prefs_;
-  identity::IdentityTestEnvironment identity_test_env_;
-  syncer::TestSyncService sync_service_;
-  scoped_refptr<AutofillWebDataService> profile_database_service_;
-  scoped_refptr<AutofillWebDataService> account_database_service_;
-  scoped_refptr<WebDatabaseService> profile_web_database_;
-  scoped_refptr<WebDatabaseService> account_web_database_;
-  AutofillTable* profile_autofill_table_ = nullptr;  // weak ref
-  AutofillTable* account_autofill_table_ = nullptr;  // weak ref
-  PersonalDataLoadedObserverMock personal_data_observer_;
   std::unique_ptr<PersonalDataManagerMock> personal_data_;
-  base::test::ScopedFeatureList scoped_features_;
-};
-
-class PersonalDataManagerTest : public PersonalDataManagerTestBase,
-                                public testing::Test {
-  void SetUp() override { SetUpTest(); }
-
-  void TearDown() override { TearDownTest(); }
 };
 
 TEST_F(PersonalDataManagerTest, AddProfile) {
@@ -572,6 +709,7 @@
 
   personal_data_->AddProfile(profile);
   personal_data_->RemoveByGUID(profile.guid());
+  personal_data_->UpdateProfile(profile);
   WaitForOnPersonalDataChanged();
 
   auto profiles = personal_data_->GetProfiles();
@@ -581,20 +719,54 @@
   personal_data_->RemoveByGUID(profile.guid());
   personal_data_->RemoveByGUID(profile.guid());
   WaitForOnPersonalDataChanged();
+
   profiles = personal_data_->GetProfiles();
   ASSERT_EQ(0U, profiles.size());
 
   personal_data_->AddProfile(profile);
   profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("new@email.com"));
   personal_data_->UpdateProfile(profile);
+  WaitForOnPersonalDataChanged();
+
+  profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+  EXPECT_EQ(profiles[0]->GetRawInfo(EMAIL_ADDRESS),
+            base::ASCIIToUTF16("new@email.com"));
+
   profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("newer@email.com"));
   personal_data_->UpdateProfile(profile);
+  profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("newest@email.com"));
+  personal_data_->UpdateProfile(profile);
   WaitForOnPersonalDataChanged();
 
   profiles = personal_data_->GetProfiles();
   ASSERT_EQ(1U, profiles.size());
   EXPECT_EQ(profiles[0]->GetRawInfo(EMAIL_ADDRESS),
-            base::ASCIIToUTF16("newer@email.com"));
+            base::ASCIIToUTF16("newest@email.com"));
+}
+
+// The changes should happen in the same order as requested. If the later change
+// is validated before an earlier one, still we should process the earlier one
+// first.
+TEST_F(PersonalDataManagerTest, InconsistentValidationSequence) {
+  auto profile = test::GetFullProfile();
+  // Slow validation.
+  personal_data_->set_client_profile_validator_for_test(
+      TestAutofillProfileValidator::GetDelayedInstance());
+  personal_data_->AddProfile(profile);
+
+  // No validator, zero delay for validation.
+  personal_data_->set_client_profile_validator_for_test(nullptr);
+  profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("new@email.com"));
+  personal_data_->UpdateProfile(profile);
+
+  WaitForOnPersonalDataChanged();
+
+  auto profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+  EXPECT_EQ(profiles[0]->GetRawInfo(EMAIL_ADDRESS),
+            base::ASCIIToUTF16("new@email.com"));
+  EXPECT_FALSE(profiles[0]->is_client_validity_states_updated());
 }
 
 // Test that a new profile has its basic information set.
@@ -1453,7 +1625,6 @@
                        "Hollywood", "CA", "91601", "US", "12345678910");
   EXPECT_FALSE(profile.IsVerified());
 
-  // Add the profile to the database.
   AddProfileToPersonalDataManager(profile);
 
   // Make sure everything is set up correctly.
@@ -2106,23 +2277,19 @@
 // Tests that suggestions based on invalid data are handled correctly.
 TEST_F(PersonalDataManagerTest,
        GetProfileSuggestions_InvalidDataBasedOnClient) {
-  // Set up 2 different profiles.
-  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
-  test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
+  // The prefs are empty, therefore, there is no server validation.
+  // Set up 2 different profiles: one valid and one invalid.
+  AutofillProfile invalid_profile(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&invalid_profile, "Marion1", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
-                       "Hollywood", "CA", "91601", "US", "9876543210");
-  profile1.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillProfile::INVALID,
-                            AutofillProfile::CLIENT);
-  profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(20));
-  AddProfileToPersonalDataManager(profile1);
+                       "Hollywood", "CA", "91601", "US", "Invalid Phone");
+  invalid_profile.set_use_date(AutofillClock::Now() -
+                               base::TimeDelta::FromDays(20));
+  AddProfileToPersonalDataManager(invalid_profile);
 
-  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
-  test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
-                       "johnwayne@me.xyz", "Fox",
-                       "456 Zoo St.\nSecond Line\nThird line", "unit 5",
-                       "Hollywood", "CA", "91601", "US", "1234567890");
-  AddProfileToPersonalDataManager(profile2);
+  AutofillProfile valid_profile(test::GetFullValidProfileForCanada());
+  AddProfileToPersonalDataManager(valid_profile);
 
   ResetPersonalDataManager(USER_MODE_NORMAL);
   {
@@ -2134,7 +2301,7 @@
         AutofillType(PHONE_HOME_WHOLE_NUMBER), base::string16(), false,
         std::vector<ServerFieldType>());
     ASSERT_EQ(1U, suggestions.size());
-    EXPECT_EQ(base::ASCIIToUTF16("1234567890"), suggestions[0].value);
+    EXPECT_EQ(base::ASCIIToUTF16("+15141112233"), suggestions[0].value);
     histogram_tester.ExpectUniqueSample(
         "Autofill.InvalidProfileData.UsedForSuggestion", false, 1);
   }
@@ -2148,8 +2315,8 @@
         AutofillType(PHONE_HOME_WHOLE_NUMBER), base::string16(), false,
         std::vector<ServerFieldType>());
     ASSERT_EQ(2U, suggestions.size());
-    EXPECT_EQ(base::ASCIIToUTF16("1234567890"), suggestions[0].value);
-    EXPECT_EQ(base::ASCIIToUTF16("9876543210"), suggestions[1].value);
+    EXPECT_EQ(base::ASCIIToUTF16("+15141112233"), suggestions[0].value);
+    EXPECT_EQ(base::ASCIIToUTF16("Invalid Phone"), suggestions[1].value);
     histogram_tester.ExpectUniqueSample(
         "Autofill.InvalidProfileData.UsedForSuggestion", true, 1);
   }
@@ -3535,13 +3702,16 @@
 } SaveImportedProfileTestCase;
 
 class SaveImportedProfileTest
-    : public PersonalDataManagerTestBase,
+    : public PersonalDataManagerHelper,
       public testing::TestWithParam<SaveImportedProfileTestCase> {
  public:
   SaveImportedProfileTest() {}
   ~SaveImportedProfileTest() override {}
 
-  void SetUp() override { SetUpTest(); }
+  void SetUp() override {
+    SetUpTest();
+    ResetPersonalDataManager(USER_MODE_NORMAL);
+  }
 
   void TearDown() override { TearDownTest(); }
 };
@@ -5344,9 +5514,6 @@
   ///////////////////////////////////////////////////////////////////////
   personal_data_->ConvertWalletAddressesAndUpdateWalletCards();
 
-  ///////////////////////////////////////////////////////////////////////
-  // Validation.
-  ///////////////////////////////////////////////////////////////////////
   // Since there should be no change in data, OnPersonalDataChanged should not
   // have been called.
   EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(0);
@@ -5418,6 +5585,7 @@
                           "2999", "1");
   local_card.set_billing_address_id(kServerAddressId);
   personal_data_->AddCreditCard(local_card);
+  WaitForOnPersonalDataChanged();
 
   std::vector<CreditCard> server_cards;
   server_cards.push_back(
@@ -6465,6 +6633,9 @@
 // Tests that all city fields in a Japan profile are moved to the street address
 // field.
 TEST_F(PersonalDataManagerTest, MoveJapanCityToStreetAddress) {
+  // Turn on sync feature to avoid calling MoveJapanCityToStreetAddress on
+  // adding the profiles implicitly.
+  ASSERT_TRUE(TurnOnSyncFeature());
   // A US profile with both street address and a city.
   std::string guid0 = base::GenerateGUID();
   {
@@ -6514,14 +6685,12 @@
                          "JP", "");
     AddProfileToPersonalDataManager(profile4);
   }
+  auto profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(5U, profiles.size());
 
-  base::RunLoop run_loop;
-  EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
-      .WillRepeatedly(QuitMessageLoop(&run_loop));
-  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-      .Times(2);  // For the Japan profiles where the city is not empty.
-  personal_data_->MoveJapanCityToStreetAddress();
-  run_loop.Run();
+  MoveJapanCityToStreetAddress(
+      personal_data_.get(),
+      2);  // For the japan profiles where the city is not empty.
 
   {
     AutofillProfile* profile0 = personal_data_->GetProfileByGUID(guid0);
@@ -6742,9 +6911,9 @@
   EXPECT_EQ(profile, *profiles[0]);
 }
 
-// Requests profiles fields validities: empty profiles, non-existent profiles,
-// and normal ones.
-TEST_F(PersonalDataManagerTest, RequestProfileValidity) {
+// Requests profiles fields validities according to the server: empty profiles,
+// non-existent profiles, and normal ones.
+TEST_F(PersonalDataManagerTest, RequestProfileServerValidity) {
   ResetPersonalDataManager(USER_MODE_NORMAL);
 
   ProfileValidityMap profile_validity_map;
@@ -6823,61 +6992,34 @@
 
 // Use the client side validation API to validate three PDM profiles. This one
 // doesn't test the upload process or saving to the database.
-TEST_F(PersonalDataManagerTest, UpdateClientValidityStates) {
-  // Create three profiles and add them to personal_data_.
-  AutofillProfile valid_profile(test::GetFullValidProfileForCanada());
-  valid_profile.set_use_date(AutofillClock::Now());
-  valid_profile.set_guid("00000000-0000-0000-0000-000000000001");
-  AddProfileToPersonalDataManager(valid_profile);
-
-  AutofillProfile profile_invalid_phone_email(
-      test::GetFullValidProfileForChina());
-  profile_invalid_phone_email.SetRawInfo(
-      PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("invalid phone number!"));
-  profile_invalid_phone_email.SetRawInfo(EMAIL_ADDRESS,
-                                         base::UTF8ToUTF16("invalid email!"));
-  profile_invalid_phone_email.set_use_date(AutofillClock::Now() -
-                                           base::TimeDelta::FromDays(10));
-  profile_invalid_phone_email.set_guid("00000000-0000-0000-0000-000000000002");
-  AddProfileToPersonalDataManager(profile_invalid_phone_email);
-
+TEST_F(PersonalDataManagerMockTest, UpdateClientValidityStates) {
   AutofillProfile profile_invalid_province(base::GenerateGUID(),
                                            test::kEmptyOrigin);
   test::SetProfileInfo(&profile_invalid_province, "Alice", "", "Munro",
                        "alice@munro.ca", "Fox", "123 Zoo St", "unit 5",
                        "Montreal", "CA", "H3C 2A3", "CA", "15142343254");
-  profile_invalid_province.set_guid("00000000-0000-0000-0000-000000000003");
-  profile_invalid_province.set_use_date(AutofillClock::Now() -
-                                        base::TimeDelta::FromDays(100));
   AddProfileToPersonalDataManager(profile_invalid_province);
 
-  ASSERT_EQ(3U, personal_data_->GetProfiles().size());
-
-  // Validate the profiles through the client validation API.
+  ASSERT_EQ(1U, personal_data_->GetProfiles().size());
   auto profiles = personal_data_->GetProfiles();
-  for (auto* profile : profiles) {
-    ASSERT_FALSE(profile->is_client_validity_states_updated());
-    // Expect OnValidated to be called for each profile.
-    ExpectOnValidated(profile);
-  }
+  profiles[0]->set_is_client_validity_states_updated(false);
 
-  personal_data_->UpdateClientValidityStates(profiles);
+  UpdateClientValidityStatesOnPersonalDataManager(profiles);
 
-  ASSERT_EQ(3U, profiles.size());
-  // The profiles are ordered according to their guid.
-  // valid_profile:
-  ASSERT_EQ(valid_profile.guid(), profiles[0]->guid());
+  profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+
   EXPECT_TRUE(profiles[0]->is_client_validity_states_updated());
   EXPECT_EQ(AutofillProfile::VALID,
             profiles[0]->GetValidityState(ADDRESS_HOME_COUNTRY,
                                           AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::VALID,
+  EXPECT_EQ(AutofillProfile::INVALID,
             profiles[0]->GetValidityState(ADDRESS_HOME_STATE,
                                           AutofillProfile::CLIENT));
   EXPECT_EQ(
       AutofillProfile::VALID,
       profiles[0]->GetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::VALID,
+  EXPECT_EQ(AutofillProfile::INVALID,
             profiles[0]->GetValidityState(ADDRESS_HOME_CITY,
                                           AutofillProfile::CLIENT));
   EXPECT_EQ(AutofillProfile::EMPTY,
@@ -6889,59 +7031,10 @@
   EXPECT_EQ(AutofillProfile::VALID,
             profiles[0]->GetValidityState(PHONE_HOME_WHOLE_NUMBER,
                                           AutofillProfile::CLIENT));
-
-  // profile_invalid_phone_email:
-  ASSERT_EQ(profile_invalid_phone_email.guid(), profiles[1]->guid());
-  EXPECT_TRUE(profiles[1]->is_client_validity_states_updated());
-  EXPECT_EQ(AutofillProfile::VALID,
-            profiles[1]->GetValidityState(ADDRESS_HOME_COUNTRY,
-                                          AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::VALID,
-            profiles[1]->GetValidityState(ADDRESS_HOME_STATE,
-                                          AutofillProfile::CLIENT));
-  EXPECT_EQ(
-      AutofillProfile::VALID,
-      profiles[1]->GetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::VALID,
-            profiles[1]->GetValidityState(ADDRESS_HOME_CITY,
-                                          AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::VALID,
-            profiles[1]->GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
-                                          AutofillProfile::CLIENT));
-  EXPECT_EQ(
-      AutofillProfile::INVALID,
-      profiles[1]->GetValidityState(EMAIL_ADDRESS, AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::INVALID,
-            profiles[1]->GetValidityState(PHONE_HOME_WHOLE_NUMBER,
-                                          AutofillProfile::CLIENT));
-
-  ASSERT_EQ(profile_invalid_province.guid(), profiles[2]->guid());
-  EXPECT_TRUE(profiles[2]->is_client_validity_states_updated());
-  EXPECT_EQ(AutofillProfile::VALID,
-            profiles[2]->GetValidityState(ADDRESS_HOME_COUNTRY,
-                                          AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::INVALID,
-            profiles[2]->GetValidityState(ADDRESS_HOME_STATE,
-                                          AutofillProfile::CLIENT));
-  EXPECT_EQ(
-      AutofillProfile::VALID,
-      profiles[2]->GetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::INVALID,
-            profiles[2]->GetValidityState(ADDRESS_HOME_CITY,
-                                          AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::EMPTY,
-            profiles[2]->GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
-                                          AutofillProfile::CLIENT));
-  EXPECT_EQ(
-      AutofillProfile::VALID,
-      profiles[2]->GetValidityState(EMAIL_ADDRESS, AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::VALID,
-            profiles[2]->GetValidityState(PHONE_HOME_WHOLE_NUMBER,
-                                          AutofillProfile::CLIENT));
 }
 
 // Check the validity update status for AutofillProfiles.
-TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_UpdatedFlag) {
+TEST_F(PersonalDataManagerMockTest, UpdateClientValidityStates_UpdatedFlag) {
   // Create two profiles and add them to personal_data_.
   AutofillProfile profile1(test::GetFullValidProfileForCanada());
   AddProfileToPersonalDataManager(profile1);
@@ -6951,18 +7044,10 @@
 
   ASSERT_EQ(2U, personal_data_->GetProfiles().size());
 
-  // Validate the profiles through the client validation API.
+  // The validities were set when the profiles were added.
   auto profiles = personal_data_->GetProfiles();
-  ASSERT_FALSE(profiles[0]->is_client_validity_states_updated());
-  ASSERT_FALSE(profiles[1]->is_client_validity_states_updated());
-
-  ExpectOnValidated(profiles[0]);
-  ExpectOnValidated(profiles[1]);
-  personal_data_->UpdateClientValidityStates(profiles);
-
-  ASSERT_EQ(2U, profiles.size());
-  EXPECT_TRUE(profiles[0]->is_client_validity_states_updated());
-  EXPECT_TRUE(profiles[1]->is_client_validity_states_updated());
+  ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
+  ASSERT_TRUE(profiles[1]->is_client_validity_states_updated());
 
   *profiles[1] = *profiles[0];
   ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
@@ -6972,73 +7057,92 @@
   ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
   ASSERT_FALSE(profiles[1]->is_client_validity_states_updated());
 
-  ExpectOnValidated(profiles[1]);
-  personal_data_->UpdateClientValidityStates(profiles);
-  ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
-  ASSERT_TRUE(profiles[1]->is_client_validity_states_updated());
-
-  profiles[1]->MergeDataFrom(*profiles[0], "en");
-  ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
-  ASSERT_FALSE(profiles[1]->is_client_validity_states_updated());
-
   profiles[0]->SetRawInfo(NAME_FULL, base::UTF8ToUTF16("Goli Boli"));
   ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
 }
 
+// Check the validity update status for AutofillProfiles.
+TEST_F(PersonalDataManagerMockTest,
+       UpdateClientValidityStates_UpdatedFlag_Merge) {
+  // Set the pref to the current major version.
+  StopTheDedupeProcess();
+
+  AutofillProfile profile1(test::GetFullValidProfileForCanada());
+  AddProfileToPersonalDataManager(profile1);
+
+  AutofillProfile profile2(test::GetFullValidProfileForCanada());
+  profile2.set_guid("00000000-0000-0000-0000-000000002019");
+  profile2.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16(""));
+  AddProfileToPersonalDataManager(profile2);
+
+  // The validities were set when the profiles were added.
+  auto profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(2U, profiles.size());
+
+  profiles[1]->MergeDataFrom(*profiles[0], "en");
+  ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
+  ASSERT_FALSE(profiles[1]->is_client_validity_states_updated());
+}
+
 // Check that the validity states are not updated when the validity flags are up
 // to date.
-TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_AlreadyUpdated) {
+TEST_F(PersonalDataManagerMockTest, UpdateClientValidityStates_AlreadyUpdated) {
   // Create two profiles and add them to personal_data_.
   AutofillProfile profile1(test::GetFullValidProfileForCanada());
   profile1.SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16("invalid email!"));
   AddProfileToPersonalDataManager(profile1);
 
-  AutofillProfile profile2(test::GetFullValidProfileForChina());
-  profile2.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("invalid state!"));
-  AddProfileToPersonalDataManager(profile2);
-
-  EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(0);
-
   auto profiles = personal_data_->GetProfiles();
-  ASSERT_EQ(2U, profiles.size());
+  ASSERT_EQ(1U, profiles.size());
+  // The validities were updated when the profile was added.
+  EXPECT_EQ(
+      AutofillProfile::INVALID,
+      profiles[0]->GetValidityState(EMAIL_ADDRESS, AutofillProfile::CLIENT));
+
+  // Change the email, the validity update would turn false.
+  profiles[0]->SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16("alice@gmail.com"));
+  EXPECT_FALSE(profiles[0]->is_client_validity_states_updated());
   // Pretend that the validity states are updated.
   profiles[0]->set_is_client_validity_states_updated(true);
-  profiles[1]->set_is_client_validity_states_updated(true);
 
   // Validating the profiles through the client validation API should not change
   // the validity states.
   personal_data_->UpdateClientValidityStates(profiles);
+
   profiles = personal_data_->GetProfiles();
-  ASSERT_EQ(2U, profiles.size());
-  EXPECT_EQ(AutofillProfile::UNVALIDATED,
-            profiles[0]->GetValidityState(ADDRESS_HOME_COUNTRY,
-                                          AutofillProfile::CLIENT));
+  ASSERT_EQ(1U, profiles.size());
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profiles[0]->GetValidityState(EMAIL_ADDRESS, AutofillProfile::CLIENT));
 
-  EXPECT_EQ(AutofillProfile::UNVALIDATED,
-            profiles[1]->GetValidityState(ADDRESS_HOME_COUNTRY,
-                                          AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::UNVALIDATED,
-            profiles[1]->GetValidityState(ADDRESS_HOME_STATE,
-                                          AutofillProfile::CLIENT));
+  // Try with the flag as not updated.
+  profiles[0]->set_is_client_validity_states_updated(false);
+
+  UpdateClientValidityStatesOnPersonalDataManager(profiles);
+
+  profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+  EXPECT_EQ(
+      AutofillProfile::VALID,
+      profiles[0]->GetValidityState(EMAIL_ADDRESS, AutofillProfile::CLIENT));
 }
 
 // Verify that the fields are validated according to the version.
-TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_Version) {
+TEST_F(PersonalDataManagerMockTest, UpdateClientValidityStates_Version) {
   // Create two profiles and add them to personal_data_. Set the guids
   // explicitly to preserve the order.
-  AutofillProfile profile1(test::GetFullValidProfileForCanada());
-  profile1.SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16("invalid email!"));
-  profile1.set_guid("00000000-0000-0000-0000-000000000001");
-  AddProfileToPersonalDataManager(profile1);
-
   AutofillProfile profile2(test::GetFullValidProfileForChina());
   profile2.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("invalid state!"));
   profile2.set_guid("00000000-0000-0000-0000-000000000002");
+  profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(200));
   AddProfileToPersonalDataManager(profile2);
 
+  AutofillProfile profile1(test::GetFullValidProfileForCanada());
+  profile1.SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16("invalid email!"));
+  profile1.set_use_date(AutofillClock::Now());
+  profile1.set_guid("00000000-0000-0000-0000-000000000001");
+  AddProfileToPersonalDataManager(profile1);
+
   auto profiles = personal_data_->GetProfiles();
 
   // Pretend that the validity states are updated.
@@ -7052,10 +7156,11 @@
   profiles = personal_data_->GetProfiles();
   ASSERT_EQ(2U, profiles.size());
 
-  ExpectOnValidated(profiles[0]);
-  ExpectOnValidated(profiles[1]);
+  UpdateClientValidityStatesOnPersonalDataManager(profiles);
 
-  personal_data_->UpdateClientValidityStates(profiles);
+  profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(2U, profiles.size());
+  ASSERT_EQ(profiles[0]->guid(), profile1.guid());
 
   EXPECT_EQ(AutofillProfile::VALID,
             profiles[0]->GetValidityState(ADDRESS_HOME_COUNTRY,
@@ -7073,17 +7178,47 @@
 
   // Verify that the version of the last update is set to this version.
   EXPECT_EQ(CHROME_VERSION_MAJOR, GetLastVersionValidatedUpdate());
+}
 
-  // Update should not update any validity state, because both the validity
-  // state flag and the version are up to date.
-  // A fake change in the validity state of profile[1].
-  profiles[1]->SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::VALID,
-                                AutofillProfile::CLIENT);
-  EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(0);
-  personal_data_->UpdateClientValidityStates(profiles);
-  EXPECT_EQ(AutofillProfile::VALID,
-            profiles[1]->GetValidityState(ADDRESS_HOME_STATE,
-                                          AutofillProfile::CLIENT));
+// Verifies that the profiles are validated when added, updated.
+TEST_F(PersonalDataManagerMockTest, UpdateProfilesValidityStates_AddUpdate) {
+  // Add
+  AutofillProfile profile1(test::GetFullValidProfileForCanada());
+  AddProfileToPersonalDataManager(profile1);
+
+  auto profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+  EXPECT_EQ(true, profiles[0]->is_client_validity_states_updated());
+
+  // Update
+  profile1.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("email!"));
+  UpdateProfileOnPersonalDataManager(profile1);
+
+  profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+  EXPECT_EQ(true, profiles[0]->is_client_validity_states_updated());
+}
+
+// Verify that slow delayed validation will still work.
+TEST_F(PersonalDataManagerMockTest, UpdateClientValidityStates_Delayed) {
+  personal_data_->set_client_profile_validator_for_test(
+      TestAutofillProfileValidator::GetDelayedInstance());
+
+  AutofillProfile profile(test::GetFullProfile());
+  AddProfileToPersonalDataManager(profile);
+
+  auto profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+
+  profiles[0]->set_is_client_validity_states_updated(false);
+
+  UpdateClientValidityStatesOnPersonalDataManager(profiles);
+  profiles[0] =
+      nullptr;  // make sure the async task doesn't depend on the pointer.
+
+  profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+  EXPECT_TRUE(profiles[0]->is_client_validity_states_updated());
 }
 
 // The validation should not happen when the feature is disabled.
diff --git a/components/autofill/core/browser/test_autofill_profile_validator.cc b/components/autofill/core/browser/test_autofill_profile_validator.cc
index d3eba5d0..88283111 100644
--- a/components/autofill/core/browser/test_autofill_profile_validator.cc
+++ b/components/autofill/core/browser/test_autofill_profile_validator.cc
@@ -49,8 +49,18 @@
   return &(instance.Get().autofill_profile_validator_);
 }
 
+// static
+TestAutofillProfileValidatorDelayed*
+TestAutofillProfileValidator::GetDelayedInstance() {
+  static base::LazyInstance<TestAutofillProfileValidator>::DestructorAtExit
+      instance = LAZY_INSTANCE_INITIALIZER;
+  return &(instance.Get().autofill_profile_validator_delayed_);
+}
+
 TestAutofillProfileValidator::TestAutofillProfileValidator()
-    : autofill_profile_validator_(GetInputSource(), GetInputStorage()) {}
+    : autofill_profile_validator_(GetInputSource(), GetInputStorage()),
+      autofill_profile_validator_delayed_(GetInputSource(), GetInputStorage()) {
+}
 
 TestAutofillProfileValidator::~TestAutofillProfileValidator() {}
 
diff --git a/components/autofill/core/browser/test_autofill_profile_validator.h b/components/autofill/core/browser/test_autofill_profile_validator.h
index 93b7eee..6fa2fbb 100644
--- a/components/autofill/core/browser/test_autofill_profile_validator.h
+++ b/components/autofill/core/browser/test_autofill_profile_validator.h
@@ -8,6 +8,7 @@
 #include "base/lazy_instance.h"
 #include "base/macros.h"
 #include "components/autofill/core/browser/autofill_profile_validator.h"
+#include "components/autofill/core/browser/test_autofill_profile_validator_delayed.h"
 
 namespace autofill {
 
@@ -15,6 +16,7 @@
 class TestAutofillProfileValidator {
  public:
   static AutofillProfileValidator* GetInstance();
+  static TestAutofillProfileValidatorDelayed* GetDelayedInstance();
 
  private:
   friend struct base::LazyInstanceTraitsBase<TestAutofillProfileValidator>;
@@ -22,8 +24,9 @@
   TestAutofillProfileValidator();
   ~TestAutofillProfileValidator();
 
-  // The only instance that exists.
+  // The only instance that exists of normal and delayed validators.
   AutofillProfileValidator autofill_profile_validator_;
+  TestAutofillProfileValidatorDelayed autofill_profile_validator_delayed_;
 
   DISALLOW_COPY_AND_ASSIGN(TestAutofillProfileValidator);
 };
diff --git a/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc b/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc
new file mode 100644
index 0000000..ed92eae
--- /dev/null
+++ b/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/test_autofill_profile_validator_delayed.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/cancelable_callback.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+
+namespace autofill {
+namespace {
+
+const int kRulesDelayedLoadingTimeSeconds = 3;
+
+}  // namespace
+
+TestAutofillProfileValidatorDelayed::TestAutofillProfileValidatorDelayed(
+    std::unique_ptr<::i18n::addressinput::Source> source,
+    std::unique_ptr<::i18n::addressinput::Storage> storage)
+    : AutofillProfileValidator(std::move(source), std::move(storage)) {}
+
+TestAutofillProfileValidatorDelayed::~TestAutofillProfileValidatorDelayed() {}
+
+void TestAutofillProfileValidatorDelayed::LoadRulesInstantly(
+    const std::string& region_code) {
+  address_validator_.LoadRules(region_code);
+}
+
+void TestAutofillProfileValidatorDelayed::LoadRulesForRegion(
+    const std::string& region_code) {
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&TestAutofillProfileValidatorDelayed::LoadRulesInstantly,
+                     base::Unretained(this), region_code),
+      base::TimeDelta::FromSeconds(kRulesDelayedLoadingTimeSeconds));
+}
+}  // namespace autofill
diff --git a/components/autofill/core/browser/test_autofill_profile_validator_delayed.h b/components/autofill/core/browser/test_autofill_profile_validator_delayed.h
new file mode 100644
index 0000000..846c249
--- /dev/null
+++ b/components/autofill/core/browser/test_autofill_profile_validator_delayed.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_PROFILE_VALIDATOR_DELAYED_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_PROFILE_VALIDATOR_DELAYED_H_
+
+#include <memory>
+#include <string>
+
+#include "components/autofill/core/browser/autofill_profile_validator.h"
+#include "third_party/libaddressinput/chromium/chrome_address_validator.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
+
+namespace autofill {
+
+// Singleton that owns a single AutofillProfileValidator instance. It's a
+// delayed validator used in tests, to make sure that the system can handle
+// possible delays in the real world.
+class TestAutofillProfileValidatorDelayed : public AutofillProfileValidator {
+ public:
+  // Takes ownership of |source| and |storage|.
+  TestAutofillProfileValidatorDelayed(
+      std::unique_ptr<::i18n::addressinput::Source> source,
+      std::unique_ptr<::i18n::addressinput::Storage> storage);
+
+  ~TestAutofillProfileValidatorDelayed() override;
+
+  // Starts loading the rules for the specified |region_code|.
+  void LoadRulesForRegion(const std::string& region_code) override;
+
+ private:
+  void LoadRulesInstantly(const std::string& region_code);
+
+  DISALLOW_COPY_AND_ASSIGN(TestAutofillProfileValidatorDelayed);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_PROFILE_VALIDATOR_DELAYED_H_
diff --git a/components/autofill/core/browser/webdata/autofill_change.h b/components/autofill/core/browser/webdata/autofill_change.h
index 16c6290f..9605de1 100644
--- a/components/autofill/core/browser/webdata/autofill_change.h
+++ b/components/autofill/core/browser/webdata/autofill_change.h
@@ -97,10 +97,33 @@
 
   ~AutofillProfileDeepChange() override {}
 
-  AutofillProfile profile() const { return profile_; }
+  const AutofillProfile* profile() const { return &profile_; }
+  bool is_ongoing_on_background() const { return is_ongoing_on_background_; }
+  void set_is_ongoing_on_background() const {
+    is_ongoing_on_background_ = true;
+  }
+
+  void validation_effort_made() const { validation_effort_made_ = true; }
+  bool has_validation_effort_made() const { return validation_effort_made_; }
+
+  void set_enforce_update() { enforce_update_ = true; }
+  bool enforce_update() const { return enforce_update_; }
 
  private:
   AutofillProfile profile_;
+  // Is true when the change is taking place on the database side on the
+  // background.
+  mutable bool is_ongoing_on_background_ = false;
+  // Is true when the |profile_| has gone through the validation process.
+  // Note: This could be different from the
+  // profile_.is_client_validity_states_updated. |validation_effort_made_| shows
+  // that the effort has been made, but not necessarily successful, and profile
+  // validity may or may not be updated.
+  mutable bool validation_effort_made_ = false;
+
+  // Is true when the update should happen regardless of an equal profile.
+  // (equal in the sense of AutofillProfile::EqualForUpdate)
+  mutable bool enforce_update_ = false;
 };
 
 }  // namespace autofill
diff --git a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
index e004fcb..a8953b8 100644
--- a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/guid.h"
+#include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
@@ -180,7 +181,12 @@
   std::unique_ptr<autofill::PersonalDataManager> personal_data_manager_;
 };
 
-TEST_F(AutofillActionTest, FillManually) {
+#if !defined(OS_ANDROID)
+#define MAYBE_FillManually FillManually
+#else
+#define MAYBE_FillManually DISABLED_FillManually
+#endif
+TEST_F(AutofillActionTest, MAYBE_FillManually) {
   InSequence seq;
 
   ActionProto action_proto = CreateUseAddressAction();
diff --git a/components/flags_ui/resources/flags.css b/components/flags_ui/resources/flags.css
index ce18774..5ccff67 100644
--- a/components/flags_ui/resources/flags.css
+++ b/components/flags_ui/resources/flags.css
@@ -16,6 +16,8 @@
   --color-light-gray: rgba(0, 0, 0, 0.54);
   --color-shadow: rgba(0, 0, 0, 0.1);
   --ease-in-out: cubic-bezier(0.4, 0.0, 0.2, 1);
+  --keyboard-focus-ring: rgba(66, 133, 244, 0.4);
+  --google-blue-400: rgb(102, 157, 246);
   --google-blue-500: rgb(66, 133, 244);
   --google-blue-700: rgb(51, 103, 214);
   --google-gray-100: rgb(245, 245, 245);
@@ -390,24 +392,24 @@
   line-height: 1.4;
 }
 
-.experiment-restart-button {
-  background: var(--google-blue-700);
+#experiment-restart-button {
+  background: var(--google-blue-500);
   border: 0;
   border-radius: 3px;
   color: white;
   font-size: 14px;
   padding: 14px 38px;
-  text-transform: uppercase;
 }
 
-.experiment-restart-button:active,
-.experiment-restart-button:focus {
-  background: var(--google-blue-500);
+#experiment-restart-button:active,
+#experiment-restart-button:focus,
+#experiment-restart-button:hover {
+  background: var(--google-blue-400);
   outline: 0;
 }
 
-.experiment-restart-button:hover {
-  background: var(--google-blue-500);
+html.focus-outline-visible #experiment-restart-button:focus {
+  box-shadow: 0 0 0 1px var(--keyboard-focus-ring);
 }
 
 #version {
@@ -433,7 +435,7 @@
     text-align: initial;
   }
 
-  .experiment-restart-button {
+  #experiment-restart-button {
     padding: 8px;
   }
 
@@ -495,7 +497,7 @@
     padding: 8px 12px;
   }
 
-  .experiment-restart-button {
+  #experiment-restart-button {
     padding: 8px 16px;
   }
 
diff --git a/components/flags_ui/resources/flags.html b/components/flags_ui/resources/flags.html
index 1de2f91f..91e4ea7 100644
--- a/components/flags_ui/resources/flags.html
+++ b/components/flags_ui/resources/flags.html
@@ -16,6 +16,8 @@
   <script src="chrome://resources/js/ios/web_ui.js"></script>
 </if>
 
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
 <script src="chrome://resources/js/util.js"></script>
 </head>
 <body>
@@ -205,7 +207,7 @@
         <div class="flex restart-notice" jstcache="0">$i18n{flagsRestartNotice}</div>
         <div class="flex">
 <if expr="not is_ios">
-          <button class="experiment-restart-button" type="button" tabindex="9">
+          <button id="experiment-restart-button" type="button" tabindex="9">
 <if expr="not chromeos">
           Relaunch Now
 </if>
diff --git a/components/flags_ui/resources/flags.js b/components/flags_ui/resources/flags.js
index c6f320f..ba4750f 100644
--- a/components/flags_ui/resources/flags.js
+++ b/components/flags_ui/resources/flags.js
@@ -467,8 +467,12 @@
   }
 };
 
-// Get and display the data upon loading.
-document.addEventListener('DOMContentLoaded', requestExperimentalFeaturesData);
+document.addEventListener('DOMContentLoaded', function() {
+  // Get and display the data upon loading.
+  requestExperimentalFeaturesData();
+
+  cr.ui.FocusOutlineManager.forDocument(document);
+});
 
 // Update the highlighted flag when the hash changes.
 window.addEventListener('hashchange', highlightReferencedFlag);
diff --git a/components/safe_browsing/web_ui/safe_browsing_ui.cc b/components/safe_browsing/web_ui/safe_browsing_ui.cc
index a02ea8f..8e2f1e9a 100644
--- a/components/safe_browsing/web_ui/safe_browsing_ui.cc
+++ b/components/safe_browsing/web_ui/safe_browsing_ui.cc
@@ -1322,6 +1322,7 @@
 
 CrSBLogMessage::~CrSBLogMessage() {
   WebUIInfoSingleton::GetInstance()->LogMessage(stream_.str());
+  DLOG(WARNING) << stream_.str();
 }
 
 }  // namespace safe_browsing
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 94543ce..119c858 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -1279,6 +1279,19 @@
   RunHtmlTest(FILE_PATH_LITERAL("form-validation-message.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(
+    DumpAccessibilityTreeTest,
+    AccessibilityFormValidationMessageRemovedAfterErrorCorrected) {
+  RunHtmlTest(FILE_PATH_LITERAL(
+      "form-validation-message-removed-after-error-corrected.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+                       AccessibilityFormValidationMessageAfterHideTimeout) {
+  RunHtmlTest(
+      FILE_PATH_LITERAL("form-validation-message-after-hide-timeout.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFrameset) {
   RunHtmlTest(FILE_PATH_LITERAL("frameset.html"));
 }
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index cb467d6f..99421a6 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -199,14 +199,6 @@
   DCHECK(!navigation_start.is_null());
   DCHECK(!IsRendererDebugURL(url));
 
-  site_url_ = SiteInstance::GetSiteForURL(frame_tree_node()
-                                              ->current_frame_host()
-                                              ->GetSiteInstance()
-                                              ->GetBrowserContext(),
-                                          url_);
-  if (redirect_chain_.empty())
-    redirect_chain_.push_back(url);
-
   starting_site_instance_ =
       frame_tree_node()->current_frame_host()->GetSiteInstance();
 
diff --git a/content/browser/frame_host/webui_navigation_throttle.cc b/content/browser/frame_host/webui_navigation_throttle.cc
index 625b1cb1..90c03d6 100644
--- a/content/browser/frame_host/webui_navigation_throttle.cc
+++ b/content/browser/frame_host/webui_navigation_throttle.cc
@@ -4,10 +4,12 @@
 
 #include "content/browser/frame_host/webui_navigation_throttle.h"
 
+#include "base/command_line.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 
 namespace content {
@@ -35,7 +37,13 @@
 std::unique_ptr<NavigationThrottle>
 WebUINavigationThrottle::CreateThrottleForNavigation(
     NavigationHandle* navigation_handle) {
-  // Create the throttle only for subframe navigations.
+  // The WebUI security model (which keeps renderes with WebUI bindings separate
+  // from untrusted renderers) only makes sense in multi-process mode.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSingleProcess))
+    return nullptr;
+
+  // Only throttle subframe navigations.
   if (navigation_handle->IsInMainFrame())
     return nullptr;
 
@@ -45,8 +53,8 @@
           ->parent()
           ->current_frame_host();
 
-  // Create a throttle only for navigations where the parent frame is either
-  // at a chrome:// URL or is in a process with WebUI bindings.
+  // Throttle if the renderer process has WebUI bindings, or if the parent frame
+  // is on a WebUI page.
   if (ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
           parent->GetProcess()->GetID()) ||
       parent->GetLastCommittedURL().SchemeIs(kChromeUIScheme)) {
diff --git a/content/browser/indexed_db/indexed_db_cursor.cc b/content/browser/indexed_db/indexed_db_cursor.cc
index 631b5f06..7f1ad84 100644
--- a/content/browser/indexed_db/indexed_db_cursor.cc
+++ b/content/browser/indexed_db/indexed_db_cursor.cc
@@ -87,9 +87,7 @@
   IDB_TRACE("IndexedDBCursor::Continue");
 
   if (closed_) {
-    callbacks->OnError(CreateError(blink::kWebIDBDatabaseExceptionUnknownError,
-                                   "The cursor has been closed.",
-                                   transaction_));
+    callbacks->OnError(CreateCursorClosedError());
 
     return;
   }
@@ -111,18 +109,16 @@
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::IO},
         base::BindOnce(
-            [](blink::mojom::IDBCursor::AdvanceCallback callback,
-               IndexedDBTransaction* transaction) {
+            [](blink::mojom::IDBCursor::AdvanceCallback callback) {
               const IndexedDBDatabaseError closed_error(
                   CreateCursorClosedError());
               DCHECK_NE(closed_error.code(), 0);
               std::move(callback).Run(
-                  CreateIDBError(closed_error.code(),
-                                 base::string16(closed_error.message()),
-                                 transaction),
+                  blink::mojom::IDBError::New(closed_error.code(),
+                                              closed_error.message()),
                   blink::mojom::IDBCursorValuePtr());
             },
-            std::move(callback), transaction_));
+            std::move(callback)));
     return;
   }
 
@@ -154,20 +150,20 @@
               std::move(callback)));
       return s;
     }
+    blink::mojom::IDBErrorPtr error = CreateIDBError(
+        blink::kWebIDBDatabaseExceptionUnknownError,
+        base::ASCIIToUTF16("Error advancing cursor"), transaction_);
     Close();
 
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::IO},
         base::BindOnce(
             [](blink::mojom::IDBCursor::AdvanceCallback callback,
-               IndexedDBTransaction* transaction) {
-              std::move(callback).Run(
-                  CreateIDBError(blink::kWebIDBDatabaseExceptionUnknownError,
-                                 base::ASCIIToUTF16("Error advancing cursor"),
-                                 transaction),
-                  blink::mojom::IDBCursorValuePtr());
+               blink::mojom::IDBErrorPtr error) {
+              std::move(callback).Run(std::move(error),
+                                      blink::mojom::IDBCursorValuePtr());
             },
-            std::move(callback), transaction_));
+            std::move(callback), std::move(error)));
     return s;
   }
 
@@ -225,9 +221,11 @@
       callbacks->OnSuccess(nullptr);
       return s;
     }
+    IndexedDBDatabaseError error =
+        CreateError(blink::kWebIDBDatabaseExceptionUnknownError,
+                    "Error continuing cursor.", transaction_);
     Close();
-    callbacks->OnError(CreateError(blink::kWebIDBDatabaseExceptionUnknownError,
-                                   "Error continuing cursor.", transaction_));
+    callbacks->OnError(error);
     return s;
   }
 
@@ -241,9 +239,7 @@
   IDB_TRACE("IndexedDBCursor::PrefetchContinue");
 
   if (closed_) {
-    callbacks->OnError(CreateError(blink::kWebIDBDatabaseExceptionUnknownError,
-                                   "The cursor has been closed.",
-                                   transaction_));
+    callbacks->OnError(CreateCursorClosedError());
     return;
   }
 
@@ -279,10 +275,11 @@
         // We've reached the end, so just return what we have.
         break;
       }
-      Close();
-      callbacks->OnError(
+      IndexedDBDatabaseError error =
           CreateError(blink::kWebIDBDatabaseExceptionUnknownError,
-                      "Error continuing cursor.", transaction_));
+                      "Error continuing cursor.", transaction_);
+      Close();
+      callbacks->OnError(error);
       return s;
     }
 
diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc
index 63a98701..34c9ed4 100644
--- a/content/browser/renderer_host/code_cache_host_impl.cc
+++ b/content/browser/renderer_host/code_cache_host_impl.cc
@@ -22,6 +22,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/url_constants.h"
+#include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/features.h"
 #include "net/base/io_buffer.h"
@@ -202,6 +203,12 @@
     const std::vector<uint8_t>& data,
     const url::Origin& cache_storage_origin,
     const std::string& cache_storage_cache_name) {
+  if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanAccessDataForOrigin(
+          render_process_id_, cache_storage_origin.GetURL())) {
+    mojo::ReportBadMessage("CODE_CACHE_INVALID_CACHE_STORAGE_ORIGIN");
+    return;
+  }
+
   if (!cache_storage_context_->cache_manager())
     return;
 
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 538ca8b..076ee3f 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -721,7 +721,6 @@
 
 // Verify that a request coming from Cryptotoken bypasses origin checks.
 TEST_F(AuthenticatorImplTest, CryptotokenBypass) {
-  EnableFeature(device::kWebAuthProxyCryptotoken);
   SimulateNavigation(GURL(kTestOrigin1));
   auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
       base::Time::Now(), base::TimeTicks::Now());
@@ -778,7 +777,6 @@
 
 // Requests originating from cryptotoken should only target U2F devices.
 TEST_F(AuthenticatorImplTest, CryptoTokenU2fOnly) {
-  EnableFeature(device::kWebAuthProxyCryptotoken);
   TestServiceManagerContext smc;
   SimulateNavigation(GURL(kTestOrigin1));
   auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
@@ -816,7 +814,6 @@
 
 // Requests originating from cryptotoken should only target U2F devices.
 TEST_F(AuthenticatorImplTest, AttestationPermitted) {
-  EnableFeature(device::kWebAuthProxyCryptotoken);
   TestServiceManagerContext smc;
   SimulateNavigation(GURL(kTestOrigin1));
   auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
@@ -1914,32 +1911,22 @@
 
 #if defined(OS_WIN)
 TEST_F(AuthenticatorContentBrowserClientTest, WinIsUVPAA) {
-  for (const bool enable_feature_flag : {false, true}) {
-    SCOPED_TRACE(enable_feature_flag ? "enable_feature_flag"
-                                     : "!enable_feature_flag");
-    for (const bool enable_win_webauthn_api : {false, true}) {
-      SCOPED_TRACE(enable_win_webauthn_api ? "enable_win_webauthn_api"
-                                           : "!enable_win_webauthn_api");
-      for (const bool is_uvpaa : {false, true}) {
-        SCOPED_TRACE(is_uvpaa ? "is_uvpaa" : "!is_uvpaa");
+  for (const bool enable_win_webauthn_api : {false, true}) {
+    SCOPED_TRACE(enable_win_webauthn_api ? "enable_win_webauthn_api"
+                                         : "!enable_win_webauthn_api");
+    for (const bool is_uvpaa : {false, true}) {
+      SCOPED_TRACE(is_uvpaa ? "is_uvpaa" : "!is_uvpaa");
 
-        base::test::ScopedFeatureList scoped_feature_list;
-        if (enable_feature_flag) {
-          scoped_feature_list.InitAndEnableFeature(
-              device::kWebAuthUseNativeWinApi);
-        }
-        device::ScopedFakeWinWebAuthnApi fake_api;
-        fake_api.set_available(enable_win_webauthn_api);
-        fake_api.set_is_uvpaa(is_uvpaa);
+      device::ScopedFakeWinWebAuthnApi fake_api;
+      fake_api.set_available(enable_win_webauthn_api);
+      fake_api.set_is_uvpaa(is_uvpaa);
 
-        AuthenticatorPtr authenticator = ConnectToAuthenticator();
-        TestIsUvpaaCallback cb;
-        authenticator->IsUserVerifyingPlatformAuthenticatorAvailable(
-            cb.callback());
-        cb.WaitForCallback();
-        EXPECT_EQ(enable_feature_flag && enable_win_webauthn_api && is_uvpaa,
-                  cb.value());
-      }
+      AuthenticatorPtr authenticator = ConnectToAuthenticator();
+      TestIsUvpaaCallback cb;
+      authenticator->IsUserVerifyingPlatformAuthenticatorAvailable(
+          cb.callback());
+      cb.WaitForCallback();
+      EXPECT_EQ(enable_win_webauthn_api && is_uvpaa, cb.value());
     }
   }
 }
@@ -1961,7 +1948,6 @@
 
 TEST_F(AuthenticatorContentBrowserClientTest,
        CryptotokenBypassesAttestationConsentPrompt) {
-  EnableFeature(device::kWebAuthProxyCryptotoken);
   TestServiceManagerContext smc;
   SimulateNavigation(GURL(kTestOrigin1));
   auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
diff --git a/content/public/test/fake_service_worker_context.cc b/content/public/test/fake_service_worker_context.cc
index 0ee205d..68e4e29 100644
--- a/content/public/test/fake_service_worker_context.cc
+++ b/content/public/test/fake_service_worker_context.cc
@@ -87,8 +87,10 @@
     const GURL& scope,
     blink::TransferableMessage message,
     ResultCallback result_callback) {
-  NOTREACHED();
+  start_service_worker_and_dispatch_message_calls_.push_back(
+      std::make_tuple(scope, std::move(message), std::move(result_callback)));
 }
+
 void FakeServiceWorkerContext::StartServiceWorkerAndDispatchLongRunningMessage(
     const GURL& scope,
     blink::TransferableMessage message,
diff --git a/content/public/test/fake_service_worker_context.h b/content/public/test/fake_service_worker_context.h
index 3528e8a..81cf1fa 100644
--- a/content/public/test/fake_service_worker_context.h
+++ b/content/public/test/fake_service_worker_context.h
@@ -24,7 +24,7 @@
 // what you need.
 class FakeServiceWorkerContext : public ServiceWorkerContext {
  public:
-  using StartServiceWorkerAndDispatchLongRunningMessageArgs =
+  using StartServiceWorkerAndDispatchMessageArgs =
       std::tuple<GURL, blink::TransferableMessage, ResultCallback>;
 
   FakeServiceWorkerContext();
@@ -79,7 +79,12 @@
     return start_service_worker_for_navigation_hint_called_;
   }
 
-  std::vector<StartServiceWorkerAndDispatchLongRunningMessageArgs>&
+  std::vector<StartServiceWorkerAndDispatchMessageArgs>&
+  start_service_worker_and_dispatch_message_calls() {
+    return start_service_worker_and_dispatch_message_calls_;
+  };
+
+  std::vector<StartServiceWorkerAndDispatchMessageArgs>&
   start_service_worker_and_dispatch_long_running_message_calls() {
     return start_service_worker_and_dispatch_long_running_message_calls_;
   };
@@ -91,7 +96,10 @@
  private:
   bool start_service_worker_for_navigation_hint_called_ = false;
 
-  std::vector<StartServiceWorkerAndDispatchLongRunningMessageArgs>
+  std::vector<StartServiceWorkerAndDispatchMessageArgs>
+      start_service_worker_and_dispatch_message_calls_;
+
+  std::vector<StartServiceWorkerAndDispatchMessageArgs>
       start_service_worker_and_dispatch_long_running_message_calls_;
 
   std::vector<GURL> stop_all_service_workers_for_origin_calls_;
diff --git a/content/renderer/input/main_thread_event_queue.cc b/content/renderer/input/main_thread_event_queue.cc
index 85c9b01f..cc128fe 100644
--- a/content/renderer/input/main_thread_event_queue.cc
+++ b/content/renderer/input/main_thread_event_queue.cc
@@ -4,6 +4,8 @@
 
 #include "content/renderer/input/main_thread_event_queue.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/containers/circular_deque.h"
 #include "base/metrics/histogram_macros.h"
@@ -116,8 +118,13 @@
     HandledEventCallback callback =
         base::BindOnce(&QueuedWebInputEvent::HandledEvent,
                        base::Unretained(this), base::RetainedRef(queue));
-    queue->HandleEventOnMainThread(coalesced_event(), latencyInfo(),
-                                   std::move(callback));
+    if (!queue->HandleEventOnMainThread(coalesced_event(), latencyInfo(),
+                                        std::move(callback))) {
+      // The |callback| won't be run, so our stored |callback_| should run
+      // indicating error.
+      HandledEvent(queue, INPUT_EVENT_ACK_STATE_NOT_CONSUMED, latencyInfo(),
+                   nullptr, base::nullopt);
+    }
   }
 
   void HandledEvent(MainThreadEventQueue* queue,
@@ -591,12 +598,15 @@
   }
 }
 
-void MainThreadEventQueue::HandleEventOnMainThread(
+bool MainThreadEventQueue::HandleEventOnMainThread(
     const blink::WebCoalescedInputEvent& event,
     const ui::LatencyInfo& latency,
     HandledEventCallback handled_callback) {
-  if (client_)
-    client_->HandleInputEvent(event, latency, std::move(handled_callback));
+  bool handled = false;
+  if (client_) {
+    handled =
+        client_->HandleInputEvent(event, latency, std::move(handled_callback));
+  }
 
   if (needs_low_latency_until_pointer_up_) {
     // Reset the needs low latency until pointer up mode if necessary.
@@ -612,6 +622,7 @@
         break;
     }
   }
+  return handled;
 }
 
 void MainThreadEventQueue::SetNeedsMainFrame() {
diff --git a/content/renderer/input/main_thread_event_queue.h b/content/renderer/input/main_thread_event_queue.h
index 37cedf6..161eab61 100644
--- a/content/renderer/input/main_thread_event_queue.h
+++ b/content/renderer/input/main_thread_event_queue.h
@@ -35,12 +35,13 @@
 // on the main thread.
 class CONTENT_EXPORT MainThreadEventQueueClient {
  public:
-  // Handle an |event| that was previously queued (possibly
-  // coalesced with another event). Implementors must implement
-  // this callback.
-  virtual void HandleInputEvent(const blink::WebCoalescedInputEvent& event,
+  // Handle an |event| that was previously queued (possibly coalesced with
+  // another event). Returns false if the event will not be handled, and the
+  // |handled_callback| will not be run.
+  virtual bool HandleInputEvent(const blink::WebCoalescedInputEvent& event,
                                 const ui::LatencyInfo& latency_info,
                                 HandledEventCallback handled_callback) = 0;
+  // Requests a BeginMainFrame callback from the compositor.
   virtual void SetNeedsMainFrame() = 0;
 };
 
@@ -126,7 +127,9 @@
   void DispatchEvents();
   void PossiblyScheduleMainFrame();
   void SetNeedsMainFrame();
-  void HandleEventOnMainThread(const blink::WebCoalescedInputEvent& event,
+  // Returns false if the event can not be handled and the HandledEventCallback
+  // will not be run.
+  bool HandleEventOnMainThread(const blink::WebCoalescedInputEvent& event,
                                const ui::LatencyInfo& latency,
                                HandledEventCallback handled_callback);
 
diff --git a/content/renderer/input/main_thread_event_queue_unittest.cc b/content/renderer/input/main_thread_event_queue_unittest.cc
index 45c4c47..7f794fe 100644
--- a/content/renderer/input/main_thread_event_queue_unittest.cc
+++ b/content/renderer/input/main_thread_event_queue_unittest.cc
@@ -151,9 +151,7 @@
                                  public MainThreadEventQueueClient {
  public:
   MainThreadEventQueueTest()
-      : main_task_runner_(new base::TestSimpleTaskRunner()),
-        needs_main_frame_(false),
-        closure_count_(0) {
+      : main_task_runner_(new base::TestSimpleTaskRunner()) {
     handler_callback_ = std::make_unique<HandledEventCallbackTracker>();
   }
 
@@ -215,15 +213,18 @@
     }
   }
 
-  void HandleInputEvent(const blink::WebCoalescedInputEvent& event,
+  // MainThreadEventQueueClient overrides.
+  bool HandleInputEvent(const blink::WebCoalescedInputEvent& event,
                         const ui::LatencyInfo& latency,
                         HandledEventCallback callback) override {
+    if (!handle_input_event_)
+      return false;
     std::unique_ptr<HandledTask> handled_event(new HandledEvent(event));
     handled_tasks_.push_back(std::move(handled_event));
     std::move(callback).Run(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, latency,
                             nullptr, base::nullopt);
+    return true;
   }
-
   void SetNeedsMainFrame() override { needs_main_frame_ = true; }
 
   std::vector<ReceivedCallback> GetAndResetCallbackResults() {
@@ -233,6 +234,8 @@
     return callback->GetReceivedCallbacks();
   }
 
+  void set_handle_input_event(bool handle) { handle_input_event_ = handle; }
+
  protected:
   scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_;
   blink::scheduler::WebMockThreadScheduler thread_scheduler_;
@@ -240,12 +243,48 @@
   std::vector<std::unique_ptr<HandledTask>> handled_tasks_;
   std::unique_ptr<HandledEventCallbackTracker> handler_callback_;
 
-  int raf_aligned_input_setting_;
-  bool needs_main_frame_;
+  bool needs_main_frame_ = false;
+  bool handle_input_event_ = true;
   base::TimeTicks frame_time_;
-  unsigned closure_count_;
+  unsigned closure_count_ = 0;
 };
 
+TEST_F(MainThreadEventQueueTest, ClientDoesntHandleInputEvent) {
+  // Prevent MainThreadEventQueueClient::HandleInputEvent() from handling the
+  // event, and have it return false. Then the MainThreadEventQueue should
+  // call the handled callback.
+  set_handle_input_event(false);
+
+  // The blocking event used in this test is reported to the scheduler.
+  EXPECT_CALL(thread_scheduler_,
+              DidHandleInputEventOnMainThread(testing::_, testing::_))
+      .Times(1);
+
+  // Inject and try to dispatch an input event. This event is not considered
+  // "non-blocking" which means the reply callback gets stored with the queued
+  // event, and will be run when we work through the queue.
+  SyntheticWebTouchEvent event;
+  event.PressPoint(10, 10);
+  event.MovePoint(0, 20, 20);
+  WebMouseWheelEvent event2 =
+      SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, 53, 0, false);
+  HandleEvent(event2, INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+  RunPendingTasksWithSimulatedRaf();
+
+  std::vector<ReceivedCallback> received = GetAndResetCallbackResults();
+  // We didn't handle the event in the client method.
+  EXPECT_EQ(handled_tasks_.size(), 0u);
+  // There's 1 reply callback for our 1 event.
+  EXPECT_EQ(received.size(), 1u);
+  // The event was queued and disaptched, then the callback was run when
+  // the client failed to handle it. If this fails, the callback was run
+  // by HandleEvent() without dispatching it (kCalledWhileHandlingEvent)
+  // or was not called at all (kPending).
+  EXPECT_THAT(received,
+              testing::Each(ReceivedCallback(
+                  CallbackReceivedState::kCalledAfterHandleEvent, false)));
+}
+
 TEST_F(MainThreadEventQueueTest, NonBlockingWheel) {
   WebMouseWheelEvent kEvents[4] = {
       SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, 53, 0, false),
@@ -1079,11 +1118,12 @@
  public:
   MainThreadEventQueueInitializationTest() {}
 
-  void HandleInputEvent(const blink::WebCoalescedInputEvent& event,
+  bool HandleInputEvent(const blink::WebCoalescedInputEvent& event,
                         const ui::LatencyInfo& latency,
                         HandledEventCallback callback) override {
     std::move(callback).Run(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, latency,
                             nullptr, base::nullopt);
+    return true;
   }
 
   void SetNeedsMainFrame() override {}
diff --git a/content/renderer/media/stream/local_media_stream_audio_source.cc b/content/renderer/media/stream/local_media_stream_audio_source.cc
index f7ebf3d..a150c2d 100644
--- a/content/renderer/media/stream/local_media_stream_audio_source.cc
+++ b/content/renderer/media/stream/local_media_stream_audio_source.cc
@@ -13,11 +13,9 @@
 LocalMediaStreamAudioSource::LocalMediaStreamAudioSource(
     int consumer_render_frame_id,
     const blink::MediaStreamDevice& device,
-    bool hotword_enabled,
     bool disable_local_echo,
     const ConstraintsCallback& started_callback)
     : MediaStreamAudioSource(true /* is_local_source */,
-                             hotword_enabled,
                              disable_local_echo),
       consumer_render_frame_id_(consumer_render_frame_id),
       started_callback_(started_callback) {
diff --git a/content/renderer/media/stream/local_media_stream_audio_source.h b/content/renderer/media/stream/local_media_stream_audio_source.h
index 7d513a9f..4062fd61 100644
--- a/content/renderer/media/stream/local_media_stream_audio_source.h
+++ b/content/renderer/media/stream/local_media_stream_audio_source.h
@@ -26,7 +26,6 @@
   // ID are read from |device_info|.
   LocalMediaStreamAudioSource(int consumer_render_frame_id,
                               const blink::MediaStreamDevice& device,
-                              bool hotword_enabled,
                               bool disable_local_echo,
                               const ConstraintsCallback& started_callback);
 
diff --git a/content/renderer/media/stream/media_stream_audio_source.cc b/content/renderer/media/stream/media_stream_audio_source.cc
index 348c2c2b..a29783a 100644
--- a/content/renderer/media/stream/media_stream_audio_source.cc
+++ b/content/renderer/media/stream/media_stream_audio_source.cc
@@ -14,10 +14,8 @@
 namespace content {
 
 MediaStreamAudioSource::MediaStreamAudioSource(bool is_local_source,
-                                               bool hotword_enabled,
                                                bool disable_local_echo)
     : is_local_source_(is_local_source),
-      hotword_enabled_(hotword_enabled),
       disable_local_echo_(disable_local_echo),
       is_stopped_(false),
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
@@ -28,7 +26,6 @@
 
 MediaStreamAudioSource::MediaStreamAudioSource(bool is_local_source)
     : MediaStreamAudioSource(is_local_source,
-                             false /* hotword_enabled */,
                              false /* disable_local_echo */) {}
 
 MediaStreamAudioSource::~MediaStreamAudioSource() {
diff --git a/content/renderer/media/stream/media_stream_audio_source.h b/content/renderer/media/stream/media_stream_audio_source.h
index 84150ff..89ce6f1 100644
--- a/content/renderer/media/stream/media_stream_audio_source.h
+++ b/content/renderer/media/stream/media_stream_audio_source.h
@@ -88,7 +88,6 @@
  public:
   explicit MediaStreamAudioSource(bool is_local_source);
   MediaStreamAudioSource(bool is_local_source,
-                         bool hotword_enabled,
                          bool disable_local_echo);
   ~MediaStreamAudioSource() override;
 
@@ -120,7 +119,6 @@
   media::AudioParameters GetAudioParameters() const;
 
   // These accessors return properties that are controlled via constraints.
-  bool hotword_enabled() const { return hotword_enabled_; }
   bool disable_local_echo() const { return disable_local_echo_; }
   bool RenderToAssociatedSinkEnabled() const;
 
@@ -193,7 +191,6 @@
   const bool is_local_source_;
 
   // Properties controlled by audio constraints.
-  const bool hotword_enabled_;
   const bool disable_local_echo_;
 
   // Set to true once this source has been permanently stopped.
diff --git a/content/renderer/media/stream/media_stream_constraints_util.cc b/content/renderer/media/stream/media_stream_constraints_util.cc
index 5d48859..37ec2aa 100644
--- a/content/renderer/media/stream/media_stream_constraints_util.cc
+++ b/content/renderer/media/stream/media_stream_constraints_util.cc
@@ -153,13 +153,11 @@
 
 AudioCaptureSettings::AudioCaptureSettings(
     std::string device_id,
-    bool enable_hotword,
     bool disable_local_echo,
     bool enable_automatic_output_device_selection,
     const AudioProcessingProperties& audio_processing_properties)
     : failed_constraint_name_(nullptr),
       device_id_(std::move(device_id)),
-      hotword_enabled_(enable_hotword),
       disable_local_echo_(disable_local_echo),
       render_to_associated_sink_(enable_automatic_output_device_selection),
       audio_processing_properties_(audio_processing_properties) {}
diff --git a/content/renderer/media/stream/media_stream_constraints_util.h b/content/renderer/media/stream/media_stream_constraints_util.h
index 975baa37..f227c36 100644
--- a/content/renderer/media/stream/media_stream_constraints_util.h
+++ b/content/renderer/media/stream/media_stream_constraints_util.h
@@ -157,7 +157,6 @@
 //     getSettings() for device-related properties such as sampleRate and
 //     channelCount.
 // The following fields are used to control various audio features:
-//   * hotword_enabled
 //   * disable_local_echo
 //   * render_to_associated_sink
 // The audio_properties field is used to control the audio-processing module,
@@ -190,7 +189,6 @@
   // Creates an object with the given values.
   explicit AudioCaptureSettings(
       std::string device_id,
-      bool enable_hotword,
       bool disable_local_echo,
       bool enable_automatic_output_device_selection,
       const AudioProcessingProperties& audio_processing_properties);
@@ -207,10 +205,6 @@
     DCHECK(HasValue());
     return device_id_;
   }
-  bool hotword_enabled() const {
-    DCHECK(HasValue());
-    return hotword_enabled_;
-  }
   bool disable_local_echo() const {
     DCHECK(HasValue());
     return disable_local_echo_;
@@ -227,7 +221,6 @@
  private:
   const char* failed_constraint_name_;
   std::string device_id_;
-  bool hotword_enabled_;
   bool disable_local_echo_;
   bool render_to_associated_sink_;
   AudioProcessingProperties audio_processing_properties_;
diff --git a/content/renderer/media/stream/media_stream_constraints_util_audio.cc b/content/renderer/media/stream/media_stream_constraints_util_audio.cc
index 4e03611..db4f1348 100644
--- a/content/renderer/media/stream/media_stream_constraints_util_audio.cc
+++ b/content/renderer/media/stream/media_stream_constraints_util_audio.cc
@@ -1059,9 +1059,6 @@
       return;
 
     MediaStreamAudioSource* source = capability.source();
-    boolean_containers_[kHotwordEnabled] =
-        BooleanContainer(BoolSet({source->hotword_enabled()}));
-
     boolean_containers_[kDisableLocalEcho] =
         BooleanContainer(BoolSet({source->disable_local_echo()}));
 
@@ -1135,12 +1132,6 @@
                                                    std::string());
     score += sub_score;
 
-    bool hotword_enabled;
-    std::tie(sub_score, hotword_enabled) =
-        boolean_containers_[kHotwordEnabled].SelectSettingsAndScore(
-            constraint_set.hotword_enabled, false);
-    score += sub_score;
-
     bool disable_local_echo;
     std::tie(sub_score, disable_local_echo) =
         boolean_containers_[kDisableLocalEcho].SelectSettingsAndScore(
@@ -1192,7 +1183,7 @@
     // in case multiple candidates are available.
     return std::make_tuple(
         score,
-        AudioCaptureSettings(device_id, hotword_enabled, disable_local_echo,
+        AudioCaptureSettings(device_id, disable_local_echo,
                              render_to_associated_sink, best_properties));
   }
 
@@ -1211,7 +1202,6 @@
 
  private:
   enum BooleanContainerId {
-    kHotwordEnabled,
     kDisableLocalEcho,
     kRenderToAssociatedSink,
     kNumBooleanContainerIds
@@ -1226,7 +1216,6 @@
 
   static constexpr BooleanPropertyContainerInfo
       kBooleanPropertyContainerInfoMap[] = {
-          {kHotwordEnabled, &ConstraintSet::hotword_enabled},
           {kDisableLocalEcho, &ConstraintSet::disable_local_echo},
           {kRenderToAssociatedSink, &ConstraintSet::render_to_associated_sink}};
 
diff --git a/content/renderer/media/stream/media_stream_constraints_util_audio.h b/content/renderer/media/stream/media_stream_constraints_util_audio.h
index b9dbe85b..7d9e9123 100644
--- a/content/renderer/media/stream/media_stream_constraints_util_audio.h
+++ b/content/renderer/media/stream/media_stream_constraints_util_audio.h
@@ -112,11 +112,10 @@
 //    For content capture, all device IDs are considered valid by
 //    SelectSettings. Actual validation is performed by the getUserMedia
 //    implementation.
-//  * Audio features: the hotword_enabled, disable_local_echo and
-//    render_to_associated_sink constraints can be used to enable the
-//    corresponding audio feature. If not specified, their default value is
-//    false, except for disable_local_echo, whose default value is false only
-//    for desktop capture.
+//  * Audio features: the disable_local_echo and render_to_associated_sink
+//    constraints can be used to enable the corresponding audio feature. If not
+//    specified, their default value is false, except for disable_local_echo,
+//    whose default value is false only for desktop capture.
 //  * Audio processing. The remaining constraints are used to control audio
 //    processing. This is how audio-processing properties are set for device
 //    capture(see the content::AudioProcessingProperties struct) :
diff --git a/content/renderer/media/stream/media_stream_constraints_util_audio_unittest.cc b/content/renderer/media/stream/media_stream_constraints_util_audio_unittest.cc
index 89b04e8..a2928cb 100644
--- a/content/renderer/media/stream/media_stream_constraints_util_audio_unittest.cc
+++ b/content/renderer/media/stream/media_stream_constraints_util_audio_unittest.cc
@@ -158,7 +158,6 @@
 
   std::unique_ptr<ProcessedLocalAudioSource> GetProcessedLocalAudioSource(
       const AudioProcessingProperties& properties,
-      bool hotword_enabled,
       bool disable_local_echo,
       bool render_to_associated_sink,
       int effects) {
@@ -170,25 +169,22 @@
     device.input.set_effects(effects);
 
     return std::make_unique<ProcessedLocalAudioSource>(
-        -1, device, hotword_enabled, disable_local_echo, properties,
+        -1, device, disable_local_echo, properties,
         blink::WebPlatformMediaStreamSource::ConstraintsCallback(),
         &pc_factory_);
   }
 
   std::unique_ptr<ProcessedLocalAudioSource> GetProcessedLocalAudioSource(
       const AudioProcessingProperties& properties,
-      bool hotword_enabled,
       bool disable_local_echo,
       bool render_to_associated_sink) {
     return GetProcessedLocalAudioSource(
-        properties, hotword_enabled, disable_local_echo,
-        render_to_associated_sink,
+        properties, disable_local_echo, render_to_associated_sink,
         media::AudioParameters::PlatformEffectsMask::NO_EFFECTS);
   }
 
   std::unique_ptr<LocalMediaStreamAudioSource> GetLocalMediaStreamAudioSource(
       bool enable_system_echo_canceller,
-      bool hotword_enabled,
       bool disable_local_echo,
       bool render_to_associated_sink) {
     blink::MediaStreamDevice device;
@@ -199,7 +195,7 @@
       device.matched_output_device_id = std::string("some_device_id");
 
     return std::make_unique<LocalMediaStreamAudioSource>(
-        -1, device, hotword_enabled, disable_local_echo,
+        -1, device, disable_local_echo,
         blink::WebPlatformMediaStreamSource::ConstraintsCallback());
   }
 
@@ -227,10 +223,6 @@
       const AudioPropertiesBoolMembers& exclude_audio_properties,
       const AudioCaptureSettings& result) {
     if (!Contains(exclude_main_settings,
-                  &AudioCaptureSettings::hotword_enabled)) {
-      EXPECT_FALSE(result.hotword_enabled());
-    }
-    if (!Contains(exclude_main_settings,
                   &AudioCaptureSettings::disable_local_echo)) {
       EXPECT_TRUE(result.disable_local_echo());
     }
@@ -282,10 +274,6 @@
       const AudioPropertiesBoolMembers& exclude_audio_properties,
       const AudioCaptureSettings& result) {
     if (!Contains(exclude_main_settings,
-                  &AudioCaptureSettings::hotword_enabled)) {
-      EXPECT_FALSE(result.hotword_enabled());
-    }
-    if (!Contains(exclude_main_settings,
                   &AudioCaptureSettings::disable_local_echo)) {
       EXPECT_EQ(GetMediaStreamSource() != blink::kMediaStreamSourceDesktop,
                 result.disable_local_echo());
@@ -416,7 +404,6 @@
 
     // The following are not audio processing.
     EXPECT_FALSE(properties.goog_audio_mirroring);
-    EXPECT_FALSE(result.hotword_enabled());
     EXPECT_EQ(GetMediaStreamSource() != blink::kMediaStreamSourceDesktop,
               result.disable_local_echo());
     EXPECT_FALSE(result.render_to_associated_sink());
@@ -448,7 +435,6 @@
 
     // The following are not audio processing.
     EXPECT_FALSE(properties.goog_audio_mirroring);
-    EXPECT_FALSE(result.hotword_enabled());
     EXPECT_EQ(GetMediaStreamSource() != blink::kMediaStreamSourceDesktop,
               result.disable_local_echo());
     EXPECT_FALSE(result.render_to_associated_sink());
@@ -504,14 +490,12 @@
 // processing properties).
 TEST_P(MediaStreamConstraintsUtilAudioTest, SingleBoolConstraint) {
   AudioSettingsBoolMembers kMainSettings = {
-      &AudioCaptureSettings::hotword_enabled,
       &AudioCaptureSettings::disable_local_echo,
       &AudioCaptureSettings::render_to_associated_sink};
 
   const std::vector<
       blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*>
       kMainBoolConstraints = {
-          &blink::WebMediaTrackConstraintSet::hotword_enabled,
           &blink::WebMediaTrackConstraintSet::disable_local_echo,
           &blink::WebMediaTrackConstraintSet::render_to_associated_sink};
 
@@ -752,7 +736,6 @@
 
   std::unique_ptr<LocalMediaStreamAudioSource> source =
       GetLocalMediaStreamAudioSource(false /* enable_system_echo_canceller */,
-                                     false /* hotword_enabled */,
                                      false /* disable_local_echo */,
                                      false /* render_to_associated_sink */);
   int channel_count = kMinChannels;
@@ -870,7 +853,6 @@
 
   std::unique_ptr<LocalMediaStreamAudioSource> source =
       GetLocalMediaStreamAudioSource(false /* enable_system_echo_canceller */,
-                                     false /* hotword_enabled */,
                                      false /* disable_local_echo */,
                                      false /* render_to_associated_sink */);
 
@@ -1028,7 +1010,6 @@
 
   std::unique_ptr<LocalMediaStreamAudioSource> source =
       GetLocalMediaStreamAudioSource(false /* enable_system_echo_canceller */,
-                                     false /* hotword_enabled */,
                                      false /* disable_local_echo */,
                                      false /* render_to_associated_sink */);
   // Test set exact sampleRate.
@@ -1234,7 +1215,6 @@
 
         // The following are not audio processing.
         EXPECT_FALSE(properties.goog_audio_mirroring);
-        EXPECT_FALSE(result.hotword_enabled());
         EXPECT_EQ(GetMediaStreamSource() != blink::kMediaStreamSourceDesktop,
                   result.disable_local_echo());
         EXPECT_FALSE(result.render_to_associated_sink());
@@ -1295,7 +1275,6 @@
 
         // The following are not audio processing.
         EXPECT_FALSE(properties.goog_audio_mirroring);
-        EXPECT_FALSE(result.hotword_enabled());
         EXPECT_EQ(GetMediaStreamSource() != blink::kMediaStreamSourceDesktop,
                   result.disable_local_echo());
         EXPECT_FALSE(result.render_to_associated_sink());
@@ -1548,7 +1527,6 @@
 
           // The following are not audio processing.
           EXPECT_FALSE(properties.goog_audio_mirroring);
-          EXPECT_FALSE(result.hotword_enabled());
           EXPECT_EQ(GetMediaStreamSource() != blink::kMediaStreamSourceDesktop,
                     result.disable_local_echo());
           EXPECT_FALSE(result.render_to_associated_sink());
@@ -1728,18 +1706,15 @@
   constraint_factory_.AddAdvanced().goog_highpass_filter.SetExact(true);
   auto& advanced2 = constraint_factory_.AddAdvanced();
   advanced2.goog_highpass_filter.SetExact(false);
-  advanced2.hotword_enabled.SetExact(true);
   constraint_factory_.AddAdvanced().goog_audio_mirroring.SetExact(true);
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
   CheckDeviceDefaults(result);
-  EXPECT_FALSE(result.hotword_enabled());
-  CheckBoolDefaults({&AudioCaptureSettings::hotword_enabled},
+  CheckBoolDefaults({},
                     {&AudioProcessingProperties::goog_audio_mirroring,
                      &AudioProcessingProperties::goog_highpass_filter},
                     result);
   CheckEchoCancellationTypeDefault(result);
-  EXPECT_FALSE(result.hotword_enabled());
   EXPECT_TRUE(result.audio_processing_properties().goog_audio_mirroring);
   EXPECT_TRUE(result.audio_processing_properties().goog_highpass_filter);
 }
@@ -1748,19 +1723,16 @@
 // set with a boolean constraint is ignored.
 TEST_P(MediaStreamConstraintsUtilAudioTest, AdvancedConflictingLastConstraint) {
   constraint_factory_.AddAdvanced().goog_highpass_filter.SetExact(true);
-  constraint_factory_.AddAdvanced().hotword_enabled.SetExact(true);
   constraint_factory_.AddAdvanced().goog_audio_mirroring.SetExact(true);
-  constraint_factory_.AddAdvanced().hotword_enabled.SetExact(false);
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
   CheckDeviceDefaults(result);
-  CheckBoolDefaults({&AudioCaptureSettings::hotword_enabled},
+  CheckBoolDefaults({},
                     {&AudioProcessingProperties::goog_audio_mirroring,
                      &AudioProcessingProperties::goog_highpass_filter},
                     result);
   CheckEchoCancellationTypeDefault(result);
   // The fourth advanced set is ignored because it contradicts the second set.
-  EXPECT_TRUE(result.hotword_enabled());
   EXPECT_TRUE(result.audio_processing_properties().goog_audio_mirroring);
   EXPECT_TRUE(result.audio_processing_properties().goog_highpass_filter);
 }
@@ -1798,7 +1770,6 @@
     std::unique_ptr<LocalMediaStreamAudioSource> source =
         GetLocalMediaStreamAudioSource(
             enable_properties /* enable_system_echo_canceller */,
-            enable_properties /* hotword_enabled */,
             enable_properties /* disable_local_echo */,
             enable_properties /* render_to_associated_sink */);
 
@@ -1807,7 +1778,6 @@
         blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*>
         kConstraints = {
             &blink::WebMediaTrackConstraintSet::echo_cancellation,
-            &blink::WebMediaTrackConstraintSet::hotword_enabled,
             &blink::WebMediaTrackConstraintSet::disable_local_echo,
             &blink::WebMediaTrackConstraintSet::render_to_associated_sink,
         };
@@ -1850,7 +1820,6 @@
   for (blink::WebString value : kEchoCancellationTypeValues) {
     std::unique_ptr<LocalMediaStreamAudioSource> source =
         GetLocalMediaStreamAudioSource(false /* enable_system_echo_canceller */,
-                                       false /* hotword_enabled */,
                                        false /* disable_local_echo */,
                                        false /* render_to_associated_sink */);
 
@@ -1898,8 +1867,7 @@
 
     std::unique_ptr<ProcessedLocalAudioSource> source =
         GetProcessedLocalAudioSource(
-            properties, use_defaults /* hotword_enabled */,
-            use_defaults /* disable_local_echo */,
+            properties, use_defaults /* disable_local_echo */,
             use_defaults /* render_to_associated_sink */);
     const std::vector<
         blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*>
@@ -1993,7 +1961,6 @@
     const std::vector<
         blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*>
         kAudioBrowserConstraints = {
-            &blink::WebMediaTrackConstraintSet::hotword_enabled,
             &blink::WebMediaTrackConstraintSet::disable_local_echo,
             &blink::WebMediaTrackConstraintSet::render_to_associated_sink,
         };
@@ -2074,8 +2041,7 @@
 
     std::unique_ptr<ProcessedLocalAudioSource> source =
         GetProcessedLocalAudioSource(
-            properties, false /* hotword_enabled */,
-            false /* disable_local_echo */,
+            properties, false /* disable_local_echo */,
             false /* render_to_associated_sink */,
             ec_type == EchoCancellationType::kEchoCancellationSystem
                 ? media::AudioParameters::PlatformEffectsMask::
@@ -2109,8 +2075,7 @@
 
   AudioProcessingProperties properties;
   std::unique_ptr<ProcessedLocalAudioSource> processed_source =
-      GetProcessedLocalAudioSource(properties, false /* hotword_enabled */,
-                                   false /* disable_local_echo */,
+      GetProcessedLocalAudioSource(properties, false /* disable_local_echo */,
                                    false /* render_to_associated_sink */);
 
   const std::string kUnusedDeviceID = "unused_device";
diff --git a/content/renderer/media/stream/processed_local_audio_source.cc b/content/renderer/media/stream/processed_local_audio_source.cc
index bd61d268..3af5deca 100644
--- a/content/renderer/media/stream/processed_local_audio_source.cc
+++ b/content/renderer/media/stream/processed_local_audio_source.cc
@@ -47,13 +47,11 @@
 ProcessedLocalAudioSource::ProcessedLocalAudioSource(
     int consumer_render_frame_id,
     const blink::MediaStreamDevice& device,
-    bool hotword_enabled,
     bool disable_local_echo,
     const AudioProcessingProperties& audio_processing_properties,
     const ConstraintsCallback& started_callback,
     PeerConnectionDependencyFactory* factory)
     : MediaStreamAudioSource(true /* is_local_source */,
-                             hotword_enabled,
                              disable_local_echo),
       consumer_render_frame_id_(consumer_render_frame_id),
       pc_factory_(factory),
diff --git a/content/renderer/media/stream/processed_local_audio_source.h b/content/renderer/media/stream/processed_local_audio_source.h
index 8caddcba..78b3a1d 100644
--- a/content/renderer/media/stream/processed_local_audio_source.h
+++ b/content/renderer/media/stream/processed_local_audio_source.h
@@ -42,7 +42,6 @@
   ProcessedLocalAudioSource(
       int consumer_render_frame_id,
       const blink::MediaStreamDevice& device,
-      bool hotword_enabled,
       bool disable_local_echo,
       const AudioProcessingProperties& audio_processing_properties,
       const ConstraintsCallback& started_callback,
diff --git a/content/renderer/media/stream/processed_local_audio_source_unittest.cc b/content/renderer/media/stream/processed_local_audio_source_unittest.cc
index f3870075..018790b 100644
--- a/content/renderer/media/stream/processed_local_audio_source_unittest.cc
+++ b/content/renderer/media/stream/processed_local_audio_source_unittest.cc
@@ -105,8 +105,7 @@
                                      "mock_audio_device_id",
                                      "Mock audio device", kSampleRate,
                                      kChannelLayout, kRequestedBufferSize),
-            false /* hotword_enabled */, false /* disable_local_echo */,
-            properties,
+            false /* disable_local_echo */, properties,
             base::Bind(&ProcessedLocalAudioSourceTest::OnAudioSourceStarted,
                        base::Unretained(this)),
             &mock_dependency_factory_);
diff --git a/content/renderer/media/stream/user_media_client_impl_unittest.cc b/content/renderer/media/stream/user_media_client_impl_unittest.cc
index b8d60371..d70b0c8 100644
--- a/content/renderer/media/stream/user_media_client_impl_unittest.cc
+++ b/content/renderer/media/stream/user_media_client_impl_unittest.cc
@@ -892,7 +892,6 @@
   EXPECT_TRUE(audio_capture_settings.HasValue());
   EXPECT_EQ(media::AudioDeviceDescription::kDefaultDeviceId,
             audio_capture_settings.device_id());
-  EXPECT_FALSE(audio_capture_settings.hotword_enabled());
   EXPECT_TRUE(audio_capture_settings.disable_local_echo());
   EXPECT_FALSE(audio_capture_settings.render_to_associated_sink());
 
@@ -956,7 +955,6 @@
   // Check default values selected by the constraints algorithm.
   EXPECT_TRUE(audio_capture_settings.HasValue());
   EXPECT_EQ(std::string(), audio_capture_settings.device_id());
-  EXPECT_FALSE(audio_capture_settings.hotword_enabled());
   EXPECT_TRUE(audio_capture_settings.disable_local_echo());
   EXPECT_FALSE(audio_capture_settings.render_to_associated_sink());
 
@@ -1015,7 +1013,6 @@
   // Check default values selected by the constraints algorithm.
   EXPECT_TRUE(audio_capture_settings.HasValue());
   EXPECT_EQ(std::string(), audio_capture_settings.device_id());
-  EXPECT_FALSE(audio_capture_settings.hotword_enabled());
   EXPECT_FALSE(audio_capture_settings.disable_local_echo());
   EXPECT_FALSE(audio_capture_settings.render_to_associated_sink());
 
@@ -1058,7 +1055,6 @@
   MockConstraintFactory factory;
   factory.basic().device_id.SetExact(
       blink::WebString::FromASCII(kFakeAudioInputDeviceId1));
-  factory.basic().hotword_enabled.SetExact(true);
   factory.basic().disable_local_echo.SetExact(true);
   factory.basic().render_to_associated_sink.SetExact(true);
   factory.basic().echo_cancellation.SetExact(false);
@@ -1081,7 +1077,6 @@
 
   EXPECT_TRUE(audio_capture_settings.HasValue());
   EXPECT_EQ(kFakeAudioInputDeviceId1, audio_capture_settings.device_id());
-  EXPECT_TRUE(audio_capture_settings.hotword_enabled());
   EXPECT_TRUE(audio_capture_settings.disable_local_echo());
   EXPECT_TRUE(audio_capture_settings.render_to_associated_sink());
 
diff --git a/content/renderer/media/stream/user_media_processor.cc b/content/renderer/media/stream/user_media_processor.cc
index ba9a785..de487c56 100644
--- a/content/renderer/media/stream/user_media_processor.cc
+++ b/content/renderer/media/stream/user_media_processor.cc
@@ -554,8 +554,6 @@
       settings.device_id();
   current_request_info_->stream_controls()->disable_local_echo =
       settings.disable_local_echo();
-  current_request_info_->stream_controls()->hotword_enabled =
-      settings.hotword_enabled();
   current_request_info_->SetAudioCaptureSettings(
       settings,
       !IsDeviceMediaType(
@@ -1008,14 +1006,14 @@
       !MediaStreamAudioProcessor::WouldModifyAudio(
           audio_processing_properties)) {
     return std::make_unique<LocalMediaStreamAudioSource>(
-        render_frame_->GetRoutingID(), device, stream_controls->hotword_enabled,
+        render_frame_->GetRoutingID(), device,
         stream_controls->disable_local_echo, source_ready);
   }
 
   // The audio device is not associated with screen capture and also requires
   // processing.
   return std::make_unique<ProcessedLocalAudioSource>(
-      render_frame_->GetRoutingID(), device, stream_controls->hotword_enabled,
+      render_frame_->GetRoutingID(), device,
       stream_controls->disable_local_echo, audio_processing_properties,
       source_ready, dependency_factory_);
 }
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
index 729e255..705c0d45 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
@@ -325,8 +325,7 @@
                 "Mock device", media::AudioParameters::kAudioCDSampleRate,
                 media::CHANNEL_LAYOUT_STEREO,
                 media::AudioParameters::kAudioCDSampleRate / 100),
-            false /* hotword_enabled */, false /* disable_local_echo */,
-            AudioProcessingProperties(),
+            false /* disable_local_echo */, AudioProcessingProperties(),
             base::Bind(&RTCPeerConnectionHandlerTest::OnAudioSourceStarted),
             mock_dependency_factory_.get());
     audio_source->SetAllowInvalidRenderFrameIdForTesting(true);
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index c6c5d9c..9545d80 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -448,9 +448,6 @@
   // browser tests delete a RenderWidget without correclty going through
   // the shutdown. https://crbug.com/545684
 
-  if (input_event_queue_)
-    input_event_queue_->ClearClient();
-
 #if defined(USE_AURA)
   // It is possible for a RenderWidget to be destroyed before it was embedded
   // in a mus window. The RendererWindowTreeClient will leak in such cases. So
@@ -676,6 +673,11 @@
     }
   }
 
+  // Stop handling main thread input events immediately so we don't have them
+  // running while things are partly shut down.
+  if (input_event_queue_)
+    input_event_queue_->ClearClient();
+
   if (for_child_local_root_frame_) {
     // Widgets for frames may be created and closed at any time while the frame
     // is alive. However, WebWidget must be closed synchronously because frame
@@ -886,28 +888,18 @@
   return input_handler_->GetFrameSinkIdAtPoint(point, local_point);
 }
 
-void RenderWidget::HandleInputEvent(
+bool RenderWidget::HandleInputEvent(
     const blink::WebCoalescedInputEvent& input_event,
     const ui::LatencyInfo& latency_info,
     HandledEventCallback callback) {
-  // This class is not removed as the MainThreadEventQueueClient until it
-  // is destroyed, so we must check |closing_| to avoid introducing input
-  // events after close.
-  if (is_frozen_ || closing_) {
-    std::move(callback).Run(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, latency_info,
-                            nullptr, base::nullopt);
-    return;
-  }
+  if (is_frozen_)
+    return false;
   input_handler_->HandleInputEvent(input_event, latency_info,
                                    std::move(callback));
+  return true;
 }
 
 void RenderWidget::SetNeedsMainFrame() {
-  // This class is not removed as the MainThreadEventQueueClient until it
-  // is destroyed.
-  if (closing_)
-    return;
-
   // The WebWidgetClient is not |this| if tests override it for the WebView and
   // WebViewClient.
   blink::WebWidgetClient* client =
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 6c95299..9469c37b 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -419,7 +419,12 @@
 
   void SetHandlingInputEvent(bool handling_input_event);
 
-  // Delivers |message| together with compositor state change updates.
+  // Queues the IPC |message| to be sent to the browser, delaying sending until
+  // the next compositor frame submission. At that time they will be sent before
+  // any message from the compositor as part of submitting its frame. This is
+  // used for messages that need synchronization with the compositor, but in
+  // general you should use Send().
+  //
   // This mechanism is not a drop-in replacement for IPC: messages sent this way
   // will not be automatically available to BrowserMessageFilter, for example.
   // FIFO ordering is preserved between messages enqueued.
@@ -498,17 +503,15 @@
   }
 
   // MainThreadEventQueueClient overrides.
-
-  // Requests a BeginMainFrame callback from the compositor.
+  bool HandleInputEvent(const blink::WebCoalescedInputEvent& input_event,
+                        const ui::LatencyInfo& latency_info,
+                        HandledEventCallback callback) override;
   void SetNeedsMainFrame() override;
 
   viz::FrameSinkId GetFrameSinkIdAtPoint(const gfx::PointF& point,
                                          gfx::PointF* local_point);
 
-  void HandleInputEvent(const blink::WebCoalescedInputEvent& input_event,
-                        const ui::LatencyInfo& latency_info,
-                        HandledEventCallback callback) override;
-
+  // Widget mojom overrides.
   void SetupWidgetInputHandler(mojom::WidgetInputHandlerRequest request,
                                mojom::WidgetInputHandlerHostPtr host) override;
 
diff --git a/content/test/data/accessibility/html/form-validation-message-after-hide-timeout-expected-blink.txt b/content/test/data/accessibility/html/form-validation-message-after-hide-timeout-expected-blink.txt
new file mode 100644
index 0000000..f055b85
--- /dev/null
+++ b/content/test/data/accessibility/html/form-validation-message-after-hide-timeout-expected-blink.txt
@@ -0,0 +1,11 @@
+rootWebArea
+++form
+++++labelText
+++++++staticText name='Pet name:'
+++++++++inlineTextBox name='Pet name:'
+++++textField required name='Pet name:' errormessageId=alert invalidState=true
+++++++genericContainer
+++++genericContainer
+++++++staticText name='ready'
+++++++++inlineTextBox name='ready'
+++alert invisible containerLiveRelevant='additions' containerLiveStatus='assertive' liveRelevant='additions' liveStatus='assertive' containerLiveAtomic=true containerLiveBusy=false liveAtomic=true
diff --git a/content/test/data/accessibility/html/form-validation-message-after-hide-timeout.html b/content/test/data/accessibility/html/form-validation-message-after-hide-timeout.html
new file mode 100644
index 0000000..44cbe8b4
--- /dev/null
+++ b/content/test/data/accessibility/html/form-validation-message-after-hide-timeout.html
@@ -0,0 +1,20 @@
+<!--
+@BLINK-ALLOW:live*
+@BLINK-ALLOW:container*
+@MAC-ALLOW:AXSubrole=AXApplicationAlert
+@WAIT-FOR:ready
+-->
+<!-- Ensure that validation errormessage relation is still avalailable after it has been hidden, as long as field is still invalid -->
+<!DOCTYPE html>
+<form>
+  <label for="in1">Pet name:</label><input id="in1" required>
+  <div id="waitfor"></div>
+</form>
+<script>
+  const in1 = document.querySelector('input');
+  in1.setCustomValidity('Please enter pet name');
+  in1.reportValidity();
+  setTimeout(() => {
+    document.getElementById('waitfor').innerText = 'ready';
+  }, 6000);
+</script>
diff --git a/content/test/data/accessibility/html/form-validation-message-expected-blink.txt b/content/test/data/accessibility/html/form-validation-message-expected-blink.txt
index 9a6bd4cd..36557eec 100644
--- a/content/test/data/accessibility/html/form-validation-message-expected-blink.txt
+++ b/content/test/data/accessibility/html/form-validation-message-expected-blink.txt
@@ -5,4 +5,4 @@
 ++++++++inlineTextBox name='Pet name:'
 ++++textField required name='Pet name:' errormessageId=alert invalidState=true
 ++++++genericContainer
-++alert containerLiveRelevant='additions' containerLiveStatus='assertive' name='Please enter pet name' liveRelevant='additions' liveStatus='assertive' containerLiveAtomic=true containerLiveBusy=false liveAtomic=true
\ No newline at end of file
+++alert containerLiveRelevant='additions' containerLiveStatus='assertive' name='Please enter pet name' liveRelevant='additions' liveStatus='assertive' containerLiveAtomic=true containerLiveBusy=false liveAtomic=true
diff --git a/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected-expected-blink.txt b/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected-expected-blink.txt
new file mode 100644
index 0000000..15358836
--- /dev/null
+++ b/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected-expected-blink.txt
@@ -0,0 +1,9 @@
+rootWebArea
+++form
+++++labelText
+++++++staticText name='Pet name:'
+++++++++inlineTextBox name='Pet name:'
+++++textField required name='Pet name:' value='ready'
+++++++genericContainer
+++++++++staticText name='ready'
+++++++++++inlineTextBox name='ready'
diff --git a/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected.html b/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected.html
new file mode 100644
index 0000000..e7fa740
--- /dev/null
+++ b/content/test/data/accessibility/html/form-validation-message-removed-after-error-corrected.html
@@ -0,0 +1,21 @@
+<!--
+# TODO(accessibility) Invalid state should not appear after required field is
+# filled, but does. This only occurs in the test, not in a real browser.
+# For now, don't check invalid state in this test.
+@BLINK-DENY:invalidState*
+@WAIT-FOR:ready
+-->
+<!-- Ensure that alert is removed after form is made valid-->
+<!DOCTYPE html>
+<form>
+  <label for="in1">Pet name:</label><input id="in1" required>
+</form>
+<script>
+  const in1 = document.querySelector('input');
+  in1.setCustomValidity('Please enter pet name');
+  in1.reportValidity();
+  setTimeout(() => {
+    in1.blur();
+    in1.value = 'ready';
+  }, 100);
+</script>
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index 1c9600e5..37a91c93 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -27,8 +27,7 @@
     self.Skip('Pixel_OffscreenCanvasWebGLSoftwareCompositingWorker',
               ['android'])
     self.Skip('Pixel_CanvasDisplayLinearRGBUnaccelerated2D', ['android'])
-    # Disable temporarily to avoid a collision, https://crbug.com/922218
-    #self.Skip('Pixel_CanvasUnacceleratedLowLatency2D', ['android'])
+    self.Skip('Pixel_CanvasUnacceleratedLowLatency2D', ['android'])
     self.Skip('Pixel_RepeatedWebGLTo2D_SoftwareCompositing', ['android'])
 
     # Tests running with SwiftShader are skipped on platforms where SwiftShader
@@ -136,7 +135,3 @@
         ['mac', ('amd', 0x679e)], bug=911413)
     self.Fail('Pixel_Video_MP4_FourColors_Rot_270',
         ['mac', ('amd', 0x679e)], bug=911413)
-
-    # TODO(mcasas): re-enable after rebaselining, https://crbug.com/922218
-    self.Fail('Pixel_CanvasLowLatency2D', bug=922218)
-    self.Fail('Pixel_CanvasUnacceleratedLowLatency2D', bug=922218)
diff --git a/device/fido/features.cc b/device/fido/features.cc
index dad7f0d1..ea36b7b 100644
--- a/device/fido/features.cc
+++ b/device/fido/features.cc
@@ -13,18 +13,10 @@
 // Controls whether on Windows, U2F/CTAP2 requests are forwarded to the
 // native WebAuthentication API, where available.
 const base::Feature kWebAuthUseNativeWinApi{"WebAuthenticationUseNativeWinApi",
-                                            base::FEATURE_DISABLED_BY_DEFAULT};
-
-// If true, the minimum API version check for integration with the native
-// Windows WebAuthentication API is disabled. This is an interim solution for
-// for manual testing while we await the release of a DLL that implements the
-// version check.
-const base::Feature kWebAuthDisableWinApiVersionCheckForTesting{
-    "WebAuthenticationDisableWinApiVersionCheckForTesting",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+                                            base::FEATURE_ENABLED_BY_DEFAULT};
 #endif  // defined(OS_WIN)
 
 extern const base::Feature kWebAuthProxyCryptotoken{
-    "WebAuthenticationProxyCryptotoken", base::FEATURE_DISABLED_BY_DEFAULT};
+    "WebAuthenticationProxyCryptotoken", base::FEATURE_ENABLED_BY_DEFAULT};
 
 }  // namespace device
diff --git a/device/fido/features.h b/device/fido/features.h
index dbcb880..1ed614c7 100644
--- a/device/fido/features.h
+++ b/device/fido/features.h
@@ -14,9 +14,6 @@
 #if defined(OS_WIN)
 COMPONENT_EXPORT(DEVICE_FIDO)
 extern const base::Feature kWebAuthUseNativeWinApi;
-
-COMPONENT_EXPORT(DEVICE_FIDO)
-extern const base::Feature kWebAuthDisableWinApiVersionCheckForTesting;
 #endif  // defined(OS_WIN)
 
 // Controls the proxying of Cryptotoken requests through WebAuthn.
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc
index 70e22c9..bf1cda064 100644
--- a/device/fido/get_assertion_handler_unittest.cc
+++ b/device/fido/get_assertion_handler_unittest.cc
@@ -8,17 +8,14 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/stl_util.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "build/build_config.h"
-#include "device/base/features.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/fido/authenticator_get_assertion_response.h"
 #include "device/fido/ctap_get_assertion_request.h"
 #include "device/fido/device_response_converter.h"
 #include "device/fido/fake_fido_discovery.h"
-#include "device/fido/features.h"
 #include "device/fido/fido_constants.h"
 #include "device/fido/fido_parsing_utils.h"
 #include "device/fido/fido_test_data.h"
@@ -693,38 +690,15 @@
 }
 
 #if defined(OS_WIN)
-class GetAssertionRequestHandlerWinTest : public ::testing::Test {
- protected:
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
-  ScopedFakeWinWebAuthnApi scoped_fake_win_webauthn_api_;
-};
-
 // Verify that the request handler instantiates a HID device backed
 // FidoDeviceAuthenticator or a WinNativeCrossPlatformAuthenticator, depending
-// on feature flag and API availability.
-TEST_F(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) {
-  enum class DeviceType {
-    kHid,
-    kWinNative,
-  };
-  const struct TestCase {
-    bool enable_win_webauthn_api;
-    bool enable_feature_flag;
-    DeviceType expect_device_type;
-  } test_cases[] = {
-      {false, false, DeviceType::kHid},
-      {false, true, DeviceType::kHid},
-      {true, false, DeviceType::kHid},
-      {true, true, DeviceType::kWinNative},
-  };
-  size_t i = 0;
-  for (const auto& test : test_cases) {
-    SCOPED_TRACE(i++);
-    scoped_fake_win_webauthn_api_.set_available(test.enable_win_webauthn_api);
-    base::test::ScopedFeatureList scoped_feature_list;
-    // Feature is default off (even with API present).
-    if (test.enable_feature_flag)
-      scoped_feature_list.InitAndEnableFeature(kWebAuthUseNativeWinApi);
+// on API availability.
+TEST(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) {
+  base::test::ScopedTaskEnvironment scoped_task_environment;
+  ScopedFakeWinWebAuthnApi scoped_fake_win_webauthn_api;
+  for (const bool enable_api : {false, true}) {
+    SCOPED_TRACE(::testing::Message() << "enable_api=" << enable_api);
+    scoped_fake_win_webauthn_api.set_available(enable_api);
 
     // Simulate a connected HID device.
     ScopedFakeHidManager fake_hid_manager;
@@ -739,14 +713,13 @@
                                 test_data::kClientDataJson),
 
         cb.callback());
-    scoped_task_environment_.RunUntilIdle();
+    scoped_task_environment.RunUntilIdle();
 
     EXPECT_EQ(1u, handler->AuthenticatorsForTesting().size());
     // Crudely distinguish authenticator type by FidoAuthenticator::GetId.
-    EXPECT_EQ(test.expect_device_type == DeviceType::kHid
-                  ? "hid:guid"
-                  : WinWebAuthnApiAuthenticator::kAuthenticatorId,
-              handler->AuthenticatorsForTesting().begin()->second->GetId());
+    EXPECT_EQ(
+        enable_api ? WinWebAuthnApiAuthenticator::kAuthenticatorId : "hid:guid",
+        handler->AuthenticatorsForTesting().begin()->second->GetId());
   }
 }
 #endif  // defined(OS_WIN)
diff --git a/device/fido/win/webauthn_api.cc b/device/fido/win/webauthn_api.cc
index 22765b41..7e88a47 100644
--- a/device/fido/win/webauthn_api.cc
+++ b/device/fido/win/webauthn_api.cc
@@ -18,7 +18,6 @@
 #include "base/task_runner_util.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread.h"
-#include "device/fido/features.h"
 #include "device/fido/win/type_conversions.h"
 
 namespace device {
@@ -88,9 +87,7 @@
 
   // WinWebAuthnApi:
   bool IsAvailable() const override {
-    return is_bound_ && (api_version_ >= kMinWinWebAuthnApiVersion ||
-                         base::FeatureList::IsEnabled(
-                             kWebAuthDisableWinApiVersionCheckForTesting));
+    return is_bound_ && (api_version_ >= kMinWinWebAuthnApiVersion);
   }
 
   HRESULT IsUserVerifyingPlatformAuthenticatorAvailable(BOOL* result) override {
diff --git a/docs/security/rule-of-2.md b/docs/security/rule-of-2.md
index 935bd72..eb1ef9e 100644
--- a/docs/security/rule-of-2.md
+++ b/docs/security/rule-of-2.md
@@ -26,9 +26,13 @@
   * have non-trivial grammars; or
   * come from untrustworthy sources.
 
-Unfortunately, essentially no format you will ever come across has a trivial
-grammar. And, of course, any arbitrary peer on the Internet is an untrustworthy
-source.
+Unfortunately, it is very rare to find a grammar trivial enough that we can
+trust ourselves to parse it successfully or fail safely. (But see
+[Normalization](#Normalization) for a potential example.)
+
+Obviously, any arbitrary peer on the Internet is an untrustworthy source without
+some evidence of trustworthiness (which includes at least [a strong assertion of
+the source's identity](#verifying-trustworthiness-source)).
 
 _Unsafe implementation languages_ are languages that lack
 [memory safety](https://en.wikipedia.org/wiki/Memory_safety), including at least
@@ -78,6 +82,7 @@
 Browsing's ZIP
 analyzer](https://cs.chromium.org/chromium/src/chrome/common/safe_browsing/zip_analyzer.h).
 
+<a href="verifying-trustworthiness-source"></a>
 ### Verifying The Trustworthiness Of A Source
 
 If you can be sure that the input comes from a trustworthy source, it can be OK
@@ -88,17 +93,29 @@
   * peer's keys are [pinned in Chrome](https://cs.chromium.org/chromium/src/net/http/transport_security_state_static.json?sq=package:chromium&g=0); and
   * peer is operated by a business entity that Chrome should trust (e.g. an [Alphabet](https://abc.xyz) company).
 
+<a name="Normalization"></a>
 ### Normalization
 
 You can 'defang' a potentially-malicious input by transforming it into a
-_normalized_ or minimal form. For example, consider the PNG image format, which
-is complex and whose [C implementation has suffered from memory corruption bugs
-in the
+_normal_ or _minimal_ form, usually by first transforming it into a format with
+a simpler grammar (such as [Farbfeld](https://tools.suckless.org/farbfeld/)).
+
+For example, consider the PNG image format, which is complex and whose [C
+implementation has suffered from memory corruption bugs in the
 past](https://www.cvedetails.com/vulnerability-list/vendor_id-7294/Libpng.html).
-An attacker would craft a malicious PNG that could trigger such a bug. But if
-you transform the image into a another format (in another, in a low-privilege
-process, of course), the malicious nature of the PNG 'should' be eliminated and
-then safe for reading at a higher privilege level.
+An attacker could craft a malicious PNG to trigger such a bug. But if you
+transform the image into a format that doesn't have PNG's complexity (in a
+low-privilege process, of course), the malicious nature of the PNG 'should' be
+eliminated and then safe for parsing at a higher privilege level. Even if the
+attacker manages to compromise the low-privilege process with a malicious PNG,
+the high-privilege process will only parse the compromised process' output with
+a simple, plausibly-safe parser. If that parse is successful, the
+higher-privilege process can then optionally further transform it into a
+normalized, minimal form (such as to save space). Otherwise, the parse can fail
+safely, without memory corruption.
+
+The trick of this technique lies in finding a sufficiently-trivial grammar, and
+committing to its limitations.
 
 ### Safe Languages
 
diff --git a/fuchsia/browser/frame_impl.cc b/fuchsia/browser/frame_impl.cc
index 77e3d729..3744b0fc 100644
--- a/fuchsia/browser/frame_impl.cc
+++ b/fuchsia/browser/frame_impl.cc
@@ -295,7 +295,7 @@
 
   content::NavigationController::LoadURLParams params_converted(validated_url);
 
-  if (!params->headers.empty()) {
+  if (params && !params->headers.empty()) {
     std::vector<base::StringPiece> extra_headers;
     extra_headers.reserve(params->headers.size());
     for (const auto& header : params->headers) {
diff --git a/ios/build/bots/chromium.mac/ios-slimnav.json b/ios/build/bots/chromium.mac/ios-slimnav.json
index 94827d46..a3913f8 100644
--- a/ios/build/bots/chromium.mac/ios-slimnav.json
+++ b/ios/build/bots/chromium.mac/ios-slimnav.json
@@ -17,7 +17,7 @@
     {
       "include": "screen_size_dependent_tests.json",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s Plus",
       "os": "12.1",
@@ -28,7 +28,7 @@
     {
       "include": "screen_size_dependent_tests.json",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
       "os": "12.1",
@@ -39,7 +39,7 @@
     {
       "include": "common_tests.json",
             "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
       "os": "12.1",
@@ -50,7 +50,7 @@
     {
       "include": "screen_size_dependent_tests.json",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "12.1",
@@ -61,7 +61,7 @@
     {
       "include": "screen_size_dependent_tests.json",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s Plus",
       "os": "11.4",
@@ -72,7 +72,7 @@
     {
       "include": "screen_size_dependent_tests.json",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
       "os": "11.4",
@@ -83,7 +83,7 @@
     {
       "include": "common_tests.json",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
       "os": "11.4",
@@ -94,7 +94,7 @@
     {
       "include": "screen_size_dependent_tests.json",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "11.4",
@@ -105,7 +105,7 @@
     {
       "include": "eg_cq_tests.json",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
       "os": "11.4",
@@ -116,7 +116,7 @@
     {
       "app": "ios_chrome_bookmarks_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "11.4",
@@ -129,7 +129,8 @@
     {
       "app": "ios_chrome_manual_fill_egtests",
       "test args": [
-        "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManager"
+        "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging",
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "11.4",
@@ -141,7 +142,7 @@
     {
       "app": "ios_chrome_web_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "11.4",
@@ -153,7 +154,7 @@
     {
       "app": "ios_chrome_settings_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "11.4",
@@ -165,7 +166,7 @@
     {
       "app": "ios_chrome_reading_list_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "11.4",
@@ -177,7 +178,7 @@
     {
       "app": "ios_showcase_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "11.4",
@@ -189,7 +190,7 @@
     {
       "app": "ios_chrome_bookmarks_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "shard size": 2,
       "device type": "iPad Air 2",
@@ -202,7 +203,8 @@
     {
       "app": "ios_chrome_manual_fill_egtests",
       "test args": [
-        "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManager"
+        "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging",
+        "--disable-features=SlimNavigationManager"
       ],
       "xctest": true,
       "device type": "iPad Air 2",
@@ -214,7 +216,7 @@
     {
       "app": "ios_chrome_web_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "12.1",
@@ -226,7 +228,7 @@
     {
       "app": "ios_chrome_settings_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "12.1",
@@ -238,7 +240,7 @@
     {
       "app": "ios_chrome_reading_list_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "12.1",
@@ -250,7 +252,7 @@
     {
       "app": "ios_showcase_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPad Air 2",
       "os": "12.1",
@@ -262,7 +264,7 @@
     {
       "app": "ios_chrome_bookmarks_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "11.4",
@@ -275,7 +277,8 @@
     {
       "app": "ios_chrome_manual_fill_egtests",
       "test args": [
-        "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManager"
+        "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging",
+        "--disable-features=SlimNavigationManager"
       ],
       "xctest": true,
       "device type": "iPhone X",
@@ -287,7 +290,7 @@
     {
       "app": "ios_chrome_web_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "11.4",
@@ -299,7 +302,7 @@
     {
       "app": "ios_chrome_settings_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "11.4",
@@ -311,7 +314,7 @@
     {
       "app": "ios_chrome_reading_list_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "11.4",
@@ -323,7 +326,7 @@
     {
       "app": "ios_showcase_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "11.4",
@@ -335,7 +338,7 @@
     {
       "app": "ios_chrome_bookmarks_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "shard size": 2,
       "device type": "iPhone X",
@@ -348,7 +351,8 @@
     {
       "app": "ios_chrome_manual_fill_egtests",
       "test args": [
-        "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging,SlimNavigationManager"
+        "--enable-features=AutofillManualFallback,AutofillManualFallbackPhaseTwo,WebFrameMessaging",
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "12.1",
@@ -360,7 +364,7 @@
     {
       "app": "ios_chrome_web_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "12.1",
@@ -372,7 +376,7 @@
     {
       "app": "ios_chrome_settings_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "12.1",
@@ -384,7 +388,7 @@
     {
       "app": "ios_chrome_reading_list_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "12.1",
@@ -396,7 +400,7 @@
     {
       "app": "ios_showcase_egtests",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "12.1",
@@ -408,7 +412,7 @@
     {
       "include": "eg_cq_tests.json",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "11.4",
@@ -419,7 +423,7 @@
     {
       "include": "eg_cq_tests.json",
       "test args": [
-        "--enable-features=SlimNavigationManager"
+        "--disable-features=SlimNavigationManager"
       ],
       "device type": "iPhone X",
       "os": "12.1",
diff --git a/ios/web/features.mm b/ios/web/features.mm
index 8c9e0223..29fe7cac 100644
--- a/ios/web/features.mm
+++ b/ios/web/features.mm
@@ -14,7 +14,7 @@
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kSlimNavigationManager{"SlimNavigationManager",
-                                           base::FEATURE_DISABLED_BY_DEFAULT};
+                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kWKHTTPSystemCookieStore{"WKHTTPSystemCookieStore",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/web_view/test/web_view_restorable_state_inttest.mm b/ios/web_view/test/web_view_restorable_state_inttest.mm
index c8b655b..fe3a4ae4 100644
--- a/ios/web_view/test/web_view_restorable_state_inttest.mm
+++ b/ios/web_view/test/web_view_restorable_state_inttest.mm
@@ -42,7 +42,7 @@
 
   // Wait for restore to finish.
   ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool {
-    return [restored_web_view canGoBack];
+    return [restored_web_view lastCommittedURL] != nil;
   }));
 
   // Verify that the state has been restored correctly.
diff --git a/media/base/mime_util_internal.cc b/media/base/mime_util_internal.cc
index c546010f..021151f 100644
--- a/media/base/mime_util_internal.cc
+++ b/media/base/mime_util_internal.cc
@@ -352,6 +352,10 @@
   AddContainerWithCodecs("audio/x-m4a", aac);
   AddContainerWithCodecs("video/x-m4v", avc_and_aac);
 
+  CodecSet video_3gpp_codecs(aac);
+  video_3gpp_codecs.emplace(H264);
+  AddContainerWithCodecs("video/3gpp", video_3gpp_codecs);
+
 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
   CodecSet mp2t_codecs{H264, MPEG2_AAC, MPEG4_AAC, MP3};
   AddContainerWithCodecs("video/mp2t", mp2t_codecs);
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc
index 8042010..630efa8 100644
--- a/media/base/mime_util_unittest.cc
+++ b/media/base/mime_util_unittest.cc
@@ -184,6 +184,7 @@
   EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-m4a"));
   EXPECT_TRUE(IsSupportedMediaMimeType("video/x-m4v"));
   EXPECT_TRUE(IsSupportedMediaMimeType("audio/aac"));
+  EXPECT_TRUE(IsSupportedMediaMimeType("video/3gpp"));
 
 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
   EXPECT_TRUE(IsSupportedMediaMimeType("video/mp2t"));
@@ -195,6 +196,7 @@
   EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-m4a"));
   EXPECT_FALSE(IsSupportedMediaMimeType("video/x-m4v"));
   EXPECT_FALSE(IsSupportedMediaMimeType("audio/aac"));
+  EXPECT_FALSE(IsSupportedMediaMimeType("video/3gpp"));
 #endif  // USE_PROPRIETARY_CODECS
   EXPECT_FALSE(IsSupportedMediaMimeType("video/mp3"));
 
diff --git a/media/gpu/android/avda_picture_buffer_manager.cc b/media/gpu/android/avda_picture_buffer_manager.cc
index e6c97ee..692fbe5 100644
--- a/media/gpu/android/avda_picture_buffer_manager.cc
+++ b/media/gpu/android/avda_picture_buffer_manager.cc
@@ -63,7 +63,8 @@
                                                1,  // depth
                                                0,  // border
                                                GL_RGBA, GL_UNSIGNED_BYTE);
-    texture_owner_ = TextureOwner::Create(std::move(texture));
+    texture_owner_ = TextureOwner::Create(std::move(texture),
+                                          TextureOwner::SecureMode::kInsecure);
     if (!texture_owner_)
       return false;
 
diff --git a/media/gpu/android/image_reader_gl_owner.cc b/media/gpu/android/image_reader_gl_owner.cc
index 1df7765..7767d3e5 100644
--- a/media/gpu/android/image_reader_gl_owner.cc
+++ b/media/gpu/android/image_reader_gl_owner.cc
@@ -69,7 +69,8 @@
 };
 
 ImageReaderGLOwner::ImageReaderGLOwner(
-    std::unique_ptr<gpu::gles2::AbstractTexture> texture)
+    std::unique_ptr<gpu::gles2::AbstractTexture> texture,
+    SecureMode secure_mode)
     : TextureOwner(std::move(texture)),
       current_image_(nullptr),
       loader_(base::android::AndroidImageReader::GetInstance()),
@@ -79,18 +80,19 @@
   DCHECK(context_);
   DCHECK(surface_);
 
-  // TODO(khushalsagar): Need plumbing here to select the correct format and
-  // usage for secure media.
-
   // Set the width, height and format to some default value. This parameters
   // are/maybe overriden by the producer sending buffers to this imageReader's
   // Surface.
   int32_t width = 1, height = 1, max_images = 3;
-  AIMAGE_FORMATS format = AIMAGE_FORMAT_YUV_420_888;
+  AIMAGE_FORMATS format = secure_mode == SecureMode::kSecure
+                              ? AIMAGE_FORMAT_PRIVATE
+                              : AIMAGE_FORMAT_YUV_420_888;
   AImageReader* reader = nullptr;
   // The usage flag below should be used when the buffer will be read from by
   // the GPU as a texture.
-  const uint64_t usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+  const uint64_t usage = secure_mode == SecureMode::kSecure
+                             ? AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT
+                             : AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
 
   // Create a new reader for images of the desired size and format.
   media_status_t return_code = loader_.AImageReader_newWithUsage(
diff --git a/media/gpu/android/image_reader_gl_owner.h b/media/gpu/android/image_reader_gl_owner.h
index ce53effc..77377dd 100644
--- a/media/gpu/android/image_reader_gl_owner.h
+++ b/media/gpu/android/image_reader_gl_owner.h
@@ -44,6 +44,8 @@
   std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
   GetAHardwareBuffer() override;
 
+  const AImageReader* image_reader_for_testing() const { return image_reader_; }
+
  protected:
   void OnTextureDestroyed(gpu::gles2::AbstractTexture*) override;
 
@@ -52,7 +54,8 @@
 
   class ScopedHardwareBufferImpl;
 
-  ImageReaderGLOwner(std::unique_ptr<gpu::gles2::AbstractTexture> texture);
+  ImageReaderGLOwner(std::unique_ptr<gpu::gles2::AbstractTexture> texture,
+                     SecureMode secure_mode);
   ~ImageReaderGLOwner() override;
 
   // Deletes the current image if it has no pending refs. Returns false on
diff --git a/media/gpu/android/image_reader_gl_owner_unittest.cc b/media/gpu/android/image_reader_gl_owner_unittest.cc
index d30aeb6..fe581b3 100644
--- a/media/gpu/android/image_reader_gl_owner_unittest.cc
+++ b/media/gpu/android/image_reader_gl_owner_unittest.cc
@@ -6,11 +6,13 @@
 
 #include <stdint.h>
 #include <memory>
+#include <utility>
 
 #include "base/message_loop/message_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "gpu/command_buffer/service/abstract_texture.h"
 #include "media/base/media_switches.h"
+#include "media/gpu/android/image_reader_gl_owner.h"
 #include "media/gpu/android/mock_abstract_texture.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/gl_bindings.h"
@@ -27,6 +29,9 @@
 
  protected:
   void SetUp() override {
+    if (!IsImageReaderSupported())
+      return;
+
     scoped_feature_list_.InitAndEnableFeature(media::kAImageReaderVideoOutput);
     gl::init::InitializeGLOneOffImplementation(gl::kGLImplementationEGLGLES2,
                                                false, false, false, true);
@@ -44,7 +49,11 @@
     std::unique_ptr<MockAbstractTexture> texture =
         std::make_unique<MockAbstractTexture>(texture_id_);
     abstract_texture_ = texture->AsWeakPtr();
-    image_reader_ = TextureOwner::Create(std::move(texture));
+    image_reader_ = TextureOwner::Create(std::move(texture), SecureMode());
+  }
+
+  virtual TextureOwner::SecureMode SecureMode() {
+    return TextureOwner::SecureMode::kInsecure;
   }
 
   void TearDown() override {
@@ -57,6 +66,10 @@
     gl::init::ShutdownGL(false);
   }
 
+  bool IsImageReaderSupported() const {
+    return base::android::AndroidImageReader::GetInstance().IsSupported();
+  }
+
   base::test::ScopedFeatureList scoped_feature_list_;
   scoped_refptr<TextureOwner> image_reader_;
   GLuint texture_id_ = 0;
@@ -70,10 +83,16 @@
 };
 
 TEST_F(ImageReaderGLOwnerTest, ImageReaderObjectCreation) {
+  if (!IsImageReaderSupported())
+    return;
+
   ASSERT_TRUE(image_reader_);
 }
 
 TEST_F(ImageReaderGLOwnerTest, ScopedJavaSurfaceCreation) {
+  if (!IsImageReaderSupported())
+    return;
+
   gl::ScopedJavaSurface temp = image_reader_->CreateJavaSurface();
   ASSERT_TRUE(temp.IsValid());
 }
@@ -81,6 +100,9 @@
 // Verify that ImageReaderGLOwner creates a bindable GL texture, and deletes
 // it during destruction.
 TEST_F(ImageReaderGLOwnerTest, GLTextureIsCreatedAndDestroyed) {
+  if (!IsImageReaderSupported())
+    return;
+
   // |texture_id| should not work anymore after we delete image_reader_.
   image_reader_ = nullptr;
   EXPECT_FALSE(abstract_texture_);
@@ -88,12 +110,18 @@
 
 // Make sure that image_reader_ remembers the correct context and surface.
 TEST_F(ImageReaderGLOwnerTest, ContextAndSurfaceAreCaptured) {
+  if (!IsImageReaderSupported())
+    return;
+
   ASSERT_EQ(context_, image_reader_->GetContext());
   ASSERT_EQ(surface_, image_reader_->GetSurface());
 }
 
 // Verify that destruction works even if some other context is current.
 TEST_F(ImageReaderGLOwnerTest, DestructionWorksWithWrongContext) {
+  if (!IsImageReaderSupported())
+    return;
+
   scoped_refptr<gl::GLSurface> new_surface(
       new gl::PbufferGLSurfaceEGL(gfx::Size(320, 240)));
   new_surface->Initialize();
@@ -115,4 +143,24 @@
   new_surface = nullptr;
 }
 
+class ImageReaderGLOwnerSecureTest : public ImageReaderGLOwnerTest {
+ public:
+  TextureOwner::SecureMode SecureMode() final {
+    return TextureOwner::SecureMode::kSecure;
+  }
+};
+
+TEST_F(ImageReaderGLOwnerSecureTest, CreatesSecureAImageReader) {
+  if (!IsImageReaderSupported())
+    return;
+
+  ASSERT_TRUE(image_reader_);
+  auto* a_image_reader = static_cast<ImageReaderGLOwner*>(image_reader_.get())
+                             ->image_reader_for_testing();
+  int32_t format = AIMAGE_FORMAT_YUV_420_888;
+  base::android::AndroidImageReader::GetInstance().AImageReader_getFormat(
+      a_image_reader, &format);
+  EXPECT_EQ(format, AIMAGE_FORMAT_PRIVATE);
+}
+
 }  // namespace media
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index 0d853fb..a4f2675 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -388,19 +388,26 @@
   lazy_init_pending_ = false;
   codec_allocator_->StartThread(this);
 
-  // SurfaceControl allows TextureOwner to be promoted to an overlay in the
-  // compositing pipeline itself.
-  const bool use_texture_owner_as_overlays = is_surface_control_enabled_;
-
   // Only ask for promotion hints if we can actually switch surfaces, since we
   // wouldn't be able to do anything with them. Also, if threaded texture
-  // mailboxes are enabled, then we turn off overlays anyway. And if texture
-  // owner can be used as an overlay, no promotion hints are necessary.
+  // mailboxes are enabled, then we turn off overlays anyway.
   const bool want_promotion_hints =
       device_info_->IsSetOutputSurfaceSupported() &&
-      !enable_threaded_texture_mailboxes_ && !use_texture_owner_as_overlays;
+      !enable_threaded_texture_mailboxes_;
+
+  VideoFrameFactory::OverlayMode overlay_mode =
+      VideoFrameFactory::OverlayMode::kDontRequestPromotionHints;
+  if (is_surface_control_enabled_) {
+    overlay_mode =
+        requires_secure_codec_
+            ? VideoFrameFactory::OverlayMode::kSurfaceControlSecure
+            : VideoFrameFactory::OverlayMode::kSurfaceControlInsecure;
+  } else if (want_promotion_hints) {
+    overlay_mode = VideoFrameFactory::OverlayMode::kRequestPromotionHints;
+  }
+
   video_frame_factory_->Initialize(
-      want_promotion_hints, use_texture_owner_as_overlays,
+      overlay_mode,
       base::Bind(&MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized,
                  weak_factory_.GetWeakPtr()));
 }
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc
index 1f09e9c..e736b98 100644
--- a/media/gpu/android/media_codec_video_decoder_unittest.cc
+++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -58,10 +58,7 @@
 
 class MockVideoFrameFactory : public VideoFrameFactory {
  public:
-  MOCK_METHOD3(Initialize,
-               void(bool wants_promotion_hint,
-                    bool use_texture_owner_as_overlay,
-                    InitCb init_cb));
+  MOCK_METHOD2(Initialize, void(OverlayMode overlay_mode, InitCb init_cb));
   MOCK_METHOD1(MockSetSurfaceBundle, void(scoped_refptr<AVDASurfaceBundle>));
   MOCK_METHOD5(
       MockCreateVideoFrame,
@@ -143,10 +140,8 @@
         std::make_unique<NiceMock<MockVideoFrameFactory>>();
     video_frame_factory_ = video_frame_factory.get();
     // Set up VFF to pass |texture_owner_| via its InitCb.
-    const bool want_promotion_hint =
-        device_info_->IsSetOutputSurfaceSupported();
-    ON_CALL(*video_frame_factory_, Initialize(want_promotion_hint, _, _))
-        .WillByDefault(RunCallback<2>(texture_owner));
+    ON_CALL(*video_frame_factory_, Initialize(ExpectedOverlayMode(), _))
+        .WillByDefault(RunCallback<1>(texture_owner));
 
     auto* observable_mcvd = new DestructionObservableMCVD(
         gpu_preferences_, gpu_feature_info_, device_info_.get(),
@@ -162,6 +157,14 @@
     destruction_observer_->ExpectDestruction();
   }
 
+  VideoFrameFactory::OverlayMode ExpectedOverlayMode() const {
+    const bool want_promotion_hint =
+        device_info_->IsSetOutputSurfaceSupported();
+    return want_promotion_hint
+               ? VideoFrameFactory::OverlayMode::kRequestPromotionHints
+               : VideoFrameFactory::OverlayMode::kDontRequestPromotionHints;
+  }
+
   void CreateCdm(bool has_media_crypto_context,
                  bool require_secure_video_decoder) {
     cdm_ = std::make_unique<MockMediaCryptoContext>(has_media_crypto_context);
@@ -309,7 +312,8 @@
 
 TEST_P(MediaCodecVideoDecoderTest, InitializeDoesntInitSurfaceOrCodec) {
   CreateMcvd();
-  EXPECT_CALL(*video_frame_factory_, Initialize(_, _, _)).Times(0);
+  EXPECT_CALL(*video_frame_factory_, Initialize(ExpectedOverlayMode(), _))
+      .Times(0);
   EXPECT_CALL(*surface_chooser_, MockUpdateState()).Times(0);
   EXPECT_CALL(*codec_allocator_, MockCreateMediaCodecAsync(_, _)).Times(0);
   Initialize(TestVideoConfig::Large(codec_));
@@ -317,7 +321,7 @@
 
 TEST_P(MediaCodecVideoDecoderTest, FirstDecodeTriggersFrameFactoryInit) {
   Initialize(TestVideoConfig::Large(codec_));
-  EXPECT_CALL(*video_frame_factory_, Initialize(_, _, _));
+  EXPECT_CALL(*video_frame_factory_, Initialize(ExpectedOverlayMode(), _));
   mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get());
 }
 
@@ -371,8 +375,8 @@
 
 TEST_P(MediaCodecVideoDecoderTest, FrameFactoryInitFailureIsAnError) {
   Initialize(TestVideoConfig::Large(codec_));
-  ON_CALL(*video_frame_factory_, Initialize(_, _, _))
-      .WillByDefault(RunCallback<2>(nullptr));
+  ON_CALL(*video_frame_factory_, Initialize(ExpectedOverlayMode(), _))
+      .WillByDefault(RunCallback<1>(nullptr));
   EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR)).Times(1);
   EXPECT_CALL(*surface_chooser_, MockUpdateState()).Times(0);
   mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get());
diff --git a/media/gpu/android/surface_texture_gl_owner_unittest.cc b/media/gpu/android/surface_texture_gl_owner_unittest.cc
index 15a8143..d9e790f 100644
--- a/media/gpu/android/surface_texture_gl_owner_unittest.cc
+++ b/media/gpu/android/surface_texture_gl_owner_unittest.cc
@@ -50,7 +50,8 @@
     std::unique_ptr<MockAbstractTexture> texture =
         std::make_unique<MockAbstractTexture>(texture_id_);
     abstract_texture_ = texture->AsWeakPtr();
-    surface_texture_ = SurfaceTextureGLOwner::Create(std::move(texture));
+    surface_texture_ = SurfaceTextureGLOwner::Create(
+        std::move(texture), TextureOwner::SecureMode::kInsecure);
     texture_id_ = surface_texture_->GetTextureId();
     EXPECT_TRUE(abstract_texture_);
   }
diff --git a/media/gpu/android/texture_owner.cc b/media/gpu/android/texture_owner.cc
index 05da30fa..f3f7e815 100644
--- a/media/gpu/android/texture_owner.cc
+++ b/media/gpu/android/texture_owner.cc
@@ -36,7 +36,8 @@
 
 // static
 scoped_refptr<TextureOwner> TextureOwner::Create(
-    std::unique_ptr<gpu::gles2::AbstractTexture> texture) {
+    std::unique_ptr<gpu::gles2::AbstractTexture> texture,
+    SecureMode secure_mode) {
   // Set the parameters on the texture.
   texture->SetParameteri(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   texture->SetParameteri(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -46,10 +47,12 @@
   // If AImageReader is supported and is enabled by media flag, use it.
   if (base::android::AndroidImageReader::GetInstance().IsSupported() &&
       base::FeatureList::IsEnabled(media::kAImageReaderVideoOutput)) {
-    return new ImageReaderGLOwner(std::move(texture));
+    return new ImageReaderGLOwner(std::move(texture), secure_mode);
   }
 
   // If not, fall back to legacy path.
+  DCHECK_EQ(secure_mode, SecureMode::kInsecure)
+      << "Can not use secure mode with SurfaceTexture";
   return new SurfaceTextureGLOwner(std::move(texture));
 }
 
diff --git a/media/gpu/android/texture_owner.h b/media/gpu/android/texture_owner.h
index f2a16d85..a2004262 100644
--- a/media/gpu/android/texture_owner.h
+++ b/media/gpu/android/texture_owner.h
@@ -45,8 +45,12 @@
   // new TextureOwner attached to it. Returns null on failure.
   // |texture| should be either from CreateAbstractTexture() or a mock.  The
   // corresponding GL context must be current.
+  // SecureMode indicates whether the video textures created using this owner
+  // should be hardware protected.
+  enum class SecureMode { kSecure, kInsecure };
   static scoped_refptr<TextureOwner> Create(
-      std::unique_ptr<gpu::gles2::AbstractTexture> texture);
+      std::unique_ptr<gpu::gles2::AbstractTexture> texture,
+      SecureMode secure_mode);
 
   // Create a texture that's appropriate for a TextureOwner.
   static std::unique_ptr<gpu::gles2::AbstractTexture> CreateTexture(
diff --git a/media/gpu/android/video_frame_factory.h b/media/gpu/android/video_frame_factory.h
index b3e87cb..c4708da 100644
--- a/media/gpu/android/video_frame_factory.h
+++ b/media/gpu/android/video_frame_factory.h
@@ -41,13 +41,22 @@
   // Initializes the factory and runs |init_cb| on the current thread when it's
   // complete. If initialization fails, the returned texture owner will be
   // null.
-  // |wants_promotion_hint| tells us whether to mark VideoFrames for compositor
-  // overlay promotion hints or not.
-  // |use_texture_owner_as_overlays| tells us whether TextureOwner can be used
-  // as an overlay, in which case java overlays will never be used.
-  virtual void Initialize(bool wants_promotion_hint,
-                          bool use_texture_owner_as_overlays,
-                          InitCb init_cb) = 0;
+  enum class OverlayMode {
+    // When using java overlays, the compositor can provide hints to the media
+    // pipeline to indicate whether the video can be promoted to an overlay.
+    // This indicates whether promotion hints are needed, if framework support
+    // for overlay promotion is available (requires MediaCodec.setOutputSurface
+    // support).
+    kDontRequestPromotionHints,
+    kRequestPromotionHints,
+
+    // When using surface control, the factory should always use a TextureOwner
+    // since it can directly be promoted to an overlay on a frame-by-frame
+    // basis. The bits below indicate whether the media uses a secure codec.
+    kSurfaceControlSecure,
+    kSurfaceControlInsecure
+  };
+  virtual void Initialize(OverlayMode overlay_mode, InitCb init_cb) = 0;
 
   // Notify us about the current surface bundle that subsequent video frames
   // should use.
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index da41d9c..6a7628e 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -51,8 +51,7 @@
     gpu_task_runner_->DeleteSoon(FROM_HERE, gpu_video_frame_factory_.release());
 }
 
-void VideoFrameFactoryImpl::Initialize(bool wants_promotion_hint,
-                                       bool use_texture_owner_as_overlays,
+void VideoFrameFactoryImpl::Initialize(OverlayMode overlay_mode,
                                        InitCb init_cb) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!gpu_video_frame_factory_);
@@ -60,8 +59,7 @@
   base::PostTaskAndReplyWithResult(
       gpu_task_runner_.get(), FROM_HERE,
       base::Bind(&GpuVideoFrameFactory::Initialize,
-                 base::Unretained(gpu_video_frame_factory_.get()),
-                 wants_promotion_hint, use_texture_owner_as_overlays,
+                 base::Unretained(gpu_video_frame_factory_.get()), overlay_mode,
                  get_stub_cb_),
       std::move(init_cb));
 }
@@ -132,12 +130,10 @@
 }
 
 scoped_refptr<TextureOwner> GpuVideoFrameFactory::Initialize(
-    bool wants_promotion_hint,
-    bool use_texture_owner_as_overlays,
+    VideoFrameFactoryImpl::OverlayMode overlay_mode,
     VideoFrameFactoryImpl::GetStubCb get_stub_cb) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  wants_promotion_hint_ = wants_promotion_hint;
-  use_texture_owner_as_overlays_ = use_texture_owner_as_overlays;
+  overlay_mode_ = overlay_mode;
   stub_ = get_stub_cb.Run();
   if (!MakeContextCurrent(stub_))
     return nullptr;
@@ -147,8 +143,12 @@
 
   decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder_context());
 
+  auto secure_mode =
+      overlay_mode_ == VideoFrameFactory::OverlayMode::kSurfaceControlSecure
+          ? TextureOwner::SecureMode::kSecure
+          : TextureOwner::SecureMode::kInsecure;
   return TextureOwner::Create(
-      TextureOwner::CreateTexture(stub_->decoder_context()));
+      TextureOwner::CreateTexture(stub_->decoder_context()), secure_mode);
 }
 
 void GpuVideoFrameFactory::CreateVideoFrame(
@@ -283,21 +283,27 @@
   if (group->gpu_preferences().enable_threaded_texture_mailboxes)
     frame->metadata()->SetBoolean(VideoFrameMetadata::COPY_REQUIRED, true);
 
+  const bool is_surface_control =
+      overlay_mode_ == VideoFrameFactory::OverlayMode::kSurfaceControlSecure ||
+      overlay_mode_ == VideoFrameFactory::OverlayMode::kSurfaceControlInsecure;
+  const bool wants_promotion_hints =
+      overlay_mode_ == VideoFrameFactory::OverlayMode::kRequestPromotionHints;
+
   bool allow_overlay = false;
-  if (use_texture_owner_as_overlays_) {
+  if (is_surface_control) {
     DCHECK(texture_owner_);
     allow_overlay = true;
   } else {
     // We unconditionally mark the picture as overlayable, even if
     // |!texture_owner_|, if we want to get hints.  It's required, else we won't
     // get hints.
-    allow_overlay = !texture_owner_ || wants_promotion_hint_;
+    allow_overlay = !texture_owner_ || wants_promotion_hints;
   }
 
   frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY,
                                 allow_overlay);
   frame->metadata()->SetBoolean(VideoFrameMetadata::WANTS_PROMOTION_HINT,
-                                wants_promotion_hint_);
+                                wants_promotion_hints);
   frame->metadata()->SetBoolean(VideoFrameMetadata::TEXTURE_OWNER,
                                 !!texture_owner_);
 
diff --git a/media/gpu/android/video_frame_factory_impl.h b/media/gpu/android/video_frame_factory_impl.h
index f93760f..01c1f2c 100644
--- a/media/gpu/android/video_frame_factory_impl.h
+++ b/media/gpu/android/video_frame_factory_impl.h
@@ -38,9 +38,7 @@
       GetStubCb get_stub_cb);
   ~VideoFrameFactoryImpl() override;
 
-  void Initialize(bool wants_promotion_hint,
-                  bool use_texture_owner_as_overlays,
-                  InitCb init_cb) override;
+  void Initialize(OverlayMode overlay_mode, InitCb init_cb) override;
   void SetSurfaceBundle(
       scoped_refptr<AVDASurfaceBundle> surface_bundle) override;
   void CreateVideoFrame(
@@ -73,8 +71,7 @@
   ~GpuVideoFrameFactory() override;
 
   scoped_refptr<TextureOwner> Initialize(
-      bool wants_promotion_hint,
-      bool use_texture_owner_as_overlays,
+      VideoFrameFactory::OverlayMode overlay_mode,
       VideoFrameFactory::GetStubCb get_stub_cb);
 
   // Creates and returns a VideoFrame with its ReleaseMailboxCB.
@@ -111,16 +108,13 @@
   // Outstanding images that should be considered for early rendering.
   std::vector<CodecImage*> images_;
 
-  gpu::CommandBufferStub* stub_;
+  gpu::CommandBufferStub* stub_ = nullptr;
 
   // Callback to notify us that an image has been destroyed.
   CodecImage::DestructionCb destruction_cb_;
 
-  // Do we want promotion hints from the compositor?
-  bool wants_promotion_hint_ = false;
-
-  // Indicates whether texture owner can be promoted to an overlay.
-  bool use_texture_owner_as_overlays_ = false;
+  VideoFrameFactory::OverlayMode overlay_mode_ =
+      VideoFrameFactory::OverlayMode::kDontRequestPromotionHints;
 
   // A helper for creating textures. Only valid while |stub_| is valid.
   std::unique_ptr<GLES2DecoderHelper> decoder_helper_;
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc
index 2ff838bf..538a29f 100644
--- a/media/renderers/video_renderer_impl.cc
+++ b/media/renderers/video_renderer_impl.cc
@@ -269,7 +269,8 @@
     base::TimeTicks deadline_min,
     base::TimeTicks deadline_max,
     bool background_rendering) {
-  TRACE_EVENT1("media", "VideoRendererImpl::Render", "id", media_log_->id());
+  TRACE_EVENT_BEGIN1("media", "VideoRendererImpl::Render", "id",
+                     media_log_->id());
   base::AutoLock auto_lock(lock_);
   DCHECK_EQ(state_, kPlaying);
   last_render_time_ = tick_clock_->NowTicks();
@@ -316,6 +317,8 @@
                      weak_factory_.GetWeakPtr(), result->format(),
                      result->natural_size()));
 
+  TRACE_EVENT_END1("media", "VideoRendererImpl::Render", "frame",
+                   result->AsHumanReadableString());
   return result;
 }
 
diff --git a/mojo/core/channel_fuzzer.cc b/mojo/core/channel_fuzzer.cc
index b72f9e7..afebf29 100644
--- a/mojo/core/channel_fuzzer.cc
+++ b/mojo/core/channel_fuzzer.cc
@@ -14,6 +14,10 @@
 #include "mojo/core/entrypoints.h"
 #include "mojo/public/cpp/platform/platform_channel.h"
 
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
 using namespace mojo::core;
 
 // A fake delegate for each Channel endpoint. By the time an incoming message
@@ -51,6 +55,23 @@
                                   ConnectionParams(channel.TakeLocalEndpoint()),
                                   Channel::HandlePolicy::kRejectHandles,
                                   environment->message_loop.task_runner());
+
+#if defined(OS_WIN)
+  // On Windows, it's important that the receiver behaves like a broker process
+  // receiving messages from a non-broker process. This is because that case can
+  // safely handle invalid HANDLE attachments without crashing. The same is not
+  // true for messages going in the reverse direction (where the non-broker
+  // receiver has to assume that the broker has already duplicated the HANDLE
+  // into the non-broker's process), but fuzzing that direction is not
+  // interesting since a compromised broker process has much bigger problems.
+  //
+  // Note that in order for this hack to work properly, the remote process
+  // handle needs to be a "real" process handle rather than the pseudo-handle
+  // returned by GetCurrentProcessHandle(). Hence the use of OpenProcess().
+  receiver->set_remote_process(mojo::core::ScopedProcessHandle(
+      ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId())));
+#endif
+
   receiver->Start();
 
   FakeChannelDelegate sender_delegate;
diff --git a/mojo/core/node_channel_fuzzer.cc b/mojo/core/node_channel_fuzzer.cc
index c9276098..aea2ead 100644
--- a/mojo/core/node_channel_fuzzer.cc
+++ b/mojo/core/node_channel_fuzzer.cc
@@ -15,6 +15,10 @@
 #include "mojo/core/node_channel.h"  // nogncheck
 #include "mojo/public/cpp/platform/platform_channel.h"
 
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
 using namespace mojo::core;
 
 // Implementation of NodeChannel::Delegate which does nothing. All of the
@@ -104,6 +108,23 @@
       &receiver_delegate, ConnectionParams(channel.TakeLocalEndpoint()),
       Channel::HandlePolicy::kRejectHandles,
       environment->message_loop.task_runner(), base::DoNothing());
+
+#if defined(OS_WIN)
+  // On Windows, it's important that the receiver behaves like a broker process
+  // receiving messages from a non-broker process. This is because that case can
+  // safely handle invalid HANDLE attachments without crashing. The same is not
+  // true for messages going in the reverse direction (where the non-broker
+  // receiver has to assume that the broker has already duplicated the HANDLE
+  // into the non-broker's process), but fuzzing that direction is not
+  // interesting since a compromised broker process has much bigger problems.
+  //
+  // Note that in order for this hack to work properly, the remote process
+  // handle needs to be a "real" process handle rather than the pseudo-handle
+  // returned by GetCurrentProcessHandle(). Hence the use of OpenProcess().
+  receiver->SetRemoteProcessHandle(mojo::core::ScopedProcessHandle(
+      ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId())));
+#endif
+
   receiver->Start();
 
   // We only use a Channel for the sender side, since it allows us to easily
diff --git a/mojo/public/tools/bindings/BUILD.gn b/mojo/public/tools/bindings/BUILD.gn
index de558a617..357f083 100644
--- a/mojo/public/tools/bindings/BUILD.gn
+++ b/mojo/public/tools/bindings/BUILD.gn
@@ -17,6 +17,7 @@
     "$mojom_generator_root/generators/cpp_templates/interface_request_validator_declaration.tmpl",
     "$mojom_generator_root/generators/cpp_templates/interface_response_validator_declaration.tmpl",
     "$mojom_generator_root/generators/cpp_templates/interface_stub_declaration.tmpl",
+    "$mojom_generator_root/generators/cpp_templates/module-params-data.h.tmpl",
     "$mojom_generator_root/generators/cpp_templates/module-shared-internal.h.tmpl",
     "$mojom_generator_root/generators/cpp_templates/module-shared-message-ids.h.tmpl",
     "$mojom_generator_root/generators/cpp_templates/module-shared.cc.tmpl",
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl
new file mode 100644
index 0000000..92cbffe
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl
@@ -0,0 +1,80 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+{%- set header_guard = "%s_PARAMS_DATA_H_"|format(
+        module.path|upper|replace("/","_")|replace(".","_")|
+            replace("-", "_")) %}
+
+#ifndef {{header_guard}}
+#define {{header_guard}}
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/buffer.h"
+#include "mojo/public/cpp/bindings/lib/validation_context.h"
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-private-field"
+#elif defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4056)
+#pragma warning(disable:4065)
+#pragma warning(disable:4756)
+#endif
+
+{%- for namespace in namespaces_as_array %}
+namespace {{namespace}} {
+{%- endfor %}
+namespace internal {
+
+{#--- Interface parameter definitions #}
+{%- for interface in interfaces %}
+{%-   for method in interface.methods %}
+{%-     set struct = method.param_struct %}
+{%      include "struct_declaration.tmpl" %}
+{%-     if method.response_parameters != None %}
+{%-       set struct = method.response_param_struct %}
+{%        include "struct_declaration.tmpl" %}
+{%-     endif %}
+{%-   endfor %}
+{%- endfor %}
+
+}  // namespace internal
+
+{#--- Interface parameter definitions #}
+{%- for interface in interfaces %}
+{%-   for method in interface.methods %}
+{%-     set struct = method.param_struct %}
+{%      include "struct_data_view_declaration.tmpl" %}
+{%-     if method.response_parameters != None %}
+{%-       set struct = method.response_param_struct %}
+{%        include "struct_data_view_declaration.tmpl" %}
+{%-     endif %}
+{%-   endfor %}
+{%- endfor %}
+
+{%- for interface in interfaces %}
+{%-   for method in interface.methods %}
+{%-     set struct = method.param_struct %}
+{%      include "struct_data_view_definition.tmpl" %}
+{%-     if method.response_parameters != None %}
+{%-       set struct = method.response_param_struct %}
+{%        include "struct_data_view_definition.tmpl" %}
+{%-     endif %}
+{%-   endfor %}
+{%- endfor %}
+
+{%- for namespace in namespaces_as_array|reverse %}
+}  // namespace {{namespace}}
+{%- endfor %}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#endif  // {{header_guard}}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl
index e32f43b..f6ee8a6 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl
@@ -78,18 +78,6 @@
 {%-   endif %}
 {%- endfor %}
 
-{#--- Interface parameter definitions #}
-{%- for interface in interfaces %}
-{%-   for method in interface.methods %}
-{%-     set struct = method.param_struct %}
-{%      include "struct_declaration.tmpl" %}
-{%-     if method.response_parameters != None %}
-{%-       set struct = method.response_param_struct %}
-{%        include "struct_declaration.tmpl" %}
-{%-     endif %}
-{%-   endfor %}
-{%- endfor %}
-
 #pragma pack(pop)
 
 }  // namespace internal
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
index c1a12f3..9742f85 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.cc.tmpl
@@ -18,6 +18,8 @@
 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
 #include "mojo/public/cpp/bindings/lib/validation_util.h"
 
+#include "{{module.path}}-params-data.h"
+
 {%- for header in extra_traits_headers %}
 #include "{{header}}"
 {%- endfor %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl
index 017f06d0..0c2e6e4 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl
@@ -140,18 +140,6 @@
 {%-   endif %}
 {%- endfor %}
 
-{#--- Interface parameter definitions #}
-{%- for interface in interfaces %}
-{%-   for method in interface.methods %}
-{%-     set struct = method.param_struct %}
-{%      include "struct_data_view_declaration.tmpl" %}
-{%-     if method.response_parameters != None %}
-{%-       set struct = method.response_param_struct %}
-{%        include "struct_data_view_declaration.tmpl" %}
-{%-     endif %}
-{%-   endfor %}
-{%- endfor %}
-
 {#--- Unions #}
 {%- for union in unions %}
 {%    include "union_data_view_declaration.tmpl" %}
@@ -203,17 +191,6 @@
 {%-   endif %}
 {%- endfor %}
 
-{%- for interface in interfaces %}
-{%-   for method in interface.methods %}
-{%-     set struct = method.param_struct %}
-{%      include "struct_data_view_definition.tmpl" %}
-{%-     if method.response_parameters != None %}
-{%-       set struct = method.response_param_struct %}
-{%        include "struct_data_view_definition.tmpl" %}
-{%-     endif %}
-{%-   endfor %}
-{%- endfor %}
-
 {%- for union in unions %}
 {%    include "union_data_view_definition.tmpl" %}
 {%- endfor %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
index 467f2b8..31a6c339 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
@@ -38,6 +38,7 @@
 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
 #include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h"
 
+#include "{{module.path}}-params-data.h"
 #include "{{module.path}}-shared-message-ids.h"
 
 {%- if for_blink %}
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index 8c5dd88..e2470eb 100644
--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -404,6 +404,10 @@
   def _GenerateModuleTestUtilsSource(self):
     return self._GetJinjaExports()
 
+  @UseJinja("module-params-data.h.tmpl")
+  def _GenerateModuleParamsDataHeader(self):
+    return self._GetJinjaExports()
+
   def GenerateFiles(self, args):
     self.module.Stylize(generator.Stylizer())
 
@@ -418,6 +422,8 @@
                    "%s-shared-internal.h" % self.module.path)
         self.Write(self._GenerateModuleSharedSource(),
                    "%s-shared.cc" % self.module.path)
+        self.Write(self._GenerateModuleParamsDataHeader(),
+                   "%s-params-data.h" % self.module.path)
     else:
       suffix = "-%s" % self.variant if self.variant else ""
       self.Write(self._GenerateModuleHeader(),
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index 4fe4e4b..bbb8c6b 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -617,6 +617,7 @@
     }
 
     generator_shared_cpp_outputs = [
+      "{{source_gen_dir}}/{{source_file_part}}-params-data.h",
       "{{source_gen_dir}}/{{source_file_part}}-shared-internal.h",
       "{{source_gen_dir}}/{{source_file_part}}-shared.cc",
       "{{source_gen_dir}}/{{source_file_part}}-shared.h",
@@ -638,6 +639,7 @@
       foreach(source, invoker.sources) {
         filelist += [ rebase_path("$source", root_build_dir) ]
         outputs += [
+          "$target_gen_dir/$source-params-data.h",
           "$target_gen_dir/$source-shared-internal.h",
           "$target_gen_dir/$source-shared.cc",
           "$target_gen_dir/$source-shared.h",
diff --git a/net/dns/host_cache.cc b/net/dns/host_cache.cc
index 6fe37c7..b7ea0dc 100644
--- a/net/dns/host_cache.cc
+++ b/net/dns/host_cache.cc
@@ -350,6 +350,10 @@
   return entry_dict;
 }
 
+// static
+const HostCache::EntryStaleness HostCache::kNotStale = {
+    base::TimeDelta::FromSeconds(-1), 0, 0};
+
 HostCache::HostCache(size_t max_entries)
     : max_entries_(max_entries),
       network_changes_(0),
diff --git a/net/dns/host_cache.h b/net/dns/host_cache.h
index 926dcf09..3788e8e 100644
--- a/net/dns/host_cache.h
+++ b/net/dns/host_cache.h
@@ -238,6 +238,9 @@
 
   using EntryMap = std::map<Key, Entry>;
 
+  // A HostCache::EntryStaleness representing a non-stale (fresh) cache entry.
+  static const HostCache::EntryStaleness kNotStale;
+
   // Constructs a HostCache that stores up to |max_entries|.
   explicit HostCache(size_t max_entries);
 
diff --git a/net/dns/host_resolver.cc b/net/dns/host_resolver.cc
index 60e28e4..275d4e5 100644
--- a/net/dns/host_resolver.cc
+++ b/net/dns/host_resolver.cc
@@ -211,7 +211,9 @@
       AddressFamilyToDnsQueryType(request_info.address_family());
   parameters.initial_priority = priority;
   parameters.source = FlagsToSource(request_info.host_resolver_flags());
-  parameters.allow_cached_response = request_info.allow_cached_response();
+  parameters.cache_usage = request_info.allow_cached_response()
+                               ? ResolveHostParameters::CacheUsage::ALLOWED
+                               : ResolveHostParameters::CacheUsage::DISALLOWED;
   parameters.include_canonical_name =
       request_info.host_resolver_flags() & HOST_RESOLVER_CANONNAME;
   parameters.loopback_only =
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h
index b08ebef..5f56be9 100644
--- a/net/dns/host_resolver.h
+++ b/net/dns/host_resolver.h
@@ -109,6 +109,15 @@
     // |ERR_IO_PENDING|.
     virtual const base::Optional<std::vector<HostPortPair>>&
     GetHostnameResults() const = 0;
+
+    // Information about the result's staleness in the host cache. Only
+    // available if results were received from the host cache.
+    //
+    // Should only be called after Start() signals completion, either by
+    // invoking the callback or by returning a result other than
+    // |ERR_IO_PENDING|.
+    virtual const base::Optional<HostCache::EntryStaleness>& GetStaleInfo()
+        const = 0;
   };
 
   // |max_concurrent_resolves| is how many resolve requests will be allowed to
@@ -222,8 +231,18 @@
     // IP literals, etc.
     HostResolverSource source = HostResolverSource::ANY;
 
-    // If |false|, results will not come from the host cache.
-    bool allow_cached_response = true;
+    enum class CacheUsage {
+      // Results may come from the host cache if non-stale.
+      ALLOWED,
+
+      // Results may come from the host cache even if stale (by expiration or
+      // network changes).
+      STALE_ALLOWED,
+
+      // Results will not come from the host cache.
+      DISALLOWED,
+    };
+    CacheUsage cache_usage = CacheUsage::ALLOWED;
 
     // If |true|, requests that the resolver include AddressList::canonical_name
     // in the results. If the resolver can do so without significant
@@ -335,7 +354,7 @@
   // Profiling information for the request is saved to |net_log| if non-NULL.
   //
   // TODO(crbug.com/821021): Delete this method once all usage has been
-  // converted to ResolveHost().
+  // converted to CreateRequest().
   virtual int Resolve(const RequestInfo& info,
                       RequestPriority priority,
                       AddressList* addresses,
@@ -343,17 +362,36 @@
                       std::unique_ptr<Request>* out_req,
                       const NetLogWithSource& net_log) = 0;
 
+  // DEPRECATION NOTE: This method is being replaced by CreateRequest(). New
+  // callers should prefer CreateRequest() if it works for their needs. Calling
+  // CreateRequest() with
+  // |parameters.source = HostResolverSource::LOCAL_ONLY| should provide
+  // capabilities equivalent to ResolveFromCache().
+  //
   // Resolves the given hostname (or IP address literal) out of cache or HOSTS
   // file (if enabled) only. This is guaranteed to complete synchronously.
   // This acts like |Resolve()| if the hostname is IP literal, or cached value
   // or HOSTS entry exists. Otherwise, ERR_DNS_CACHE_MISS is returned.
+  //
+  // TODO(crbug.com/821021): Delete this method once all usage has been
+  // converted to CreateRequest().
   virtual int ResolveFromCache(const RequestInfo& info,
                                AddressList* addresses,
                                const NetLogWithSource& net_log) = 0;
 
+  // DEPRECATION NOTE: This method is being replaced by CreateRequest(). New
+  // callers should prefer CreateRequest() if it works for their needs. Calling
+  // CreateRequest() with
+  // |parameters.source = HostResolverSource::LOCAL_ONLY| and
+  // |parameters.cache_usage = ResolveHostParameters::CacheUsage::STALE_ALLOWED|
+  // should provide capabilities equivalent to ResolveStaleFromCache()
+  //
   // Like |ResolveFromCache()|, but can return a stale result if the
   // implementation supports it. Fills in |*stale_info| if a response is
   // returned to indicate how stale (or not) it is.
+  //
+  // TODO(crbug.com/821021): Delete this method once all usage has been
+  // converted to CreateRequest().
   virtual int ResolveStaleFromCache(const RequestInfo& info,
                                     AddressList* addresses,
                                     HostCache::EntryStaleness* stale_info,
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 9503444..131a8f0 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -462,14 +462,6 @@
   size_t counts_[NUM_PRIORITIES];
 };
 
-void MakeNotStale(HostCache::EntryStaleness* stale_info) {
-  if (!stale_info)
-    return;
-  stale_info->expired_by = base::TimeDelta::FromSeconds(-1);
-  stale_info->network_changes = 0;
-  stale_info->stale_hits = 0;
-}
-
 // Is |dns_server| within the list of known DNS servers that also support
 // DNS-over-HTTPS?
 bool DnsServerSupportsDoh(const IPAddress& dns_server) {
@@ -591,6 +583,12 @@
     return results_ ? results_.value().hostnames() : *nullopt_result;
   }
 
+  const base::Optional<HostCache::EntryStaleness>& GetStaleInfo()
+      const override {
+    DCHECK(complete_);
+    return stale_info_;
+  }
+
   void set_results(HostCache::Entry results) {
     // Should only be called at most once and before request is marked
     // completed.
@@ -601,6 +599,16 @@
     results_ = std::move(results);
   }
 
+  void set_stale_info(HostCache::EntryStaleness stale_info) {
+    // Should only be called at most once and before request is marked
+    // completed.
+    DCHECK(!complete_);
+    DCHECK(!stale_info_);
+    DCHECK(!parameters_.is_speculative);
+
+    stale_info_ = std::move(stale_info);
+  }
+
   void ChangeRequestPriority(RequestPriority priority);
 
   void AssignJob(Job* job) {
@@ -679,6 +687,7 @@
 
   bool complete_;
   base::Optional<HostCache::Entry> results_;
+  base::Optional<HostCache::EntryStaleness> stale_info_;
 
   base::TimeTicks request_time_;
 
@@ -1733,6 +1742,10 @@
       case HostResolverSource::MULTICAST_DNS:
         StartMdnsTask();
         break;
+      case HostResolverSource::LOCAL_ONLY:
+        // If no external source allowed, a job should not be created or started
+        NOTREACHED();
+        break;
     }
 
     // Caution: Job::Start must not complete synchronously.
@@ -2328,13 +2341,16 @@
   // Update the net log and notify registered observers.
   LogStartRequest(source_net_log, info);
 
-  Key key;
+  Key unused_key;
+  base::Optional<HostCache::EntryStaleness> unused_stale_info;
   HostCache::Entry results = ResolveLocally(
       info.host_port_pair().host(),
       AddressFamilyToDnsQueryType(info.address_family()),
       FlagsToSource(info.host_resolver_flags()), info.host_resolver_flags(),
-      info.allow_cached_response(), false /* allow_stale */,
-      nullptr /* stale_info */, source_net_log, &key);
+      info.allow_cached_response()
+          ? ResolveHostParameters::CacheUsage::ALLOWED
+          : ResolveHostParameters::CacheUsage::DISALLOWED,
+      source_net_log, &unused_key, &unused_stale_info);
 
   if (results.addresses()) {
     *addresses = AddressList::CopyWithPort(results.addresses().value(),
@@ -2357,17 +2373,21 @@
   // Update the net log and notify registered observers.
   LogStartRequest(source_net_log, info);
 
-  Key key;
-  HostCache::Entry results =
-      ResolveLocally(info.host_port_pair().host(),
-                     AddressFamilyToDnsQueryType(info.address_family()),
-                     FlagsToSource(info.host_resolver_flags()),
-                     info.host_resolver_flags(), info.allow_cached_response(),
-                     true /* allow_stale */, stale_info, source_net_log, &key);
+  Key unused_key;
+  base::Optional<HostCache::EntryStaleness> optional_stale_info;
+  HostCache::Entry results = ResolveLocally(
+      info.host_port_pair().host(),
+      AddressFamilyToDnsQueryType(info.address_family()),
+      FlagsToSource(info.host_resolver_flags()), info.host_resolver_flags(),
+      info.allow_cached_response()
+          ? ResolveHostParameters::CacheUsage::STALE_ALLOWED
+          : ResolveHostParameters::CacheUsage::DISALLOWED,
+      source_net_log, &unused_key, &optional_stale_info);
 
   if (results.addresses()) {
     *addresses = AddressList::CopyWithPort(results.addresses().value(),
                                            info.host_port_pair().port());
+    *stale_info = std::move(optional_stale_info).value_or(HostCache::kNotStale);
   }
 
   LogFinishRequest(source_net_log, results.error());
@@ -2521,27 +2541,32 @@
   DCHECK(!request->job());
   // Request may only be resolved once.
   DCHECK(!request->complete());
-  // MDNS requests do not support skipping cache.
+  // MDNS requests do not support skipping cache or stale lookups.
   // TODO(crbug.com/846423): Either add support for skipping the MDNS cache, or
   // merge to use the normal host cache for MDNS requests.
   DCHECK(request->parameters().source != HostResolverSource::MULTICAST_DNS ||
-         request->parameters().allow_cached_response);
+         request->parameters().cache_usage ==
+             ResolveHostParameters::CacheUsage::ALLOWED);
 
   request->set_request_time(tick_clock_->NowTicks());
 
   LogStartRequest(request->source_net_log(), request->request_host());
 
   Key key;
+  base::Optional<HostCache::EntryStaleness> stale_info;
   HostCache::Entry results = ResolveLocally(
       request->request_host().host(), request->parameters().dns_query_type,
       request->parameters().source, request->host_resolver_flags(),
-      request->parameters().allow_cached_response, false /* allow_stale */,
-      nullptr /* stale_info */, request->source_net_log(), &key);
-  if (results.error() == OK && !request->parameters().is_speculative) {
-    request->set_results(
-        results.CopyWithDefaultPort(request->request_host().port()));
-  }
-  if (results.error() != ERR_DNS_CACHE_MISS) {
+      request->parameters().cache_usage, request->source_net_log(), &key,
+      &stale_info);
+  if (results.error() != ERR_DNS_CACHE_MISS ||
+      request->parameters().source == HostResolverSource::LOCAL_ONLY) {
+    if (results.error() == OK && !request->parameters().is_speculative) {
+      request->set_results(
+          results.CopyWithDefaultPort(request->request_host().port()));
+    }
+    if (stale_info && !request->parameters().is_speculative)
+      request->set_stale_info(std::move(stale_info).value());
     LogFinishRequest(request->source_net_log(), results.error());
     RecordTotalTime(request->parameters().is_speculative, true /* from_cache */,
                     base::TimeDelta());
@@ -2560,11 +2585,13 @@
     DnsQueryType dns_query_type,
     HostResolverSource source,
     HostResolverFlags flags,
-    bool allow_cache,
-    bool allow_stale,
-    HostCache::EntryStaleness* stale_info,
+    ResolveHostParameters::CacheUsage cache_usage,
     const NetLogWithSource& source_net_log,
-    Key* out_key) {
+    Key* out_key,
+    base::Optional<HostCache::EntryStaleness>* out_stale_info) {
+  DCHECK(out_stale_info);
+  *out_stale_info = base::nullopt;
+
   IPAddress ip_address;
   IPAddress* ip_address_ptr = nullptr;
   if (ip_address.AssignFromIPLiteral(hostname)) {
@@ -2582,39 +2609,39 @@
   *out_key = GetEffectiveKeyForRequest(hostname, dns_query_type, source, flags,
                                        ip_address_ptr, source_net_log);
 
-  DCHECK(allow_stale == !!stale_info);
   // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
   // On Windows it gives the default interface's address, whereas on Linux it
   // gives an error. We will make it fail on all platforms for consistency.
   if (hostname.empty() || hostname.size() > kMaxHostLength) {
-    MakeNotStale(stale_info);
     return HostCache::Entry(ERR_NAME_NOT_RESOLVED,
                             HostCache::Entry::SOURCE_UNKNOWN);
   }
 
   base::Optional<HostCache::Entry> resolved =
       ResolveAsIP(*out_key, ip_address_ptr);
-  if (resolved) {
-    MakeNotStale(stale_info);
+  if (resolved)
     return resolved.value();
-  }
 
   // Special-case localhost names, as per the recommendations in
   // https://tools.ietf.org/html/draft-west-let-localhost-be-localhost.
   resolved = ServeLocalhost(*out_key);
-  if (resolved) {
-    MakeNotStale(stale_info);
+  if (resolved)
     return resolved.value();
-  }
 
-  if (allow_cache) {
-    resolved = ServeFromCache(*out_key, allow_stale, stale_info);
+  if (cache_usage == ResolveHostParameters::CacheUsage::ALLOWED ||
+      cache_usage == ResolveHostParameters::CacheUsage::STALE_ALLOWED) {
+    resolved = ServeFromCache(
+        *out_key,
+        cache_usage == ResolveHostParameters::CacheUsage::STALE_ALLOWED,
+        out_stale_info);
     if (resolved) {
+      DCHECK(out_stale_info->has_value());
       source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_CACHE_HIT,
                               resolved.value().CreateNetLogCallback());
       // |ServeFromCache()| will update |*stale_info| as needed.
       return resolved.value();
     }
+    DCHECK(!out_stale_info->has_value());
   }
 
   // TODO(szym): Do not do this if nsswitch.conf instructs not to.
@@ -2623,7 +2650,6 @@
   if (resolved) {
     source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_HOSTS_HIT,
                             resolved.value().CreateNetLogCallback());
-    MakeNotStale(stale_info);
     return resolved.value();
   }
 
@@ -2685,19 +2711,31 @@
 base::Optional<HostCache::Entry> HostResolverImpl::ServeFromCache(
     const Key& key,
     bool allow_stale,
-    HostCache::EntryStaleness* stale_info) {
-  DCHECK(allow_stale == !!stale_info);
+    base::Optional<HostCache::EntryStaleness>* out_stale_info) {
+  DCHECK(out_stale_info);
+  *out_stale_info = base::nullopt;
+
   if (!cache_.get())
     return base::nullopt;
 
+  // Local-only requests search the cache for non-local-only results.
+  Key effective_key = key;
+  if (effective_key.host_resolver_source == HostResolverSource::LOCAL_ONLY)
+    effective_key.host_resolver_source = HostResolverSource::ANY;
+
   const HostCache::Entry* cache_entry;
-  if (allow_stale)
-    cache_entry = cache_->LookupStale(key, tick_clock_->NowTicks(), stale_info);
-  else
-    cache_entry = cache_->Lookup(key, tick_clock_->NowTicks());
+  HostCache::EntryStaleness staleness;
+  if (allow_stale) {
+    cache_entry =
+        cache_->LookupStale(effective_key, tick_clock_->NowTicks(), &staleness);
+  } else {
+    cache_entry = cache_->Lookup(effective_key, tick_clock_->NowTicks());
+    staleness = HostCache::kNotStale;
+  }
   if (!cache_entry)
     return base::nullopt;
 
+  *out_stale_info = std::move(staleness);
   return *cache_entry;
 }
 
diff --git a/net/dns/host_resolver_impl.h b/net/dns/host_resolver_impl.h
index e2d0c94..5d5f1bf 100644
--- a/net/dns/host_resolver_impl.h
+++ b/net/dns/host_resolver_impl.h
@@ -251,23 +251,23 @@
   // sources.
   //
   // On ERR_DNS_CACHE_MISS and OK, the cache key for the request is written to
-  // |key|. On other errors, it may not be.
+  // |out_key|. On other errors, it may not be.
   //
-  // If |allow_stale| is true, then stale cache entries can be returned.
-  // |stale_info| must be non-null, and will be filled in with details of the
-  // entry's staleness (if an entry is returned).
+  // If results are returned from the host cache, |out_stale_info| will be
+  // filled in with information on how stale or fresh the result is. Otherwise,
+  // |out_stale_info| will be set to |base::nullopt|.
   //
-  // If |allow_stale| is false, then stale cache entries will not be returned,
-  // and |stale_info| must be null.
-  HostCache::Entry ResolveLocally(const std::string& hostname,
-                                  DnsQueryType requested_address_family,
-                                  HostResolverSource source,
-                                  HostResolverFlags flags,
-                                  bool allow_cache,
-                                  bool allow_stale,
-                                  HostCache::EntryStaleness* stale_info,
-                                  const NetLogWithSource& request_net_log,
-                                  Key* out_key);
+  // If |cache_usage == ResolveHostParameters::CacheUsage::STALE_ALLOWED|, then
+  // stale cache entries can be returned.
+  HostCache::Entry ResolveLocally(
+      const std::string& hostname,
+      DnsQueryType requested_address_family,
+      HostResolverSource source,
+      HostResolverFlags flags,
+      ResolveHostParameters::CacheUsage cache_usage,
+      const NetLogWithSource& request_net_log,
+      Key* out_key,
+      base::Optional<HostCache::EntryStaleness>* out_stale_info);
 
   // Attempts to create and start a Job to asynchronously attempt to resolve
   // |key|. On success, returns ERR_IO_PENDING and attaches the Job to
@@ -280,17 +280,15 @@
                                                const IPAddress* ip_address);
 
   // Returns the result iff a positive match is found for |key| in the cache.
+  // |out_stale_info| must be non-null, and will be filled in with details of
+  // the entry's staleness if an entry is returned, otherwise it will be set to
+  // |base::nullopt|.
   //
   // If |allow_stale| is true, then stale cache entries can be returned.
-  // |stale_info| must be non-null, and will be filled in with details of the
-  // entry's staleness (if an entry is returned).
-  //
-  // If |allow_stale| is false, then stale cache entries will not be returned,
-  // and |stale_info| must be null.
   base::Optional<HostCache::Entry> ServeFromCache(
       const Key& key,
       bool allow_stale,
-      HostCache::EntryStaleness* stale_info);
+      base::Optional<HostCache::EntryStaleness>* out_stale_info);
 
   // Iff we have a DnsClient with a valid DnsConfig, and |key| can be resolved
   // from the HOSTS file, return the results.
diff --git a/net/dns/host_resolver_impl_fuzzer.cc b/net/dns/host_resolver_impl_fuzzer.cc
index dae59e5..6ccb374 100644
--- a/net/dns/host_resolver_impl_fuzzer.cc
+++ b/net/dns/host_resolver_impl_fuzzer.cc
@@ -162,7 +162,10 @@
     }
 #endif  // !BUILDFLAG(ENABLE_MDNS)
 
-    parameters.allow_cached_response = data_provider_->ConsumeBool();
+    parameters.cache_usage =
+        data_provider_->ConsumeBool()
+            ? net::HostResolver::ResolveHostParameters::CacheUsage::ALLOWED
+            : net::HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED;
     parameters.include_canonical_name = data_provider_->ConsumeBool();
 
     const char* hostname = data_provider_->PickValueInArray(kHostNames);
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index fdde5e38..400b7cce 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -777,6 +777,7 @@
   EXPECT_THAT(response.result_error(), IsOk());
   EXPECT_THAT(response.request()->GetAddressResults().value().endpoints(),
               testing::ElementsAre(CreateExpected("192.168.1.42", 80)));
+  EXPECT_FALSE(response.request()->GetStaleInfo());
 
   EXPECT_EQ("just.testing", proc_->GetCaptureList()[0].hostname);
 }
@@ -910,6 +911,7 @@
   EXPECT_THAT(response.result_error(), IsOk());
   EXPECT_THAT(response.request()->GetAddressResults().value().endpoints(),
               testing::ElementsAre(CreateExpected(kIpLiteral, 80)));
+  EXPECT_FALSE(response.request()->GetStaleInfo());
 }
 
 TEST_F(HostResolverImplTest, EmptyListMeansNameNotResolved) {
@@ -932,6 +934,7 @@
 
   EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED));
   EXPECT_FALSE(response.request()->GetAddressResults());
+  EXPECT_FALSE(response.request()->GetStaleInfo());
 
   EXPECT_EQ("just.testing", proc_->GetCaptureList()[0].hostname);
 }
@@ -960,6 +963,7 @@
       HostPortPair("just.testing", 80), NetLogWithSource(), base::nullopt));
   EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED));
   EXPECT_FALSE(response.request()->GetAddressResults());
+  EXPECT_FALSE(response.request()->GetStaleInfo());
 
   EXPECT_EQ("just.testing", proc_->GetCaptureList()[0].hostname);
 
@@ -1659,7 +1663,8 @@
   EXPECT_EQ(1u, proc_->GetCaptureList().size());
 
   HostResolver::ResolveHostParameters parameters;
-  parameters.allow_cached_response = false;
+  parameters.cache_usage =
+      HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED;
   ResolveHostResponseHelper cache_bypassed_response(resolver_->CreateRequest(
       HostPortPair("a", 80), NetLogWithSource(), parameters));
   EXPECT_THAT(cache_bypassed_response.result_error(), IsOk());
@@ -2534,6 +2539,121 @@
   EXPECT_THAT(requests_[1]->WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
 }
 
+TEST_F(HostResolverImplTest, SourceNone_FromCache) {
+  proc_->AddRuleForAllFamilies("just.testing", "192.168.1.42");
+  proc_->SignalMultiple(1u);  // Need only one.
+
+  HostResolver::ResolveHostParameters source_none_parameters;
+  source_none_parameters.source = HostResolverSource::LOCAL_ONLY;
+
+  // First NONE query expected to complete synchronously with a cache miss.
+  ResolveHostResponseHelper cache_miss_request(
+      resolver_->CreateRequest(HostPortPair("just.testing", 80),
+                               NetLogWithSource(), source_none_parameters));
+  EXPECT_TRUE(cache_miss_request.complete());
+  EXPECT_THAT(cache_miss_request.result_error(), IsError(ERR_DNS_CACHE_MISS));
+  EXPECT_FALSE(cache_miss_request.request()->GetAddressResults());
+  EXPECT_FALSE(cache_miss_request.request()->GetStaleInfo());
+
+  // Normal query to populate the cache.
+  ResolveHostResponseHelper normal_request(resolver_->CreateRequest(
+      HostPortPair("just.testing", 80), NetLogWithSource(), base::nullopt));
+  EXPECT_THAT(normal_request.result_error(), IsOk());
+  EXPECT_FALSE(normal_request.request()->GetStaleInfo());
+
+  // Second NONE query expected to complete synchronously with cache hit.
+  ResolveHostResponseHelper cache_hit_request(
+      resolver_->CreateRequest(HostPortPair("just.testing", 80),
+                               NetLogWithSource(), source_none_parameters));
+  EXPECT_TRUE(cache_hit_request.complete());
+  EXPECT_THAT(cache_hit_request.result_error(), IsOk());
+  EXPECT_THAT(
+      cache_hit_request.request()->GetAddressResults().value().endpoints(),
+      testing::ElementsAre(CreateExpected("192.168.1.42", 80)));
+  EXPECT_FALSE(cache_hit_request.request()->GetStaleInfo().value().is_stale());
+}
+
+TEST_F(HostResolverImplTest, SourceNone_StaleEntry) {
+  proc_->AddRuleForAllFamilies("just.testing", "192.168.1.42");
+  proc_->SignalMultiple(1u);  // Need only one.
+
+  HostResolver::ResolveHostParameters source_none_parameters;
+  source_none_parameters.source = HostResolverSource::LOCAL_ONLY;
+
+  // First NONE query expected to complete synchronously with a cache miss.
+  ResolveHostResponseHelper cache_miss_request(
+      resolver_->CreateRequest(HostPortPair("just.testing", 80),
+                               NetLogWithSource(), source_none_parameters));
+  EXPECT_TRUE(cache_miss_request.complete());
+  EXPECT_THAT(cache_miss_request.result_error(), IsError(ERR_DNS_CACHE_MISS));
+  EXPECT_FALSE(cache_miss_request.request()->GetAddressResults());
+  EXPECT_FALSE(cache_miss_request.request()->GetStaleInfo());
+
+  // Normal query to populate the cache.
+  ResolveHostResponseHelper normal_request(resolver_->CreateRequest(
+      HostPortPair("just.testing", 80), NetLogWithSource(), base::nullopt));
+  EXPECT_THAT(normal_request.result_error(), IsOk());
+  EXPECT_FALSE(normal_request.request()->GetStaleInfo());
+
+  MakeCacheStale();
+
+  // Second NONE query still expected to complete synchronously with cache miss.
+  ResolveHostResponseHelper stale_request(
+      resolver_->CreateRequest(HostPortPair("just.testing", 80),
+                               NetLogWithSource(), source_none_parameters));
+  EXPECT_TRUE(stale_request.complete());
+  EXPECT_THAT(stale_request.result_error(), IsError(ERR_DNS_CACHE_MISS));
+  EXPECT_FALSE(stale_request.request()->GetAddressResults());
+  EXPECT_FALSE(stale_request.request()->GetStaleInfo());
+}
+
+TEST_F(HostResolverImplTest, SourceNone_FromIp) {
+  HostResolver::ResolveHostParameters source_none_parameters;
+  source_none_parameters.source = HostResolverSource::LOCAL_ONLY;
+
+  ResolveHostResponseHelper response(resolver_->CreateRequest(
+      HostPortPair("1.2.3.4", 56), NetLogWithSource(), source_none_parameters));
+
+  // Expected to resolve synchronously.
+  EXPECT_TRUE(response.complete());
+  EXPECT_THAT(response.result_error(), IsOk());
+  EXPECT_THAT(response.request()->GetAddressResults().value().endpoints(),
+              testing::ElementsAre(CreateExpected("1.2.3.4", 56)));
+  EXPECT_FALSE(response.request()->GetStaleInfo());
+}
+
+TEST_F(HostResolverImplTest, SourceNone_InvalidName) {
+  proc_->AddRuleForAllFamilies("foo,bar.com", "192.168.1.42");
+
+  HostResolver::ResolveHostParameters source_none_parameters;
+  source_none_parameters.source = HostResolverSource::LOCAL_ONLY;
+
+  ResolveHostResponseHelper response(
+      resolver_->CreateRequest(HostPortPair("foo,bar.com", 57),
+                               NetLogWithSource(), source_none_parameters));
+
+  // Expected to fail synchronously.
+  EXPECT_TRUE(response.complete());
+  EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED));
+  EXPECT_FALSE(response.request()->GetAddressResults());
+  EXPECT_FALSE(response.request()->GetStaleInfo());
+}
+
+TEST_F(HostResolverImplTest, SourceNone_InvalidLocalhost) {
+  HostResolver::ResolveHostParameters source_none_parameters;
+  source_none_parameters.source = HostResolverSource::LOCAL_ONLY;
+
+  ResolveHostResponseHelper response(
+      resolver_->CreateRequest(HostPortPair("foo,bar.localhost", 58),
+                               NetLogWithSource(), source_none_parameters));
+
+  // Expected to fail synchronously.
+  EXPECT_TRUE(response.complete());
+  EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED));
+  EXPECT_FALSE(response.request()->GetAddressResults());
+  EXPECT_FALSE(response.request()->GetStaleInfo());
+}
+
 TEST_F(HostResolverImplTest, ResolveStaleFromCache) {
   proc_->AddRuleForAllFamilies("just.testing", "192.168.1.42");
   proc_->SignalMultiple(1u);  // Need only one.
@@ -2615,6 +2735,79 @@
   EXPECT_TRUE(requests_[6]->staleness().is_stale());
 }
 
+TEST_F(HostResolverImplTest, StaleAllowed) {
+  proc_->AddRuleForAllFamilies("just.testing", "192.168.1.42");
+  proc_->SignalMultiple(1u);  // Need only one.
+
+  HostResolver::ResolveHostParameters stale_allowed_parameters;
+  stale_allowed_parameters.source = HostResolverSource::LOCAL_ONLY;
+  stale_allowed_parameters.cache_usage =
+      HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
+
+  // First query expected to complete synchronously as a cache miss.
+  ResolveHostResponseHelper cache_miss_request(
+      resolver_->CreateRequest(HostPortPair("just.testing", 80),
+                               NetLogWithSource(), stale_allowed_parameters));
+  EXPECT_TRUE(cache_miss_request.complete());
+  EXPECT_THAT(cache_miss_request.result_error(), IsError(ERR_DNS_CACHE_MISS));
+  EXPECT_FALSE(cache_miss_request.request()->GetAddressResults());
+  EXPECT_FALSE(cache_miss_request.request()->GetStaleInfo());
+
+  // Normal query to populate cache
+  ResolveHostResponseHelper normal_request(resolver_->CreateRequest(
+      HostPortPair("just.testing", 80), NetLogWithSource(), base::nullopt));
+  EXPECT_THAT(normal_request.result_error(), IsOk());
+  EXPECT_FALSE(normal_request.request()->GetStaleInfo());
+
+  MakeCacheStale();
+
+  // Second NONE query expected to get a stale cache hit.
+  ResolveHostResponseHelper stale_request(
+      resolver_->CreateRequest(HostPortPair("just.testing", 84),
+                               NetLogWithSource(), stale_allowed_parameters));
+  EXPECT_TRUE(stale_request.complete());
+  EXPECT_THAT(stale_request.result_error(), IsOk());
+  EXPECT_THAT(stale_request.request()->GetAddressResults().value().endpoints(),
+              testing::ElementsAre(CreateExpected("192.168.1.42", 84)));
+  EXPECT_TRUE(stale_request.request()->GetStaleInfo().value().is_stale());
+}
+
+TEST_F(HostResolverImplTest, StaleAllowed_NonLocal) {
+  proc_->AddRuleForAllFamilies("just.testing", "192.168.2.42");
+  proc_->SignalMultiple(1u);  // Need only one.
+
+  HostResolver::ResolveHostParameters stale_allowed_parameters;
+  stale_allowed_parameters.cache_usage =
+      HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
+
+  // Normal non-local resolves should still work normally with the STALE_ALLOWED
+  // parameter, and there should be no stale info.
+  ResolveHostResponseHelper response(
+      resolver_->CreateRequest(HostPortPair("just.testing", 85),
+                               NetLogWithSource(), stale_allowed_parameters));
+  EXPECT_THAT(response.result_error(), IsOk());
+  EXPECT_THAT(response.request()->GetAddressResults().value().endpoints(),
+              testing::ElementsAre(CreateExpected("192.168.2.42", 85)));
+  EXPECT_FALSE(response.request()->GetStaleInfo());
+}
+
+TEST_F(HostResolverImplTest, StaleAllowed_FromIp) {
+  HostResolver::ResolveHostParameters stale_allowed_parameters;
+  stale_allowed_parameters.cache_usage =
+      HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
+
+  ResolveHostResponseHelper response(
+      resolver_->CreateRequest(HostPortPair("1.2.3.4", 57), NetLogWithSource(),
+                               stale_allowed_parameters));
+
+  // Expected to resolve synchronously without stale info.
+  EXPECT_TRUE(response.complete());
+  EXPECT_THAT(response.result_error(), IsOk());
+  EXPECT_THAT(response.request()->GetAddressResults().value().endpoints(),
+              testing::ElementsAre(CreateExpected("1.2.3.4", 57)));
+  EXPECT_FALSE(response.request()->GetStaleInfo());
+}
+
 // TODO(mgersh): add a test case for errors with positive TTL after
 // https://crbug.com/115051 is fixed.
 
@@ -6231,6 +6424,34 @@
   EXPECT_THAT(cache_entry->ttl(), base::TimeDelta::FromSeconds(86400));
 }
 
+TEST_F(HostResolverImplDnsTest, CachedError) {
+  CreateResolver();
+  set_allow_fallback_to_proctask(false);
+  ChangeDnsConfig(CreateValidDnsConfig());
+
+  HostResolver::ResolveHostParameters cache_only_parameters;
+  cache_only_parameters.source = HostResolverSource::LOCAL_ONLY;
+
+  // Expect cache initially empty.
+  ResolveHostResponseHelper cache_miss_response(resolver_->CreateRequest(
+      HostPortPair("nodomain", 80), NetLogWithSource(), cache_only_parameters));
+  EXPECT_THAT(cache_miss_response.result_error(), IsError(ERR_DNS_CACHE_MISS));
+  EXPECT_FALSE(cache_miss_response.request()->GetStaleInfo());
+
+  // Populate cache with an error.
+  ResolveHostResponseHelper no_domain_response(resolver_->CreateRequest(
+      HostPortPair("nodomain", 80), NetLogWithSource(), base::nullopt));
+  EXPECT_THAT(no_domain_response.result_error(),
+              IsError(ERR_NAME_NOT_RESOLVED));
+
+  // Expect the error result can be resolved from the cache.
+  ResolveHostResponseHelper cache_hit_response(resolver_->CreateRequest(
+      HostPortPair("nodomain", 80), NetLogWithSource(), cache_only_parameters));
+  EXPECT_THAT(cache_hit_response.result_error(),
+              IsError(ERR_NAME_NOT_RESOLVED));
+  EXPECT_FALSE(cache_hit_response.request()->GetStaleInfo().value().is_stale());
+}
+
 TEST_F(HostResolverImplDnsTest, NoCanonicalName) {
   MockDnsClientRuleList rules;
   AddDnsRule(&rules, "alias", dns_protocol::kTypeA, IPAddress::IPv4Localhost(),
diff --git a/net/dns/host_resolver_source.h b/net/dns/host_resolver_source.h
index 794c5f3..cf9633b 100644
--- a/net/dns/host_resolver_source.h
+++ b/net/dns/host_resolver_source.h
@@ -26,12 +26,19 @@
   // Results will only come from Multicast DNS queries.
   MULTICAST_DNS,
 
-  MAX = MULTICAST_DNS
+  // No external sources will be used. Results will only come from fast local
+  // sources that are available no matter the source setting, e.g. cache, hosts
+  // file, IP literal resolution, etc. Resolves with this setting are guaranteed
+  // to finish synchronously.
+  LOCAL_ONLY,
+
+  MAX = LOCAL_ONLY
 };
 
 const HostResolverSource kHostResolverSources[] = {
     HostResolverSource::ANY, HostResolverSource::SYSTEM,
-    HostResolverSource::DNS, HostResolverSource::MULTICAST_DNS};
+    HostResolverSource::DNS, HostResolverSource::MULTICAST_DNS,
+    HostResolverSource::LOCAL_ONLY};
 
 static_assert(
     base::size(kHostResolverSources) ==
diff --git a/net/dns/mapped_host_resolver.cc b/net/dns/mapped_host_resolver.cc
index 64ef729..1724cea 100644
--- a/net/dns/mapped_host_resolver.cc
+++ b/net/dns/mapped_host_resolver.cc
@@ -40,6 +40,13 @@
     return *nullopt_result;
   }
 
+  const base::Optional<HostCache::EntryStaleness>& GetStaleInfo()
+      const override {
+    static const base::NoDestructor<base::Optional<HostCache::EntryStaleness>>
+        nullopt_result;
+    return *nullopt_result;
+  }
+
  private:
   const int error_;
 };
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc
index fa014afa..28612c4 100644
--- a/net/dns/mock_host_resolver.cc
+++ b/net/dns/mock_host_resolver.cc
@@ -128,7 +128,15 @@
     return *nullopt_result;
   }
 
-  void set_address_results(const AddressList& address_results) {
+  const base::Optional<HostCache::EntryStaleness>& GetStaleInfo()
+      const override {
+    DCHECK(complete_);
+    return staleness_;
+  }
+
+  void set_address_results(
+      const AddressList& address_results,
+      base::Optional<HostCache::EntryStaleness> staleness) {
     // Should only be called at most once and before request is marked
     // completed.
     DCHECK(!complete_);
@@ -136,6 +144,7 @@
     DCHECK(!parameters_.is_speculative);
 
     address_results_ = address_results;
+    staleness_ = std::move(staleness);
   }
 
   void OnAsyncCompleted(size_t id, int error) {
@@ -177,6 +186,7 @@
   int host_resolver_flags_;
 
   base::Optional<AddressList> address_results_;
+  base::Optional<HostCache::EntryStaleness> staleness_;
 
   // Used while stored with the resolver for async resolution.  Otherwise 0.
   size_t id_;
@@ -357,10 +367,14 @@
   num_resolve_from_cache_++;
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   next_request_id_++;
+  base::Optional<HostCache::EntryStaleness> stale_info;
   int rv = ResolveFromIPLiteralOrCache(
       info.host_port_pair(), AddressFamilyToDnsQueryType(info.address_family()),
       info.host_resolver_flags(), HostResolverSource::ANY,
-      info.allow_cached_response(), addresses);
+      info.allow_cached_response()
+          ? HostResolver::ResolveHostParameters::CacheUsage::ALLOWED
+          : HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED,
+      addresses, &stale_info);
   return rv;
 }
 
@@ -373,15 +387,21 @@
 int MockHostResolverBase::ResolveStaleFromCache(
     const RequestInfo& info,
     AddressList* addresses,
-    HostCache::EntryStaleness* stale_info,
+    HostCache::EntryStaleness* out_stale_info,
     const NetLogWithSource& net_log) {
   num_resolve_from_cache_++;
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   next_request_id_++;
+  base::Optional<HostCache::EntryStaleness> stale_info;
   int rv = ResolveFromIPLiteralOrCache(
       info.host_port_pair(), AddressFamilyToDnsQueryType(info.address_family()),
       info.host_resolver_flags(), HostResolverSource::ANY,
-      info.allow_cached_response(), addresses, stale_info);
+      info.allow_cached_response()
+          ? HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED
+          : HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED,
+      addresses, &stale_info);
+  if (rv == OK)
+    *out_stale_info = std::move(stale_info).value_or(HostCache::kNotStale);
   return rv;
 }
 
@@ -423,7 +443,7 @@
       DnsQueryTypeToAddressFamily(req->parameters().dns_query_type),
       req->host_resolver_flags(), req->parameters().source, &addresses);
   if (error == OK && !req->parameters().is_speculative)
-    req->set_address_results(addresses);
+    req->set_address_results(addresses, base::nullopt);
   req->OnAsyncCompleted(id, error);
 }
 
@@ -513,12 +533,13 @@
   last_request_priority_ = request->parameters().initial_priority;
   num_resolve_++;
   AddressList addresses;
+  base::Optional<HostCache::EntryStaleness> stale_info;
   int rv = ResolveFromIPLiteralOrCache(
       request->request_host(), request->parameters().dns_query_type,
       request->host_resolver_flags(), request->parameters().source,
-      request->parameters().allow_cached_response, &addresses);
+      request->parameters().cache_usage, &addresses, &stale_info);
   if (rv == OK && !request->parameters().is_speculative)
-    request->set_address_results(addresses);
+    request->set_address_results(addresses, std::move(stale_info));
   if (rv != ERR_DNS_CACHE_MISS)
     return rv;
 
@@ -534,7 +555,7 @@
         request->host_resolver_flags(), request->parameters().source,
         &addresses);
     if (rv == OK && !request->parameters().is_speculative)
-      request->set_address_results(addresses);
+      request->set_address_results(addresses, base::nullopt);
     return rv;
   }
 
@@ -557,9 +578,13 @@
     DnsQueryType dns_query_type,
     HostResolverFlags flags,
     HostResolverSource source,
-    bool allow_cache,
+    HostResolver::ResolveHostParameters::CacheUsage cache_usage,
     AddressList* addresses,
-    HostCache::EntryStaleness* stale_info) {
+    base::Optional<HostCache::EntryStaleness>* out_stale_info) {
+  DCHECK(addresses);
+  DCHECK(out_stale_info);
+  *out_stale_info = base::nullopt;
+
   IPAddress ip_address;
   if (ip_address.AssignFromIPLiteral(host.host())) {
     // This matches the behavior HostResolverImpl.
@@ -575,18 +600,27 @@
     return OK;
   }
   int rv = ERR_DNS_CACHE_MISS;
-  if (cache_.get() && allow_cache) {
+  bool cache_allowed =
+      cache_usage == HostResolver::ResolveHostParameters::CacheUsage::ALLOWED ||
+      cache_usage ==
+          HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
+  if (cache_.get() && cache_allowed) {
     HostCache::Key key(host.host(), dns_query_type, flags, source);
     const HostCache::Entry* entry;
-    if (stale_info)
-      entry = cache_->LookupStale(key, tick_clock_->NowTicks(), stale_info);
-    else
+    HostCache::EntryStaleness stale_info = HostCache::kNotStale;
+    if (cache_usage ==
+        HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED) {
+      entry = cache_->LookupStale(key, tick_clock_->NowTicks(), &stale_info);
+    } else {
       entry = cache_->Lookup(key, tick_clock_->NowTicks());
+    }
     if (entry) {
       rv = entry->error();
-      if (rv == OK)
+      if (rv == OK) {
         *addresses =
             AddressList::CopyWithPort(entry->addresses().value(), host.port());
+        *out_stale_info = std::move(stale_info);
+      }
     }
   }
   return rv;
@@ -889,6 +923,11 @@
     IMMEDIATE_CRASH();
   }
 
+  const base::Optional<HostCache::EntryStaleness>& GetStaleInfo()
+      const override {
+    IMMEDIATE_CRASH();
+  }
+
   void ChangeRequestPriority(RequestPriority priority) override {}
 
  private:
diff --git a/net/dns/mock_host_resolver.h b/net/dns/mock_host_resolver.h
index 968ec79..f42da7bc2 100644
--- a/net/dns/mock_host_resolver.h
+++ b/net/dns/mock_host_resolver.h
@@ -217,9 +217,9 @@
       DnsQueryType dns_query_type,
       HostResolverFlags flags,
       HostResolverSource source,
-      bool allow_cache,
+      HostResolver::ResolveHostParameters::CacheUsage cache_usage,
       AddressList* addresses,
-      HostCache::EntryStaleness* stale_info = nullptr);
+      base::Optional<HostCache::EntryStaleness>* stale_info);
   // Resolve via |proc_|.
   int ResolveProc(const HostPortPair& host,
                   AddressFamily requested_address_family,
diff --git a/remoting/host/file_transfer/file_transfer_message_handler.cc b/remoting/host/file_transfer/file_transfer_message_handler.cc
index 5caeb36..9a7ac683 100644
--- a/remoting/host/file_transfer/file_transfer_message_handler.cc
+++ b/remoting/host/file_transfer/file_transfer_message_handler.cc
@@ -82,9 +82,10 @@
       Close();
       break;
     case protocol::FileTransfer::kError:
-      LOG(ERROR) << "File transfer error from client: " << message.error();
-      FALLTHROUGH;
-    case protocol::FileTransfer::kCancel:
+      if (message.error().type() !=
+          protocol::FileTransfer_Error_Type_CANCELED) {
+        LOG(ERROR) << "File transfer error from client: " << message.error();
+      }
       Cancel();
       break;
     default:
diff --git a/remoting/proto/file_transfer.proto b/remoting/proto/file_transfer.proto
index e67d597e..1cbeecd 100644
--- a/remoting/proto/file_transfer.proto
+++ b/remoting/proto/file_transfer.proto
@@ -33,27 +33,24 @@
   // Next Id: 1
   message Success {}
 
-  // Bidirectional message canceling the transfer as the result of a user action
-  // or otherwise not due to an error. When Cancel is received, no more messages
-  // relating to the transfer should be sent, but the canceling end should be
-  // prepared to handle any messages that may already be on the wire.
-  // Next Id: 1
-  message Cancel {}
-
-  // Bidirectional message aborting the transfer due to an error. This may be
-  // sent by the sender to signal a read error, by the receiver to signal a
-  // write error, or by either side to signal any of the myriad of other things
-  // that can go wrong while attempting to transfer a file.
+  // Bidirectional message aborting the transfer due to an error or user
+  // cancellation. This may be sent by the sender to signal a read error, by the
+  // receiver to signal a write error, or by either side to signal any of the
+  // myriad of other things that can go wrong while attempting to transfer a
+  // file. When Error is received, no more messages relating to the transfer
+  // should be sent, but the end sending the error should be prepared to handle
+  // any messages that may already be on the wire.
   // Next Id: 6
   message Error {
     enum Type {
       UNSPECIFIED = 0;
-      UNEXPECTED_ERROR = 1;
-      PROTOCOL_ERROR = 2;
-      PERMISSION_DENIED = 3;
-      OUT_OF_DISK_SPACE = 4;
-      IO_ERROR = 5;
-      NOT_LOGGED_IN = 6;
+      CANCELED = 1;
+      UNEXPECTED_ERROR = 2;
+      PROTOCOL_ERROR = 3;
+      PERMISSION_DENIED = 4;
+      OUT_OF_DISK_SPACE = 5;
+      IO_ERROR = 6;
+      NOT_LOGGED_IN = 7;
     }
 
     // An error category to be used to select a user-displayed error message.
@@ -73,7 +70,6 @@
     Data data = 2;
     End end = 3;
     Success success = 4;
-    Cancel cancel = 5;
-    Error error = 6;
+    Error error = 5;
   }
 }
diff --git a/services/network/host_resolver.cc b/services/network/host_resolver.cc
index a9039450..851c115 100644
--- a/services/network/host_resolver.cc
+++ b/services/network/host_resolver.cc
@@ -34,7 +34,10 @@
   parameters.dns_query_type = mojo_parameters->dns_query_type;
   parameters.initial_priority = mojo_parameters->initial_priority;
   parameters.source = mojo_parameters->source;
-  parameters.allow_cached_response = mojo_parameters->allow_cached_response;
+  parameters.cache_usage =
+      mojo_parameters->allow_cached_response
+          ? net::HostResolver::ResolveHostParameters::CacheUsage::ALLOWED
+          : net::HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED;
   parameters.include_canonical_name = mojo_parameters->include_canonical_name;
   parameters.loopback_only = mojo_parameters->loopback_only;
   parameters.is_speculative = mojo_parameters->is_speculative;
diff --git a/services/network/public/cpp/host_resolver_mojom_traits.cc b/services/network/public/cpp/host_resolver_mojom_traits.cc
index 424cba4..5a2b4a3a 100644
--- a/services/network/public/cpp/host_resolver_mojom_traits.cc
+++ b/services/network/public/cpp/host_resolver_mojom_traits.cc
@@ -274,6 +274,8 @@
       return ResolveHostParameters::Source::DNS;
     case net::HostResolverSource::MULTICAST_DNS:
       return ResolveHostParameters::Source::MULTICAST_DNS;
+    case net::HostResolverSource::LOCAL_ONLY:
+      return ResolveHostParameters::Source::LOCAL_ONLY;
   }
 }
 
@@ -294,6 +296,9 @@
     case ResolveHostParameters::Source::MULTICAST_DNS:
       *output = net::HostResolverSource::MULTICAST_DNS;
       return true;
+    case ResolveHostParameters::Source::LOCAL_ONLY:
+      *output = net::HostResolverSource::LOCAL_ONLY;
+      return true;
   }
 }
 
diff --git a/services/network/public/mojom/host_resolver.mojom b/services/network/public/mojom/host_resolver.mojom
index 3fe9011e..cca14fe 100644
--- a/services/network/public/mojom/host_resolver.mojom
+++ b/services/network/public/mojom/host_resolver.mojom
@@ -156,6 +156,11 @@
 
     // Results will only come from Multicast DNS queries.
     MULTICAST_DNS,
+
+    // No external sources will be used. Results will only come from fast local
+    // sources that are available no matter the source setting, e.g. cache,
+    // hosts file, IP literal resolution, etc.
+    LOCAL_ONLY,
   };
 
   // The source to use for resolved addresses. Default allows the resolver to
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index c4d0d8b8c..b5d9cb71 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -23694,6 +23694,9 @@
     ],
     "isolated_scripts": [
       {
+        "args": [
+          "--gtest-benchmark-name=components_perftests"
+        ],
         "isolate_name": "components_perftests",
         "merge": {
           "args": [
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 3bfb863..9063433 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -13696,6 +13696,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=components_perftests"
+        ],
         "isolate_name": "components_perftests",
         "merge": {
           "args": [
@@ -13754,6 +13757,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 695a26a..a0e989d 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -891,6 +891,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=components_perftests"
+        ],
         "isolate_name": "components_perftests",
         "merge": {
           "args": [
@@ -949,6 +952,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -6654,6 +6660,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -10805,6 +10814,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -12220,6 +12232,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=components_perftests"
+        ],
         "isolate_name": "components_perftests",
         "merge": {
           "args": [
@@ -12320,6 +12335,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 366884b..1767e67 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -677,6 +677,34 @@
             }
           ]
         },
+        "test": "cast_runner_browsertests"
+      },
+      {
+        "args": [
+          "--qemu-require-kvm"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1"
+            }
+          ]
+        },
+        "test": "cast_runner_integration_tests"
+      },
+      {
+        "args": [
+          "--qemu-require-kvm"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1"
+            }
+          ]
+        },
         "test": "cast_runner_unittests"
       },
       {
@@ -919,6 +947,34 @@
             }
           ]
         },
+        "test": "web_runner_integration_tests"
+      },
+      {
+        "args": [
+          "--qemu-require-kvm"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1"
+            }
+          ]
+        },
+        "test": "webrunner_browsertests"
+      },
+      {
+        "args": [
+          "--qemu-require-kvm"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1"
+            }
+          ]
+        },
         "test": "webrunner_unittests"
       }
     ]
@@ -1675,6 +1731,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -2391,6 +2450,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -3063,6 +3125,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -4319,6 +4384,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index d96b5b0..47cecc1 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -995,6 +995,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=components_perftests"
+        ],
         "isolate_name": "components_perftests",
         "merge": {
           "args": [
@@ -1092,6 +1095,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -2133,6 +2139,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=components_perftests"
+        ],
         "isolate_name": "components_perftests",
         "merge": {
           "args": [
@@ -2230,6 +2239,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -3354,6 +3366,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=components_perftests"
+        ],
         "isolate_name": "components_perftests",
         "merge": {
           "args": [
@@ -3451,6 +3466,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -4492,6 +4510,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=components_perftests"
+        ],
         "isolate_name": "components_perftests",
         "merge": {
           "args": [
@@ -4570,6 +4591,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -5679,6 +5703,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index c95e65de..0aa98c44 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -6,9 +6,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "components_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "components_perftests"
         ],
         "isolate_name": "components_perftests",
         "merge": {
@@ -47,9 +45,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "gpu_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "gpu_perftests"
         ],
         "isolate_name": "gpu_perftests",
         "merge": {
@@ -88,9 +84,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "tracing_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "tracing_perftests"
         ],
         "isolate_name": "tracing_perftests",
         "merge": {
@@ -270,9 +264,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "angle_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "angle_perftests"
         ],
         "isolate_name": "angle_perftests",
         "merge": {
@@ -309,9 +301,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "load_library_perf_tests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "load_library_perf_tests"
         ],
         "isolate_name": "load_library_perf_tests",
         "merge": {
@@ -348,9 +338,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "media_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "media_perftests"
         ],
         "isolate_name": "media_perftests",
         "merge": {
@@ -388,8 +376,6 @@
         "args": [
           "--gtest-benchmark-name",
           "passthrough_command_buffer_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true",
           "--use-cmd-decoder=passthrough",
           "--use-angle=gl-null"
         ],
@@ -429,8 +415,6 @@
         "args": [
           "--gtest-benchmark-name",
           "validating_command_buffer_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true",
           "--use-cmd-decoder=validating",
           "--use-stub"
         ],
@@ -514,9 +498,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "components_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "components_perftests"
         ],
         "isolate_name": "components_perftests",
         "merge": {
@@ -553,9 +535,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "load_library_perf_tests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "load_library_perf_tests"
         ],
         "isolate_name": "load_library_perf_tests",
         "merge": {
@@ -592,9 +572,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "media_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "media_perftests"
         ],
         "isolate_name": "media_perftests",
         "merge": {
@@ -729,8 +707,6 @@
         "args": [
           "--gtest-benchmark-name",
           "angle_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true",
           "--shard-timeout=300"
         ],
         "isolate_name": "angle_perftests",
@@ -770,9 +746,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "base_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "base_perftests"
         ],
         "isolate_name": "base_perftests",
         "merge": {
@@ -811,9 +785,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "components_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "components_perftests"
         ],
         "isolate_name": "components_perftests",
         "merge": {
@@ -852,9 +824,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "gpu_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "gpu_perftests"
         ],
         "isolate_name": "gpu_perftests",
         "merge": {
@@ -893,9 +863,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "media_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "media_perftests"
         ],
         "isolate_name": "media_perftests",
         "merge": {
@@ -934,9 +902,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "tracing_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "tracing_perftests"
         ],
         "isolate_name": "tracing_perftests",
         "merge": {
@@ -1034,9 +1000,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "base_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "base_perftests"
         ],
         "isolate_name": "base_perftests",
         "merge": {
@@ -1073,9 +1037,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "load_library_perf_tests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "load_library_perf_tests"
         ],
         "isolate_name": "load_library_perf_tests",
         "merge": {
@@ -1112,9 +1074,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "media_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "media_perftests"
         ],
         "isolate_name": "media_perftests",
         "merge": {
@@ -1151,9 +1111,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "net_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "net_perftests"
         ],
         "isolate_name": "net_perftests",
         "merge": {
@@ -1190,9 +1148,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "performance_browser_tests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "performance_browser_tests"
         ],
         "isolate_name": "performance_browser_tests",
         "merge": {
@@ -1229,9 +1185,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "tracing_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "tracing_perftests"
         ],
         "isolate_name": "tracing_perftests",
         "merge": {
@@ -1313,9 +1267,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "load_library_perf_tests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "load_library_perf_tests"
         ],
         "isolate_name": "load_library_perf_tests",
         "merge": {
@@ -1352,9 +1304,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "performance_browser_tests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "performance_browser_tests"
         ],
         "isolate_name": "performance_browser_tests",
         "merge": {
@@ -1436,9 +1386,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "base_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "base_perftests"
         ],
         "isolate_name": "base_perftests",
         "merge": {
@@ -1475,9 +1423,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "media_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "media_perftests"
         ],
         "isolate_name": "media_perftests",
         "merge": {
@@ -1514,9 +1460,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "net_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "net_perftests"
         ],
         "isolate_name": "net_perftests",
         "merge": {
@@ -1553,9 +1497,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "performance_browser_tests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "performance_browser_tests"
         ],
         "isolate_name": "performance_browser_tests",
         "merge": {
@@ -1592,9 +1534,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "views_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "views_perftests"
         ],
         "isolate_name": "views_perftests",
         "merge": {
@@ -1682,8 +1622,6 @@
         "args": [
           "--gtest-benchmark-name",
           "angle_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true",
           "--shard-timeout=300"
         ],
         "isolate_name": "angle_perftests",
@@ -1721,9 +1659,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "base_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "base_perftests"
         ],
         "isolate_name": "base_perftests",
         "merge": {
@@ -1760,9 +1696,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "components_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "components_perftests"
         ],
         "isolate_name": "components_perftests",
         "merge": {
@@ -1799,9 +1733,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "media_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "media_perftests"
         ],
         "isolate_name": "media_perftests",
         "merge": {
@@ -1838,9 +1770,7 @@
       {
         "args": [
           "--gtest-benchmark-name",
-          "views_perftests",
-          "--non-telemetry=true",
-          "--migrated-test=true"
+          "views_perftests"
         ],
         "isolate_name": "views_perftests",
         "merge": {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index ec61861..76b3661 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -716,6 +716,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=components_perftests"
+        ],
         "isolate_name": "components_perftests",
         "merge": {
           "args": [
@@ -786,6 +789,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -3382,6 +3388,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -4116,6 +4125,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=components_perftests"
+        ],
         "isolate_name": "components_perftests",
         "merge": {
           "args": [
@@ -4186,6 +4198,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
@@ -4972,6 +4987,9 @@
         }
       },
       {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
         "isolate_name": "views_perftests",
         "merge": {
           "args": [
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 772fb5f8..13487c28 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -127,6 +127,8 @@
   "angle_perftests": {
     "args": [
       "angle_perftests",
+      "--non-telemetry=true",
+      "--migrated-test=true",
       "--test-launcher-print-test-stdio=always",
       "--test-launcher-jobs=1",
       "--test-launcher-retry-limit=0",
@@ -251,6 +253,8 @@
   "base_perftests": {
     "args": [
       "base_perftests",
+      "--non-telemetry=true",
+      "--migrated-test=true",
       "--test-launcher-print-test-stdio=always",
       "--test-launcher-jobs=1",
       "--test-launcher-retry-limit=0",
@@ -619,6 +623,8 @@
   "command_buffer_perftests": {
     "args": [
       "command_buffer_perftests",
+      "--non-telemetry=true",
+      "--migrated-test=true",
       "--adb-path",
       "src/third_party/android_tools/sdk/platform-tools/adb",
     ],
@@ -649,7 +655,6 @@
   "components_perftests": {
     "args": [
       "--xvfb",
-      "--gtest-benchmark-name=components_perftests",
       "--non-telemetry=true",
       "--migrated-test=true",
       "components_perftests",
@@ -1028,6 +1033,8 @@
   "gpu_perftests": {
     "args": [
       "gpu_perftests",
+      "--non-telemetry=true",
+      "--migrated-test=true",
       "--adb-path",
       "src/third_party/android_tools/sdk/platform-tools/adb",
     ],
@@ -1353,6 +1360,8 @@
   "load_library_perf_tests": {
     "args": [
       "load_library_perf_tests",
+      "--non-telemetry=true",
+      "--migrated-test=true",
       "--test-launcher-print-test-stdio=always",
     ],
     "label": "//chrome/test:load_library_perf_tests",
@@ -1390,6 +1399,8 @@
   "media_perftests": {
     "args": [
       "media_perftests",
+      "--non-telemetry=true",
+      "--migrated-test=true",
       "--single-process-tests",
       "--test-launcher-retry-limit=0",
       "--isolated-script-test-filter=*::-*_unoptimized::*_unaligned::*unoptimized_aligned",
@@ -1789,6 +1800,8 @@
   "net_perftests": {
     "args": [
       "net_perftests",
+      "--non-telemetry=true",
+      "--migrated-test=true",
     ],
     "label": "//net:net_perftests",
     "script": "//testing/scripts/run_performance_tests_wrapper.py",
@@ -2018,6 +2031,8 @@
   "performance_browser_tests": {
     "args": [
       "performance_browser_tests",
+      "--non-telemetry=true",
+      "--migrated-test=true",
       "--test-launcher-print-test-stdio=always",
       # TODO(crbug.com/759866): Figure out why CastV2PerformanceTest/0 sometimes
       # takes 15-30 seconds to start up and, once fixed, remove this workaround
@@ -2434,6 +2449,8 @@
   "tracing_perftests": {
     "args": [
       "tracing_perftests",
+      "--non-telemetry=true",
+      "--migrated-test=true",
       "--test-launcher-print-test-stdio=always",
       "--adb-path",
       "src/third_party/android_tools/sdk/platform-tools/adb",
@@ -2574,7 +2591,6 @@
   "views_perftests": {
     "args": [
       "--xvfb",
-      "--gtest-benchmark-name=views_perftests",
       "--non-telemetry=true",
       "--migrated-test=true",
       "views_perftests",
@@ -2614,8 +2630,7 @@
   "vr_common_perftests": {
     "args": [
       "vr_common_perftests",
-      "--non-telemetry=1",
-      "--gtest-benchmark-name=xr.vr.common_perftests",
+      "--non-telemetry=true",
       "--adb-path",
       "src/third_party/android_tools/sdk/platform-tools/adb",
     ],
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 09be9f0..c7e4927 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -233,20 +233,6 @@
       },
     },
   },
-  'cast_runner_browsertests': {
-    # TODO(crbug.com/910799): Enable this once we're confident that it
-    # passes.
-    'remove_from': [
-      # chromium.linux
-      'Fuchsia x64',
-    ],
-  },
-  'cast_runner_integration_tests': {
-    'remove_from': [
-      # chromium.linux
-      'Fuchsia x64', # TODO(https://crbug.com/918586): Flaky install failures.
-    ],
-  },
   'cast_shell_browsertests': {
     'modifications': {
       'Cast Audio Linux': {
@@ -1336,12 +1322,6 @@
       'linux-chromeos-dbg',  # https://crbug.com/859307
     ],
   },
-  'web_runner_integration_tests': {
-    'remove_from': [
-      # chromium.linux
-      'Fuchsia x64', # TODO(https://crbug.com/918586): Flaky install failures.
-    ],
-  },
   'webgl2_conformance_tests': {
     'remove_from': [
       # The Mac NVIDIA Retina bots don't have the capacity to run
@@ -1696,12 +1676,6 @@
       },
     },
   },
-  'webrunner_browsertests': {
-    'remove_from': [
-      # chromium.linux
-      'Fuchsia x64', # TODO(https://crbug.com/918586): Flaky install failures.
-    ],
-  },
   'webui_polymer2_browser_tests': {
     'remove_from': [
       # chromium.win
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 372cf4bc..5384527 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -2657,6 +2657,9 @@
             '--smoke-test-mode',
           ],
         },
+        'args': [
+          '--gtest-benchmark-name=components_perftests',
+        ],
       },
     },
 
@@ -2707,6 +2710,9 @@
             '--smoke-test-mode',
           ],
         },
+        'args': [
+          '--gtest-benchmark-name=views_perftests',
+        ],
       },
       'webkit_layout_tests': {
         # layout test failures are retried 3 times when '--test-list' is not
diff --git a/third_party/blink/public/common/mediastream/media_stream_controls.h b/third_party/blink/public/common/mediastream/media_stream_controls.h
index 1c3f1f0..8a73b7ba 100644
--- a/third_party/blink/public/common/mediastream/media_stream_controls.h
+++ b/third_party/blink/public/common/mediastream/media_stream_controls.h
@@ -50,7 +50,7 @@
   TrackControls audio;
   TrackControls video;
   // Hotword functionality (chromeos only)
-  // See crbug.com/564574 for discussion on possibly #ifdef'ing this out.
+  // TODO(crbug.com/577627): this is now never set and needs to be removed.
   bool hotword_enabled = false;
   bool disable_local_echo = false;
 };
diff --git a/third_party/blink/public/platform/web_media_constraints.h b/third_party/blink/public/platform/web_media_constraints.h
index 4f9dc52..c46d181 100644
--- a/third_party/blink/public/platform/web_media_constraints.h
+++ b/third_party/blink/public/platform/web_media_constraints.h
@@ -251,7 +251,6 @@
   // the legacy name interface.
   StringConstraint media_stream_source;  // tab, screen, desktop, system
   BooleanConstraint render_to_associated_sink;
-  BooleanConstraint hotword_enabled;
   BooleanConstraint goog_echo_cancellation;
   BooleanConstraint goog_experimental_echo_cancellation;
   BooleanConstraint goog_auto_gain_control;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index df5e45e..fdb14ac 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -7871,6 +7871,18 @@
   if (frame_->Loader().StateMachine()->IsDisplayingInitialEmptyDocument())
     load_event_progress_ = kLoadEventNotRun;
   frame_->Loader().Progress().ProgressStarted();
+  // Some sites appear to depend on javascript:'' synchronously populating an
+  // iframe, similar to about:blank. See https://crbug.com/923585
+  // TODO(japhet): The spec doesn't say anything about ever loading JS urls
+  // synchronously. It's unclear whether the problem is that JS url navigation
+  // has to be sync in certain situations, or if these are just legacy websites
+  // assuming non-spec-compliant behavior. Either way, this special case seems
+  // hacky.
+  if (frame_->Loader().StateMachine()->IsDisplayingInitialEmptyDocument() &&
+      (url == "javascript:''" || url == "javascript:\"\"")) {
+    ExecuteJavaScriptUrl(url, disposition);
+    return;
+  }
   javascript_url_task_handle_ = PostCancellableTask(
       *GetTaskRunner(TaskType::kNetworking), FROM_HERE,
       WTF::Bind(&Document::ExecuteJavaScriptUrl, WrapWeakPersistent(this), url,
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 841f864..7dc3264 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -751,7 +751,7 @@
   ScriptForbiddenScope forbid_script;
 
   if (IsInPerformLayout() || ShouldThrottleRendering() ||
-      !frame_->GetDocument()->IsActive())
+      !frame_->GetDocument()->IsActive() || frame_->IsProvisional())
     return;
 
   TRACE_EVENT0("blink,benchmark", "LocalFrameView::layout");
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 161a879..af5613a 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -1643,7 +1643,6 @@
     auto fragments = NGPaintFragment::InlineFragmentsFor(this);
     if (fragments.IsInLayoutNGInlineFormattingContext()) {
       for (auto* fragment : fragments) {
-        fragment->SetVisualRect(LayoutRect());
         fragment->SetSelectionVisualRect(LayoutRect());
       }
     }
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 86c9d68..945893ca 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -269,6 +269,10 @@
     return FirstFragment().PartialInvalidationVisualRect();
   }
 
+  LayoutRect VisualRectForInlineBox() const {
+    return AdjustVisualRectForInlineBox(VisualRect());
+  }
+
   String DebugName() const final;
 
   // End of DisplayItemClient methods.
@@ -2456,9 +2460,6 @@
   void ApplyPseudoStyleChanges(const ComputedStyle* old_style);
   void ApplyFirstLineChanges(const ComputedStyle* old_style);
 
-  LayoutRect VisualRectForInlineBox() const {
-    return AdjustVisualRectForInlineBox(VisualRect());
-  }
   LayoutRect PartialInvalidationVisualRectForInlineBox() const {
     return AdjustVisualRectForInlineBox(PartialInvalidationVisualRect());
   }
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index 7902101..1c80c99 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -2428,9 +2428,7 @@
 
 scoped_refptr<AbstractInlineTextBox> LayoutText::FirstAbstractInlineTextBox() {
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    LayoutObject* const first_letter_part = GetFirstLetterPart();
-    auto fragments = NGPaintFragment::InlineFragmentsFor(
-        first_letter_part ? first_letter_part : this);
+    auto fragments = NGPaintFragment::InlineFragmentsFor(this);
     if (!fragments.IsEmpty() &&
         fragments.IsInLayoutNGInlineFormattingContext()) {
       has_abstract_inline_text_box_ = true;
diff --git a/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc b/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
index b3147d3..c3439ea 100644
--- a/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
@@ -44,6 +44,22 @@
   DCHECK(!line_layout_item_);
 }
 
+LayoutText* AbstractInlineTextBox::GetFirstLetterPseudoLayoutText() const {
+  // We only want to apply the first letter to the first inline text box
+  // for a LayoutObject.
+  if (!IsFirst())
+    return nullptr;
+
+  Node* node = GetLineLayoutItem().GetNode();
+  if (!node)
+    return nullptr;
+
+  LayoutObject* layout_object = node->GetLayoutObject();
+  if (!layout_object || !layout_object->IsText())
+    return nullptr;
+  return ToLayoutText(layout_object)->GetFirstLetterPart();
+}
+
 // ----
 
 LegacyAbstractInlineTextBox::InlineToLegacyAbstractInlineTextBoxHashMap*
@@ -186,29 +202,29 @@
   if (!inline_text_box_ || !GetLineLayoutItem())
     return String();
 
-  unsigned start = inline_text_box_->Start();
-  unsigned len = inline_text_box_->Len();
-  if (Node* node = GetLineLayoutItem().GetNode()) {
-    if (node->IsTextNode()) {
-      return PlainText(
-          EphemeralRange(Position(node, start), Position(node, start + len)),
-          TextIteratorBehavior::IgnoresStyleVisibilityBehavior());
-    }
-    return PlainText(
-        EphemeralRange(Position(node, PositionAnchorType::kBeforeAnchor),
-                       Position(node, PositionAnchorType::kAfterAnchor)),
-        TextIteratorBehavior::IgnoresStyleVisibilityBehavior());
+  String result = inline_text_box_->GetText();
+
+  // Simplify all whitespace to just a space character, except for
+  // actual line breaks.
+  if (!inline_text_box_->IsLineBreak())
+    result = result.SimplifyWhiteSpace(WTF::kDoNotStripWhiteSpace);
+
+  // When the CSS first-letter pseudoselector is used, the LayoutText for the
+  // first letter is excluded from the accessibility tree, so we need to prepend
+  // its text here.
+  if (LayoutText* first_letter = GetFirstLetterPseudoLayoutText()) {
+    result = first_letter->GetText().SimplifyWhiteSpace() + result;
   }
 
-  String result = GetLineLayoutItem()
-                      .GetText()
-                      .Substring(start, len)
-                      .SimplifyWhiteSpace(WTF::kDoNotStripWhiteSpace);
-  if (inline_text_box_->NextForSameLayoutObject() &&
-      inline_text_box_->NextForSameLayoutObject()->Start() >
-          inline_text_box_->end() &&
-      result.length() && !result.Right(1).ContainsOnlyWhitespaceOrEmpty())
-    return result + " ";
+  // Insert a space at the end of this if necessary.
+  if (InlineTextBox* next = inline_text_box_->NextForSameLayoutObject()) {
+    if (next->Start() > inline_text_box_->Start() + inline_text_box_->Len() &&
+        result.length() && !result.Right(1).ContainsOnlyWhitespaceOrEmpty() &&
+        next->GetText().length() &&
+        !next->GetText().Left(1).ContainsOnlyWhitespaceOrEmpty())
+      return result + " ";
+  }
+
   return result;
 }
 
diff --git a/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h b/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h
index ed8ea401..81c5f70b1 100644
--- a/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h
+++ b/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.h
@@ -79,6 +79,8 @@
  protected:
   explicit AbstractInlineTextBox(LineLayoutText line_layout_item);
 
+  LayoutText* GetFirstLetterPseudoLayoutText() const;
+
  private:
   // Weak ptrs; these are nulled when InlineTextBox::destroy() calls
   // AbstractInlineTextBox::willDestroy.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
index a416f652..39036706 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
@@ -166,6 +166,9 @@
 String NGAbstractInlineTextBox::GetText() const {
   if (!fragment_ || !GetLineLayoutItem())
     return String();
+
+  String result = PhysicalTextFragment().Text().ToString();
+
   // For compatibility with |InlineTextBox|, we should have a space character
   // for soft line break.
   // Following tests require this:
@@ -173,8 +176,15 @@
   //  - accessibility/inline-text-changes.html
   //  - accessibility/inline-text-word-boundaries.html
   if (NeedsTrailingSpace())
-    return PhysicalTextFragment().Text().ToString() + " ";
-  return PhysicalTextFragment().Text().ToString();
+    result = result + " ";
+
+  // When the CSS first-letter pseudoselector is used, the LayoutText for the
+  // first letter is excluded from the accessibility tree, so we need to prepend
+  // its text here.
+  if (LayoutText* first_letter = GetFirstLetterPseudoLayoutText())
+    result = first_letter->GetText().SimplifyWhiteSpace() + result;
+
+  return result;
 }
 
 bool NGAbstractInlineTextBox::IsFirst() const {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index deb9dc7..4d210a13 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -41,7 +41,6 @@
                                    public ImageResourceObserver {
   void* pointers[6];
   NGPhysicalOffset offsets[2];
-  LayoutRect rects[1];
   unsigned flags;
 };
 
@@ -552,6 +551,35 @@
   return fragment;
 }
 
+LayoutRect NGPaintFragment::VisualRect() const {
+  // VisualRect is computed from fragment tree and set to LayoutObject in
+  // pre-paint. Use the stored value in the LayoutObject.
+  const NGPhysicalFragment& fragment = PhysicalFragment();
+  if (const LayoutObject* layout_object = fragment.GetLayoutObject()) {
+    // For inline fragments, InlineBox uses one united rect for the LayoutObject
+    // even when it is fragmented across lines. Use the same technique.
+    //
+    // Atomic inlines have two VisualRect; one for the LayoutBox and another as
+    // InlineBox. NG creates two NGPaintFragment, one as the root of an inline
+    // formatting context and another as a child of the inline formatting
+    // context it participates. |Parent()| can distinguish them because a tree
+    // is created for each inline formatting context.
+    if (Parent())
+      return layout_object->VisualRectForInlineBox();
+
+    return static_cast<const DisplayItemClient*>(layout_object)->VisualRect();
+  }
+
+  // Line box does not have corresponding LayoutObject. Use VisualRect of the
+  // containing LayoutBlockFlow as RootInlineBox does so.
+  DCHECK(fragment.IsLineBox());
+  // Line box is always a direct child of its containing block.
+  NGPaintFragment* containing_block_fragment = Parent();
+  DCHECK(containing_block_fragment);
+  DCHECK(containing_block_fragment->GetLayoutObject());
+  return containing_block_fragment->GetLayoutObject()->VisualRectForInlineBox();
+}
+
 bool NGPaintFragment::FlippedLocalVisualRectFor(
     const LayoutObject* layout_object,
     LayoutRect* visual_rect) {
@@ -574,19 +602,6 @@
   return true;
 }
 
-void NGPaintFragment::UpdateVisualRectForNonLayoutObjectChildren() {
-  // Scan direct children only beause line boxes are always direct children of
-  // the inline formatting context.
-  for (NGPaintFragment* child : Children()) {
-    if (!child->PhysicalFragment().IsLineBox())
-      continue;
-    LayoutRect union_of_children;
-    for (const NGPaintFragment* descendant : child->Children())
-      union_of_children.Unite(descendant->VisualRect());
-    child->SetVisualRect(union_of_children);
-  }
-}
-
 void NGPaintFragment::AddSelfOutlineRect(Vector<LayoutRect>* outline_rects,
                                          const LayoutPoint& additional_offset,
                                          NGOutlineType outline_type) const {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
index ce17ea1..12d683ce2 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -155,10 +155,6 @@
     return inline_offset_to_container_box_;
   }
 
-  // Update VisualRect for fragments without LayoutObjects (i.e., line boxes,)
-  // after its descendants were updated.
-  void UpdateVisualRectForNonLayoutObjectChildren();
-
   void AddSelfOutlineRect(Vector<LayoutRect>*,
                           const LayoutPoint& offset,
                           NGOutlineType) const;
@@ -169,8 +165,7 @@
   bool ShouldClipOverflow() const;
   bool HasSelfPaintingLayer() const;
   // This is equivalent to LayoutObject::VisualRect
-  LayoutRect VisualRect() const override { return visual_rect_; }
-  void SetVisualRect(const LayoutRect& rect) { visual_rect_ = rect; }
+  LayoutRect VisualRect() const override;
 
   LayoutRect SelectionVisualRect() const;
   void SetSelectionVisualRect(const LayoutRect& rect);
@@ -355,12 +350,6 @@
   // For an inline box, this flag helps to avoid traversing up to its line box
   // every time.
   unsigned is_dirty_inline_ : 1;
-
-  //
-  // Following fields are computed in the pre-paint phase.
-  //
-
-  LayoutRect visual_rect_;
 };
 
 extern template class CORE_EXTERN_TEMPLATE_EXPORT
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
index 2ff8b5d..af258b9 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
@@ -111,28 +111,30 @@
   )HTML");
   const NGPaintFragment* container = GetPaintFragmentByElementId("container");
   EXPECT_EQ(2u, container->Children().size());
-  const NGPaintFragment& line1 = *container->FirstChild();
+  auto lines = ToList(container->Children());
+  const NGPaintFragment& line1 = *lines[0];
   EXPECT_EQ(2u, line1.Children().size());
 
   // Inline boxes without box decorations (border, background, etc.) do not
   // generate box fragments and that their child fragments are placed directly
   // under the line box.
-  const NGPaintFragment& outer_text = *line1.FirstChild();
+  auto line1_children = ToList(line1.Children());
+  const NGPaintFragment& outer_text = *line1_children[0];
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             outer_text.PhysicalFragment().Type());
   EXPECT_EQ(LayoutRect(0, 0, 60, 10), outer_text.VisualRect());
 
-  const NGPaintFragment& inner_text1 = *ToList(line1.Children())[1];
+  const NGPaintFragment& inner_text1 = *line1_children[1];
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             inner_text1.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(60, 0, 30, 10), inner_text1.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 0, 90, 20), inner_text1.VisualRect());
 
-  const NGPaintFragment& line2 = *ToList(container->Children())[1];
+  const NGPaintFragment& line2 = *lines[1];
   EXPECT_EQ(1u, line2.Children().size());
   const NGPaintFragment& inner_text2 = *line2.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             inner_text2.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(0, 10, 30, 10), inner_text2.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 00, 90, 20), inner_text2.VisualRect());
 }
 
 TEST_F(NGPaintFragmentTest, InlineBoxWithDecorations) {
@@ -150,37 +152,39 @@
   )HTML");
   const NGPaintFragment* container = GetPaintFragmentByElementId("container");
   EXPECT_EQ(2u, container->Children().size());
-  const NGPaintFragment& line1 = *container->FirstChild();
+  auto lines = ToList(container->Children());
+  const NGPaintFragment& line1 = *lines[0];
   EXPECT_EQ(2u, line1.Children().size());
 
-  const NGPaintFragment& outer_text = *line1.FirstChild();
+  auto line1_children = ToList(line1.Children());
+  const NGPaintFragment& outer_text = *line1_children[0];
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             outer_text.PhysicalFragment().Type());
   EXPECT_EQ(LayoutRect(0, 0, 60, 10), outer_text.VisualRect());
 
   // Inline boxes with box decorations generate box fragments.
-  const NGPaintFragment& inline_box1 = *ToList(line1.Children())[1];
+  const NGPaintFragment& inline_box1 = *line1_children[1];
   EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
             inline_box1.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(60, 0, 30, 10), inline_box1.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 0, 90, 20), inline_box1.VisualRect());
 
   EXPECT_EQ(1u, inline_box1.Children().size());
   const NGPaintFragment& inner_text1 = *inline_box1.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             inner_text1.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(60, 0, 30, 10), inner_text1.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 0, 90, 20), inner_text1.VisualRect());
 
-  const NGPaintFragment& line2 = *ToList(container->Children())[1];
+  const NGPaintFragment& line2 = *lines[1];
   EXPECT_EQ(1u, line2.Children().size());
   const NGPaintFragment& inline_box2 = *line2.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
             inline_box2.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(0, 10, 30, 10), inline_box2.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 0, 90, 20), inline_box2.VisualRect());
 
   const NGPaintFragment& inner_text2 = *inline_box2.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             inner_text2.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(0, 10, 30, 10), inner_text2.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 0, 90, 20), inner_text2.VisualRect());
 }
 
 TEST_F(NGPaintFragmentTest, InlineBlock) {
@@ -308,14 +312,14 @@
   const NGPaintFragment& inner_text1 = *ToList(line1.Children())[1];
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             inner_text1.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(60, 10, 30, 10), inner_text1.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 10, 90, 20), inner_text1.VisualRect());
 
   const NGPaintFragment& line2 = *ToList(container->Children())[1];
   EXPECT_EQ(1u, line2.Children().size());
   const NGPaintFragment& inner_text2 = *line2.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             inner_text2.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(0, 20, 30, 10), inner_text2.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 10, 90, 20), inner_text2.VisualRect());
 }
 
 TEST_F(NGPaintFragmentTest, RelativeInline) {
@@ -333,36 +337,38 @@
   )HTML");
   const NGPaintFragment* container = GetPaintFragmentByElementId("container");
   EXPECT_EQ(2u, container->Children().size());
-  const NGPaintFragment& line1 = *container->FirstChild();
+  auto lines = ToList(container->Children());
+  const NGPaintFragment& line1 = *lines[0];
   EXPECT_EQ(2u, line1.Children().size());
 
-  const NGPaintFragment& outer_text = *line1.FirstChild();
+  auto line1_children = ToList(line1.Children());
+  const NGPaintFragment& outer_text = *line1_children[0];
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             outer_text.PhysicalFragment().Type());
   EXPECT_EQ(LayoutRect(0, 0, 60, 10), outer_text.VisualRect());
 
-  const NGPaintFragment& inline_box1 = *ToList(line1.Children())[1];
+  const NGPaintFragment& inline_box1 = *line1_children[1];
   EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
             inline_box1.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(60, 10, 30, 10), inline_box1.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 10, 90, 20), inline_box1.VisualRect());
 
   EXPECT_EQ(1u, inline_box1.Children().size());
   const NGPaintFragment& inner_text1 = *inline_box1.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             inner_text1.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(60, 10, 30, 10), inner_text1.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 10, 90, 20), inner_text1.VisualRect());
 
-  const NGPaintFragment& line2 = *ToList(container->Children())[1];
+  const NGPaintFragment& line2 = *lines[1];
   EXPECT_EQ(1u, line2.Children().size());
   const NGPaintFragment& inline_box2 = *line2.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
             inline_box2.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(0, 20, 30, 10), inline_box2.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 10, 90, 20), inline_box2.VisualRect());
 
   const NGPaintFragment& inner_text2 = *inline_box2.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             inner_text2.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(0, 20, 30, 10), inner_text2.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 10, 90, 20), inner_text2.VisualRect());
 }
 
 TEST_F(NGPaintFragmentTest, RelativeBlockAndInline) {
@@ -380,36 +386,38 @@
   )HTML");
   const NGPaintFragment* container = GetPaintFragmentByElementId("container");
   EXPECT_EQ(2u, container->Children().size());
-  const NGPaintFragment& line1 = *container->FirstChild();
+  auto lines = ToList(container->Children());
+  const NGPaintFragment& line1 = *lines[0];
   EXPECT_EQ(2u, line1.Children().size());
 
-  const NGPaintFragment& outer_text = *line1.FirstChild();
+  auto line1_children = ToList(line1.Children());
+  const NGPaintFragment& outer_text = *line1_children[0];
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             outer_text.PhysicalFragment().Type());
   EXPECT_EQ(LayoutRect(0, 10, 60, 10), outer_text.VisualRect());
 
-  const NGPaintFragment& inline_box1 = *ToList(line1.Children())[1];
+  const NGPaintFragment& inline_box1 = *line1_children[1];
   EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
             inline_box1.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(60, 20, 30, 10), inline_box1.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 20, 90, 20), inline_box1.VisualRect());
 
   EXPECT_EQ(1u, inline_box1.Children().size());
   const NGPaintFragment& inner_text1 = *inline_box1.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             inner_text1.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(60, 20, 30, 10), inner_text1.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 20, 90, 20), inner_text1.VisualRect());
 
-  const NGPaintFragment& line2 = *ToList(container->Children())[1];
+  const NGPaintFragment& line2 = *lines[1];
   EXPECT_EQ(1u, line2.Children().size());
   const NGPaintFragment& inline_box2 = *line2.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentBox,
             inline_box2.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(0, 30, 30, 10), inline_box2.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 20, 90, 20), inline_box2.VisualRect());
 
   const NGPaintFragment& inner_text2 = *inline_box2.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentText,
             inner_text2.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(0, 30, 30, 10), inner_text2.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 20, 90, 20), inner_text2.VisualRect());
 }
 
 TEST_F(NGPaintFragmentTest, FlippedBlock) {
@@ -433,27 +441,29 @@
   )HTML");
   const NGPaintFragment* container = GetPaintFragmentByElementId("container");
   EXPECT_EQ(2u, container->Children().size());
-  const NGPaintFragment& line1 = *container->FirstChild();
+  auto lines = ToList(container->Children());
+  const NGPaintFragment& line1 = *lines[0];
   EXPECT_EQ(NGPhysicalFragment::kFragmentLineBox,
             line1.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(190, 0, 10, 100), line1.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 0, 200, 100), line1.VisualRect());
   EXPECT_EQ(1u, line1.Children().size());
 
   const NGPaintFragment& text1 = *line1.FirstChild();
   EXPECT_EQ(NGPhysicalFragment::kFragmentText, text1.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(190, 0, 10, 100), text1.VisualRect());
+  EXPECT_EQ(LayoutRect(180, 0, 20, 100), text1.VisualRect());
 
-  const NGPaintFragment& line2 = *ToList(container->Children())[1];
+  const NGPaintFragment& line2 = *lines[1];
   EXPECT_EQ(NGPhysicalFragment::kFragmentLineBox,
             line2.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(180, 0, 10, 70), line2.VisualRect());
+  EXPECT_EQ(LayoutRect(0, 0, 200, 100), line2.VisualRect());
   EXPECT_EQ(2u, line2.Children().size());
 
-  const NGPaintFragment& text2 = *line2.FirstChild();
+  auto line2_children = ToList(line2.Children());
+  const NGPaintFragment& text2 = *line2_children[0];
   EXPECT_EQ(NGPhysicalFragment::kFragmentText, text2.PhysicalFragment().Type());
-  EXPECT_EQ(LayoutRect(180, 0, 10, 40), text2.VisualRect());
+  EXPECT_EQ(LayoutRect(180, 0, 20, 100), text2.VisualRect());
 
-  const NGPaintFragment& box = *ToList(line2.Children())[1];
+  const NGPaintFragment& box = *line2_children[1];
   EXPECT_EQ(NGPhysicalFragment::kFragmentBox, box.PhysicalFragment().Type());
   EXPECT_EQ(LayoutRect(180, 40, 10, 30), box.VisualRect());
   EXPECT_EQ(1u, box.Children().size());
diff --git a/third_party/blink/renderer/core/paint/paint_invalidator.cc b/third_party/blink/renderer/core/paint/paint_invalidator.cc
index 745a165a..47597e79 100644
--- a/third_party/blink/renderer/core/paint/paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/paint_invalidator.cc
@@ -323,19 +323,11 @@
   fragment_data.SetVisualRect(new_visual_rect);
 
   // For LayoutNG, update NGPaintFragments.
+  // TODO(kojii): If we can compute SelectionVisualRect when needed, the
+  // following code path will not be needed.
   if (!RuntimeEnabledFeatures::LayoutNGEnabled())
     return;
 
-  // TODO(kojii): multi-col needs additional logic. What's needed is to be
-  // figured out.
-  if (object.IsLayoutNGMixin()) {
-    if (NGPaintFragment* fragment = ToLayoutBlockFlow(object).PaintFragment())
-      fragment->SetVisualRect(new_visual_rect);
-
-    // Also check IsInline below. Inline block is LayoutBlockFlow but is also in
-    // an inline formatting context.
-  }
-
   if (object.IsInline()) {
     // An inline LayoutObject can produce multiple NGPaintFragment. Compute
     // VisualRect for each fragment from |new_visual_rect|.
@@ -345,10 +337,6 @@
           object.IsText() && ToLayoutText(object).IsSelected();
       if (!has_selection_in_this_object) {
         for (NGPaintFragment* fragment : fragments) {
-          LayoutRect local_visual_rect = fragment->SelfInkOverflow();
-          fragment->SetVisualRect(MapFragmentLocalRectToVisualRect(
-              local_visual_rect, object, *fragment, context));
-
           if (UNLIKELY(!fragment->SelectionVisualRect().IsEmpty())) {
             context.painting_layer->SetNeedsRepaint();
             ObjectPaintInvalidator(object).InvalidateDisplayItemClient(
@@ -363,13 +351,9 @@
         for (NGPaintFragment* fragment : fragments) {
           LayoutRect local_selection_rect =
               ComputeFragmentLocalSelectionRect(*fragment);
-          LayoutRect local_visual_rect =
-              UnionRect(fragment->SelfInkOverflow(), local_selection_rect);
-          fragment->SetVisualRect(MapFragmentLocalRectToVisualRect(
-              local_visual_rect, object, *fragment, context));
-
           LayoutRect selection_visual_rect = MapFragmentLocalRectToVisualRect(
               local_selection_rect, object, *fragment, context);
+          new_visual_rect.Unite(selection_visual_rect);
           const bool should_invalidate =
               object.ShouldInvalidateSelection() ||
               selection_visual_rect != fragment->SelectionVisualRect();
@@ -382,6 +366,9 @@
             fragment->SetSelectionVisualRect(selection_visual_rect);
           }
         }
+        // TODO(kojii): Not sure why do we need to include SelectionVisualRect
+        // to VisualRect only in NG, but this is needed to pass some tests.
+        fragment_data.SetVisualRect(new_visual_rect);
       }
     }
   }
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index d6e8e9e..b85cfef0 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -473,14 +473,6 @@
     // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281).
   }
 
-  // Because current |PrePaintTreeWalk| walks LayoutObject tree, NGPaintFragment
-  // that are not mapped to LayoutObject are not updated. Ensure they are
-  // updated after all descendants were updated.
-  if (RuntimeEnabledFeatures::LayoutNGEnabled() && object.IsLayoutNGMixin()) {
-    if (NGPaintFragment* fragment = ToLayoutBlockFlow(object).PaintFragment())
-      fragment->UpdateVisualRectForNonLayoutObjectChildren();
-  }
-
   object.GetMutableForPainting().ClearPaintFlags();
   context_storage_.pop_back();
 }
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 8d0e93e..63a7b889 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -2785,7 +2785,7 @@
 void AXLayoutObject::AddValidationMessageChild() {
   if (!IsWebArea())
     return;
-  AXObject* ax_object = AXObjectCache().ValidationMessageObjectIfVisible();
+  AXObject* ax_object = AXObjectCache().ValidationMessageObjectIfInvalid();
   if (ax_object)
     children_.push_back(ax_object);
 }
@@ -2803,7 +2803,7 @@
   if (this != AXObjectCache().FocusedObject())
     return nullptr;
 
-  return AXObjectCache().ValidationMessageObjectIfVisible();
+  return AXObjectCache().ValidationMessageObjectIfInvalid();
 }
 
 void AXLayoutObject::LineBreaks(Vector<int>& line_breaks) const {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc b/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc
index dd9627cf..edcb448 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_media_controls.cc
@@ -62,9 +62,7 @@
       return AXMediaControlsContainer::Create(layout_object, ax_object_cache);
 
     case kMediaSliderThumb:
-    case kMediaTextTrackList:
     case kMediaTimelineContainer:
-    case kMediaTrackSelectionCheckmark:
     case kMediaCastOffButton:
     case kMediaCastOnButton:
     case kMediaOverlayCastOffButton:
@@ -123,9 +121,7 @@
     case kMediaOverflowButton:
       return QueryString(WebLocalizedString::kAXMediaOverflowButton);
     case kMediaSliderThumb:
-    case kMediaTextTrackList:
     case kMediaTimelineContainer:
-    case kMediaTrackSelectionCheckmark:
     case kMediaControlsPanel:
     case kMediaOverflowList:
     case kMediaScrubbingMessage:
@@ -162,9 +158,7 @@
     case kMediaOverlayCastOnButton:
       return "";
     case kMediaSliderThumb:
-    case kMediaTextTrackList:
     case kMediaTimelineContainer:
-    case kMediaTrackSelectionCheckmark:
     case kMediaControlsPanel:
     case kMediaOverflowList:
     case kMediaScrubbingMessage:
@@ -202,13 +196,11 @@
       return ax::mojom::Role::kButton;
 
     case kMediaTimelineContainer:
-    case kMediaTextTrackList:
     case kMediaOverflowList:
       return ax::mojom::Role::kGroup;
 
     case kMediaControlsPanel:
     case kMediaSliderThumb:
-    case kMediaTrackSelectionCheckmark:
     case kMediaScrubbingMessage:
     case kMediaAnimatedArrowContainer:
       return ax::mojom::Role::kUnknown;
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 6f67e81..a989f53d 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -1421,13 +1421,14 @@
   if (!attribute_value.IsEmpty())
     return ax::mojom::InvalidState::kOther;
 
-  if (GetNode() && GetNode()->IsElementNode() &&
-      ToElement(GetNode())->IsFormControlElement()) {
-    HTMLFormControlElement* element = ToHTMLFormControlElement(GetNode());
-    return element->IsNotCandidateOrValid() ? ax::mojom::InvalidState::kFalse
-                                            : ax::mojom::InvalidState::kTrue;
+  if (GetElement()) {
+    ListedElement* form_control = ListedElement::From(*GetElement());
+    if (form_control) {
+      return form_control->IsNotCandidateOrValid()
+                 ? ax::mojom::InvalidState::kFalse
+                 : ax::mojom::InvalidState::kTrue;
+    }
   }
-
   return AXObject::GetInvalidState();
 }
 
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 1606304..3e1fce6 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
@@ -1140,37 +1140,52 @@
     // Cache the validation message container for reuse.
     validation_message_axid_ = GetOrCreateAXID(message_ax_object);
     message_ax_object->Init();
+    // Validation message alert object is a child of the document, as not all
+    // form controls can have a child. Also, there are form controls such as
+    // listbox that technically can have children, but they are probably not
+    // expected to have alerts within AT client code.
+    ChildrenChanged(document_);
   }
   return message_ax_object;
 }
 
-AXObject* AXObjectCacheImpl::ValidationMessageObjectIfVisible() {
+AXObject* AXObjectCacheImpl::ValidationMessageObjectIfInvalid() {
   Element* focused_element = document_->FocusedElement();
-  if (!focused_element)
-    return nullptr;
-  ListedElement* form_control = ListedElement::From(*focused_element);
-  if (!form_control || !form_control->IsValidationMessageVisible())
-    return nullptr;
+  if (focused_element) {
+    ListedElement* form_control = ListedElement::From(*focused_element);
+    if (form_control && !form_control->IsNotCandidateOrValid()) {
+      // These must both be true:
+      // * Focused control is currently invalid.
+      // * Validation message was previously created but hidden
+      // from timeout or currently visible.
+      bool was_validation_message_already_created = validation_message_axid_;
+      if (was_validation_message_already_created ||
+          form_control->IsValidationMessageVisible()) {
+        AXObject* focused_object = this->FocusedObject();
+        DCHECK(focused_object);
 
-  AXObject* focused_object = this->FocusedObject();
-  DCHECK(focused_object);
+        // Return as long as the focused form control isn't overriding with a
+        // different message via aria-errormessage.
+        bool override_native_validation_message =
+            focused_object->GetAOMPropertyOrARIAAttribute(
+                AOMRelationProperty::kErrorMessage);
+        if (!override_native_validation_message) {
+          AXObject* message = GetOrCreateValidationMessageObject();
+          if (message && !was_validation_message_already_created)
+            ChildrenChanged(document_);
+          return message;
+        }
+      }
+    }
+  }
 
-  // Return as long as the focused form control isn't overriding with a
-  // different message via aria-errormessage.
-  bool override_native_validation_message =
-      focused_object->GetAOMPropertyOrARIAAttribute(
-          AOMRelationProperty::kErrorMessage);
-  if (override_native_validation_message)
-    return nullptr;
-
-  return GetOrCreateValidationMessageObject();
+  // No focused, invalid form control.
+  RemoveValidationMessageObject();
+  return nullptr;
 }
 
-// Native validation error popup for focused form control in current document.
-void AXObjectCacheImpl::HandleValidationMessageVisibilityChanged(
-    const Element* form_control) {
-  AXObject* message_ax_object = ValidationMessageObjectIfVisible();
-  if (!message_ax_object && validation_message_axid_) {
+void AXObjectCacheImpl::RemoveValidationMessageObject() {
+  if (validation_message_axid_) {
     // Remove when it becomes hidden, so that a new object is created the next
     // time the message becomes visible. It's not possible to reuse the same
     // alert, because the event generator will not generate an alert event if
@@ -1178,16 +1193,20 @@
     // user submits the form when an alert is already visible.
     Remove(validation_message_axid_);
     validation_message_axid_ = 0;
+    ChildrenChanged(document_);
   }
+}
 
-  // Form control will now have an error message relation to message container.
+// Native validation error popup for focused form control in current document.
+void AXObjectCacheImpl::HandleValidationMessageVisibilityChanged(
+    const Element* form_control) {
+  AXObject* message_ax_object = ValidationMessageObjectIfInvalid();
+  if (message_ax_object)
+    MarkAXObjectDirty(message_ax_object, false);  // May be invisible now.
+
+  // If the form control is invalid, it will now have an error message relation
+  // to the message container.
   MarkElementDirty(form_control, false);
-
-  // Validation message alert object is a child of the document, as not all form
-  // controls can have a child. Also, there are form controls such as listbox
-  // that technically can have children, but they are probably not expected to
-  // have alerts within AT client code.
-  ChildrenChanged(document_);
 }
 
 void AXObjectCacheImpl::LabelChanged(Element* element) {
@@ -1309,6 +1328,8 @@
 
 void AXObjectCacheImpl::HandleFocusedUIElementChanged(Node* old_focused_node,
                                                       Node* new_focused_node) {
+  RemoveValidationMessageObject();
+
   if (!new_focused_node)
     return;
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
index 684b1f4..fcc7f99 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -232,7 +232,7 @@
   void RequestAOMEventListenerPermission();
 
   // For built-in HTML form validation messages.
-  AXObject* ValidationMessageObjectIfVisible();
+  AXObject* ValidationMessageObjectIfInvalid();
 
  protected:
   void PostPlatformNotification(AXObject*, ax::mojom::Event);
@@ -303,6 +303,7 @@
 
   // Object for HTML validation alerts. Created at most once per object cache.
   AXObject* GetOrCreateValidationMessageObject();
+  void RemoveValidationMessageObject();
 
   // Whether the user has granted permission for the user to install event
   // listeners for accessibility events using the AOM.
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h
index 6115905..da1cb2e8 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_element_type.h
@@ -11,9 +11,7 @@
 enum MediaControlElementType {
   kMediaSlider,
   kMediaSliderThumb,
-  kMediaTextTrackList,
   kMediaTimelineContainer,
-  kMediaTrackSelectionCheckmark,
   kMediaControlsPanel,
   kMediaCastOffButton,
   kMediaCastOnButton,
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc
index 0bb25a541..4b91143 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_text_track_list_element.cc
@@ -51,7 +51,7 @@
 
 MediaControlTextTrackListElement::MediaControlTextTrackListElement(
     MediaControlsImpl& media_controls)
-    : MediaControlPopupMenuElement(media_controls, kMediaTextTrackList) {
+    : MediaControlPopupMenuElement(media_controls, kMediaIgnore) {
   setAttribute(html_names::kRoleAttr, "menu");
   setAttribute(html_names::kAriaLabelAttr,
                WTF::AtomicString(GetLocale().QueryString(
diff --git a/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc b/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
index b7e868f..0bbbf37f 100644
--- a/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
@@ -81,7 +81,6 @@
     "chromeRenderToAssociatedSink";
 // RenderToAssociatedSink will be going away some time.
 const char kMediaStreamAudioHotword[] = "googHotword";
-// TODO(hta): googHotword should go away. https://crbug.com/577627
 const char kEchoCancellation[] = "echoCancellation";
 const char kDisableLocalEcho[] = "disableLocalEcho";
 const char kGoogEchoCancellation[] = "googEchoCancellation";
@@ -308,8 +307,6 @@
       // Should give TypeError when it's not parseable.
       // https://crbug.com/576582
       result.render_to_associated_sink.SetExact(ToBoolean(constraint.value_));
-    } else if (constraint.name_.Equals(kMediaStreamAudioHotword)) {
-      result.hotword_enabled.SetExact(ToBoolean(constraint.value_));
     } else if (constraint.name_.Equals(kGoogEchoCancellation)) {
       result.goog_echo_cancellation.SetExact(ToBoolean(constraint.value_));
     } else if (constraint.name_.Equals(kGoogExperimentalEchoCancellation)) {
@@ -416,7 +413,8 @@
     } else if (constraint.name_.Equals(kGoogLeakyBucket) ||
                constraint.name_.Equals(kGoogBeamforming) ||
                constraint.name_.Equals(kGoogArrayGeometry) ||
-               constraint.name_.Equals(kPowerLineFrequency)) {
+               constraint.name_.Equals(kPowerLineFrequency) ||
+               constraint.name_.Equals(kMediaStreamAudioHotword)) {
       // TODO(crbug.com/856176): Remove the kGoogBeamforming and
       // kGoogArrayGeometry special cases.
       context->AddConsoleMessage(ConsoleMessage::Create(
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
index 8a2ca93..e082018 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -164,10 +164,6 @@
     counter.Count(WebFeature::kMediaStreamConstraintsRenderToAssociatedSink);
   }
   if (RequestUsesDiscreteConstraint(
-          constraints, &WebMediaTrackConstraintSet::hotword_enabled)) {
-    counter.Count(WebFeature::kMediaStreamConstraintsHotwordEnabled);
-  }
-  if (RequestUsesDiscreteConstraint(
           constraints, &WebMediaTrackConstraintSet::goog_echo_cancellation)) {
     counter.Count(WebFeature::kMediaStreamConstraintsGoogEchoCancellation);
   }
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc
index 017c7c27..a13967d 100644
--- a/third_party/blink/renderer/modules/xr/xr.cc
+++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -130,7 +130,6 @@
 
 ScriptPromise XR::supportsSessionMode(ScriptState* script_state,
                                       const String& mode) {
-  LOG(ERROR) << __FUNCTION__;
   LocalFrame* frame = GetFrame();
   if (!frame) {
     // Reject if the frame is inaccessible.
@@ -161,7 +160,6 @@
         resolver, XRSession::stringToSessionMode(mode));
 
     if (!device_) {
-      LOG(ERROR) << "!device";
       pending_mode_queries_.push_back(query);
 
       // The pending queries will be resolved once the device is returned.
@@ -171,13 +169,10 @@
     }
   }
 
-  LOG(ERROR) << "/" << __FUNCTION__;
-
   return promise;
 }
 
 void XR::DispatchSupportsSessionMode(PendingSessionQuery* query) {
-  LOG(ERROR) << __FUNCTION__;
   if (!device_) {
     // If we don't have a device by the time we reach this call it indicates
     // that there's no WebXR hardware. Reject as not supported.
@@ -193,7 +188,6 @@
       std::move(session_options),
       WTF::Bind(&XR::OnSupportsSessionReturned, WrapPersistent(this),
                 WrapPersistent(query)));
-  LOG(ERROR) << "/" << __FUNCTION__;
 }
 
 ScriptPromise XR::requestSession(ScriptState* script_state,
@@ -320,7 +314,6 @@
 }
 
 void XR::EnsureDevice() {
-  LOG(ERROR) << __FUNCTION__;
   // Exit if we have a device or are waiting for a device.
   if (device_ || pending_device_) {
     return;
@@ -329,7 +322,6 @@
   service_->RequestDevice(
       WTF::Bind(&XR::OnRequestDeviceReturned, WrapPersistent(this)));
   pending_device_ = true;
-  LOG(ERROR) << "/" << __FUNCTION__;
 }
 
 // This will be called when the XR hardware or capabilities have potentially
@@ -340,15 +332,12 @@
 }
 
 void XR::OnRequestDeviceReturned(device::mojom::blink::XRDevicePtr device) {
-  LOG(ERROR) << __FUNCTION__;
   pending_device_ = false;
   if (device) {
-    LOG(ERROR) << "Got device";
     device_ = std::move(device);
 
     // Log metrics
     if (!did_log_returned_device_ || !did_log_supports_immersive_) {
-      LOG(ERROR) << "Doing Logging";
       Document* doc = GetFrame() ? GetFrame()->GetDocument() : nullptr;
       if (doc) {
         ukm::builders::XR_WebXR ukm_builder(ukm_source_id_);
@@ -371,11 +360,9 @@
   }
 
   DispatchPendingSessionCalls();
-  LOG(ERROR) << "/" << __FUNCTION__;
 }
 
 void XR::DispatchPendingSessionCalls() {
-  LOG(ERROR) << __FUNCTION__;
   // Process any calls that were waiting for the device query to be returned.
   for (auto& query : pending_mode_queries_) {
     DispatchSupportsSessionMode(query);
@@ -386,17 +373,14 @@
     DispatchRequestSession(query);
   }
   pending_session_requests_.clear();
-  LOG(ERROR) << "/" << __FUNCTION__;
 }
 
 void XR::OnSupportsSessionReturned(PendingSessionQuery* query,
                                    bool supports_session) {
-  LOG(ERROR) << __FUNCTION__;
   supports_session
       ? query->resolver->Resolve()
       : query->resolver->Reject(DOMException::Create(
             DOMExceptionCode::kNotSupportedError, kSessionNotSupported));
-  LOG(ERROR) << "/" << __FUNCTION__;
 }
 
 void XR::OnRequestSessionReturned(
@@ -449,7 +433,6 @@
 }
 
 void XR::ReportImmersiveSupported(bool supported) {
-  LOG(ERROR) << __FUNCTION__;
   Document* doc = GetFrame() ? GetFrame()->GetDocument() : nullptr;
   if (doc && !did_log_supports_immersive_ && supported) {
     ukm::builders::XR_WebXR ukm_builder(ukm_source_id_);
@@ -457,7 +440,6 @@
     ukm_builder.Record(doc->UkmRecorder());
     did_log_supports_immersive_ = true;
   }
-  LOG(ERROR) << "/" << __FUNCTION__;
 }
 
 void XR::AddedEventListener(const AtomicString& event_type,
diff --git a/third_party/blink/renderer/platform/exported/web_media_constraints.cc b/third_party/blink/renderer/platform/exported/web_media_constraints.cc
index 05c0f753..8f28f0d2 100644
--- a/third_party/blink/renderer/platform/exported/web_media_constraints.cc
+++ b/third_party/blink/renderer/platform/exported/web_media_constraints.cc
@@ -358,7 +358,6 @@
       focal_length_y("focalLengthY"),
       media_stream_source("mediaStreamSource"),
       render_to_associated_sink("chromeRenderToAssociatedSink"),
-      hotword_enabled("hotwordEnabled"),
       goog_echo_cancellation("googEchoCancellation"),
       goog_experimental_echo_cancellation("googExperimentalEchoCancellation"),
       goog_auto_gain_control("autoGainControl"),
@@ -420,7 +419,6 @@
                                   &media_stream_source,
                                   &disable_local_echo,
                                   &render_to_associated_sink,
-                                  &hotword_enabled,
                                   &goog_echo_cancellation,
                                   &goog_experimental_echo_cancellation,
                                   &goog_auto_gain_control,
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index 5e59394..b49055e5 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -343,7 +343,8 @@
     scoped_refptr<media::VideoFrame> video_frame) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(video_frame);
-  TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitFrame");
+  TRACE_EVENT1("media", "VideoFrameSubmitter::SubmitFrame", "frame",
+               video_frame->AsHumanReadableString());
 
   if (!compositor_frame_sink_ || !ShouldSubmit())
     return false;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 01e19b5..a41fe8c 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -642,6 +642,7 @@
     },
     {
       name: "IntersectionObserverV2",
+      status: "stable",
     },
     {
       name: "InvisibleDOM",
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 74ac9161..bd4d7b0 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3048,6 +3048,7 @@
 crbug.com/626703 [ Mac10.10 ] external/wpt/css/css-layout-api/auto-block-size-absolute.https.html [ Failure ]
 crbug.com/626703 external/wpt/infrastructure/testdriver/file_upload.sub.html [ Skip ]
 crbug.com/626703 crbug.com/913932 [ Android Mac ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html [ Failure Timeout ]
+crbug.com/626703 crbug.com/913932 [ Win ] external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html [ Failure Timeout ]
 crbug.com/626703 external/wpt/css/css-text/white-space/text-space-collapse-preserve-breaks-001.xht [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/text-space-collapse-discard-001.xht [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/text-space-trim-trim-inner-001.xht [ Failure ]
@@ -5418,10 +5419,6 @@
 crbug.com/873873 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html [ Timeout Pass ]
 crbug.com/873873 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html [ Timeout Pass ]
 
-# IntersectionObserverV2 tests run in a virtual test suite
-crbug.com/827639 intersection-observer/v2 [ Skip ]
-crbug.com/827639 http/tests/intersection-observer/v2 [ Skip ]
-
 crbug.com/875884 [ Linux ] lifecycle/background-change-lifecycle-count.html [ Pass Failure ]
 crbug.com/875884 [ Win ] lifecycle/background-change-lifecycle-count.html [ Pass Failure ]
 crbug.com/875884 [ Linux ] virtual/threaded/lifecycle/background-change-lifecycle-count.html [ Pass Failure ]
@@ -5860,4 +5857,4 @@
 crbug.com/924670 external/wpt/webvr/webvr-supported-by-feature-policy.html [ Failure ]
 
 # Sheriff 2019-01-25
-crbug.com/925325 [ Mac ] storage/indexeddb/index-population.html [ Pass Failure ]
\ No newline at end of file
+crbug.com/925325 [ Mac ] storage/indexeddb/index-population.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index ebd8407..d3783e0 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -742,16 +742,6 @@
     "args": ["--enable-features=OriginPolicy"]
   },
   {
-    "prefix": "intersection-observer-v2",
-    "base": "intersection-observer/v2",
-    "args": ["--enable-blink-features=IntersectionObserverV2"]
-  },
-  {
-    "prefix": "intersection-observer-v2",
-    "base": "http/tests/intersection-observer/v2",
-    "args": ["--enable-blink-features=IntersectionObserverV2"]
-  },
-  {
     "prefix" : "lazyload-policy",
     "base": "external/wpt/feature-policy/experimental-features/lazyload",
     "args": ["--enable-blink-features=LazyFrameLoading,LazyImageLoading"]
diff --git a/third_party/blink/web_tests/accessibility/css-first-letter-children.html b/third_party/blink/web_tests/accessibility/css-first-letter-children.html
index 7fda0d5..9dca0399 100644
--- a/third_party/blink/web_tests/accessibility/css-first-letter-children.html
+++ b/third_party/blink/web_tests/accessibility/css-first-letter-children.html
@@ -25,7 +25,6 @@
     for (let i = 0; i < childrenCount; i++) {
       let child = element.childAtIndex(i);
       children.push(child);
-      child.children = getAccessibilityChildren(child);
     }
     return children;
   }
diff --git a/third_party/blink/web_tests/accessibility/first-letter-text-transform-causes-crash-expected.txt b/third_party/blink/web_tests/accessibility/first-letter-text-transform-causes-crash-expected.txt
index ff4e905..7ed39de 100644
--- a/third_party/blink/web_tests/accessibility/first-letter-text-transform-causes-crash-expected.txt
+++ b/third_party/blink/web_tests/accessibility/first-letter-text-transform-causes-crash-expected.txt
@@ -9,7 +9,7 @@
 AXRole: AXWebArea
     AXRole: AXDescriptionListTerm
         AXRole: AXStaticText "Dt"
-            AXRole: AXInlineTextBox "D"
+            AXRole: AXInlineTextBox "Dt"
     AXRole: AXParagraph
         AXRole: AXStaticText "End of test"
 
diff --git a/third_party/blink/web_tests/accessibility/first-letter-text-transform.html b/third_party/blink/web_tests/accessibility/first-letter-text-transform.html
new file mode 100644
index 0000000..d63382b
--- /dev/null
+++ b/third_party/blink/web_tests/accessibility/first-letter-text-transform.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<style>
+  #para {
+      width: 0px;
+      overflow: visible;
+  }
+  #para:first-letter {
+      text-transform:uppercase;
+  }
+</style>
+<p id="para">
+  hello world
+</p>
+
+<script>
+test(function(t) {
+    var axPara = accessibilityController.accessibleElementById("para");
+    assert_equals(axPara.role, "AXRole: AXParagraph");
+    var axStaticText = axPara.childAtIndex(0);
+    assert_equals(axStaticText.role, "AXRole: AXStaticText");
+    var inlineText = '';
+    for (var i = 0; i < axStaticText.childrenCount; i++) {
+        inlineText += axStaticText.childAtIndex(i).name;
+    }
+    assert_equals(inlineText, axStaticText.name);
+}, "Inline text boxes appended equal static text, even with first-letter.");
+</script>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
index 948357c..500610d 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -141361,6 +141361,11 @@
      {}
     ]
    ],
+   "css/css-syntax/input-preprocessing-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-syntax/unicode-range-selector-expected.txt": [
     [
      {}
@@ -160086,6 +160091,21 @@
      {}
     ]
    ],
+   "fetch/stale-while-revalidate/stale-css.py": [
+    [
+     {}
+    ]
+   ],
+   "fetch/stale-while-revalidate/stale-image.py": [
+    [
+     {}
+    ]
+   ],
+   "fetch/stale-while-revalidate/stale-script.py": [
+    [
+     {}
+    ]
+   ],
    "fonts/AD.woff": [
     [
      {}
@@ -169246,6 +169266,11 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-iframe-element/support/download_stash.py": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-iframe-element/support/iframe-that-opens-modals.html": [
     [
      {}
@@ -169401,6 +169426,11 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-iframe-element/support/iframe_sandbox_download_helper.js": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-iframe-element/support/load-into-the-iframe.html": [
     [
      {}
@@ -181986,6 +182016,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/clients-get-resultingClientId.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/clients-matchall-client-types.https-expected.txt": [
     [
      {}
@@ -182861,6 +182896,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/get-resultingClientId-worker.js": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/http-to-https-redirect-and-register-iframe.html": [
     [
      {}
@@ -212854,12 +212894,36 @@
      {}
     ]
    ],
+   "css/css-syntax/inclusive-ranges.html": [
+    [
+     "/css/css-syntax/inclusive-ranges.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/input-preprocessing.html": [
+    [
+     "/css/css-syntax/input-preprocessing.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/unclosed-constructs.html": [
+    [
+     "/css/css-syntax/unclosed-constructs.html",
+     {}
+    ]
+   ],
    "css/css-syntax/unicode-range-selector.html": [
     [
      "/css/css-syntax/unicode-range-selector.html",
      {}
     ]
    ],
+   "css/css-syntax/whitespace.html": [
+    [
+     "/css/css-syntax/whitespace.html",
+     {}
+    ]
+   ],
    "css/css-tables/bounding-box-computation-1.html": [
     [
      "/css/css-tables/bounding-box-computation-1.html",
@@ -234470,6 +234534,30 @@
      {}
     ]
    ],
+   "fetch/stale-while-revalidate/fetch.tentative.html": [
+    [
+     "/fetch/stale-while-revalidate/fetch.tentative.html",
+     {}
+    ]
+   ],
+   "fetch/stale-while-revalidate/stale-css.tentative.html": [
+    [
+     "/fetch/stale-while-revalidate/stale-css.tentative.html",
+     {}
+    ]
+   ],
+   "fetch/stale-while-revalidate/stale-image.tentative.html": [
+    [
+     "/fetch/stale-while-revalidate/stale-image.tentative.html",
+     {}
+    ]
+   ],
+   "fetch/stale-while-revalidate/stale-script.tentative.html": [
+    [
+     "/fetch/stale-while-revalidate/stale-script.tentative.html",
+     {}
+    ]
+   ],
    "fullscreen/api/document-exit-fullscreen-active-document.html": [
     [
      "/fullscreen/api/document-exit-fullscreen-active-document.html",
@@ -240890,6 +240978,18 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_anchor_download_allow_downloads_without_user_activation.sub.tentative.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_anchor_download_allow_downloads_without_user_activation.sub.tentative.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_anchor_download_block_downloads_without_user_activation.sub.tentative.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_anchor_download_block_downloads_without_user_activation.sub.tentative.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_block_modals-1.html": [
     [
      "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_block_modals-1.html",
@@ -240938,6 +241038,18 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigation_download_allow_downloads_without_user_activation.sub.tentative.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigation_download_allow_downloads_without_user_activation.sub.tentative.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigation_download_block_downloads_without_user_activation.sub.tentative.html": [
+    [
+     "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigation_download_block_downloads_without_user_activation.sub.tentative.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html": [
     [
      "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html",
@@ -274840,6 +274952,12 @@
      {}
     ]
    ],
+   "service-workers/service-worker/clients-get-resultingClientId.https.html": [
+    [
+     "/service-workers/service-worker/clients-get-resultingClientId.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/clients-get.https.html": [
     [
      "/service-workers/service-worker/clients-get.https.html",
@@ -287526,18 +287644,6 @@
      {}
     ]
    ],
-   "webxr/navigator_xr_requestDevice.https.html": [
-    [
-     "/webxr/navigator_xr_requestDevice.https.html",
-     {}
-    ]
-   ],
-   "webxr/navigator_xr_requestDevice_no_device.https.html": [
-    [
-     "/webxr/navigator_xr_requestDevice_no_device.https.html",
-     {}
-    ]
-   ],
    "webxr/webGLCanvasContext_create_xrcompatible.https.html": [
     [
      "/webxr/webGLCanvasContext_create_xrcompatible.https.html",
@@ -287616,6 +287722,12 @@
      {}
     ]
    ],
+   "webxr/xrSession_mode.https.html": [
+    [
+     "/webxr/xrSession_mode.https.html",
+     {}
+    ]
+   ],
    "webxr/xrSession_prevent_multiple_exclusive.https.html": [
     [
      "/webxr/xrSession_prevent_multiple_exclusive.https.html",
@@ -355429,6 +355541,22 @@
    "36faef9357746f4492d00a3fbb1e33ffd2021bb4",
    "testharness"
   ],
+  "css/css-syntax/inclusive-ranges.html": [
+   "ac486bde569842417910cf75f33607f1d2e5de52",
+   "testharness"
+  ],
+  "css/css-syntax/input-preprocessing-expected.txt": [
+   "046fc641d4288ee11e2a9ef0fc4f32096763cc65",
+   "support"
+  ],
+  "css/css-syntax/input-preprocessing.html": [
+   "9ef9a730820d85a015b51cb230aa09f397a78400",
+   "testharness"
+  ],
+  "css/css-syntax/unclosed-constructs.html": [
+   "3d7940387c810572159bd55fcc79fc10626221dc",
+   "testharness"
+  ],
   "css/css-syntax/unicode-range-selector-expected.txt": [
    "36bb5fa54626d9af05892bb7874ab513bb13147e",
    "support"
@@ -355437,6 +355565,10 @@
    "db09540bb08c47f62b4255be6ba72b289987d64c",
    "testharness"
   ],
+  "css/css-syntax/whitespace.html": [
+   "bc7aa7ebda518a42a32a154c3ed13f00be86429a",
+   "testharness"
+  ],
   "css/css-tables/META.yml": [
    "b5372064ac2721687998bb23a9a9b95226d74afd",
    "support"
@@ -394610,7 +394742,7 @@
    "support"
   ],
   "feature-policy/reporting/xr-report-only.https.html": [
-   "b52bdbfaa47071b89702cfb51166f08b405a95de",
+   "6844226f2bd2189e44c2e74396ba449ce1a49c10",
    "testharness"
   ],
   "feature-policy/reporting/xr-report-only.https.html.headers": [
@@ -394618,7 +394750,7 @@
    "support"
   ],
   "feature-policy/reporting/xr-reporting.https.html": [
-   "b737bb9a6047e79d0b35c6eedec39b6888b09eb0",
+   "1982ea544c53bad508c422befe589e9e15dabcb6",
    "testharness"
   ],
   "feature-policy/reporting/xr-reporting.https.html.headers": [
@@ -396437,6 +396569,34 @@
    "20d307e9188405dcec011042487aa2c7354930bf",
    "support"
   ],
+  "fetch/stale-while-revalidate/fetch.tentative.html": [
+   "01a991ebfb1cb42288a01da37c76b09fa53f407c",
+   "testharness"
+  ],
+  "fetch/stale-while-revalidate/stale-css.py": [
+   "6f3014db5246994383354b139e7900306297dd57",
+   "support"
+  ],
+  "fetch/stale-while-revalidate/stale-css.tentative.html": [
+   "df03bd96243138cbaee076dc9b0a6cc3d15d9a16",
+   "testharness"
+  ],
+  "fetch/stale-while-revalidate/stale-image.py": [
+   "42d0764eb91e7145cfe1638d90421ca7492379db",
+   "support"
+  ],
+  "fetch/stale-while-revalidate/stale-image.tentative.html": [
+   "d8383acb319c2e0398bd83632377ac8cb219da49",
+   "testharness"
+  ],
+  "fetch/stale-while-revalidate/stale-script.py": [
+   "c17528d8e6314e60407085ca778ba2ff70666985",
+   "support"
+  ],
+  "fetch/stale-while-revalidate/stale-script.tentative.html": [
+   "2e04e3905780add84f3da805a238946256ebda87",
+   "testharness"
+  ],
   "fonts/AD.woff": [
    "3df8ea8efdabd11bc45fdcc6d4f3fec771be6650",
    "support"
@@ -409493,6 +409653,14 @@
    "042851bbb492365e9d176aff8d678feb645f1d18",
    "testharness"
   ],
+  "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_anchor_download_allow_downloads_without_user_activation.sub.tentative.html": [
+   "32409f220f0a273f165741e2d79ca60846d61648",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_anchor_download_block_downloads_without_user_activation.sub.tentative.html": [
+   "abd4d7c5e0d76d04cd678b00a153d5a8f10bddf7",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_block_modals-1.html": [
    "ce171bfb8e10f90ed581fbcdc0b4e0605d150b88",
    "testharness"
@@ -409525,6 +409693,14 @@
    "12c4e0ca50236caacae89c76da3b81effd7b44be",
    "testharness"
   ],
+  "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigation_download_allow_downloads_without_user_activation.sub.tentative.html": [
+   "4fee27f9ba92482b85ecbcb7e1abe541fbfe83b9",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigation_download_block_downloads_without_user_activation.sub.tentative.html": [
+   "9b9246c393ec9b4ee3b9762d6d06ea65ff0ff5d1",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html": [
    "342d422036426655457bb5e886871a310bb1dd3a",
    "testharness"
@@ -409733,6 +409909,10 @@
    "18ecdcb795c33d6ab7bbb43f647947defca5634d",
    "support"
   ],
+  "html/semantics/embedded-content/the-iframe-element/support/download_stash.py": [
+   "24e1dfd58f760e1fa99846e0fac063a32a258e58",
+   "support"
+  ],
   "html/semantics/embedded-content/the-iframe-element/support/iframe-that-opens-modals.html": [
    "50f56c6278a77e5ff80e5036c7d600d0b1fa4b91",
    "support"
@@ -409857,6 +410037,10 @@
    "67733d8101b94e788f670393f624b35b7a9c7876",
    "support"
   ],
+  "html/semantics/embedded-content/the-iframe-element/support/iframe_sandbox_download_helper.js": [
+   "fb6d273ec998d7bcec12d0c7a0c65b58d568b7b7",
+   "support"
+  ],
   "html/semantics/embedded-content/the-iframe-element/support/load-into-the-iframe.html": [
    "05a80be73745465ddcd65bc5745a674824974590",
    "support"
@@ -442777,6 +442961,14 @@
    "1e4acfb286c6bcf2375fc762f9d60ea2d9f1cdc4",
    "testharness"
   ],
+  "service-workers/service-worker/clients-get-resultingClientId.https-expected.txt": [
+   "f943b7f243fe6a869a1379c27ee84023e4cbff99",
+   "support"
+  ],
+  "service-workers/service-worker/clients-get-resultingClientId.https.html": [
+   "3419cf14b523db41af70c7896d4aaa497441fb9b",
+   "testharness"
+  ],
   "service-workers/service-worker/clients-get.https.html": [
    "4cfbf595cadeeea5fc8a5089127c5687ec174f53",
    "testharness"
@@ -444013,6 +444205,10 @@
    "7fc35f18914c1345e0f5ccab93305938180fe9eb",
    "support"
   ],
+  "service-workers/service-worker/resources/get-resultingClientId-worker.js": [
+   "f0e6c7becab6126496fefa3f40a5e788dc64775b",
+   "support"
+  ],
   "service-workers/service-worker/resources/http-to-https-redirect-and-register-iframe.html": [
    "bcab35364dff6f4494d73adfa150d800efc6bf70",
    "support"
@@ -458030,27 +458226,19 @@
    "support"
   ],
   "webxr/idlharness.https.window-expected.txt": [
-   "a9193b434e7bb9dd90327e5a21b30d502c393053",
+   "9934c0e74341e721507df3958ae09289e90cbfc2",
    "support"
   ],
   "webxr/idlharness.https.window.js": [
    "3e54e367787cb95dada398790fe23b10174df29f",
    "testharness"
   ],
-  "webxr/navigator_xr_requestDevice.https.html": [
-   "c51dd8db165a14514dcf364c760b8da6a81af0b0",
-   "testharness"
-  ],
-  "webxr/navigator_xr_requestDevice_no_device.https.html": [
-   "3cd149bb0ce0df4b7006f4d99a83d2de09e0f282",
-   "testharness"
-  ],
   "webxr/resources/webxr_check.html": [
    "2d8e5b387dc88588921ccfa49dd14db58009900c",
    "support"
   ],
   "webxr/resources/webxr_util.js": [
-   "10bdc12810c3b34d140e6f04b0068c28c9dc1873",
+   "7344fa05f655cded22a3ba9b099a8726a0c4beb3",
    "support"
   ],
   "webxr/webGLCanvasContext_create_xrcompatible.https.html": [
@@ -458066,63 +458254,67 @@
    "testharness"
   ],
   "webxr/xrDevice_requestSession_immersive.https.html": [
-   "e9e7b9bc131b12d68fa8a2886967a7395a5b0f99",
+   "c5956e7f3d12745638092558abb0b41749fb16d6",
    "testharness"
   ],
   "webxr/xrDevice_requestSession_immersive_no_gesture.https.html": [
-   "9f0f5f3d8ae0c4b7cb8794ad41cd1015cd942374",
+   "c1b3286709d3a7d4dc45029253e3bbffb579e237",
    "testharness"
   ],
   "webxr/xrDevice_requestSession_immersive_unsupported.https.html": [
-   "e0d2688e997be1c765e3e146ff1eb0db212b976e",
+   "60e9e6cc6e1c0fa990af396e42418bb16984a5e8",
    "testharness"
   ],
   "webxr/xrDevice_requestSession_non_immersive_no_gesture.https.html": [
-   "1634dfe9cba3a6798652613c407ec21b5e3c4d8e",
+   "6cf50f521c4836dede6f763b6e7f3e263e30f68e",
    "testharness"
   ],
   "webxr/xrDevice_supportsSession_immersive.https.html": [
-   "3ca5eb11c53baa319c5188f74c6a0651801e0183",
+   "c0b47013f9d11ad292fdef2e51968c3a28c35f55",
    "testharness"
   ],
   "webxr/xrDevice_supportsSession_immersive_unsupported.https.html": [
-   "0c1dd25869fcad3a442cde8e849365f0f326b3c9",
+   "2b17b96b1bc11693c87b931a5debc0e4f1c2336c",
    "testharness"
   ],
   "webxr/xrDevice_supportsSession_non_immersive.https.html": [
-   "535b0bcbbc282ee5aaa7500cbd3a35ba21fed3d4",
+   "69a35c2510983550993f630ea6f0a165c2e89369",
    "testharness"
   ],
   "webxr/xrSession_cancelAnimationFrame.https.html": [
-   "26c0e95605468634c9bc65bf959260e594998a2d",
+   "9b08f93eead693c1c9aa6d7e2458988aa7dae442",
    "testharness"
   ],
   "webxr/xrSession_cancelAnimationFrame_invalidhandle.https.html": [
-   "4f4b8dfe5ff47b4433f0de0d244b12dd434eaa0d",
+   "bc9b625fb9ed2e9001da1ddaf0a01230631b084e",
    "testharness"
   ],
   "webxr/xrSession_end.https.html": [
-   "69bbda85fda9f732a0d682cf57be53115eb73854",
+   "2719bdd7dd1b4a73e8b2004f477beecf03d131bb",
+   "testharness"
+  ],
+  "webxr/xrSession_mode.https.html": [
+   "4b54d9480211b3641997f78a61dfdc7058592ecd",
    "testharness"
   ],
   "webxr/xrSession_prevent_multiple_exclusive.https.html": [
-   "ff3eaef81dd19d945a8c7128c7b5e677ea450689",
+   "c2e7f3bf444d38506f6a54c2cf9904c2927b2ad5",
    "testharness"
   ],
   "webxr/xrSession_requestAnimationFrame_callback_calls.https.html": [
-   "48dc88779abcdd37a3778f860473569f7c55c6de",
+   "268efcd596e03125e3f7b90fa7f08eba2ae716a8",
    "testharness"
   ],
   "webxr/xrSession_requestAnimationFrame_data_valid.https.html": [
-   "b5f4f180c1a911e7260310da34b32891443001c8",
+   "f873a11588045d612cb16f2487a6efa14b555679",
    "testharness"
   ],
   "webxr/xrSession_requestAnimationFrame_getViewerPose.https.html": [
-   "17b5307f019dc7ec4696dbceef5eb3d5cd21d361",
+   "ca6a71758c691e16aad512e68c83e2fd42a8efbb",
    "testharness"
   ],
   "webxr/xrSession_requestReferenceSpace.https.html": [
-   "d97852c917bc8f42f4999e5b0d1c13a7fef364ab",
+   "1eb49e0b875b1c686c9f5474c007af8c9d4790d0",
    "testharness"
   ],
   "workers/META.yml": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/inclusive-ranges.html b/third_party/blink/web_tests/external/wpt/css/css-syntax/inclusive-ranges.html
new file mode 100644
index 0000000..ac486bd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-syntax/inclusive-ranges.html
@@ -0,0 +1,60 @@
+<!doctype html>
+<title>Inclusive Ranges</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+
+foo { z-index: 0; }
+
+</style>
+
+<meta name="author" title="Tab Atkins-Bittner">
+<link rel=help href="https://drafts.csswg.org/css-syntax/#digit">
+<link rel=help href="https://drafts.csswg.org/css-syntax/#non-printable-code-point">
+
+<script>
+
+function roundtripIdent(str) {
+    const rule = document.styleSheets[0].cssRules[0];
+    rule.selectorText = "original-ident";
+    rule.selectorText = str;
+    // Check for parse error.
+    if(rule.selectorText == "original-ident") return "parse error";
+    return rule.selectorText;
+}
+function roundtripInteger(str) {
+    const rule = document.styleSheets[0].cssRules[0];
+    rule.style.zIndex = "12345";
+    rule.style.zIndex = str;
+    // Check for parse error.
+    if(rule.style.zIndex == "12345") return "parse error";
+    return rule.style.zIndex;
+}
+function testInteger(input, expected) {
+    test(()=>{
+        assert_equals(roundtripInteger(input), expected);
+    }, `"${input}" becomes "${expected}"`);
+}
+function testIdent(input, expected) {
+    test(()=>{
+        assert_equals(roundtripIdent(input), expected);
+    }, `"${input}" becomes "${expected}"`);
+}
+
+/* Digits are the inclusive range 0-9 */
+for(var i = 0; i <= 9; i++) {
+    testInteger(i+"", i+"");
+}
+
+/* Non-printables are the inclusive ranges 0-8, b, e-1f, or 7f */
+// 0 never shows up due to preprocessing, so start at 1
+for(var i = 1; i <= 8; i++) {
+    testIdent("foo"+String.fromCodePoint(i), "parse error");
+}
+testIdent("foo"+String.fromCodePoint(0xb), "parse error");
+for(var i = 0xe; i <= 0x1f; i++) {
+    testIdent("foo"+String.fromCodePoint(i), "parse error");
+}
+testIdent("foo" + String.fromCodePoint(0x7f), "parse error");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/input-preprocessing-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-syntax/input-preprocessing-expected.txt
new file mode 100644
index 0000000..046fc64
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-syntax/input-preprocessing-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+PASS "foo\0" becomes "foo�"
+PASS "f\0oo" becomes "f�oo"
+PASS "\0foo" becomes "�foo"
+PASS "\0" becomes "�"
+PASS "\0\0\0" becomes "���"
+FAIL "fooí Â€" becomes "foo�" assert_equals: expected "foo\ufffd" but got "fooí Â€"
+FAIL "fí Â€oo" becomes "f�oo" assert_equals: expected "f\ufffdoo" but got "fí Â€oo"
+FAIL "í Â€foo" becomes "�foo" assert_equals: expected "\ufffdfoo" but got "í Â€foo"
+FAIL "í Â€" becomes "�" assert_equals: expected "\ufffd" but got "í Â€"
+FAIL "í Â€í Â€í Â€" becomes "���" assert_equals: expected "\ufffd\ufffd\ufffd" but got "í Â€í Â€í Â€"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/input-preprocessing.html b/third_party/blink/web_tests/external/wpt/css/css-syntax/input-preprocessing.html
new file mode 100644
index 0000000..9ef9a73
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-syntax/input-preprocessing.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<title>Input Preprocessing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+
+foo { color: blue; }
+
+</style>
+
+<meta name="author" title="Tab Atkins-Bittner">
+<link rel=help href="https://drafts.csswg.org/css-syntax/#input-preprocessing">
+
+<script>
+
+function roundtripIdent(str) {
+    const rule = document.styleSheets[0].cssRules[0];
+    rule.selectorText = "original-ident";
+    rule.selectorText = str;
+    // Check for parse error.
+    if(rule.selectorText == "original-ident") return "parse error";
+    return rule.selectorText;
+}
+function testParsing(input, expected) {
+    test(()=>{
+        assert_equals(roundtripIdent(input), expected);
+    }, `"${input}" becomes "${expected}"`);
+}
+
+/* Can't figure out how to test the newline normalization... */
+
+/* NULL becomes FFFD */
+testParsing("foo\x00", "foo\ufffd");
+testParsing("f\x00oo", "f\ufffdoo");
+testParsing("\x00foo", "\ufffdfoo");
+testParsing("\x00", "\ufffd");
+testParsing("\x00\x00\x00", "\ufffd\ufffd\ufffd");
+
+/* surrogates become FFFD */
+testParsing("foo\ud800", "foo\ufffd");
+testParsing("f\ud800oo", "f\ufffdoo");
+testParsing("\ud800foo", "\ufffdfoo");
+testParsing("\ud800", "\ufffd");
+testParsing("\ud800\ud800\ud800", "\ufffd\ufffd\ufffd");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/unclosed-constructs.html b/third_party/blink/web_tests/external/wpt/css/css-syntax/unclosed-constructs.html
new file mode 100644
index 0000000..3d79403
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-syntax/unclosed-constructs.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<title>Unclosed Constructs Are Valid</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<meta name="author" title="Tab Atkins-Bittner">
+<link rel=help href="https://drafts.csswg.org/css-syntax/#rule-defs">
+
+<!--
+Tests that unclosed constructs are valid and match grammars,
+because grammar-matching only sees the "block",
+not the opening/closing characters themselves.
+-->
+
+<script>
+
+function validSelector(str) {
+    try {
+        document.querySelector(str);
+        return true;
+    } catch(e) {
+        return false;
+    }
+}
+function shouldBeValid(str) {
+    test(()=>{
+        assert_true(validSelector(str));
+    }, `"${str}" is a valid selector`)
+}
+
+shouldBeValid("[foo]");
+shouldBeValid("[foo");
+shouldBeValid(":nth-child(1)");
+shouldBeValid(":nth-child(1");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/whitespace.html b/third_party/blink/web_tests/external/wpt/css/css-syntax/whitespace.html
new file mode 100644
index 0000000..bc7aa7e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-syntax/whitespace.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<title>CSS Whitespace</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<meta name="author" title="Tab Atkins-Bittner">
+<link rel=help href="https://drafts.csswg.org/css-syntax/#whitespace">
+
+<div class=a><b></b></div>
+<div id=foo></div>
+
+<!--
+CSS's definition of "whitespace" matches HTML,
+and includes only the five ASCII characters
+U+0009, U+000A, U+000C, U+000D, and U+0020.
+The rest of Unicode's whitespace characters,
+many of which are recognized as whitespace by JS,
+are not valid whitespace in CSS.
+-->
+
+<script>
+
+function isWhitespace(codepoint) {
+    const char = String.fromCodePoint(codepoint);
+    const codepointName = "U+" + codepoint.toString(16).padStart(4, "0");
+    test(()=>{
+        const withSpace = document.querySelector(".a b");
+        const withChar = document.querySelector(`.a${char}b`);
+        assert_equals(withSpace, withChar);
+    }, `${codepointName} is CSS whitespace`);
+}
+function isNotWhitespace(codepoint) {
+    const char = String.fromCodePoint(codepoint);
+    const codepointName = "U+" + codepoint.toString(16).padStart(4, "0");
+    test(()=>{
+        const withSpace = document.querySelector(".a b");
+        document.querySelector("#foo").setAttribute("class", `.a${char}b`);
+        try {
+            var withChar = document.querySelector(`.a${char}b`);
+        } catch(e) {
+            assert_true(true, `${codepointName} isn't valid in a selector at all`);
+            return;
+        }
+        assert_not_equals(withSpace, withChar);
+    }, `${codepointName} is *not* CSS whitespace`);
+}
+
+// CSS Whitespace characters
+var whitespace = [0x9, 0xa, 0xc, 0xd, 0x20];
+
+// Unicode Whitespace characters not recognized by CSS
+// https://en.wikipedia.org/wiki/Whitespace_character#Unicode
+var notWhitespace = [0xb, 0x85, 0xa0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x2928, 0x2029, 0x202f, 0x205f, 0x3000, 0x180e, 0x200b, 0x200c, 0x200d, 0x2060, 0xfeff];
+
+for(var codepoint of whitespace) {
+    isWhitespace(codepoint);
+}
+for(var codepoint of notWhitespace) {
+    isNotWhitespace(codepoint);
+}
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch.tentative.html b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch.tentative.html
new file mode 100644
index 0000000..01a991eb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch.tentative.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<!---
+Tentative test against:
+https://github.com/whatwg/fetch/pull/853
+-->
+<meta charset="utf-8">
+<title>Tests Stale While Revalidate is not executed for fetch API</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(async (test) => {
+  const response = await fetch(`stale-script.py`);
+  const response2 = await fetch(`stale-script.py`);
+
+  assert_not_equals(response.headers.get('Token'), response2.headers.get('Token'));
+}, 'Second fetch does not return same response');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-css.py b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-css.py
new file mode 100644
index 0000000..6f3014d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-css.py
@@ -0,0 +1,20 @@
+def main(request, response):
+
+    cookie = request.cookies.first("Count", None)
+    count = 0
+    if cookie != None:
+      count = int(cookie.value)
+    if request.GET.first("query", None) != None:
+      headers = [("Count", count)]
+      content = ""
+      return 200, headers, content
+    else:
+      count = count + 1
+      content = "body { background: rgb(0, 128, 0); }"
+      if count > 1:
+        content = "body { background: rgb(255, 0, 0); }"
+
+      headers = [("Content-Type", "text/css"),
+               ("Set-Cookie", "Count={}".format(count)),
+               ("Cache-Control", "private, max-age=0, stale-while-revalidate=10")]
+      return 200, headers, content
diff --git a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-css.tentative.html b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-css.tentative.html
new file mode 100644
index 0000000..df03bd962
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-css.tentative.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<!---
+Tentative test against:
+https://github.com/whatwg/fetch/pull/853
+-->
+<meta charset="utf-8">
+<title>Tests Stale While Revalidate works for css</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+
+async_test(t => {
+  window.onload = t.step_func(() => {
+    step_timeout(() => {
+      assert_equals(window.getComputedStyle(document.body).getPropertyValue('background-color'), "rgb(0, 128, 0)");
+      var link2 = document.createElement("link");
+      link2.onload = t.step_func(() => {
+        assert_equals(window.getComputedStyle(document.body).getPropertyValue('background-color'), "rgb(0, 128, 0)");
+        var checkResult = () => {
+          // We poll because we don't know when the revalidation will occur.
+          fetch("stale-css.py?query").then(t.step_func((response) => {
+            var count = response.headers.get("Count");
+            if (count == '2') {
+                t.done();
+            } else {
+              t.step_timeout(checkResult, 25);
+            }
+          }));
+        };
+        t.step_timeout(checkResult, 25);
+      });
+      link2.rel = "stylesheet";
+      link2.type = "text/css";
+      link2.href = "stale-css.py";
+      document.body.appendChild(link2);
+    }, 0);
+  });
+}, 'Cache returns stale resource');
+
+var link = document.createElement("link");
+link.rel = "stylesheet";
+link.type = "text/css";
+link.href = "stale-css.py";
+document.body.appendChild(link);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-image.py b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-image.py
new file mode 100644
index 0000000..42d0764
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-image.py
@@ -0,0 +1,30 @@
+import os.path
+
+def main(request, response):
+
+    cookie = request.cookies.first("Count", None)
+    count = 0
+    if cookie != None:
+      count = int(cookie.value)
+    if request.GET.first("query", None) != None:
+      headers = [("Count", count)]
+      content = ""
+      return 200, headers, content
+    else:
+      count = count + 1
+      filename = "green-16x16.png"
+      if cookie > 1:
+        filename = "green-256x256.png"
+
+      path = os.path.join(os.path.dirname(__file__), "../../images", filename)
+      body = open(path, "rb").read()
+
+      response.add_required_headers = False
+      response.writer.write_status(200)
+      response.writer.write_header("content-length", len(body))
+      response.writer.write_header("Cache-Control", "private, max-age=0, stale-while-revalidate=10")
+      response.writer.write_header("content-type", "image/png")
+      response.writer.write_header("Set-Cookie", "Count={}".format(count))
+      response.writer.end_headers()
+
+      response.writer.write(body)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-image.tentative.html b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-image.tentative.html
new file mode 100644
index 0000000..d8383ac
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-image.tentative.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!---
+Tentative test against:
+https://github.com/whatwg/fetch/pull/853
+-->
+<meta charset="utf-8">
+<title>Tests Stale While Revalidate works for images</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<!--
+Use a child document to load the second stale image into because
+an image loaded into the same document will skip cache-control headers.
+See: https://html.spec.whatwg.org/#the-list-of-available-images
+-->
+<iframe id="child" srcdoc=""></iframe>
+<script>
+
+async_test(t => {
+  window.onload = t.step_func(() => {
+    step_timeout(() => {
+      assert_equals(document.getElementById("firstimage").width, 16, "Width is 16");
+      var childDocument = document.getElementById('child').contentDocument;
+      var img2 = childDocument.createElement("img");
+      img2.onload = t.step_func(() => {
+        assert_equals(img2.width, 16, "image dimension");
+        var checkResult = () => {
+          // We poll because we don't know when the revalidation will occur.
+          fetch("stale-image.py?query").then(t.step_func((response) => {
+            var count = response.headers.get("Count");
+            if (count == '2') {
+                t.done();
+            } else {
+              t.step_timeout(checkResult, 25);
+            }
+          }));
+        };
+        t.step_timeout(checkResult, 25);
+      });
+      img2.src = "stale-image.py";
+      childDocument.body.appendChild(img2);
+    }, 0);
+  });
+}, 'Cache returns stale resource');
+
+var img = document.createElement("img");
+img.src = "stale-image.py";
+img.id = "firstimage";
+document.body.appendChild(img);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-script.py b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-script.py
new file mode 100644
index 0000000..c17528d8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-script.py
@@ -0,0 +1,25 @@
+import random, string, datetime
+
+def token():
+   letters = string.ascii_lowercase
+   return ''.join(random.choice(letters) for i in range(20))
+
+def main(request, response):
+    cookie = request.cookies.first("Count", None)
+    count = 0
+    if cookie != None:
+      count = int(cookie.value)
+    if request.GET.first("query", None) != None:
+      headers = [("Count", count)]
+      content = ""
+      return 200, headers, content
+    else:
+      count = count + 1
+
+      unique_id = token()
+      headers = [("Content-Type", "text/javascript"),
+                 ("Cache-Control", "private, max-age=0, stale-while-revalidate=10"),
+                 ("Set-Cookie", "Count={}".format(count)),
+                 ("Token", unique_id)]
+      content = "report('{}')".format(unique_id)
+      return 200, headers, content
diff --git a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-script.tentative.html b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-script.tentative.html
new file mode 100644
index 0000000..2e04e390
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/stale-script.tentative.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!---
+Tentative test against:
+https://github.com/whatwg/fetch/pull/853
+-->
+<meta charset="utf-8">
+<title>Tests Stale While Revalidate works for scripts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+var last_modified;
+var last_modified_count = 0;
+
+// The script will call report via a uniquely generated ID on the subresource.
+// If it is a cache hit the ID will be the same and the test will pass.
+function report(mod) {
+  if (!last_modified) {
+    last_modified = mod;
+    last_modified_count = 1;
+  } else if (last_modified == mod) {
+    last_modified_count++;
+  }
+}
+
+async_test(t => {
+  window.onload = t.step_func(() => {
+    step_timeout(() => {
+      var script = document.createElement("script");
+      script.src = "stale-script.py";
+      document.body.appendChild(script);
+      script.onload = t.step_func(() => {
+          assert_equals(last_modified_count, 2, "last modified");
+          var checkResult = () => {
+            // We poll because we don't know when the revalidation will occur.
+            fetch("stale-script.py?query").then(t.step_func((response) => {
+              var count = response.headers.get("Count");
+              if (count == '2') {
+                  t.done();
+              } else {
+                t.step_timeout(checkResult, 25);
+              }
+            }));
+          };
+          t.step_timeout(checkResult, 25);
+      });
+    }, 0);
+  });
+}, 'Cache returns stale resource');
+
+var script = document.createElement("script");
+script.src = "stale-script.py";
+document.body.appendChild(script);
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-get-resultingClientId.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-get-resultingClientId.https-expected.txt
new file mode 100644
index 0000000..f943b7f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-get-resultingClientId.https-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS global setup
+PASS get(resultingClientId) for same-origin document
+PASS get(resultingClientId) on cross-origin redirect
+FAIL get(resultingClientId) for document sandboxed by CSP header assert_equals: promiseValue expected "undefinedValue" but got "client"
+PASS get(resultingClientId) for document sandboxed by CSP header with allow-same-origin
+PASS global cleanup
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-get-resultingClientId.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-get-resultingClientId.https.html
new file mode 100644
index 0000000..3419cf14
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-get-resultingClientId.https.html
@@ -0,0 +1,177 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test clients.get(resultingClientId)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+const scope = "resources/";
+let worker;
+
+// Setup. Keep this as the first promise_test.
+promise_test(async (t) => {
+  const registration = await service_worker_unregister_and_register(
+      t, 'resources/get-resultingClientId-worker.js',
+      scope);
+  worker = registration.installing;
+  await wait_for_state(t, worker, 'activated');
+}, 'global setup');
+
+// Sends |command| to the worker and returns a promise that resolves to its
+// response. There should only be one inflight command at a time.
+async function sendCommand(command) {
+  const saw_message = new Promise((resolve) => {
+    navigator.serviceWorker.onmessage = (event) => {
+      resolve(event.data);
+    };
+  });
+  worker.postMessage(command);
+  return saw_message;
+}
+
+// Wrapper for 'startTest' command. Tells the worker a test is starting,
+// so it resets state and keeps itself alive until 'finishTest'.
+async function startTest(t) {
+  const result = await sendCommand({command: 'startTest'});
+  assert_equals(result, 'ok', 'startTest');
+
+  t.add_cleanup(async () => {
+    return finishTest();
+  });
+}
+
+// Wrapper for 'finishTest' command.
+async function finishTest() {
+  const result = await sendCommand({command: 'finishTest'});
+  assert_equals(result, 'ok', 'finishTest');
+}
+
+// Wrapper for 'getResultingClient' command. Tells the worker to return
+// clients.get(event.resultingClientId) for the navigation that occurs
+// during this test.
+//
+// The return value describes how clients.get() settled. It also includes
+// |queriedId| which is the id passed to clients.get() (the resultingClientId
+// in this case).
+//
+// Example value:
+// {
+//   queriedId: 'abc',
+//   promiseState: fulfilled,
+//   promiseValue: client,
+//   client: {
+//     id: 'abc',
+//     url: '//example.com/client'
+//   }
+// }
+async function getResultingClient() {
+  return sendCommand({command: 'getResultingClient'});
+}
+
+// Wrapper for 'getClient' command. Tells the worker to return
+// clients.get(|id|). The return value is as in the getResultingClient()
+// documentation.
+async function getClient(id) {
+  return sendCommand({command: 'getClient', id: id});
+}
+
+// Navigates to |url|. Returns the result of clients.get() on the
+// resultingClientId.
+async function navigateAndGetResultingClient(t, url) {
+  const resultPromise = getResultingClient();
+  const frame = await with_iframe(url);
+  t.add_cleanup(() => {
+    frame.remove();
+  });
+  const result = await resultPromise;
+  const resultingClientId = result.queriedId;
+
+  // First test clients.get(event.resultingClientId) inside the fetch event. The
+  // behavior of this is subtle due to the use of iframes and about:blank
+  // replacement. The spec probably requires that it resolve to the original
+  // about:blank client, and that later that client should be discarded after
+  // load if the load was to another origin. Implementations might differ. For
+  // now, this test just asserts that the promise resolves. See
+  // https://github.com/w3c/ServiceWorker/issues/1385.
+  assert_equals(result.promiseState, 'fulfilled',
+                'get(event.resultingClientId) in the fetch event should fulfill');
+
+  // Test clients.get() on the previous resultingClientId again. By this
+  // time the load finished, so it's more straightforward how this promise
+  // should settle. Return the result of this promise.
+  return await getClient(resultingClientId);
+}
+
+// Test get(resultingClientId) in the basic same-origin case.
+promise_test(async (t) => {
+  await startTest(t);
+
+  const url = new URL('resources/empty.html', window.location);
+  const result = await navigateAndGetResultingClient(t, url);
+  assert_equals(result.promiseState, 'fulfilled', 'promiseState');
+  assert_equals(result.promiseValue, 'client', 'promiseValue');
+  assert_equals(result.client.url, url.href, 'client.url',);
+  assert_equals(result.client.id, result.queriedId, 'client.id');
+}, 'get(resultingClientId) for same-origin document');
+
+// Test get(resultingClientId) when the response redirects to another origin.
+promise_test(async (t) => {
+  await startTest(t);
+
+  // Navigate to a URL that redirects to another origin.
+  const base_url = new URL('.', window.location);
+  const host_info = get_host_info();
+  const other_origin_url = new URL(base_url.pathname + 'resources/empty.html',
+                                   host_info['HTTPS_REMOTE_ORIGIN']);
+  const url = new URL('resources/empty.html', window.location);
+  const pipe = `status(302)|header(Location, ${other_origin_url})`;
+  url.searchParams.set('pipe', pipe);
+
+  // The original reserved client should have been discarded on cross-origin
+  // redirect.
+  const result = await navigateAndGetResultingClient(t, url);
+  assert_equals(result.promiseState, 'fulfilled', 'promiseState');
+  assert_equals(result.promiseValue, 'undefinedValue', 'promiseValue');
+}, 'get(resultingClientId) on cross-origin redirect');
+
+// Test get(resultingClientId) when the document is sandboxed to a unique
+// origin using a CSP HTTP response header.
+promise_test(async (t) => {
+  await startTest(t);
+
+  // Navigate to a URL that has CSP sandboxing set in the HTTP response header.
+  const url = new URL('resources/empty.html', window.location);
+  const pipe = 'header(Content-Security-Policy, sandbox)';
+  url.searchParams.set('pipe', pipe);
+
+  // The original reserved client should have been discarded upon loading
+  // the sandboxed document.
+  const result = await navigateAndGetResultingClient(t, url);
+  assert_equals(result.promiseState, 'fulfilled', 'promiseState');
+  assert_equals(result.promiseValue, 'undefinedValue', 'promiseValue');
+}, 'get(resultingClientId) for document sandboxed by CSP header');
+
+// Test get(resultingClientId) when the document is sandboxed with
+// allow-same-origin.
+promise_test(async (t) => {
+  await startTest(t);
+
+  // Navigate to a URL that has CSP sandboxing set in the HTTP response header.
+  const url = new URL('resources/empty.html', window.location);
+  const pipe = 'header(Content-Security-Policy, sandbox allow-same-origin)';
+  url.searchParams.set('pipe', pipe);
+
+  // The client should be the original reserved client, as it's same-origin.
+  const result = await navigateAndGetResultingClient(t, url);
+  assert_equals(result.promiseState, 'fulfilled', 'promiseState');
+  assert_equals(result.promiseValue, 'client', 'promiseValue');
+  assert_equals(result.client.url, url.href, 'client.url',);
+  assert_equals(result.client.id, result.queriedId, 'client.id');
+}, 'get(resultingClientId) for document sandboxed by CSP header with allow-same-origin');
+
+// Cleanup. Keep this as the last promise_test.
+promise_test(async (t) => {
+  return service_worker_unregister(t, scope);
+}, 'global cleanup');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/get-resultingClientId-worker.js b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/get-resultingClientId-worker.js
new file mode 100644
index 0000000..f0e6c7b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/get-resultingClientId-worker.js
@@ -0,0 +1,107 @@
+// This worker expects a fetch event for a navigation and messages back the
+// result of clients.get(event.resultingClientId).
+
+// Resolves when the test finishes.
+let testFinishPromise;
+let resolveTestFinishPromise;
+let rejectTestFinishPromise;
+
+// Resolves to clients.get(event.resultingClientId) from the fetch event.
+let getPromise;
+let resolveGetPromise;
+let rejectGetPromise;
+
+let resultingClientId;
+
+function startTest() {
+  testFinishPromise = new Promise((resolve, reject) => {
+    resolveTestFinishPromise = resolve;
+    rejectTestFinishPromise = reject;
+  });
+
+  getPromise = new Promise((resolve, reject) => {
+    resolveGetPromise = resolve;
+    rejectGetPromise = reject;
+  });
+}
+
+async function describeGetPromiseResult(promise) {
+  const result = {};
+
+  await promise.then(
+    (client) => {
+      result.promiseState = 'fulfilled';
+      if (client === undefined) {
+        result.promiseValue = 'undefinedValue';
+      } else if (client instanceof Client) {
+        result.promiseValue = 'client';
+        result.client = {
+          id:  client.id,
+          url: client.url
+        };
+      } else {
+        result.promiseValue = 'unknown';
+      }
+    },
+    (error) => {
+      result.promiseState = 'rejected';
+    });
+
+  return result;
+}
+
+async function handleGetResultingClient(event) {
+  // Note that this message can arrive before |resultingClientId| is populated.
+  const result = await describeGetPromiseResult(getPromise);
+  // |resultingClientId| must be populated by now.
+  result.queriedId = resultingClientId;
+  event.source.postMessage(result);
+};
+
+async function handleGetClient(event) {
+  const id = event.data.id;
+  const result = await describeGetPromiseResult(self.clients.get(id));
+  result.queriedId = id;
+  event.source.postMessage(result);
+};
+
+self.addEventListener('message', (event) => {
+  if (event.data.command == 'startTest') {
+    startTest();
+    event.waitUntil(testFinishPromise);
+    event.source.postMessage('ok');
+    return;
+  }
+
+  if (event.data.command == 'finishTest') {
+    resolveTestFinishPromise();
+    event.source.postMessage('ok');
+    return;
+  }
+
+  if (event.data.command == 'getResultingClient') {
+    event.waitUntil(handleGetResultingClient(event));
+    return;
+  }
+
+  if (event.data.command == 'getClient') {
+    event.waitUntil(handleGetClient(event));
+    return;
+  }
+});
+
+async function handleFetch(event) {
+  try {
+    resultingClientId = event.resultingClientId;
+    const client = await self.clients.get(resultingClientId);
+    resolveGetPromise(client);
+  } catch (error) {
+    rejectGetPromise(error);
+  }
+}
+
+self.addEventListener('fetch', (event) => {
+  if (event.request.mode != 'navigate')
+    return;
+  event.waitUntil(handleFetch(event));
+});
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/compositing/squashing/selection-repaint-with-gaps-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/compositing/squashing/selection-repaint-with-gaps-expected.txt
index 08122d9..1044da7 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/compositing/squashing/selection-repaint-with-gaps-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/compositing/squashing/selection-repaint-with-gaps-expected.txt
@@ -33,13 +33,13 @@
       "bounds": [100, 210],
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'lorem'",
-          "rect": [0, 80, 40, 20],
+          "object": "NGPhysicalTextFragment 'ipsum'",
+          "rect": [0, 80, 40, 40],
           "reason": "selection"
         },
         {
-          "object": "NGPhysicalTextFragment 'ipsum'",
-          "rect": [0, 100, 38, 20],
+          "object": "NGPhysicalTextFragment 'lorem'",
+          "rect": [0, 80, 40, 40],
           "reason": "selection"
         }
       ]
@@ -93,23 +93,23 @@
       "bounds": [100, 210],
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'lorem'",
-          "rect": [0, 160, 40, 20],
+          "object": "NGPhysicalTextFragment 'ipsum'",
+          "rect": [0, 160, 40, 40],
           "reason": "selection"
         },
         {
           "object": "NGPhysicalTextFragment 'lorem'",
-          "rect": [0, 80, 40, 20],
+          "rect": [0, 160, 40, 40],
           "reason": "selection"
         },
         {
           "object": "NGPhysicalTextFragment 'ipsum'",
-          "rect": [0, 180, 38, 20],
+          "rect": [0, 80, 40, 40],
           "reason": "selection"
         },
         {
-          "object": "NGPhysicalTextFragment 'ipsum'",
-          "rect": [0, 100, 38, 20],
+          "object": "NGPhysicalTextFragment 'lorem'",
+          "rect": [0, 80, 40, 40],
           "reason": "selection"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/multiple-captions-display-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/multiple-captions-display-expected.png
index f10aa8e..4825c46 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/multiple-captions-display-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/multiple-captions-display-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/place-ellipsis-in-inline-blocks-2-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/place-ellipsis-in-inline-blocks-2-expected.png
index 4c8fb1e..9a009211 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/place-ellipsis-in-inline-blocks-2-expected.png
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/place-ellipsis-in-inline-blocks-2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/http/tests/html/validation-bubble-oopif-clip-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/http/tests/html/validation-bubble-oopif-clip-expected.png
new file mode 100644
index 0000000..ddbaf4b3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/http/tests/html/validation-bubble-oopif-clip-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/box/invalidate-box-shadow-currentColor-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/box/invalidate-box-shadow-currentColor-expected.txt
index f99be9c..5c462d7 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/box/invalidate-box-shadow-currentColor-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/box/invalidate-box-shadow-currentColor-expected.txt
@@ -18,13 +18,13 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalBoxFragment LayoutInline SPAN id='target'",
-          "rect": [8, 8, 29, 24],
+          "object": "NGPhysicalTextFragment 'Text'",
+          "rect": [8, 8, 29, 19],
           "reason": "style change"
         },
         {
-          "object": "NGPhysicalTextFragment 'Text'",
-          "rect": [8, 8, 29, 19],
+          "object": "NGPhysicalBoxFragment LayoutInline SPAN id='target'",
+          "rect": [8, 8, 28, 24],
           "reason": "style change"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt
index 59bdf3c..d70963fc 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt
@@ -28,33 +28,43 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'vel fringilla orci nibh sed neque.'",
-          "rect": [10, 178, 291, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Quisque eu nulla non nisi molestie'",
-          "rect": [10, 198, 290, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'ac, laoreet non, suscipit sed, sapien.'",
-          "rect": [10, 238, 278, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'accumsan. Etiam tellus urna, laoreet'",
-          "rect": [10, 218, 270, 19],
+          "object": "NGPhysicalTextFragment 'Curabitur pretium, quam quis semper'",
+          "rect": [10, 138, 291, 159],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'Phasellus vehicula, sem at posuere'",
-          "rect": [10, 258, 261, 19],
+          "rect": [10, 138, 291, 159],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Quisque eu nulla non nisi molestie'",
+          "rect": [10, 138, 291, 159],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'ac, laoreet non, suscipit sed, sapien.'",
+          "rect": [10, 138, 291, 159],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'accumsan. Etiam tellus urna, laoreet'",
+          "rect": [10, 138, 291, 159],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'malesuada, est libero feugiat libero,'",
-          "rect": [10, 158, 245, 19],
+          "rect": [10, 138, 291, 159],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'vehicula, augue nibh molestie nisl,'",
+          "rect": [10, 138, 291, 159],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'vel fringilla orci nibh sed neque.'",
+          "rect": [10, 138, 291, 159],
           "reason": "geometry"
         },
         {
@@ -74,28 +84,58 @@
         },
         {
           "object": "NGPhysicalTextFragment 'Curabitur pretium, quam quis semper'",
-          "rect": [10, 138, 234, 19],
+          "rect": [10, 138, 234, 199],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Phasellus vehicula, sem at posuere'",
+          "rect": [10, 138, 234, 199],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Quisque eu nulla non nisi molestie'",
+          "rect": [10, 138, 234, 199],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'ac, laoreet non, suscipit sed, sapien.'",
+          "rect": [10, 138, 234, 199],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'accumsan. Etiam tellus urna, laoreet'",
+          "rect": [10, 138, 234, 199],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'malesuada, est libero feugiat libero,'",
+          "rect": [10, 138, 234, 199],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'nec ullamcorper lacus ante vulputate'",
-          "rect": [10, 298, 229, 19],
+          "rect": [10, 138, 234, 199],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'pede.'",
+          "rect": [10, 138, 234, 199],
           "reason": "appeared"
         },
         {
           "object": "NGPhysicalTextFragment 'vehicula, augue nibh molestie nisl,'",
-          "rect": [10, 278, 217, 19],
+          "rect": [10, 138, 234, 199],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'vel fringilla orci nibh sed neque.'",
+          "rect": [10, 138, 234, 199],
           "reason": "geometry"
         },
         {
           "object": "LayoutNGTableCell TD id='col1'",
           "rect": [252, 138, 50, 215],
           "reason": "incremental"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'pede.'",
-          "rect": [10, 318, 34, 19],
-          "reason": "appeared"
         }
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/text-color-change-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/text-color-change-expected.txt
index 896186d2..bc5340a 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/text-color-change-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/text-color-change-expected.txt
@@ -19,62 +19,62 @@
       "paintInvalidations": [
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 221, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 205, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 189, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 173, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 157, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 141, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 125, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 109, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 93, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 77, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 61, 48, 16],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment '  Text'",
-          "rect": [8, 237, 48, 9],
+          "rect": [8, 61, 48, 185],
           "reason": "style change"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt
index a6f705f..986267f 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt
@@ -28,78 +28,78 @@
           "reason": "style change"
         },
         {
-          "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
-          "rect": [138, 168, 636, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
-          "rect": [148, 168, 635, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
-          "rect": [148, 168, 635, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
-          "rect": [138, 128, 635, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
-          "rect": [148, 128, 634, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
-          "rect": [148, 128, 634, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
-          "rect": [138, 188, 627, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
-          "rect": [148, 188, 626, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
-          "rect": [148, 188, 626, 19],
+          "rect": [138, 128, 636, 99],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'",
-          "rect": [138, 148, 618, 19],
+          "rect": [138, 128, 636, 99],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
+          "rect": [138, 128, 636, 99],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
+          "rect": [138, 128, 636, 99],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
+          "rect": [138, 128, 636, 99],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
+          "rect": [148, 128, 635, 99],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
+          "rect": [148, 128, 635, 99],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'",
-          "rect": [148, 148, 617, 19],
+          "rect": [148, 128, 635, 99],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'",
-          "rect": [148, 148, 617, 19],
+          "rect": [148, 128, 635, 99],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
+          "rect": [148, 128, 635, 99],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
+          "rect": [148, 128, 635, 99],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
+          "rect": [148, 128, 635, 99],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
+          "rect": [148, 128, 635, 99],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
-          "rect": [138, 208, 573, 19],
+          "rect": [148, 128, 635, 99],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
-          "rect": [148, 208, 572, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
-          "rect": [148, 208, 572, 19],
+          "rect": [148, 128, 635, 99],
           "reason": "geometry"
         },
         {
@@ -113,33 +113,48 @@
           "reason": "incremental"
         },
         {
-          "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
-          "rect": [400, 208, 391, 19],
+          "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
+          "rect": [400, 128, 391, 179],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id'",
-          "rect": [400, 268, 385, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
-          "rect": [400, 168, 385, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'sapien, in condimentum leo neque sed nulla. Nunc quis porta'",
-          "rect": [400, 248, 384, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'",
-          "rect": [400, 148, 383, 19],
+          "rect": [400, 128, 391, 179],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
+          "rect": [400, 128, 391, 179],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis'",
-          "rect": [400, 228, 382, 19],
+          "rect": [400, 128, 391, 179],
+          "reason": "disappeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id'",
+          "rect": [400, 128, 391, 179],
+          "reason": "disappeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
+          "rect": [400, 128, 391, 179],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
+          "rect": [400, 128, 391, 179],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'quam.'",
+          "rect": [400, 128, 391, 179],
+          "reason": "disappeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'sapien, in condimentum leo neque sed nulla. Nunc quis porta'",
+          "rect": [400, 128, 391, 179],
           "reason": "disappeared"
         },
         {
@@ -151,11 +166,6 @@
           "object": "LayoutNGBlockFlow DIV id='left'",
           "rect": [8, 128, 140, 100],
           "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'quam.'",
-          "rect": [400, 288, 39, 19],
-          "reason": "disappeared"
         }
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt
index c13e1d6..613f94c5 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt
@@ -18,83 +18,133 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'AAAAA AAAA AAAA'",
-          "rect": [0, 120, 300, 20],
+          "object": "NGPhysicalTextFragment 'A A A A A AA AA'",
+          "rect": [0, 0, 300, 200],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'A A A A A AA AA'",
-          "rect": [0, 0, 300, 20],
+          "object": "NGPhysicalTextFragment 'A A'",
+          "rect": [0, 0, 300, 200],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'AA AA AA A A A'",
-          "rect": [0, 160, 280, 20],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AAA AAA AAA AA'",
-          "rect": [0, 140, 280, 20],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AAAAAA AAAAAAA'",
-          "rect": [0, 80, 280, 20],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AAA AAAA AAAA'",
-          "rect": [0, 40, 260, 20],
+          "rect": [0, 0, 300, 200],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'AA AA AAA AAA'",
-          "rect": [0, 20, 260, 20],
+          "rect": [0, 0, 300, 200],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'AAAAAA AAAAA'",
-          "rect": [0, 100, 240, 20],
+          "object": "NGPhysicalTextFragment 'AAA AAA AAA AA'",
+          "rect": [0, 0, 300, 200],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAA AAAA AAAA'",
+          "rect": [0, 0, 300, 200],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAAAA AAAA AAAA'",
+          "rect": [0, 0, 300, 200],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'AAAAA AAAAA'",
-          "rect": [0, 60, 220, 20],
+          "rect": [0, 0, 300, 200],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'AA AA AA A'",
-          "rect": [0, 260, 200, 20],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AAA AAA AA'",
-          "rect": [0, 240, 200, 20],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AAAAA AAAA'",
-          "rect": [0, 200, 200, 20],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'A A A A A'",
-          "rect": [0, 300, 180, 20],
+          "object": "NGPhysicalTextFragment 'AAAAAA AAAAA'",
+          "rect": [0, 0, 300, 200],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'AAAA AAA'",
-          "rect": [0, 220, 160, 20],
-          "reason": "disappeared"
+          "object": "NGPhysicalTextFragment 'AAAAAA AAAAAAA'",
+          "rect": [0, 0, 300, 200],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'A A A A A AA AA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'A A A A'",
-          "rect": [0, 280, 140, 20],
+          "rect": [0, 0, 200, 300],
           "reason": "disappeared"
         },
         {
           "object": "NGPhysicalTextFragment 'A A'",
-          "rect": [0, 180, 100, 20],
+          "rect": [0, 0, 200, 300],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AA AA AA A A A'",
+          "rect": [0, 0, 200, 300],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AA AA AA A'",
+          "rect": [0, 0, 200, 300],
+          "reason": "disappeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AA AA AAA AAA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAA AAA AA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "disappeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAA AAA AAA AA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAA AAAA AAAA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAAA AAA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "disappeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAAAA AAAA AAAA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAAAA AAAA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "disappeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAAAA AAAAA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAAAAA AAAAA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAAAAA AAAAAAA'",
+          "rect": [0, 0, 200, 300],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'A A A A A'",
+          "rect": [0, 300, 180, 20],
           "reason": "geometry"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-1-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-1-expected.txt
index 955482f..c6735ee 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-1-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-1-expected.txt
@@ -23,103 +23,143 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
+          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 340, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 320, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 300, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 280, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 260, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
-          "rect": [14, 480, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
-          "rect": [14, 460, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [65, 360, 306, 19],
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
+          "rect": [14, 80, 406, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
+          "rect": [14, 80, 406, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
+          "rect": [14, 80, 406, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
+          "rect": [14, 80, 406, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
+          "rect": [14, 80, 406, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
+          "rect": [14, 80, 406, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'about once in a minute.'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'game indeed.'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
+          "rect": [14, 420, 355, 39],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
-          "rect": [65, 420, 304, 19],
+          "rect": [14, 420, 355, 39],
           "reason": "geometry"
         },
         {
@@ -128,41 +168,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
-          "rect": [14, 440, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'about once in a minute.'",
-          "rect": [14, 500, 147, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [65, 380, 85, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) DIV id='pinkFloat'",
           "rect": [378, 18, 70, 150],
           "reason": "geometry"
@@ -173,11 +178,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 360, 49, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
           "rect": [372, 403, 48, 81],
           "reason": "geometry"
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-10-expected.txt
index 77e5f108..8013ca3 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-10-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -23,108 +23,158 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
+          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 340, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 320, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 300, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 280, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 260, 406, 19],
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
-          "rect": [14, 480, 355, 19],
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 520, 406, 80],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
-          "rect": [14, 460, 355, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 520, 406, 80],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 520, 406, 80],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 520, 406, 80],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment ' was in a furious passion, and went stamping'",
-          "rect": [56, 460, 313, 19],
+          "rect": [14, 460, 355, 59],
           "reason": "appeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [65, 360, 306, 19],
+          "object": "NGPhysicalTextFragment 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'her head!\u2019 about once in a minute.'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
+          "rect": [14, 460, 355, 59],
+          "reason": "disappeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'game indeed.'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Queen'",
+          "rect": [14, 440, 355, 39],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'the'",
+          "rect": [14, 440, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
+          "rect": [14, 420, 355, 39],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
-          "rect": [65, 420, 304, 19],
+          "rect": [14, 420, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
+          "rect": [14, 80, 354, 119],
           "reason": "geometry"
         },
         {
@@ -133,56 +183,11 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
-          "rect": [14, 440, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
-          "rect": [65, 440, 285, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her head!\u2019 about once in a minute.'",
-          "rect": [14, 500, 214, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [65, 380, 85, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'the'",
           "rect": [302, 440, 68, 19],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 360, 49, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
           "rect": [372, 403, 48, 81],
           "reason": "geometry"
@@ -198,11 +203,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'Queen'",
-          "rect": [14, 460, 42, 19],
-          "reason": "appeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'would'",
           "rect": [238, 180, 41, 19],
           "reason": "geometry"
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt
index 34bbea70..05a7e744 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt
@@ -23,178 +23,253 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 581, 406, 19],
+          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
+          "rect": [14, 241, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 561, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 541, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 521, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 241, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 341, 406, 19],
+          "rect": [14, 241, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
+          "rect": [14, 241, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
+          "rect": [14, 241, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
+          "rect": [14, 241, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
+          "rect": [14, 241, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 340, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 321, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 320, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 301, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 300, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 281, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 280, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 261, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 260, 406, 19],
+          "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 181, 407, 79],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 221, 406, 19],
+          "rect": [14, 181, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 181, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
+          "rect": [14, 181, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 201, 406, 19],
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 521, 406, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 521, 406, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 521, 406, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 521, 406, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'about once in a minute.'",
+          "rect": [14, 461, 355, 59],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
-          "rect": [14, 481, 355, 19],
+          "rect": [14, 461, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
+          "rect": [14, 461, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'about once in a minute.'",
+          "rect": [14, 460, 355, 59],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
-          "rect": [14, 480, 355, 19],
+          "rect": [14, 460, 355, 59],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
-          "rect": [14, 461, 355, 19],
+          "rect": [14, 460, 355, 59],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
-          "rect": [14, 460, 355, 19],
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [65, 361, 355, 39],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
+          "object": "NGPhysicalTextFragment 'game indeed.'",
+          "rect": [65, 361, 355, 39],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [65, 360, 355, 39],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
+          "object": "NGPhysicalTextFragment 'game indeed.'",
+          "rect": [65, 360, 355, 39],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
+          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
+          "rect": [14, 421, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
+          "rect": [14, 421, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
+          "rect": [14, 420, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
+          "rect": [14, 420, 355, 39],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
+          "rect": [14, 80, 354, 120],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [65, 361, 306, 19],
+          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
+          "rect": [14, 80, 354, 120],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [65, 360, 306, 19],
+          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
+          "rect": [14, 80, 354, 120],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
-          "rect": [65, 421, 304, 19],
+          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
+          "rect": [14, 80, 354, 120],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
-          "rect": [65, 420, 304, 19],
+          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
+          "rect": [14, 80, 354, 120],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
+          "rect": [14, 80, 354, 120],
           "reason": "geometry"
         },
         {
@@ -208,76 +283,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
-          "rect": [14, 441, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
-          "rect": [14, 440, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 241, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 181, 222, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 241, 178, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'about once in a minute.'",
-          "rect": [14, 501, 147, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'about once in a minute.'",
-          "rect": [14, 500, 147, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [279, 181, 142, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [65, 381, 85, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [65, 380, 85, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [302, 441, 68, 19],
           "reason": "geometry"
@@ -288,16 +293,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 361, 49, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 360, 49, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
           "rect": [372, 404, 48, 81],
           "reason": "geometry"
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-3-expected.txt
index f1a5a6c9..e566ac87 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-3-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -23,103 +23,168 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
+          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 340, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 320, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 300, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 280, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 260, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
-          "rect": [14, 480, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a furious passion, and went stamping about, and'",
-          "rect": [14, 460, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [65, 360, 306, 19],
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for turns,'",
+          "rect": [14, 400, 406, 59],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehogs; and in a very short time '",
+          "rect": [14, 400, 406, 59],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'quarrelling all the while, and fighting for the'",
-          "rect": [65, 420, 304, 19],
+          "rect": [14, 400, 406, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'a furious passion, and went stamping about, and'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'about once in a minute.'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'game indeed.'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' was in'",
+          "rect": [14, 440, 339, 79],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'a furious passion, and went stamping about, and'",
+          "rect": [14, 440, 339, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'about once in a minute.'",
+          "rect": [14, 440, 339, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
+          "rect": [14, 440, 339, 79],
           "reason": "geometry"
         },
         {
@@ -128,41 +193,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'hedgehogs; and in a very short time '",
-          "rect": [14, 440, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'about once in a minute.'",
-          "rect": [14, 500, 147, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [65, 380, 85, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [302, 440, 68, 19],
           "reason": "geometry"
@@ -178,16 +208,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for turns,'",
-          "rect": [362, 400, 58, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 360, 49, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
           "rect": [372, 403, 48, 81],
           "reason": "geometry"
@@ -198,11 +218,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment ' was in'",
-          "rect": [307, 440, 46, 19],
-          "reason": "appeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'would'",
           "rect": [238, 180, 41, 19],
           "reason": "geometry"
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-4-expected.txt
index ace625e..5b5858d 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-4-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -23,103 +23,143 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
+          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019 about once'",
-          "rect": [14, 480, 406, 19],
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 340, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 320, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 300, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 280, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 260, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
-          "rect": [14, 460, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [65, 360, 306, 19],
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'in a minute.'",
+          "rect": [14, 460, 406, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019 about once'",
+          "rect": [14, 460, 406, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
+          "rect": [14, 460, 406, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'game indeed.'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
+          "rect": [14, 420, 355, 39],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
-          "rect": [65, 420, 304, 19],
+          "rect": [14, 420, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
+          "rect": [14, 80, 354, 119],
           "reason": "geometry"
         },
         {
@@ -128,51 +168,11 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
-          "rect": [14, 440, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'in a minute.'",
-          "rect": [14, 500, 147, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [65, 380, 85, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [302, 440, 68, 19],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 360, 49, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
           "rect": [372, 403, 48, 81],
           "reason": "geometry"
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-5-expected.txt
index e285559..cfbb924 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-5-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -23,103 +23,153 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
+          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 340, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 320, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 300, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 280, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 260, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u2018Off with his head!\u2019 or \u2018Off with her head!\u2019 about once'",
-          "rect": [14, 480, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'furious passion, and went stamping about, and shouting'",
-          "rect": [14, 460, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [49, 360, 322, 19],
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [49, 360, 371, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'game indeed.'",
+          "rect": [49, 360, 371, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' was in a'",
+          "rect": [14, 440, 355, 79],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'furious passion, and went stamping about, and shouting'",
+          "rect": [14, 440, 355, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'in a minute.'",
+          "rect": [14, 440, 355, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment '\u2018Off with his head!\u2019 or \u2018Off with her head!\u2019 about once'",
+          "rect": [14, 440, 355, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for'",
+          "rect": [14, 400, 355, 59],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehogs; and in a very short time '",
+          "rect": [14, 400, 355, 59],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'turns, quarrelling all the while, and fighting for the'",
-          "rect": [49, 420, 320, 19],
+          "rect": [14, 400, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
+          "rect": [14, 80, 354, 119],
           "reason": "geometry"
         },
         {
@@ -133,46 +183,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'hedgehogs; and in a very short time '",
-          "rect": [14, 440, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'in a minute.'",
-          "rect": [14, 500, 147, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [65, 380, 85, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [49, 380, 85, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [302, 440, 68, 19],
           "reason": "geometry"
@@ -183,16 +193,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment ' was in a'",
-          "rect": [311, 440, 58, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 360, 49, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
           "rect": [372, 403, 48, 81],
           "reason": "geometry"
@@ -206,11 +206,6 @@
           "object": "NGPhysicalTextFragment 'would'",
           "rect": [238, 180, 41, 19],
           "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'for'",
-          "rect": [350, 400, 19, 19],
-          "reason": "appeared"
         }
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-6-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-6-expected.txt
index 057731b..859491d3 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-6-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-6-expected.txt
@@ -23,103 +23,143 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
+          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 340, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 320, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 300, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 280, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 260, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
-          "rect": [14, 480, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
-          "rect": [14, 460, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [65, 360, 306, 19],
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'about once in a minute.'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'game indeed.'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
+          "rect": [14, 420, 355, 39],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
-          "rect": [65, 420, 304, 19],
+          "rect": [14, 420, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
+          "rect": [14, 80, 354, 119],
           "reason": "geometry"
         },
         {
@@ -128,51 +168,11 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
-          "rect": [14, 440, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'about once in a minute.'",
-          "rect": [14, 500, 147, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [65, 380, 85, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [302, 440, 68, 19],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 360, 49, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
           "rect": [372, 403, 48, 81],
           "reason": "geometry"
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-7-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-7-expected.txt
index 935c626..c416b2e8 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-7-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-7-expected.txt
@@ -23,103 +23,143 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
+          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 340, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 320, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 300, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 280, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 260, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
-          "rect": [14, 480, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
-          "rect": [14, 460, 355, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [65, 360, 306, 19],
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'about once in a minute.'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'game indeed.'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
+          "rect": [14, 420, 355, 39],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
-          "rect": [65, 420, 304, 19],
+          "rect": [14, 420, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
+          "rect": [14, 80, 354, 119],
           "reason": "geometry"
         },
         {
@@ -128,51 +168,11 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
-          "rect": [14, 440, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'about once in a minute.'",
-          "rect": [14, 500, 147, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'game indeed.'",
-          "rect": [65, 380, 85, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [298, 440, 72, 19],
           "reason": "style change"
         },
         {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 360, 49, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
           "rect": [372, 403, 48, 81],
           "reason": "geometry"
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt
index ca4b54d..b6d80681 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -23,108 +23,158 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
+          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 340, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 320, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 300, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 280, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 260, 406, 19],
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'with his head!\u2019 or \u2018Off with her head!\u2019 about once in a'",
-          "rect": [14, 480, 355, 19],
+          "object": "NGPhysicalTextFragment 'difficult game'",
+          "rect": [14, 360, 407, 39],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'indeed.'",
+          "rect": [14, 360, 407, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 520, 406, 80],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' was in a furious'",
+          "rect": [14, 440, 355, 79],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'minute.'",
+          "rect": [14, 440, 355, 79],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'passion, and went stamping about, and shouting \u2018Off'",
-          "rect": [14, 460, 355, 19],
+          "rect": [14, 440, 355, 79],
           "reason": "geometry"
         },
         {
+          "object": "NGPhysicalTextFragment 'with his head!\u2019 or \u2018Off with her head!\u2019 about once in a'",
+          "rect": [14, 440, 355, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'and in a very short time '",
+          "rect": [14, 400, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for turns,'",
+          "rect": [14, 400, 355, 59],
+          "reason": "appeared"
+        },
+        {
           "object": "NGPhysicalTextFragment 'quarrelling all the while, and fighting for the hedgehogs;'",
-          "rect": [14, 420, 355, 19],
+          "rect": [14, 400, 355, 59],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
-          "reason": "geometry"
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [65, 360, 355, 39],
+          "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
+          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
+          "rect": [14, 80, 354, 119],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
+          "rect": [14, 80, 354, 119],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
+          "rect": [14, 80, 354, 119],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [14, 360, 317, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
-          "rect": [65, 360, 306, 19],
+          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
+          "rect": [14, 80, 354, 119],
           "reason": "geometry"
         },
         {
@@ -138,51 +188,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'and in a very short time '",
-          "rect": [14, 440, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'minute.'",
-          "rect": [14, 500, 147, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' was in a furious'",
-          "rect": [252, 440, 117, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'difficult game'",
-          "rect": [330, 360, 91, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'indeed.'",
-          "rect": [65, 380, 85, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [184, 440, 70, 19],
           "reason": "geometry"
@@ -193,16 +198,6 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for turns,'",
-          "rect": [311, 400, 58, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 360, 49, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
           "rect": [372, 403, 48, 81],
           "reason": "geometry"
@@ -213,11 +208,6 @@
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'indeed.'",
-          "rect": [14, 380, 46, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'would'",
           "rect": [238, 180, 41, 19],
           "reason": "geometry"
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-9-expected.txt
index 570c09b..ee3ef0c 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-9-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -23,108 +23,163 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
+          "object": "NGPhysicalTextFragment 'and was in the act of crawling away: besides all this,'",
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [14, 540, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
-          "rect": [14, 520, 406, 19],
-          "reason": "geometry"
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 407, 139],
+          "reason": "disappeared"
         },
         {
           "object": "NGPhysicalTextFragment 'ground, Alice soon came to the conclusion that it was a very'",
-          "rect": [14, 360, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'were always getting up and walking off to other parts of the'",
-          "rect": [14, 340, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'wanted to send the hedgehog to, and, as the doubled-up soldiers'",
-          "rect": [14, 320, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'there was generally a ridge or furrow in the way wherever she'",
-          "rect": [14, 300, 406, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'and was in the act of crawling away: besides all this,'",
-          "rect": [14, 280, 406, 19],
+          "rect": [14, 240, 407, 139],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself,'",
-          "rect": [14, 260, 406, 19],
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'there was generally a ridge or furrow in the way wherever she'",
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'wanted to send the hedgehog to, and, as the doubled-up soldiers'",
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'were always getting up and walking off to other parts of the'",
+          "rect": [14, 240, 407, 139],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment ' twist itself round and'",
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
+          "rect": [14, 180, 407, 79],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'head down, and was going to '",
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
+          "rect": [14, 180, 407, 79],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
-          "rect": [14, 480, 355, 19],
+          "object": "NGPhysicalTextFragment 'begin again, it was very'",
+          "rect": [14, 240, 406, 139],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "rect": [14, 520, 406, 80],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
-          "rect": [14, 460, 355, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
+          "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
+          "rect": [14, 520, 406, 80],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "rect": [14, 520, 406, 80],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+          "rect": [14, 520, 406, 80],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment ' was in a furious passion, and went stamping'",
-          "rect": [56, 460, 313, 19],
+          "rect": [14, 460, 355, 59],
           "reason": "appeared"
         },
         {
+          "object": "NGPhysicalTextFragment 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'her head!\u2019 about once in a minute.'",
+          "rect": [14, 460, 355, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
+          "rect": [14, 460, 355, 59],
+          "reason": "disappeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'difficult game indeed.'",
+          "rect": [65, 360, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'difficult'",
+          "rect": [65, 360, 355, 39],
+          "reason": "disappeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'Queen'",
+          "rect": [14, 440, 355, 39],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'the'",
+          "rect": [14, 440, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
+          "rect": [14, 420, 355, 39],
+          "reason": "geometry"
+        },
+        {
           "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
-          "rect": [65, 420, 304, 19],
+          "rect": [14, 420, 355, 39],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
+          "rect": [14, 80, 354, 119],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
+          "rect": [14, 80, 354, 119],
           "reason": "geometry"
         },
         {
@@ -133,61 +188,11 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
-          "rect": [14, 440, 289, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
-          "rect": [65, 440, 285, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her head!\u2019 about once in a minute.'",
-          "rect": [14, 500, 214, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [212, 240, 157, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'difficult game indeed.'",
-          "rect": [65, 380, 138, 19],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'the'",
           "rect": [302, 440, 68, 19],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'difficult'",
-          "rect": [371, 360, 49, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
           "rect": [372, 403, 48, 81],
           "reason": "geometry"
@@ -208,11 +213,6 @@
           "reason": "appeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'Queen'",
-          "rect": [14, 460, 42, 19],
-          "reason": "appeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'would'",
           "rect": [238, 180, 41, 19],
           "reason": "geometry"
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt
index 25c13a1e..b8415b0 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt
@@ -18,49 +18,49 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'sollicitudin nisi ut urna blandit'",
-          "rect": [8, 182, 194, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'adipiscing, enim in scelerisque'",
-          "rect": [8, 102, 192, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'pulvinar velit. Integer'",
-          "rect": [8, 162, 167, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'lacus, at sagittis eros leo'",
-          "rect": [8, 142, 151, 19],
+          "object": "NGPhysicalTextFragment ' eleifend'",
+          "rect": [8, 122, 195, 99],
           "reason": "appeared"
         },
         {
           "object": "NGPhysicalTextFragment 'convallis.'",
-          "rect": [8, 202, 139, 19],
+          "rect": [8, 122, 195, 99],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'Cras faucibus. Nunc'",
-          "rect": [8, 82, 129, 19],
+          "object": "NGPhysicalTextFragment 'lacus, at sagittis eros leo'",
+          "rect": [8, 122, 195, 99],
+          "reason": "appeared"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'pulvinar velit. Integer'",
+          "rect": [8, 122, 195, 99],
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'convallis, augue '",
-          "rect": [8, 122, 106, 19],
+          "object": "NGPhysicalTextFragment 'sollicitudin nisi ut urna blandit'",
+          "rect": [8, 122, 195, 99],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment ' eleifend lacus,'",
-          "rect": [103, 142, 94, 19],
+          "rect": [8, 142, 194, 79],
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment ' eleifend'",
-          "rect": [149, 122, 54, 19],
-          "reason": "appeared"
+          "object": "NGPhysicalTextFragment 'Cras faucibus. Nunc'",
+          "rect": [8, 82, 192, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'adipiscing, enim in scelerisque'",
+          "rect": [8, 82, 192, 59],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'convallis, augue '",
+          "rect": [8, 82, 192, 59],
+          "reason": "geometry"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutInline SPAN id='t'",
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-redraw-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-redraw-expected.txt
index 2c1a5e8..a960fa2e7 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-redraw-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-redraw-expected.txt
@@ -18,63 +18,63 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'text in the reflection'",
-          "rect": [380, 287, 286, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'text in the reflection'",
-          "rect": [70, 287, 286, 19],
-          "reason": "style change"
-        },
-        {
           "object": "NGPhysicalTextFragment 'The color of this'",
-          "rect": [391, 267, 264, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The color of this'",
-          "rect": [81, 267, 264, 19],
+          "rect": [380, 267, 286, 59],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment 'should be green'",
-          "rect": [393, 307, 260, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'should be green'",
-          "rect": [83, 307, 260, 19],
+          "rect": [380, 267, 286, 59],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment 'text in the reflection'",
-          "rect": [305, 54, 126, 142],
+          "rect": [380, 267, 286, 59],
+          "reason": "style change"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'The color of this'",
+          "rect": [70, 267, 286, 59],
+          "reason": "style change"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'should be green'",
+          "rect": [70, 267, 286, 59],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment 'text in the reflection'",
-          "rect": [305, 397, 126, 116],
+          "rect": [70, 267, 286, 59],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment 'The color of this'",
-          "rect": [316, 377, 104, 156],
+          "rect": [305, 34, 126, 182],
+          "reason": "style change"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'should be green'",
+          "rect": [305, 34, 126, 182],
+          "reason": "style change"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'text in the reflection'",
+          "rect": [305, 34, 126, 182],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment 'The color of this'",
-          "rect": [316, 74, 104, 102],
+          "rect": [305, 377, 126, 156],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment 'should be green'",
-          "rect": [318, 34, 100, 182],
+          "rect": [305, 377, 126, 156],
           "reason": "style change"
         },
         {
-          "object": "NGPhysicalTextFragment 'should be green'",
-          "rect": [318, 417, 100, 76],
+          "object": "NGPhysicalTextFragment 'text in the reflection'",
+          "rect": [305, 377, 126, 156],
           "reason": "style change"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-expected.txt
index 3a8a499..6070a7d4b 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-expected.txt
@@ -19,12 +19,12 @@
       "paintInvalidations": [
         {
           "object": "NGPhysicalTextFragment 'xx'",
-          "rect": [8, 8, 48, 16],
+          "rect": [8, 8, 48, 32],
           "reason": "selection"
         },
         {
           "object": "NGPhysicalTextFragment 'y'",
-          "rect": [8, 24, 16, 16],
+          "rect": [8, 8, 48, 32],
           "reason": "selection"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-rtl-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-rtl-expected.txt
index 976d307..27aaf261 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-rtl-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-rtl-expected.txt
@@ -19,12 +19,12 @@
       "paintInvalidations": [
         {
           "object": "NGPhysicalTextFragment 'xx'",
-          "rect": [0, 8, 40, 16],
+          "rect": [0, 8, 40, 32],
           "reason": "selection"
         },
         {
           "object": "NGPhysicalTextFragment 'y'",
-          "rect": [24, 24, 16, 16],
+          "rect": [0, 8, 40, 32],
           "reason": "selection"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt
index 241bf07..50593eb3 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt
@@ -19,12 +19,12 @@
       "paintInvalidations": [
         {
           "object": "NGPhysicalTextFragment 'xx'",
-          "rect": [8, 8, 16, 48],
+          "rect": [8, 8, 32, 48],
           "reason": "selection"
         },
         {
           "object": "NGPhysicalTextFragment 'y'",
-          "rect": [24, 8, 16, 16],
+          "rect": [8, 8, 32, 48],
           "reason": "selection"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-rl-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-rl-expected.txt
index 9434d15b..50593eb3 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-rl-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-rl-expected.txt
@@ -19,12 +19,12 @@
       "paintInvalidations": [
         {
           "object": "NGPhysicalTextFragment 'xx'",
-          "rect": [24, 8, 16, 48],
+          "rect": [8, 8, 32, 48],
           "reason": "selection"
         },
         {
           "object": "NGPhysicalTextFragment 'y'",
-          "rect": [8, 8, 16, 16],
+          "rect": [8, 8, 32, 48],
           "reason": "selection"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/japanese-rl-selection-clear-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/japanese-rl-selection-clear-expected.txt
index 9810f141..83917c0d 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/japanese-rl-selection-clear-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/japanese-rl-selection-clear-expected.txt
@@ -18,63 +18,73 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment '\u305B\u3063\u304B\u304F\u898B\u3064\u3051\u305F\u3059\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B'",
-          "rect": [745, 123, 32, 404],
-          "reason": "selection"
-        },
-        {
           "object": "NGPhysicalTextFragment '\u3042\u3063\u305F\u304B\u5FD8\u308C\u3066\u3057\u307E\u3063\u305F\u7D4C\u9A13\u306F\u3042\u308A\u307E\u3059\u304B'",
-          "rect": [713, 123, 32, 404],
-          "reason": "selection"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u306A\u3089\u30BF\u30A4\u30C8\u30EB\u3068\u30A2\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F'",
-          "rect": [681, 123, 32, 404],
+          "rect": [334, 123, 443, 404],
           "reason": "selection"
         },
         {
           "object": "NGPhysicalTextFragment '\u3057\u305F\u30A6\u30A7\u30D6\u30DA\u30FC\u30B8\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u304B\u3089\u3082\u691C\u7D22'",
-          "rect": [649, 123, 32, 404],
-          "reason": "selection"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002\u305B\u3063\u304B\u304F\u898B\u3064\u3051\u305F\u3059'",
-          "rect": [617, 123, 32, 404],
-          "reason": "selection"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B\u3042\u3063\u305F\u304B\u5FD8\u308C\u3066\u3057\u307E'",
-          "rect": [585, 123, 32, 404],
-          "reason": "selection"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F\u3057\u305F\u30A6\u30A7\u30D6\u30DA\u30FC\u30B8'",
-          "rect": [521, 123, 32, 404],
-          "reason": "selection"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u304B\u3089\u3082\u691C\u7D22\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E'",
-          "rect": [489, 123, 32, 404],
+          "rect": [334, 123, 443, 404],
           "reason": "selection"
         },
         {
           "object": "NGPhysicalTextFragment '\u3059\u3002\u8A2A\u554F\u3057\u305F\u30A6\u30A7\u30D6\u30DA\u30FC\u30B8\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u304B'",
-          "rect": [457, 123, 32, 404],
+          "rect": [334, 123, 443, 404],
           "reason": "selection"
         },
         {
-          "object": "NGPhysicalTextFragment '\u3089\u3082\u691C\u7D22\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002\u305B\u3063\u304B\u304F\u898B'",
-          "rect": [425, 123, 32, 404],
+          "object": "NGPhysicalTextFragment '\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002\u305B\u3063\u304B\u304F\u898B\u3064\u3051\u305F\u3059'",
+          "rect": [334, 123, 443, 404],
           "reason": "selection"
         },
         {
-          "object": "NGPhysicalTextFragment '\u3064\u3051\u305F\u3059\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B\u3042\u3063\u305F\u304B\u5FD8'",
-          "rect": [393, 123, 32, 399],
+          "object": "NGPhysicalTextFragment '\u305B\u3063\u304B\u304F\u898B\u3064\u3051\u305F\u3059\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B'",
+          "rect": [334, 123, 443, 404],
           "reason": "selection"
         },
         {
           "object": "NGPhysicalTextFragment '\u3063\u305F\u7D4C\u9A13\u306F\u3042\u308A\u307E\u3059\u304B \u306A\u3089\u30BF\u30A4\u30C8\u30EB\u3068\u30A2'",
-          "rect": [553, 123, 32, 388],
+          "rect": [334, 123, 443, 404],
+          "reason": "selection"
+        },
+        {
+          "object": "NGPhysicalTextFragment '\u3064\u3051\u305F\u3059\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B\u3042\u3063\u305F\u304B\u5FD8'",
+          "rect": [334, 123, 443, 404],
+          "reason": "selection"
+        },
+        {
+          "object": "NGPhysicalTextFragment '\u306A\u3089\u30BF\u30A4\u30C8\u30EB\u3068\u30A2\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F'",
+          "rect": [334, 123, 443, 404],
+          "reason": "selection"
+        },
+        {
+          "object": "NGPhysicalTextFragment '\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u304B\u3089\u3082\u691C\u7D22\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E'",
+          "rect": [334, 123, 443, 404],
+          "reason": "selection"
+        },
+        {
+          "object": "NGPhysicalTextFragment '\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B\u3042\u3063\u305F\u304B\u5FD8\u308C\u3066\u3057\u307E'",
+          "rect": [334, 123, 443, 404],
+          "reason": "selection"
+        },
+        {
+          "object": "NGPhysicalTextFragment '\u3089\u3082\u691C\u7D22\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002\u305B\u3063\u304B\u304F\u898B'",
+          "rect": [334, 123, 443, 404],
+          "reason": "selection"
+        },
+        {
+          "object": "NGPhysicalTextFragment '\u308C\u3066\u3057\u307E\u3063\u305F\u7D4C\u9A13\u306F\u3042\u308A\u307E\u3059\u304B \u306A\u3089\u30BF\u30A4'",
+          "rect": [334, 123, 443, 404],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment '\u30C8\u30EB\u3068\u30A2\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F'",
+          "rect": [334, 123, 443, 404],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment '\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F\u3057\u305F\u30A6\u30A7\u30D6\u30DA\u30FC\u30B8'",
+          "rect": [334, 123, 443, 404],
           "reason": "selection"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt
index b164aeb8..08797be0c 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt
@@ -23,14 +23,14 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment '\u00A0'",
-          "rect": [8, 8, 97, 100],
-          "reason": "selection"
+          "object": "NGPhysicalTextFragment 'not run'",
+          "rect": [8, 8, 97, 200],
+          "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'not run'",
-          "rect": [8, 108, 49, 100],
-          "reason": "disappeared"
+          "object": "NGPhysicalTextFragment '\u00A0'",
+          "rect": [8, 8, 97, 200],
+          "reason": "selection"
         }
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt
index af9fde84..cc32a464 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt
@@ -18,38 +18,38 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'sagittis aliquam nunc. Nullam pharetra molestie eros. Donec tempus purus ut ligula. Phasellus non nisl. Etiam eu mauris.'",
-          "rect": [8, 144, 756, 19],
-          "reason": "full"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'laoreet feugiat. Phasellus mollis pulvinar mi. Etiam ut neque sed eros egestas laoreet. Vestibulum ullamcorper, nulla non'",
-          "rect": [8, 84, 751, 19],
-          "reason": "full"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'pellentesque cursus. Proin vitae nulla. Vivamus in ipsum. Etiam mi. Nam malesuada purus in sem. Sed eget elit vel erat'",
-          "rect": [8, 64, 748, 19],
+          "object": "NGPhysicalTextFragment 'Curabitur a velit.'",
+          "rect": [8, 44, 756, 139],
           "reason": "full"
         },
         {
           "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse placerat. Morbi tristique. Mauris eu lacus sed felis'",
-          "rect": [8, 44, 744, 19],
+          "rect": [8, 44, 756, 139],
           "reason": "full"
         },
         {
           "object": "NGPhysicalTextFragment 'fermentum ut, tortor. Sed rhoncus. Quisque enim metus, luctus tincidunt, vestibulum eu, vestibulum eu, libero. Mauris'",
-          "rect": [8, 124, 740, 19],
+          "rect": [8, 44, 756, 139],
           "reason": "full"
         },
         {
           "object": "NGPhysicalTextFragment 'feugiat molestie, mi lorem bibendum leo, ac gravida orci nunc nec nulla. Nunc nunc lorem, rhoncus et, rutrum ac,'",
-          "rect": [8, 104, 713, 19],
+          "rect": [8, 44, 756, 139],
           "reason": "full"
         },
         {
-          "object": "NGPhysicalTextFragment 'Curabitur a velit.'",
-          "rect": [8, 164, 106, 19],
+          "object": "NGPhysicalTextFragment 'laoreet feugiat. Phasellus mollis pulvinar mi. Etiam ut neque sed eros egestas laoreet. Vestibulum ullamcorper, nulla non'",
+          "rect": [8, 44, 756, 139],
+          "reason": "full"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'pellentesque cursus. Proin vitae nulla. Vivamus in ipsum. Etiam mi. Nam malesuada purus in sem. Sed eget elit vel erat'",
+          "rect": [8, 44, 756, 139],
+          "reason": "full"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'sagittis aliquam nunc. Nullam pharetra molestie eros. Donec tempus purus ut ligula. Phasellus non nisl. Etiam eu mauris.'",
+          "rect": [8, 44, 756, 139],
           "reason": "full"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt
index da208b84..eb3f1e6 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt
@@ -19,12 +19,12 @@
       "paintInvalidations": [
         {
           "object": "NGPhysicalTextFragment 'After change'",
-          "rect": [18, 130, 251, 19],
+          "rect": [18, 130, 251, 39],
           "reason": "appeared"
         },
         {
           "object": "NGPhysicalTextFragment 'Find-in-page 'findme', then click here)'",
-          "rect": [18, 150, 240, 19],
+          "rect": [18, 130, 251, 39],
           "reason": "disappeared"
         },
         {
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/vertical-rl-as-paint-container-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/vertical-rl-as-paint-container-expected.txt
index dfb202b..b411417 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/vertical-rl-as-paint-container-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/vertical-rl-as-paint-container-expected.txt
@@ -25,22 +25,22 @@
       "paintInvalidations": [
         {
           "object": "NGPhysicalTextFragment 'Lorem ipsum dolor'",
-          "rect": [580, 0, 20, 340],
+          "rect": [520, 0, 80, 340],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment 'adipiscing elit.'",
-          "rect": [520, 0, 20, 320],
+          "rect": [520, 0, 80, 340],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment 'consectetur'",
-          "rect": [540, 0, 20, 220],
+          "rect": [520, 0, 80, 340],
           "reason": "style change"
         },
         {
           "object": "NGPhysicalTextFragment 'sit amet,'",
-          "rect": [560, 0, 20, 180],
+          "rect": [520, 0, 80, 340],
           "reason": "style change"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt
index cbab591..5f41eca 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt
@@ -133,53 +133,53 @@
           "reason": "incremental"
         },
         {
-          "object": "NGPhysicalTextFragment 'GGGG HHHH IIII JJJJ'",
-          "rect": [581, 8, 68, 561],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'GGGG HHHH IIII JJJJ'",
-          "rect": [181, 8, 68, 561],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'KKKK LLLL MMMM'",
-          "rect": [510, 8, 68, 560],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'KKKK LLLL MMMM'",
-          "rect": [110, 8, 68, 560],
-          "reason": "geometry"
-        },
-        {
           "object": "NGPhysicalTextFragment 'AAAA BBBB CCCC'",
-          "rect": [723, 8, 68, 519],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AAAA BBBB CCCC'",
-          "rect": [323, 8, 68, 519],
+          "rect": [439, 8, 352, 561],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'DDDD EEEE FFFF'",
-          "rect": [652, 8, 68, 482],
+          "rect": [439, 8, 352, 561],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'GGGG HHHH IIII JJJJ'",
+          "rect": [439, 8, 352, 561],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'KKKK LLLL MMMM'",
+          "rect": [439, 8, 352, 561],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'NNNN'",
+          "rect": [439, 8, 352, 561],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'AAAA BBBB CCCC'",
+          "rect": [39, 8, 352, 561],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'DDDD EEEE FFFF'",
-          "rect": [252, 8, 68, 482],
+          "rect": [39, 8, 352, 561],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'GGGG HHHH IIII JJJJ'",
+          "rect": [39, 8, 352, 561],
+          "reason": "geometry"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'KKKK LLLL MMMM'",
+          "rect": [39, 8, 352, 561],
           "reason": "geometry"
         },
         {
           "object": "NGPhysicalTextFragment 'NNNN'",
-          "rect": [439, 8, 68, 172],
-          "reason": "geometry"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'NNNN'",
-          "rect": [39, 8, 68, 172],
+          "rect": [39, 8, 352, 561],
           "reason": "geometry"
         }
       ]
diff --git a/third_party/blink/web_tests/virtual/intersection-observer-v2/http/tests/intersection-observer/v2/README.txt b/third_party/blink/web_tests/virtual/intersection-observer-v2/http/tests/intersection-observer/v2/README.txt
deleted file mode 100644
index bc9ca94..0000000
--- a/third_party/blink/web_tests/virtual/intersection-observer-v2/http/tests/intersection-observer/v2/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-This is for testing IntersectionObserverV2 -- now with occlusion detection!
diff --git a/third_party/blink/web_tests/virtual/intersection-observer-v2/intersection-observer/v2/README.txt b/third_party/blink/web_tests/virtual/intersection-observer-v2/intersection-observer/v2/README.txt
deleted file mode 100644
index bc9ca94..0000000
--- a/third_party/blink/web_tests/virtual/intersection-observer-v2/intersection-observer/v2/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-This is for testing IntersectionObserverV2 -- now with occlusion detection!
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 09d26393..b2b7398 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3603,9 +3603,11 @@
     method getTargetRanges
 interface IntersectionObserver
     attribute @@toStringTag
+    getter delay
     getter root
     getter rootMargin
     getter thresholds
+    getter trackVisibility
     method constructor
     method disconnect
     method observe
@@ -3617,6 +3619,7 @@
     getter intersectionRatio
     getter intersectionRect
     getter isIntersecting
+    getter isVisible
     getter rootBounds
     getter target
     getter time
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index e6cadb2b..c0487d7 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -4214,9 +4214,11 @@
     method getTargetRanges
 interface IntersectionObserver
     attribute @@toStringTag
+    getter delay
     getter root
     getter rootMargin
     getter thresholds
+    getter trackVisibility
     method constructor
     method disconnect
     method observe
@@ -4228,6 +4230,7 @@
     getter intersectionRatio
     getter intersectionRect
     getter isIntersecting
+    getter isVisible
     getter rootBounds
     getter target
     getter time
diff --git a/third_party/closure_compiler/externs/chrome_extensions.js b/third_party/closure_compiler/externs/chrome_extensions.js
index 8800ee7a..6039cc2 100644
--- a/third_party/closure_compiler/externs/chrome_extensions.js
+++ b/third_party/closure_compiler/externs/chrome_extensions.js
@@ -10343,193 +10343,6 @@
 
 /**
  * @const
- * @see https://cs.chromium.org/chromium/src/extensions/common/api/bluetooth_private.idl
- */
-chrome.bluetoothPrivate = {};
-
-
-
-/** @constructor */
-chrome.bluetoothPrivate.PairingEvent = function() {};
-
-
-/** @type {string} */
-chrome.bluetoothPrivate.PairingEvent.prototype.pairing;
-
-
-/** @type {!chrome.bluetooth.Device} */
-chrome.bluetoothPrivate.PairingEvent.prototype.device;
-
-
-/** @type {string|undefined} */
-chrome.bluetoothPrivate.PairingEvent.prototype.pincode;
-
-
-/** @type {number|undefined} */
-chrome.bluetoothPrivate.PairingEvent.prototype.passkey;
-
-
-/** @type {number|undefined} */
-chrome.bluetoothPrivate.PairingEvent.prototype.enteredKey;
-
-
-/**
- * @typedef {{
- *   name: (string|undefined),
- *   powered: (boolean|undefined),
- *   discoverable: (boolean|undefined)
- * }}
- */
-chrome.bluetoothPrivate.NewAdapterState;
-
-
-/**
- * @typedef {{
- *   device: !chrome.bluetooth.Device,
- *   response: (string|undefined),
- *   pincode: (string|undefined),
- *   passkey: (number|undefined),
- *   enteredKey: (number|undefined)
- * }}
- */
-chrome.bluetoothPrivate.SetPairingResponseOptions;
-
-
-/**
- * @param {!chrome.bluetoothPrivate.NewAdapterState} adapterState
- * @param {function()} callback
- * @return {undefined}
- */
-chrome.bluetoothPrivate.setAdapterState = function(adapterState, callback) {};
-
-
-/**
- * @param {!chrome.bluetoothPrivate.SetPairingResponseOptions} options
- * @param {function()} callback
- * @return {undefined}
- */
-chrome.bluetoothPrivate.setPairingResponse = function(options, callback) {};
-
-
-/**
- * @param {string} deviceAddress
- * @param {function():void=} callback
- */
-chrome.bluetoothPrivate.disconnectAll = function(deviceAddress, callback) {};
-
-
-/**
- * @param {string} deviceAddress
- * @param {function():void=} callback
- * @return {undefined}
- */
-chrome.bluetoothPrivate.forgetDevice = function(deviceAddress, callback) {};
-
-
-/**
- * @typedef {{
- *   transport: (!chrome.bluetoothPrivate.TransportType|undefined),
- *   uuids: ((string|!Array<string>)|undefined),
- *   rssi: (number|undefined),
- *   pathloss: (number|undefined)
- * }}
- */
-chrome.bluetoothPrivate.DiscoveryFilter;
-
-
-/**
- * Set or clear discovery filter.
- * @param {!chrome.bluetoothPrivate.DiscoveryFilter} discoveryFilter
- * @param {function():void=} callback
- */
-chrome.bluetoothPrivate.setDiscoveryFilter = function(
-    discoveryFilter, callback) {};
-
-
-/**
- * Event whose listeners take a PairingEvent parameter.
- * @interface
- * @extends {ChromeBaseEvent<function(!chrome.bluetoothPrivate.PairingEvent)>}
- */
-chrome.bluetoothPrivate.PairingEventEvent = function() {};
-
-
-/** @type {!chrome.bluetoothPrivate.PairingEventEvent} */
-chrome.bluetoothPrivate.onPairing;
-
-
-/**
- * @param {string} deviceAddress
- * @param {function(number, string): void=} opt_callback
- */
-chrome.bluetoothPrivate.pair = function(deviceAddress, opt_callback) {};
-
-
-/**
- * @enum {string}
- * @see https://developer.chrome.com/extensions/bluetoothPrivate#type-PairingResponse
- */
-chrome.bluetoothPrivate.PairingResponse = {
-  CONFIRM: '',
-  REJECT: '',
-  CANCEL: '',
-};
-
-
-/**
- * @enum {string}
- * @see https://developer.chrome.com/extensions/bluetoothPrivate#type-PairingEventType
- */
-chrome.bluetoothPrivate.PairingEventType = {
-  REQUEST_PINCODE: '',
-  DISPLAY_PINCODE: '',
-  REQUEST_PASSKEY: '',
-  DISPLAY_PASSKEY: '',
-  KEYS_ENTERED: '',
-  CONFIRM_PASSKEY: '',
-  REQUEST_AUTHORIZATION: '',
-  COMPLETE: '',
-};
-
-
-/**
- * @enum {string}
- * @see https://developer.chrome.com/extensions/bluetoothPrivate#type-ConnectResultType
- */
-chrome.bluetoothPrivate.ConnectResultType = {
-  ALREADY_CONNECTED: '',
-  ATTRIBUTE_LENGTH_INVALID: '',
-  AUTH_CANCELED: '',
-  AUTH_FAILED: '',
-  AUTH_REJECTED: '',
-  AUTH_TIMEOUT: '',
-  CONNECTION_CONGESTED: '',
-  FAILED: '',
-  IN_PROGRESS: '',
-  INSUFFICIENT_ENCRYPTION: '',
-  OFFSET_INVALID: '',
-  READ_NOT_PERMITTED: '',
-  REQUEST_NOT_SUPPORTED: '',
-  SUCCESS: '',
-  UNKNOWN_ERROR: '',
-  UNSUPPORTED_DEVICE: '',
-  WRITE_NOT_PERMITTED: '',
-};
-
-
-/**
- * @enum {string}
- * @see https://developer.chrome.com/extensions/bluetoothPrivate#type-TransportType
- */
-chrome.bluetoothPrivate.TransportType = {
-  LE: '',
-  BREDR: '',
-  DUAL: '',
-};
-
-
-/**
- * @const
  * @see http://goo.gl/XmVdHm
  */
 chrome.inlineInstallPrivate = {};
diff --git a/tools/binary_size/libsupersize/diff.py b/tools/binary_size/libsupersize/diff.py
index 2a0b9601..9cf6e2a 100644
--- a/tools/binary_size/libsupersize/diff.py
+++ b/tools/binary_size/libsupersize/diff.py
@@ -113,8 +113,10 @@
   # Create a DeltaSymbol to represent the zero'd out padding of matched symbols.
   for section_name, padding in padding_by_section_name.iteritems():
     if padding != 0:
-      after_sym = models.Symbol(section_name, padding,
-                                name="** aggregate padding of diff'ed symbols")
+      after_sym = models.Symbol(
+          section_name,
+          padding,
+          name="Overhead: aggregate padding of diff'ed symbols")
       after_sym.padding = padding
       all_deltas.append(models.DeltaSymbol(None, after_sym))
 
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index a63f7de..8b2cb76d 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -35,7 +35,7 @@
   CLANG_REVISION = 'HEAD'
 
 # This is incremented when pushing a new build of Clang at the same revision.
-CLANG_SUB_REVISION=1
+CLANG_SUB_REVISION=2
 
 PACKAGE_VERSION = "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION)
 
@@ -535,6 +535,8 @@
                      # Statically link MSVCRT to avoid DLL dependencies.
                      '-DLLVM_USE_CRT_RELEASE=MT',
                      '-DCLANG_PLUGIN_SUPPORT=OFF',
+                     '-DCLANG_ENABLE_STATIC_ANALYZER=OFF',
+                     '-DCLANG_ENABLE_ARCMT=OFF',
                      ]
 
   if sys.platform != 'win32':
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 4c17ccfd..e055688 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -51368,6 +51368,7 @@
 <enum name="SystemNotificationActionType">
   <int value="0" label="Download paused"/>
   <int value="1" label="Download resumed"/>
+  <int value="2" label="Download canceled"/>
 </enum>
 
 <enum name="SystemNotificationType">
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 544a19f..968d173 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -931,27 +931,20 @@
 
   return test_args
 
+
 def generate_non_telemetry_args(test_name):
   # --gtest-benchmark-name so the benchmark name is consistent with the test
   # step's name. This is not always the same as the test binary's name (see
   # crbug.com/870692).
-  # --non-telemetry tells run_performance_tests.py that this test needs
-  #   to be executed differently
-  # --migrated-test tells run_performance_test_wrapper that this has
-  #   non-telemetry test has been migrated to the new recipe.
   return [
     '--gtest-benchmark-name', test_name,
-    '--non-telemetry=true',
-    '--migrated-test=true'
   ]
 
+
 def generate_performance_test(tester_config, test):
   isolate_name = test['isolate']
 
-  # Check to see if the name is different than the isolate
-  test_suite = isolate_name
-  if test.get('test_suite', False):
-    test_suite = test['test_suite']
+  test_suite = test.get('test_suite', isolate_name)
 
   if test.get('telemetry', True):
     test_args = generate_telemetry_args(tester_config)
diff --git a/tools/perf/core/perf_data_generator_unittest.py b/tools/perf/core/perf_data_generator_unittest.py
index 9925042..2e6b27e2 100644
--- a/tools/perf/core/perf_data_generator_unittest.py
+++ b/tools/perf/core/perf_data_generator_unittest.py
@@ -72,8 +72,7 @@
     expected_generated_test = {
         'override_compile_targets': ['angle_perftest'],
         'isolate_name': 'angle_perftest',
-        'args': ['--gtest-benchmark-name', 'angle_perftest',
-                 '--non-telemetry=true', '--migrated-test=true'],
+        'args': ['--gtest-benchmark-name', 'angle_perftest'],
         'trigger_script': {
           'args': [
             '--multiple-dimension-script-verbose',
@@ -121,7 +120,8 @@
         'override_compile_targets': ['performance_test_suite'],
         'isolate_name': 'performance_test_suite',
         'args': ['-v', '--browser=android-webview', '--upload-results',
-                 '--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk',
+                 '--webview-embedder-apk=../../out/Release'
+                 '/apks/SystemWebViewShell.apk',
                  '--run-ref-build',
                  '--test-shard-map-filename=shard_map.json'],
         'trigger_script': {
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index f4cfa59e..9da43a6 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -1217,9 +1217,8 @@
     return;
 
   bool inline_settings_visible = !settings_row_->visible();
-
-  if (!inline_settings_visible && block_all_button_->checked())
-    MessageCenter::Get()->DisableNotification(notification_id());
+  bool disable_notification =
+      settings_row_->visible() && block_all_button_->checked();
 
   settings_row_->SetVisible(inline_settings_visible);
   content_row_->SetVisible(!inline_settings_visible);
@@ -1241,6 +1240,11 @@
 
   Layout();
   SchedulePaint();
+
+  // Call DisableNotification() at the end, because |this| can be deleted at any
+  // point after it's called.
+  if (disable_notification)
+    MessageCenter::Get()->DisableNotification(notification_id());
 }
 
 void NotificationViewMD::UpdateCornerRadius(int top_radius, int bottom_radius) {
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h
index 586d8aa..9ec098ae 100644
--- a/ui/message_center/views/notification_view_md.h
+++ b/ui/message_center/views/notification_view_md.h
@@ -225,6 +225,8 @@
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, InlineSettings);
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateViewsOrderingTest);
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestDeleteOnToggleExpanded);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest,
+                           TestDeleteOnDisableNotification);
 
   friend class NotificationViewMDTest;
 
diff --git a/ui/message_center/views/notification_view_md_unittest.cc b/ui/message_center/views/notification_view_md_unittest.cc
index 3549f1a..bf98dcaf 100644
--- a/ui/message_center/views/notification_view_md_unittest.cc
+++ b/ui/message_center/views/notification_view_md_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "ui/message_center/views/notification_view_md.h"
 
+#include <memory>
+
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -14,6 +16,7 @@
 #include "ui/events/test/event_generator.h"
 #include "ui/gfx/canvas.h"
 #include "ui/message_center/message_center.h"
+#include "ui/message_center/message_center_observer.h"
 #include "ui/message_center/public/cpp/message_center_constants.h"
 #include "ui/message_center/views/bounded_label.h"
 #include "ui/message_center/views/notification_control_buttons_view.h"
@@ -102,7 +105,8 @@
 class NotificationViewMDTest
     : public views::ViewsTestBase,
       public views::ViewObserver,
-      public message_center::MessageView::SlideObserver {
+      public message_center::MessageView::SlideObserver,
+      public message_center::MessageCenterObserver {
  public:
   NotificationViewMDTest();
   ~NotificationViewMDTest() override;
@@ -125,11 +129,19 @@
   // Overridden from message_center::MessageView::Observer:
   void OnSlideChanged(const std::string& notification_id) override {}
 
+  // Overridden from message_center::MessageCenterObserver:
+  void OnNotificationRemoved(const std::string& notification_id,
+                             bool by_user) override;
+
   void set_delete_on_preferred_size_changed(
       bool delete_on_preferred_size_changed) {
     delete_on_preferred_size_changed_ = delete_on_preferred_size_changed;
   }
 
+  void set_delete_on_notification_removed(bool delete_on_notification_removed) {
+    delete_on_notification_removed_ = delete_on_notification_removed;
+  }
+
  protected:
   const gfx::Image CreateTestImage(int width, int height) const;
   const SkBitmap CreateBitmap(int width, int height) const;
@@ -150,6 +162,7 @@
   views::View* GetCloseButton();
 
   bool delete_on_preferred_size_changed_ = false;
+  bool delete_on_notification_removed_ = false;
   std::set<std::string> removed_ids_;
   scoped_refptr<NotificationTestDelegate> delegate_;
   std::unique_ptr<NotificationViewMD> notification_view_;
@@ -188,10 +201,15 @@
 
   std::unique_ptr<Notification> notification = CreateSimpleNotification();
   UpdateNotificationViews(*notification);
+
+  MessageCenter::Get()->AddObserver(this);
 }
 
 void NotificationViewMDTest::TearDown() {
-  DCHECK(notification_view_ || delete_on_preferred_size_changed_);
+  MessageCenter::Get()->RemoveObserver(this);
+
+  DCHECK(notification_view_ || delete_on_preferred_size_changed_ ||
+         delete_on_notification_removed_);
   if (notification_view_) {
     notification_view_->SetInkDropMode(MessageView::InkDropMode::OFF);
     notification_view_->RemoveObserver(this);
@@ -213,6 +231,16 @@
   widget()->SetSize(notification_view()->GetPreferredSize());
 }
 
+void NotificationViewMDTest::OnNotificationRemoved(
+    const std::string& notification_id,
+    bool by_user) {
+  if (delete_on_notification_removed_) {
+    widget()->CloseNow();
+    notification_view_.reset();
+    return;
+  }
+}
+
 const gfx::Image NotificationViewMDTest::CreateTestImage(int width,
                                                          int height) const {
   return gfx::Image::CreateFrom1xBitmap(CreateBitmap(width, height));
@@ -1115,4 +1143,19 @@
                                      DummyEvent());
 }
 
+TEST_F(NotificationViewMDTest, TestDeleteOnDisableNotification) {
+  std::unique_ptr<Notification> notification = CreateSimpleNotification();
+  notification->set_type(NOTIFICATION_TYPE_SIMPLE);
+  UpdateNotificationViews(*notification);
+
+  notification_view()->OnSettingsButtonPressed(DummyEvent());
+  notification_view()->block_all_button_->NotifyClick(DummyEvent());
+
+  // After DisableNotification() is called, |notification_view| can be deleted.
+  // https://crbug.com/924922
+  set_delete_on_notification_removed(true);
+  notification_view()->ButtonPressed(notification_view()->settings_done_button_,
+                                     DummyEvent());
+}
+
 }  // namespace message_center
diff --git a/ui/webui/resources/cr_elements/cr_icons_css.html b/ui/webui/resources/cr_elements/cr_icons_css.html
index 07e27e4..a686eea 100644
--- a/ui/webui/resources/cr_elements/cr_icons_css.html
+++ b/ui/webui/resources/cr_elements/cr_icons_css.html
@@ -41,56 +41,64 @@
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-back {
         background-image: url(../images/icon_arrow_back.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-back {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-back {
         background-image: url(../images/dark/icon_arrow_back.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel {
         background-image: url(../images/icon_cancel.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-cancel {
         background-image: url(../images/dark/icon_cancel.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-cancel {
         background-image: url(../images/icon_toolbar_cancel.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-cancel {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-cancel {
         background-image: url(../images/dark/icon_toolbar_cancel.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-clear {
         background-image: url(../images/icon_clear.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-clear {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-clear {
         background-image: url(../images/dark/icon_clear.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-gray {
         background-image: url(../images/icon_delete_gray.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-gray {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-delete-gray {
         background-image: url(../images/dark/icon_delete_gray.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-picture-delete {
         background-image: url(../images/icon_picture_delete.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-picture-delete {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-picture-delete {
         background-image: url(../images/dark/icon_picture_delete.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-less {
         background-image: url(../images/icon_expand_less.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-less {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-less {
         background-image: url(../images/dark/icon_expand_less.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-more {
         background-image: url(../images/icon_expand_more.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-more {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-expand-more {
         background-image: url(../images/dark/icon_expand_more.svg);
       }
 
@@ -102,63 +110,72 @@
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-menu {
         background-image: url(../images/icon_toolbar_menu.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-menu {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-toolbar-menu {
         background-image: url(../images/dark/icon_toolbar_menu.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-more-vert {
         background-image: url(../images/icon_more_vert.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-more-vert {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-more-vert {
         background-image: url(../images/dark/icon_more_vert.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-refresh {
         background-image: url(../images/icon_refresh.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-refresh {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-refresh {
         background-image: url(../images/dark/icon_refresh.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-settings {
         background-image: url(../images/icon_settings.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-settings {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-settings {
         background-image: url(../images/dark/icon_settings.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-search {
         background-image: url(../images/icon_search.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-search {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-search {
         background-image: url(../images/dark/icon_search.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-dropdown {
         background-image: url(../images/icon_arrow_dropdown.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-dropdown {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-arrow-dropdown {
         background-image: url(../images/dark/icon_arrow_dropdown.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).subpage-arrow {
         background-image: url(../images/arrow_right.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).subpage-arrow {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).subpage-arrow {
         background-image: url(../images/dark/arrow_right.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility {
         background-image: url(../images/icon_visibility.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility {
         background-image: url(../images/dark/icon_visibility.svg);
       }
 
       :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility-off {
         background-image: url(../images/icon_visibility_off.svg);
       }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility-off {
+      :host-context([dark])
+          :-webkit-any(paper-icon-button-light, .cr-icon).icon-visibility-off {
         background-image: url(../images/dark/icon_visibility_off.svg);
       }
     </style>
diff --git a/ui/webui/resources/cr_elements_images.grdp b/ui/webui/resources/cr_elements_images.grdp
index 6ac69e4..c80227d4 100644
--- a/ui/webui/resources/cr_elements_images.grdp
+++ b/ui/webui/resources/cr_elements_images.grdp
@@ -9,8 +9,52 @@
            file="images/arrow_right.svg" type="BINDATA" compress="gzip" />
   <include name="IDR_WEBUI_IMAGES_DARK_ARROW_DOWN"
            file="images/dark/arrow_down.svg" type="BINDATA" compress="gzip" />
-  <include name="IDR_WEBUI_IMAGES_OPEN_IN_NEW"
-           file="images/open_in_new.svg" type="BINDATA" compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ARROW_RIGHT"
+           file="images/dark/arrow_right.svg" type="BINDATA" compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_ARROW_BACK"
+           file="images/dark/icon_arrow_back.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_ARROW_DROPDOWN"
+           file="images/dark/icon_arrow_dropdown.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_CANCEL"
+           file="images/dark/icon_cancel.svg" type="BINDATA" compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_CLEAR"
+           file="images/dark/icon_clear.svg" type="BINDATA" compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_DELETE_GRAY"
+           file="images/dark/icon_delete_gray.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_EXPAND_LESS"
+           file="images/dark/icon_expand_less.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_EXPAND_MORE"
+           file="images/dark/icon_expand_more.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_MORE_VERT"
+           file="images/dark/icon_more_vert.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_PICTURE_DELETE"
+           file="images/dark/icon_picture_delete.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_REFRESH"
+           file="images/dark/icon_refresh.svg" type="BINDATA" compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_SETTINGS"
+           file="images/dark/icon_settings.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_SEARCH"
+           file="images/dark/icon_search.svg" type="BINDATA" compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_TOOLBAR_CANCEL"
+           file="images/dark/icon_toolbar_cancel.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_TOOLBAR_MENU"
+           file="images/dark/icon_toolbar_menu.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_VISIBILITY"
+           file="images/dark/icon_visibility.svg" type="BINDATA"
+           compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_DARK_ICON_VISIBILITY_OFF"
+           file="images/dark/icon_visibility_off.svg" type="BINDATA"
+           compress="gzip" />
   <include name="IDR_WEBUI_IMAGES_ICON_ARROW_BACK"
            file="images/icon_arrow_back.svg" type="BINDATA" compress="gzip" />
   <include name="IDR_WEBUI_IMAGES_ICON_ARROW_DROPDOWN"
@@ -31,13 +75,14 @@
   <include name="IDR_WEBUI_IMAGES_ICON_MORE_VERT"
            file="images/icon_more_vert.svg" type="BINDATA" compress="gzip" />
   <include name="IDR_WEBUI_IMAGES_ICON_PICTURE_DELETE"
-           file="images/icon_picture_delete.svg" type="BINDATA" compress="gzip" />
+           file="images/icon_picture_delete.svg" type="BINDATA"
+           compress="gzip" />
   <include name="IDR_WEBUI_IMAGES_ICON_REFRESH"
            file="images/icon_refresh.svg" type="BINDATA" compress="gzip" />
-  <include name="IDR_WEBUI_IMAGES_ICON_SETTINGS"
-           file="images/icon_settings.svg" type="BINDATA" compress="gzip" />
   <include name="IDR_WEBUI_IMAGES_ICON_SEARCH"
            file="images/icon_search.svg" type="BINDATA" compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_ICON_SETTINGS"
+           file="images/icon_settings.svg" type="BINDATA" compress="gzip" />
   <include name="IDR_WEBUI_IMAGES_ICON_TOOLBAR_CANCEL"
            file="images/icon_toolbar_cancel.svg" type="BINDATA"
            compress="gzip" />
@@ -48,6 +93,8 @@
   <include name="IDR_WEBUI_IMAGES_ICON_VISIBILITY_OFF"
            file="images/icon_visibility_off.svg" type="BINDATA"
            compress="gzip" />
+  <include name="IDR_WEBUI_IMAGES_OPEN_IN_NEW"
+           file="images/open_in_new.svg" type="BINDATA" compress="gzip" />
   <if expr="chromeos">
     <include name="IDR_CR_ELEMENTS_CAMERA_ALT_ICON_SVG"
              file="cr_elements/chromeos/cr_picture/camera_alt_icon.svg"