diff --git a/DEPS b/DEPS
index 60bc1d7..6270b75 100644
--- a/DEPS
+++ b/DEPS
@@ -129,11 +129,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '29c1c8029a52f95250180b58f13c639dd6c59b39',
+  'skia_revision': 'c0bd9f9fe533a7b8644392240c1250195aaee537',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '2723b1866729248e4e384c440dd1b07c0bad3646',
+  'v8_revision': 'b80da604362f132504ddab67085232980e29aa02',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -141,11 +141,11 @@
   # 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': 'cb8f677cbfb4b6c70b170322920644f51b0f3722',
+  'angle_revision': 'c9a9cfcca1763743d89e0954c7710e77f339bfd2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'ea1b0983c7b43146e098498e41438075772da018',
+  'swiftshader_revision': 'b328e0d3c3196acc4515b2abf4c79661ba8eee66',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -196,7 +196,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '429d9b410d9caa64ee9c1e69c1e0a0ee089f5a5b',
+  'catapult_revision': 'e8240283b8f09f4906dcd539b02024232348a314',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -805,7 +805,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '95b5ef9328dd1dcfb46d23a51c71f8c05a445752',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'd153d1ae1284d0e86ba7dec787dc76f643ece03a',
       'condition': 'checkout_linux',
   },
 
@@ -830,7 +830,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0d8271895be710d8d04130b5dfa96c002cada6c2',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '323487161e02721098b8ce95550ebd0c0e6f56ad',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -865,7 +865,7 @@
   },
 
   'src/third_party/ffmpeg':
-    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'e02fc00c5da42ea5cdf2bf5b9bab93c323a1e698',
+    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '1b9f48f542058549f984d981ef331951559f9cb0',
 
   'src/third_party/flac':
     Var('chromium_git') + '/chromium/deps/flac.git' + '@' + 'af862024c8c8fa0ae07ced05e89013d881b00596',
@@ -1183,7 +1183,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '505f9c976576a0b521a8bba8a9008eab4445a0dd',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '85fd37e47245f4c611f4a4daf6b9dd91a0b82cf5',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1395,7 +1395,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2695bdcbd7bb4f49f17b7802b9a7e989dca1e7ed',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@07ff5e7b4122bf9148ca6e3f60e114b07a1165c4',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index b1313f0..ae9ce9a 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -629,12 +629,18 @@
                   '|/cachestorage/',
     },
     'cast': {
-      'filepath': 'media/cast/'\
-                  '|chrome/browser/extensions/api/cast_streaming/'\
-                  '|chrome/browser/media/cast'\
-                  '|chrome/renderer/media/cast'\
-                  '|chrome/test/data/extensions/api_test/cast_'\
-                  '|content/public/renderer/media_stream_'\
+      'filepath': 'media/cast/' \
+                  '|chrome/browser/extensions/api/cast_streaming/' \
+                  '|chrome/browser/media/cast/' \
+                  '|chrome/browser/media/router/providers/cast/' \
+                  '|chrome/browser/resources/cast/' \
+                  '|chrome/browser/ui/webui/cast/' \
+                  '|chrome/common/media_router/providers/cast/' \
+                  '|chrome/renderer/media/cast/' \
+                  '|chrome/test/data/extensions/api_test/cast/' \
+                  '|chrome/test/data/extensions/api_test/cast_streaming/' \
+                  '|components/mirroring/' \
+                  '|content/public/renderer/media_stream_' \
                   '|content/renderer/media/(media_stream|(.+audio_source))',
     },
     'cast_certificate': {
@@ -872,11 +878,6 @@
     'devtools': {
       'filepath': 'devtools',
     },
-    'dial': {
-      'filepath': 'chrome/(browser|common)/extensions/api/dial' \
-                  '|chrome/browser/media/router/discovery/dial/' \
-                  '|chrome/test/data/extensions/api_test/dial/'
-    },
     'disk_cache': {
       'filepath': 'net/disk_cache/|http_cache',
     },
@@ -1160,8 +1161,8 @@
                   '|media/remoting/',
     },
     'media_router': {
-      'filepath': 'chrome/android/(java|junit)/src/org/chromium/chrome/browser/media/router/' \
-                  '|chrome/android/features/media_router/' \
+      'filepath': 'chrome/android/features/media_router/' \
+                  '|chrome/app/media_router_strings.grdp' \
                   '|chrome/browser/media/router/' \
                   '|chrome/browser/resources/media_router/' \
                   '|chrome/browser/ui/media_router/' \
@@ -1445,10 +1446,11 @@
       'filepath': 'prerender'
     },
     'presentation': {
-      'filepath': 'content/(browser|common|renderer)/presentation/' \
-                  '|third_party/blink/public/platform/modules/presentation/' \
-                  '|third_party/blink/web_tests/presentation/' \
-                  '|third_party/blink/renderer/modules/presentation/'
+      'filepath': 'content/browser/presentation/' \
+                  '|content/public/browser/presentation_' \
+                  '|third_party/blink/public/mojom/presentation/' \
+                  '|third_party/blink/renderer/modules/presentation/' \
+                  '|third_party/blink/web_tests/(virtual/)?presentation/'
     },
     'print_preview': {
       'filepath': 'chrome/browser/resources/print_preview/' \
@@ -1462,6 +1464,18 @@
                   'ios/chrome/browser/reading_list|'\
                   'ios/chrome/browser/ui/reading_list',
     },
+    'remoteplayback': {
+      'filepath': 'chrome/android/features/media_router/java/src/org/chromium/chrome/browser/media/router/FlingingController' \
+                  '|chrome/android/java/src/org/chromium/chrome/browser/media/remote/' \
+                  '|chrome/browser/media/android/remote/' \
+                  '|media/blink/remote_playback' \
+                  '|media/renderers/remote_playback' \
+                  '|third_party/blink/public/platform/modules/remoteplayback/' \
+                  '|third_party/blink/renderer/core/html/media/remote_playback' \
+                  '|third_party/blink/renderer/modules/remoteplayback/' \
+                  '|third_party/blink/web_tests/media/remoteplayback/' \
+                  '|third_party/blink/web_tests/virtual/new-remote-playback-pipeline/'
+    },
     'remoting': {
       'filepath': '^remoting/' \
                   '|^testing/chromoting'
@@ -2124,17 +2138,14 @@
                       'msramek+watch@chromium.org'],
     'bubble': ['hcarmona+bubble@chromium.org'],
     'cache_storage': ['nhiroki@chromium.org'],
-    'cast': ['aburago+watch@chromium.org',
-             'imcheng+watch@chromium.org',
-             'isheriff+watch@chromium.org',
-             'jasonroberts+watch@google.com',
+    'cast': ['jasonroberts+watch@google.com',
              'miu+watch@chromium.org',
+             'mfoltz+watch@chromium.org',
              'pthatcher+watch@chromium.org'],
     'cast_certificate': ['dougsteed+watch@chromium.org',
                          'mfoltz+watch@chromium.org',
                          'ryanchung+watch@chromium.org'],
-    'cast_channel': ['imcheng+watch@chromium.org',
-                     'mfoltz+watch@chromium.org',
+    'cast_channel': ['mfoltz+watch@chromium.org',
                      'ryanchung+watch@chromium.org'],
     'cc': ['cc-bugs@chromium.org'],
     'cc-animation': ['yigu@chromium.org',
@@ -2244,8 +2255,6 @@
                        'odejesush+watch@chromium.org'],
     'devtools': ['devtools-reviews@chromium.org',
                  'pfeldman@chromium.org'],
-    'dial': ['mfoltz+watch@chromium.org',
-             'zhaobin+watch@chromium.org'],
     'disk_cache': ['gavinp+disk@chromium.org'],
     'download': ['dtrainor+watch@chromium.org'],
     'downloads_ui': ['dbeam+watch-downloads-ui@chromium.org',
@@ -2360,13 +2369,11 @@
                    'xhwang+watch@chromium.org'],
     'media_recorder': ['emircan+watch+mediarecorder@chromium.org',
                        'mcasas+mediarecorder@chromium.org'],
-    'media_remoting': ['aburago+watch@chromium.org',
-                       'erickung+watch@chromium.org',
+    'media_remoting': ['erickung+watch@chromium.org',
                        'mfoltz+watch@chromium.org',
                        'miu+watch@chromium.org',
                        'pthatcher+watch@chromium.org'],
-    'media_router': ['imcheng+watch@chromium.org',
-                     'mfoltz+watch@chromium.org',
+    'media_router': ['mfoltz+watch@chromium.org',
                      'pthatcher+watch@chromium.org',
                      'takumif+watch@chromium.org'],
     'media_win': ['media-win-reviews@chromium.org'],
@@ -2465,6 +2472,7 @@
     'print_preview': ['rbpotter@chromium.org'],
     'push_messaging': ['peter@chromium.org'],
     'reading_list': ['stkhapugin@chromium.org'],
+    'remoteplayback': ['mfoltz+watch@chromium.org'],
     'remoting': ['chromoting-reviews@chromium.org'],
     'rlz_id': ['gab+watch@chromium.org',
                'robertshield+watch@chromium.org'],
@@ -2534,6 +2542,7 @@
                'tzik@chromium.org'],
     'tab_alert_indicators': ['miu+watch@chromium.org'],
     'tab_capture': ['miu+watch@chromium.org',
+                    'mfoltz+watch@chromium.org',
                     'pthatcher+watch@chromium.org'],
     'tab_contents': ['ajwong+watch@chromium.org',
                      'avi@chromium.org',
diff --git a/android_webview/apk/java/AndroidManifest.xml b/android_webview/apk/java/AndroidManifest.xml
index 747af3f0..00c5cf8 100644
--- a/android_webview/apk/java/AndroidManifest.xml
+++ b/android_webview/apk/java/AndroidManifest.xml
@@ -21,7 +21,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 
-    <application android:label="Android System WebView"
+    <application android:label="{{ application_label|default('Android System WebView') }}"
                  android:icon="@{{manifest_package|default('com.android.webview')}}:drawable/icon_webview"
                  android:name="{{ application_name|default('com.android.webview.chromium.WebViewApplication') }}"
                  android:multiArch="true"
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc
index a6a8a54..1dcdd2d 100644
--- a/android_webview/browser/aw_contents.cc
+++ b/android_webview/browser/aw_contents.cc
@@ -179,19 +179,6 @@
 }
 
 // static
-AwContents* AwContents::FromID(int render_process_id, int render_view_id) {
-  content::RenderViewHost* rvh =
-      content::RenderViewHost::FromID(render_process_id, render_view_id);
-  if (!rvh)
-    return NULL;
-  content::WebContents* web_contents =
-      content::WebContents::FromRenderViewHost(rvh);
-  if (!web_contents)
-    return NULL;
-  return FromWebContents(web_contents);
-}
-
-// static
 void JNI_AwContents_UpdateDefaultLocale(
     JNIEnv* env,
     const JavaParamRef<jstring>& locale,
diff --git a/android_webview/browser/aw_contents.h b/android_webview/browser/aw_contents.h
index bc7e248..7776b46f 100644
--- a/android_webview/browser/aw_contents.h
+++ b/android_webview/browser/aw_contents.h
@@ -65,10 +65,6 @@
   // Returns the AwContents instance associated with |web_contents|, or NULL.
   static AwContents* FromWebContents(content::WebContents* web_contents);
 
-  // Returns the AwContents instance associated with with the given
-  // render_process_id and render_view_id, or NULL.
-  static AwContents* FromID(int render_process_id, int render_view_id);
-
   static std::string GetLocale();
 
   static std::string GetLocaleList();
diff --git a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
index d73e3c1..f56c790 100644
--- a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
+++ b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
@@ -285,7 +285,11 @@
 void InterceptedRequest::Restart() {
   std::unique_ptr<AwContentsIoThreadClient> io_thread_client =
       GetIoThreadClient();
-  DCHECK(io_thread_client);
+
+  if (!io_thread_client) {
+    SendErrorAndCompleteImmediately(net::ERR_ABORTED);
+    return;
+  }
 
   if (ShouldBlockURL(request_.url, io_thread_client.get())) {
     SendErrorAndCompleteImmediately(net::ERR_ACCESS_DENIED);
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 431fcf3..ed018a3a 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -69,6 +69,22 @@
     Shell::Get()->assistant_controller()->ui_controller()->CloseUi(exit_point);
 }
 
+app_list::TabletModeAnimationTransition CalculateAnimationTransitionForMetrics(
+    HomeScreenDelegate::AnimationTrigger trigger,
+    bool launcher_should_show) {
+  switch (trigger) {
+    case HomeScreenDelegate::AnimationTrigger::kHideForWindow:
+      return app_list::TabletModeAnimationTransition::
+          kHideHomeLauncherForWindow;
+    case HomeScreenDelegate::AnimationTrigger::kLauncherButton:
+      return app_list::TabletModeAnimationTransition::kAppListButtonShow;
+    case HomeScreenDelegate::AnimationTrigger::kDragRelease:
+      return launcher_should_show
+                 ? app_list::TabletModeAnimationTransition::kDragReleaseShow
+                 : app_list::TabletModeAnimationTransition::kDragReleaseHide;
+  }
+}
+
 }  // namespace
 
 AppListControllerImpl::AppListControllerImpl()
@@ -1288,4 +1304,11 @@
   model_->RemoveObserver(this);
 }
 
+void AppListControllerImpl::NotifyHomeLauncherAnimationTransition(
+    AnimationTrigger trigger,
+    bool launcher_will_show) {
+  presenter_.GetView()->OnTabletModeAnimationTransitionNotified(
+      CalculateAnimationTransitionForMetrics(trigger, launcher_will_show));
+}
+
 }  // namespace ash
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index 31f1a99..3df2c53 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -268,6 +268,8 @@
   base::Optional<base::TimeDelta> GetOptionalAnimationDuration() override;
   bool ShouldShowShelfOnHomeScreen() const override;
   bool ShouldShowStatusAreaOnHomeScreen() const override;
+  void NotifyHomeLauncherAnimationTransition(AnimationTrigger trigger,
+                                             bool launcher_will_show) override;
 
   bool onscreen_keyboard_shown() const { return onscreen_keyboard_shown_; }
 
diff --git a/ash/app_list/app_list_metrics.h b/ash/app_list/app_list_metrics.h
index c5a4880d..28acc6fd 100644
--- a/ash/app_list/app_list_metrics.h
+++ b/ash/app_list/app_list_metrics.h
@@ -217,6 +217,21 @@
   kTileList = 1,
 };
 
+// Different ways to trigger launcher animation in tablet mode.
+enum TabletModeAnimationTransition {
+  // Release drag to show the launcher (launcher animates the rest of the way).
+  kDragReleaseShow,
+
+  // Release drag to hide the launcher (launcher animates the rest of the way).
+  kDragReleaseHide,
+
+  // Click the AppList button in tablet mode.
+  kAppListButtonShow,
+
+  // Activate a window from shelf to hide the launcher in tablet mode.
+  kHideHomeLauncherForWindow
+};
+
 void RecordFolderShowHideAnimationSmoothness(int actual_frames,
                                              int ideal_duration_ms,
                                              float refresh_rate);
diff --git a/ash/app_list/presenter/app_list_presenter_impl.cc b/ash/app_list/presenter/app_list_presenter_impl.cc
index c9be62b..6914b32 100644
--- a/ash/app_list/presenter/app_list_presenter_impl.cc
+++ b/ash/app_list/presenter/app_list_presenter_impl.cc
@@ -241,7 +241,14 @@
   // We want to animate the expand arrow, suggestion chips and apps grid in
   // app_list_main_view, and the search box.
   ui::Layer* layer = view_->GetWidget()->GetNativeWindow()->layer();
-  layer->GetAnimator()->StopAnimating();
+
+  if (layer->GetAnimator()->is_animating()) {
+    layer->GetAnimator()->StopAnimating();
+
+    // Reset the animation metrics reporter when the animation is interrupted.
+    view_->ResetTransitionMetricsReporter();
+  }
+
   std::unique_ptr<ui::ScopedLayerAnimationSettings> settings;
   if (!callback.is_null()) {
     settings = std::make_unique<ui::ScopedLayerAnimationSettings>(
@@ -249,6 +256,15 @@
     callback.Run(settings.get());
   }
   layer->SetOpacity(opacity);
+
+  // Only record animation metrics for transformation animation. Because the
+  // animation triggered by setting opacity should have the same metrics values
+  // with the transformation animation.
+  if (settings.get()) {
+    settings->SetAnimationMetricsReporter(
+        view_->GetStateTransitionMetricsReporter());
+  }
+
   layer->SetTransform(translation);
 
   // Update child views' y positions to target state to avoid stale positions.
@@ -386,6 +402,7 @@
         HandleCloseOpenSearchBox();
       } else if (applist_window->Contains(gained_focus)) {
         home_launcher_shown_ = true;
+        view_->ResetForShow();
       }
     }
 
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index f30bd9b..6838876b 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -190,6 +190,9 @@
 
 }  // namespace
 
+////////////////////////////////////////////////////////////////////////////////
+// AppListView::StateAnimationMetricsReporter
+
 class AppListView::StateAnimationMetricsReporter
     : public ui::AnimationMetricsReporter {
  public:
@@ -201,7 +204,8 @@
     target_state_ = target_state;
   }
 
-  void Start() {
+  void Start(bool is_in_tablet_mode) {
+    is_in_tablet_mode_ = is_in_tablet_mode;
 #if defined(DCHECK)
     DCHECK(!started_);
     started_ = ui::ScopedAnimationDurationScaleMode::duration_scale_mode() !=
@@ -209,54 +213,113 @@
 #endif
   }
 
-  void Report(int value) override {
-    UMA_HISTOGRAM_PERCENTAGE("Apps.StateTransition.AnimationSmoothness", value);
-    switch (*target_state_) {
-      case ash::mojom::AppListViewState::kClosed:
-        UMA_HISTOGRAM_PERCENTAGE(
-            "Apps.StateTransition.AnimationSmoothness.Close.ClamshellMode",
-            value);
-        break;
-      case ash::mojom::AppListViewState::kPeeking:
-        UMA_HISTOGRAM_PERCENTAGE(
-            "Apps.StateTransition.AnimationSmoothness.Peeking.ClamshellMode",
-            value);
-        break;
-      case ash::mojom::AppListViewState::kHalf:
-        UMA_HISTOGRAM_PERCENTAGE(
-            "Apps.StateTransition.AnimationSmoothness.Half.ClamshellMode",
-            value);
-        break;
-      case ash::mojom::AppListViewState::kFullscreenAllApps:
-        UMA_HISTOGRAM_PERCENTAGE(
-            "Apps.StateTransition.AnimationSmoothness.FullscreenAllApps."
-            "ClamshellMode",
-            value);
-        break;
-      case ash::mojom::AppListViewState::kFullscreenSearch:
-        UMA_HISTOGRAM_PERCENTAGE(
-            "Apps.StateTransition.AnimationSmoothness.FullscreenSearch."
-            "ClamshellMode",
-            value);
-        break;
-    }
-    target_state_.reset();
-    view_->OnStateTransitionAnimationCompleted();
-#if defined(DCHECK)
-    started_ = false;
-#endif
+  void Reset();
+
+  void SetTabletModeAnimationTransition(
+      TabletModeAnimationTransition transition) {
+    tablet_transition_ = transition;
   }
 
+  // ui::AnimationMetricsReporter:
+  void Report(int value) override;
+
  private:
+  void RecordMetricsInTablet(int value);
+  void RecordMetricsInClamshell(int value);
+
 #if defined(DCHECK)
   bool started_ = false;
 #endif
   base::Optional<ash::mojom::AppListViewState> target_state_;
+  base::Optional<TabletModeAnimationTransition> tablet_transition_;
+  bool is_in_tablet_mode_ = false;
   AppListView* view_;
 
   DISALLOW_COPY_AND_ASSIGN(StateAnimationMetricsReporter);
 };
 
+void AppListView::StateAnimationMetricsReporter::Reset() {
+#if defined(DCHECK)
+  started_ = false;
+#endif
+  tablet_transition_.reset();
+  target_state_.reset();
+}
+
+void AppListView::StateAnimationMetricsReporter::Report(int value) {
+  UMA_HISTOGRAM_PERCENTAGE("Apps.StateTransition.AnimationSmoothness", value);
+  if (is_in_tablet_mode_)
+    RecordMetricsInTablet(value);
+  else
+    RecordMetricsInClamshell(value);
+  view_->OnStateTransitionAnimationCompleted();
+  Reset();
+}
+
+void AppListView::StateAnimationMetricsReporter::RecordMetricsInTablet(
+    int value) {
+  DCHECK(tablet_transition_.has_value());
+  switch (*tablet_transition_) {
+    case TabletModeAnimationTransition::kDragReleaseShow:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.HomeLauncherTransition.AnimationSmoothness.DragReleaseShow",
+          value);
+      break;
+    case TabletModeAnimationTransition::kDragReleaseHide:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.HomeLauncherTransition.AnimationSmoothness."
+          "DragReleaseHide",
+          value);
+      break;
+    case TabletModeAnimationTransition::kAppListButtonShow:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.HomeLauncherTransition.AnimationSmoothness."
+          "PressAppListButtonShow",
+          value);
+      break;
+    case TabletModeAnimationTransition::kHideHomeLauncherForWindow:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.HomeLauncherTransition.AnimationSmoothness."
+          "HideLauncherForWindow",
+          value);
+      break;
+  }
+}
+
+void AppListView::StateAnimationMetricsReporter::RecordMetricsInClamshell(
+    int value) {
+  DCHECK(target_state_.has_value());
+  switch (*target_state_) {
+    case ash::mojom::AppListViewState::kClosed:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.StateTransition.AnimationSmoothness.Close.ClamshellMode",
+          value);
+      break;
+    case ash::mojom::AppListViewState::kPeeking:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.StateTransition.AnimationSmoothness.Peeking.ClamshellMode",
+          value);
+      break;
+    case ash::mojom::AppListViewState::kHalf:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.StateTransition.AnimationSmoothness.Half.ClamshellMode", value);
+      break;
+    case ash::mojom::AppListViewState::kFullscreenAllApps:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.StateTransition.AnimationSmoothness.FullscreenAllApps."
+          "ClamshellMode",
+          value);
+      break;
+    case ash::mojom::AppListViewState::kFullscreenSearch:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.StateTransition.AnimationSmoothness.FullscreenSearch."
+          "ClamshellMode",
+          value);
+      break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // An animation observer to hide the view at the end of the animation.
 class HideViewAnimationObserver : public ui::ImplicitAnimationObserver {
  public:
@@ -452,6 +515,16 @@
   GetWidget()->Deactivate();
 }
 
+void AppListView::ResetForShow() {
+  if (GetFocusManager()->GetFocusedView() != GetInitiallyFocusedView())
+    GetInitiallyFocusedView()->RequestFocus();
+
+  if (GetAppsPaginationModel()->total_pages() > 0 &&
+      GetAppsPaginationModel()->selected_page() != 0) {
+    GetAppsPaginationModel()->SelectPage(0, false /* animate */);
+  }
+}
+
 void AppListView::CloseOpenedPage() {
   if (HandleCloseOpenFolder())
     return;
@@ -1642,7 +1715,7 @@
 }
 
 ui::AnimationMetricsReporter* AppListView::GetStateTransitionMetricsReporter() {
-  state_animation_metrics_reporter_->Start();
+  state_animation_metrics_reporter_->Start(is_tablet_mode_);
   return state_animation_metrics_reporter_.get();
 }
 
@@ -1662,6 +1735,10 @@
   presentation_time_recorder_.reset();
 }
 
+void AppListView::ResetTransitionMetricsReporter() {
+  state_animation_metrics_reporter_->Reset();
+}
+
 void AppListView::OnWindowDestroying(aura::Window* window) {
   DCHECK_EQ(fullscreen_widget_->GetNativeView(), window);
   window->RemoveObserver(this);
@@ -1922,4 +1999,10 @@
   delegate_->OnStateTransitionAnimationCompleted(app_list_state_);
 }
 
+void AppListView::OnTabletModeAnimationTransitionNotified(
+    TabletModeAnimationTransition animation_transition) {
+  state_animation_metrics_reporter_->SetTabletModeAnimationTransition(
+      animation_transition);
+}
+
 }  // namespace app_list
diff --git a/ash/app_list/views/app_list_view.h b/ash/app_list/views/app_list_view.h
index af13acd..d57ddec 100644
--- a/ash/app_list/views/app_list_view.h
+++ b/ash/app_list/views/app_list_view.h
@@ -150,6 +150,9 @@
   // Dismisses the UI, cleans up and sets the state to CLOSED.
   void Dismiss();
 
+  // Resets the child views before showing the AppListView.
+  void ResetForShow();
+
   // Closes opened folder or search result page if they are opened.
   void CloseOpenedPage();
 
@@ -262,6 +265,9 @@
   void OnHomeLauncherDragInProgress();
   void OnHomeLauncherDragEnd();
 
+  // Resets the animation metrics reporter for state transition.
+  void ResetTransitionMetricsReporter();
+
   // WindowObserver overrides:
   void OnWindowDestroying(aura::Window* window) override;
   void OnWindowBoundsChanged(aura::Window* window,
@@ -272,6 +278,9 @@
   // Called when state transition animation is completed.
   void OnStateTransitionAnimationCompleted();
 
+  void OnTabletModeAnimationTransitionNotified(
+      TabletModeAnimationTransition animation_transition);
+
   views::Widget* get_fullscreen_widget_for_test() const {
     return fullscreen_widget_;
   }
diff --git a/ash/home_screen/home_launcher_gesture_handler.cc b/ash/home_screen/home_launcher_gesture_handler.cc
index 604005c..147c85e 100644
--- a/ash/home_screen/home_launcher_gesture_handler.cc
+++ b/ash/home_screen/home_launcher_gesture_handler.cc
@@ -10,7 +10,6 @@
 #include "ash/app_list/app_list_controller_impl.h"
 #include "ash/home_screen/home_launcher_gesture_handler_observer.h"
 #include "ash/home_screen/home_screen_controller.h"
-#include "ash/home_screen/home_screen_delegate.h"
 #include "ash/root_window_controller.h"
 #include "ash/scoped_animation_disabler.h"
 #include "ash/screen_util.h"
@@ -359,7 +358,7 @@
       // triggered by opening |active_window_| with modal dialog in
       // OnPressEvent(). In that case, just leave the |active_window_| in show
       // state and stop tracking.
-      AnimateToFinalState();
+      AnimateToFinalState(AnimationTrigger::kDragRelease);
       RemoveObserversAndStopTracking();
       return true;
     }
@@ -367,7 +366,7 @@
   }
 
   last_event_location_ = base::make_optional(location);
-  AnimateToFinalState();
+  AnimateToFinalState(AnimationTrigger::kDragRelease);
   return true;
 }
 
@@ -379,7 +378,7 @@
   DCHECK(home_screen_delegate);
   home_screen_delegate->OnHomeLauncherDragEnd();
 
-  AnimateToFinalState();
+  AnimateToFinalState(AnimationTrigger::kDragRelease);
   return;
 }
 
@@ -398,7 +397,7 @@
   mode_ = Mode::kSlideUpToShow;
 
   UpdateWindows(0.0, /*animate=*/false);
-  AnimateToFinalState();
+  AnimateToFinalState(AnimationTrigger::kLauncherButton);
   return true;
 }
 
@@ -418,7 +417,7 @@
   mode_ = Mode::kSlideDownToHide;
 
   UpdateWindows(1.0, /*animate=*/false);
-  AnimateToFinalState();
+  AnimateToFinalState(AnimationTrigger::kHideForWindow);
   return true;
 }
 
@@ -572,8 +571,10 @@
   RemoveObserversAndStopTracking();
 }
 
-void HomeLauncherGestureHandler::AnimateToFinalState() {
+void HomeLauncherGestureHandler::AnimateToFinalState(AnimationTrigger trigger) {
   const bool is_final_state_show = IsFinalStateShow();
+  GetHomeScreenDelegate()->NotifyHomeLauncherAnimationTransition(
+      trigger, is_final_state_show);
   UpdateWindows(is_final_state_show ? 1.0 : 0.0, /*animate=*/true);
 
   if (!is_final_state_show && mode_ == Mode::kSlideDownToHide) {
diff --git a/ash/home_screen/home_launcher_gesture_handler.h b/ash/home_screen/home_launcher_gesture_handler.h
index 965482e..cb62c2f4 100644
--- a/ash/home_screen/home_launcher_gesture_handler.h
+++ b/ash/home_screen/home_launcher_gesture_handler.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "ash/ash_export.h"
+#include "ash/home_screen/home_screen_delegate.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_observer.h"
 #include "base/macros.h"
@@ -97,6 +98,8 @@
   FRIEND_TEST_ALL_PREFIXES(HomeLauncherModeGestureHandlerTest,
                            AnimatingToEndResetsState);
 
+  using AnimationTrigger = HomeScreenDelegate::AnimationTrigger;
+
   // Stores the initial and target opacities and transforms of window.
   struct WindowValues {
     float initial_opacity;
@@ -105,8 +108,9 @@
     gfx::Transform target_transform;
   };
 
-  // Animates the items based on IsFinalStateShow().
-  void AnimateToFinalState();
+  // Animates the items based on IsFinalStateShow(). |trigger| is what triggered
+  // the animation.
+  void AnimateToFinalState(AnimationTrigger trigger);
 
   // Updates |settings| based on what we want for this class.
   void UpdateSettings(ui::ScopedLayerAnimationSettings* settings);
diff --git a/ash/home_screen/home_launcher_gesture_handler_unittest.cc b/ash/home_screen/home_launcher_gesture_handler_unittest.cc
index 0541325..d8a5c2dd 100644
--- a/ash/home_screen/home_launcher_gesture_handler_unittest.cc
+++ b/ash/home_screen/home_launcher_gesture_handler_unittest.cc
@@ -36,6 +36,9 @@
   void SetUp() override {
     AshTestBase::SetUp();
 
+    // Wait for TabletModeController::Ctor to finish.
+    base::RunLoop().RunUntilIdle();
+
     Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
   }
 
diff --git a/ash/home_screen/home_screen_delegate.h b/ash/home_screen/home_screen_delegate.h
index 1f5b4eb..bf6c1e0f 100644
--- a/ash/home_screen/home_screen_delegate.h
+++ b/ash/home_screen/home_screen_delegate.h
@@ -23,6 +23,17 @@
   using UpdateAnimationSettingsCallback =
       base::RepeatingCallback<void(ui::ScopedLayerAnimationSettings* settings)>;
 
+  enum class AnimationTrigger {
+    // Launcher animation is triggered by drag release.
+    kDragRelease,
+
+    // Launcher animation is triggered by pressing the AppList button.
+    kLauncherButton,
+
+    // Launcher animation is triggered by window activation.
+    kHideForWindow
+  };
+
   virtual ~HomeScreenDelegate() = default;
 
   // Shows the home screen view.
@@ -62,6 +73,12 @@
   virtual void OnHomeLauncherDragStart() {}
   virtual void OnHomeLauncherDragInProgress() {}
   virtual void OnHomeLauncherDragEnd() {}
+
+  // Propagates the home launcher animation transition. |trigger| is what
+  // triggers the home launcher animation; |launcher_will_show| indicates
+  // whether the launcher will show by the end of animation.
+  virtual void NotifyHomeLauncherAnimationTransition(AnimationTrigger trigger,
+                                                     bool launcher_will_show) {}
 };
 
 }  // namespace ash
diff --git a/ash/wm/overview/caption_container_view.cc b/ash/wm/overview/caption_container_view.cc
index a5aad39..d98f4b66 100644
--- a/ash/wm/overview/caption_container_view.cc
+++ b/ash/wm/overview/caption_container_view.cc
@@ -205,6 +205,16 @@
   AnimateLayerOpacity(close_button_->layer(), close_button_visible);
 }
 
+void CaptionContainerView::FadeInCloseIconAfterSnap() {
+  DCHECK(close_button_->layer());
+  current_header_visibility_ = HeaderVisibility::kVisible;
+  close_button_->layer()->SetOpacity(0.f);
+  ScopedOverviewAnimationSettings settings(
+      OVERVIEW_ANIMATION_OVERVIEW_CLOSE_ICON_FADE_IN_ON_SNAP,
+      close_button_->layer()->GetAnimator());
+  close_button_->layer()->SetOpacity(1.f);
+}
+
 void CaptionContainerView::SetBackdropVisibility(bool visible) {
   if (!backdrop_view_ && !visible)
     return;
diff --git a/ash/wm/overview/caption_container_view.h b/ash/wm/overview/caption_container_view.h
index 42fe3c4..7fde9b36 100644
--- a/ash/wm/overview/caption_container_view.h
+++ b/ash/wm/overview/caption_container_view.h
@@ -65,8 +65,18 @@
   CaptionContainerView(EventDelegate* event_delegate, aura::Window* window);
   ~CaptionContainerView() override;
 
+  // Fades in and out the app icon, title, and close button, choosing an
+  // overview animation type based on whether fading in or fading out. When a
+  // window gets snapped, use |FadeInCloseIconAfterSnap| instead.
   void SetHeaderVisibility(HeaderVisibility visibility);
 
+  // Fade in the close icon with a special overview animation type (specifically
+  // |OVERVIEW_ANIMATION_OVERVIEW_CLOSE_ICON_FADE_IN_ON_SNAP|) for when a
+  // dragged window gets snapped. This function may be called before or after
+  // the window is snapped. It is called before the snap in case of dragging
+  // from the top, but after the snap in case of dragging from overview.
+  void FadeInCloseIconAfterSnap();
+
   // Sets the visiblity of |backdrop_view_|. Creates it if it is null.
   void SetBackdropVisibility(bool visible);
 
diff --git a/ash/wm/overview/overview_animation_type.h b/ash/wm/overview/overview_animation_type.h
index 618d9c6..b87e83b 100644
--- a/ash/wm/overview/overview_animation_type.h
+++ b/ash/wm/overview/overview_animation_type.h
@@ -46,9 +46,13 @@
   // arrow keys.
   OVERVIEW_ANIMATION_SELECTION_WINDOW_SHADOW,
   OVERVIEW_ANIMATION_SELECTION_WINDOW,
-  // Used to animate the overview items header visibility.
+  // Used to fade in and out each overview item's app icon, title, and close
+  // button, except when a window gets snapped (see the next value).
   OVERVIEW_ANIMATION_OVERVIEW_TITLE_FADE_IN,
   OVERVIEW_ANIMATION_OVERVIEW_TITLE_FADE_OUT,
+  // Used to fade in the close icons for items remaining in overview on one side
+  // of the screen when a window gets snapped on the other side.
+  OVERVIEW_ANIMATION_OVERVIEW_CLOSE_ICON_FADE_IN_ON_SNAP,
 };
 
 }  // namespace ash
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 30fbd38e..b1eb93b 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -712,9 +712,9 @@
     overview_mode_item->OnSelectorItemDragStarted(item);
 }
 
-void OverviewGrid::OnSelectorItemDragEnded() {
+void OverviewGrid::OnSelectorItemDragEnded(bool snap) {
   for (auto& overview_mode_item : window_list_)
-    overview_mode_item->OnSelectorItemDragEnded();
+    overview_mode_item->OnSelectorItemDragEnded(snap);
 }
 
 void OverviewGrid::OnWindowDragStarted(aura::Window* dragged_window,
@@ -791,7 +791,8 @@
 
 void OverviewGrid::OnWindowDragEnded(aura::Window* dragged_window,
                                      const gfx::PointF& location_in_screen,
-                                     bool should_drop_window_into_overview) {
+                                     bool should_drop_window_into_overview,
+                                     bool snap) {
   DCHECK_EQ(dragged_window->GetRootWindow(), root_window_);
   DCHECK(drop_target_widget_.get());
 
@@ -810,7 +811,7 @@
   RemoveDropTarget();
 
   // Called to reset caption and title visibility after dragging.
-  OnSelectorItemDragEnded();
+  OnSelectorItemDragEnded(snap);
 
   // After drag ends, if the dragged window needs to merge into another window
   // |target_window|, and we may need to update |minimized_widget_| that holds
diff --git a/ash/wm/overview/overview_grid.h b/ash/wm/overview/overview_grid.h
index 14528b9..aba2e45 100644
--- a/ash/wm/overview/overview_grid.h
+++ b/ash/wm/overview/overview_grid.h
@@ -147,7 +147,7 @@
   // Called when any OverviewItem on any OverviewGrid has started/ended being
   // dragged.
   void OnSelectorItemDragStarted(OverviewItem* item);
-  void OnSelectorItemDragEnded();
+  void OnSelectorItemDragEnded(bool snap);
 
   // Called when a window (either it's browser window or an app window)
   // start/continue/end being dragged in tablet mode.
@@ -157,7 +157,8 @@
                              IndicatorState indicator_state);
   void OnWindowDragEnded(aura::Window* dragged_window,
                          const gfx::PointF& location_in_screen,
-                         bool should_drop_window_into_overview);
+                         bool should_drop_window_into_overview,
+                         bool snap);
 
   // Returns true if |window| is the placeholder window from the drop target.
   bool IsDropTargetWindow(aura::Window* window) const;
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index 119a243d..dda9d9b 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -445,18 +445,26 @@
   }
 }
 
-void OverviewItem::OnSelectorItemDragEnded() {
-  // Re-show mask and shadow for the dragged overview item after drag ends.
+void OverviewItem::OnSelectorItemDragEnded(bool snap) {
+  // Stop caching render surface after overview window dragging.
+  window_surface_cache_observers_.reset();
+
   if (is_being_dragged_) {
     is_being_dragged_ = false;
+    // Do nothing further with the dragged overview item if it is being snapped.
+    if (snap)
+      return;
+    // Re-show mask and shadow for the dragged overview item after drag ends.
     UpdateMaskAndShadow();
   }
 
-  caption_container_view_->SetHeaderVisibility(
-      CaptionContainerView::HeaderVisibility::kVisible);
-
-  // Stop caching render surface after overview window dragging.
-  window_surface_cache_observers_.reset();
+  // Update the header.
+  if (snap) {
+    caption_container_view_->FadeInCloseIconAfterSnap();
+  } else {
+    caption_container_view_->SetHeaderVisibility(
+        CaptionContainerView::HeaderVisibility::kVisible);
+  }
 }
 
 ScopedOverviewTransformWindow::GridWindowFillMode
diff --git a/ash/wm/overview/overview_item.h b/ash/wm/overview/overview_item.h
index d01449e..a4432c6e 100644
--- a/ash/wm/overview/overview_item.h
+++ b/ash/wm/overview/overview_item.h
@@ -120,7 +120,7 @@
   // when a drag is started, and reshows it when a drag is finished.
   // Additionally hides the title and window icon if |item| is this.
   void OnSelectorItemDragStarted(OverviewItem* item);
-  void OnSelectorItemDragEnded();
+  void OnSelectorItemDragEnded(bool snap);
 
   ScopedOverviewTransformWindow::GridWindowFillMode GetWindowDimensionsType()
       const;
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index 52597d75..c5c2f33 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -509,10 +509,11 @@
                                    const gfx::PointF& location_in_screen) {
   DCHECK(window_drag_controller_);
   DCHECK_EQ(item, window_drag_controller_->item());
-  window_drag_controller_->CompleteDrag(location_in_screen);
-
+  const bool snap =
+      window_drag_controller_->CompleteDrag(location_in_screen) ==
+      OverviewWindowDragController::DragResult::kSuccessfulDragToSnap;
   for (std::unique_ptr<OverviewGrid>& grid : grid_list_)
-    grid->OnSelectorItemDragEnded();
+    grid->OnSelectorItemDragEnded(snap);
 }
 
 void OverviewSession::StartSplitViewDragMode(
@@ -529,9 +530,12 @@
   if (!window_drag_controller_ || item != window_drag_controller_->item())
     return;
 
-  window_drag_controller_->Fling(location_in_screen, velocity_x, velocity_y);
+  const bool snap =
+      window_drag_controller_->Fling(location_in_screen, velocity_x,
+                                     velocity_y) ==
+      OverviewWindowDragController::DragResult::kSuccessfulDragToSnap;
   for (std::unique_ptr<OverviewGrid>& grid : grid_list_)
-    grid->OnSelectorItemDragEnded();
+    grid->OnSelectorItemDragEnded(snap);
 }
 
 void OverviewSession::ActivateDraggedWindow() {
@@ -541,7 +545,7 @@
 void OverviewSession::ResetDraggedWindowGesture() {
   window_drag_controller_->ResetGesture();
   for (std::unique_ptr<OverviewGrid>& grid : grid_list_)
-    grid->OnSelectorItemDragEnded();
+    grid->OnSelectorItemDragEnded(/*snap=*/false);
 }
 
 void OverviewSession::OnWindowDragStarted(aura::Window* dragged_window,
@@ -566,13 +570,14 @@
 }
 void OverviewSession::OnWindowDragEnded(aura::Window* dragged_window,
                                         const gfx::PointF& location_in_screen,
-                                        bool should_drop_window_into_overview) {
+                                        bool should_drop_window_into_overview,
+                                        bool snap) {
   OverviewGrid* target_grid =
       GetGridWithRootWindow(dragged_window->GetRootWindow());
   if (!target_grid)
     return;
   target_grid->OnWindowDragEnded(dragged_window, location_in_screen,
-                                 should_drop_window_into_overview);
+                                 should_drop_window_into_overview, snap);
 }
 
 void OverviewSession::PositionWindows(
@@ -590,6 +595,17 @@
   return false;
 }
 
+OverviewItem* OverviewSession::GetOverviewItemForWindow(
+    const aura::Window* window) {
+  for (const std::unique_ptr<OverviewGrid>& grid : grid_list_) {
+    OverviewItem* item = grid->GetOverviewItemContaining(window);
+    if (item)
+      return item;
+  }
+  NOTREACHED();
+  return nullptr;
+}
+
 void OverviewSession::SetWindowListNotAnimatedWhenExiting(
     aura::Window* root_window) {
   // Find the grid accociated with |root_window|.
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index 3f2eeba..3f0b7685 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -181,7 +181,8 @@
                              IndicatorState indicator_state);
   void OnWindowDragEnded(aura::Window* dragged_window,
                          const gfx::PointF& location_in_screen,
-                         bool should_drop_window_into_overview);
+                         bool should_drop_window_into_overview,
+                         bool snap);
 
   // Positions all overview items except those in |ignored_items|.
   void PositionWindows(bool animate,
@@ -190,6 +191,9 @@
   // Returns true if |window| is currently showing in overview.
   bool IsWindowInOverview(const aura::Window* window);
 
+  // Returns the overview item for |window|.
+  OverviewItem* GetOverviewItemForWindow(const aura::Window* window);
+
   // Set the window grid that's displaying in |root_window| not animate when
   // exiting overview mode, i.e., all window items in the grid will not animate
   // when exiting overview mode. It may be called in two cases: 1) When a window
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index 3394650..819136f 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -141,7 +141,8 @@
   item_->SetBounds(bounds, OVERVIEW_ANIMATION_NONE);
 }
 
-void OverviewWindowDragController::CompleteDrag(
+OverviewWindowDragController::DragResult
+OverviewWindowDragController::CompleteDrag(
     const gfx::PointF& location_in_screen) {
   // Update the split view divider bar stuatus if necessary. The divider bar
   // should be placed above the dragged window after drag ends. Note here the
@@ -161,38 +162,54 @@
         IndicatorState::kNone, gfx::Point());
   }
 
-  if (!did_move_) {
-    ActivateDraggedWindow();
-  } else if (current_drag_behavior_ == DragBehavior::kDragToClose) {
-    // If we are in drag to close mode close the window if it has been dragged
-    // enough, otherwise reposition it and set its opacity back to its original
-    // value.
-    overview_session_->GetGridWithRootWindow(item_->root_window())->EndNudge();
-    if (std::abs((location_in_screen - initial_event_location_).y()) >
-        kDragToCloseDistanceThresholdDp) {
-      item_->AnimateAndCloseWindow(
-          (location_in_screen - initial_event_location_).y() < 0);
-    } else {
-      item_->SetOpacity(original_opacity_);
-      overview_session_->PositionWindows(/*animate=*/true);
-    }
-  } else if (current_drag_behavior_ == DragBehavior::kDragToSnap) {
-    overview_session_->RemoveDropTargetForDraggingFromOverview(item_);
-    // If the window was dragged around but should not be snapped, move it back
-    // to overview window grid.
-    if (!ShouldUpdateDragIndicatorsOrSnap(location_in_screen) ||
-        snap_position_ == SplitViewController::NONE) {
-      item_->set_should_restack_on_animation_end(true);
-      overview_session_->PositionWindows(/*animate=*/true);
-    } else {
-      SnapWindow(snap_position_);
-    }
+  DragResult result;
+  switch (current_drag_behavior_) {
+    case DragBehavior::kNoDrag:
+      NOTREACHED();
+      result = DragResult::kNeverDisambiguated;
+      break;
+    case DragBehavior::kUndefined:
+      ActivateDraggedWindow();
+      result = DragResult::kNeverDisambiguated;
+      break;
+    case DragBehavior::kDragToSnap:
+      overview_session_->RemoveDropTargetForDraggingFromOverview(item_);
+      // If the window was dragged around but should not be snapped, move it
+      // back to overview window grid.
+      if (!ShouldUpdateDragIndicatorsOrSnap(location_in_screen) ||
+          snap_position_ == SplitViewController::NONE) {
+        item_->set_should_restack_on_animation_end(true);
+        overview_session_->PositionWindows(/*animate=*/true);
+        result = DragResult::kCanceledDragToSnap;
+      } else {
+        SnapWindow(snap_position_);
+        result = DragResult::kSuccessfulDragToSnap;
+      }
+      break;
+    case DragBehavior::kDragToClose:
+      // If we are in drag to close mode close the window if it has been dragged
+      // enough, otherwise reposition it and set its opacity back to its
+      // original value.
+      overview_session_->GetGridWithRootWindow(item_->root_window())
+          ->EndNudge();
+      if (std::abs((location_in_screen - initial_event_location_).y()) >
+          kDragToCloseDistanceThresholdDp) {
+        item_->AnimateAndCloseWindow(
+            (location_in_screen - initial_event_location_).y() < 0);
+        result = DragResult::kSuccessfulDragToClose;
+      } else {
+        item_->SetOpacity(original_opacity_);
+        overview_session_->PositionWindows(/*animate=*/true);
+        result = DragResult::kCanceledDragToClose;
+      }
+      break;
   }
   did_move_ = false;
   item_ = nullptr;
   current_drag_behavior_ = DragBehavior::kNoDrag;
   UnpauseOcclusionTracker();
   presentation_time_recorder_.reset();
+  return result;
 }
 
 void OverviewWindowDragController::StartSplitViewDragMode(
@@ -217,9 +234,10 @@
     split_view_controller_->OnWindowDragStarted(item_->GetWindow());
 }
 
-void OverviewWindowDragController::Fling(const gfx::PointF& location_in_screen,
-                                         float velocity_x,
-                                         float velocity_y) {
+OverviewWindowDragController::DragResult OverviewWindowDragController::Fling(
+    const gfx::PointF& location_in_screen,
+    float velocity_x,
+    float velocity_y) {
   if (current_drag_behavior_ == DragBehavior::kDragToClose ||
       current_drag_behavior_ == DragBehavior::kUndefined) {
     if (std::abs(velocity_y) > kFlingToCloseVelocityThreshold) {
@@ -235,13 +253,13 @@
       item_ = nullptr;
       current_drag_behavior_ = DragBehavior::kNoDrag;
       UnpauseOcclusionTracker();
-      return;
+      return DragResult::kSuccessfulDragToClose;
     }
   }
 
   // If the fling velocity was not high enough, or flings should be ignored,
   // treat it as a scroll end event.
-  CompleteDrag(location_in_screen);
+  return CompleteDrag(location_in_screen);
 }
 
 void OverviewWindowDragController::ActivateDraggedWindow() {
diff --git a/ash/wm/overview/overview_window_drag_controller.h b/ash/wm/overview/overview_window_drag_controller.h
index b6e586b74..565f947e 100644
--- a/ash/wm/overview/overview_window_drag_controller.h
+++ b/ash/wm/overview/overview_window_drag_controller.h
@@ -34,17 +34,27 @@
     kDragToClose,  // On drag complete, the window will be closed, if it meets
                    // requirements.
   };
+  enum class DragResult {
+    kNeverDisambiguated,     // The drag ended without ever being disambiguated
+                             // between drag-to-snap and drag-to-close.
+    kSuccessfulDragToSnap,   // The drag resulted in snapping the window.
+    kCanceledDragToSnap,     // The drag was considered as drag-to-snap, but did
+                             // not result in snapping the window.
+    kSuccessfulDragToClose,  // The drag resulted in closing the window.
+    kCanceledDragToClose,  // The drag was considered as drag-to-close, but did
+                           // not result in closing the window.
+  };
 
   explicit OverviewWindowDragController(OverviewSession* overview_session);
   ~OverviewWindowDragController();
 
   void InitiateDrag(OverviewItem* item, const gfx::PointF& location_in_screen);
   void Drag(const gfx::PointF& location_in_screen);
-  void CompleteDrag(const gfx::PointF& location_in_screen);
+  DragResult CompleteDrag(const gfx::PointF& location_in_screen);
   void StartSplitViewDragMode(const gfx::PointF& location_in_screen);
-  void Fling(const gfx::PointF& location_in_screen,
-             float velocity_x,
-             float velocity_y);
+  DragResult Fling(const gfx::PointF& location_in_screen,
+                   float velocity_x,
+                   float velocity_y);
   void ActivateDraggedWindow();
   void ResetGesture();
 
diff --git a/ash/wm/overview/scoped_overview_animation_settings.cc b/ash/wm/overview/scoped_overview_animation_settings.cc
index b5d6218..62cc0c7 100644
--- a/ash/wm/overview/scoped_overview_animation_settings.cc
+++ b/ash/wm/overview/scoped_overview_animation_settings.cc
@@ -56,6 +56,14 @@
 constexpr base::TimeDelta kOverviewTitleFadeInDelay =
     base::TimeDelta::FromMilliseconds(83);
 
+// Duration of the show animation of close icons when a window is snapped.
+constexpr base::TimeDelta kOverviewCloseIconFadeInOnSnap =
+    base::TimeDelta::FromMilliseconds(300);
+
+// Delay before the show animation of close icons when a window is snapped.
+constexpr base::TimeDelta kOverviewCloseIconFadeInOnSnapDelay =
+    base::TimeDelta::FromMilliseconds(750);
+
 base::TimeDelta GetAnimationDuration(OverviewAnimationType animation_type) {
   switch (animation_type) {
     case OVERVIEW_ANIMATION_NONE:
@@ -86,6 +94,8 @@
     case OVERVIEW_ANIMATION_OVERVIEW_TITLE_FADE_IN:
     case OVERVIEW_ANIMATION_OVERVIEW_TITLE_FADE_OUT:
       return kOverviewTitleFade;
+    case OVERVIEW_ANIMATION_OVERVIEW_CLOSE_ICON_FADE_IN_ON_SNAP:
+      return kOverviewCloseIconFadeInOnSnap;
   };
   NOTREACHED();
   return base::TimeDelta();
@@ -155,6 +165,7 @@
     case OVERVIEW_ANIMATION_SELECTION_WINDOW:
     case OVERVIEW_ANIMATION_OVERVIEW_TITLE_FADE_IN:
     case OVERVIEW_ANIMATION_OVERVIEW_TITLE_FADE_OUT:
+    case OVERVIEW_ANIMATION_OVERVIEW_CLOSE_ICON_FADE_IN_ON_SNAP:
       return nullptr;
     case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN:
     case OVERVIEW_ANIMATION_LAYOUT_OVERVIEW_ITEMS_ON_ENTER:
@@ -264,6 +275,13 @@
       animation_settings_->SetPreemptionStrategy(
           ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
       break;
+    case OVERVIEW_ANIMATION_OVERVIEW_CLOSE_ICON_FADE_IN_ON_SNAP:
+      animation_settings_->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
+      animation_settings_->SetPreemptionStrategy(
+          ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
+      animator->SchedulePauseForProperties(kOverviewCloseIconFadeInOnSnapDelay,
+                                           ui::LayerAnimationElement::OPACITY);
+      break;
   }
   animation_settings_->SetTransitionDuration(
       GetAnimationDuration(animation_type));
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 308139b..196e97f 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -383,8 +383,19 @@
 
   if (split_view_type_ == SplitViewType::kTabletType) {
     // Insert the previous snapped window to overview if overview is active.
-    if (previous_snapped_window)
+    if (previous_snapped_window && GetOverviewSession()) {
       InsertWindowToOverview(previous_snapped_window);
+      // Ensure that the close icon will fade in. This part is redundant for
+      // dragging from overview, but necessary for dragging from the top. For
+      // dragging from overview, |OverviewItem::OnSelectorItemDragEnded| will be
+      // called on all overview items including the |previous_snapped_window|
+      // item anyway, whereas for dragging from the top,
+      // |OverviewItem::OnSelectorItemDragEnded| already was called on all
+      // overview items and |previous_snapped_window| was not yet among them.
+      GetOverviewSession()
+          ->GetOverviewItemForWindow(previous_snapped_window)
+          ->OnSelectorItemDragEnded(/*snap=*/true);
+    }
 
     // Update the divider position and window bounds before snapping a new
     // window. Since the minimum size of |window| maybe larger than currently
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
index bf63e308..92c4c08 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
@@ -261,7 +261,8 @@
   if (overview_session) {
     GetOverviewSession()->OnWindowDragEnded(
         dragged_window_, gfx::PointF(location_in_screen),
-        ShouldDropWindowIntoOverview(snap_position, location_in_screen));
+        ShouldDropWindowIntoOverview(snap_position, location_in_screen),
+        snap_position != SplitViewController::NONE);
   }
   split_view_controller_->OnWindowDragEnded(dragged_window_, snap_position,
                                             location_in_screen);
diff --git a/base/at_exit.cc b/base/at_exit.cc
index b9d41d54..eb7d26cd 100644
--- a/base/at_exit.cc
+++ b/base/at_exit.cc
@@ -48,11 +48,11 @@
 // static
 void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
   DCHECK(func);
-  RegisterTask(base::Bind(func, param));
+  RegisterTask(base::BindOnce(func, param));
 }
 
 // static
-void AtExitManager::RegisterTask(base::Closure task) {
+void AtExitManager::RegisterTask(base::OnceClosure task) {
   if (!g_top_manager) {
     NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
     return;
@@ -75,7 +75,7 @@
   // Callbacks may try to add new callbacks, so run them without holding
   // |lock_|. This is an error and caught by the DCHECK in RegisterTask(), but
   // handle it gracefully in release builds so we don't deadlock.
-  base::stack<base::Closure> tasks;
+  base::stack<base::OnceClosure> tasks;
   {
     AutoLock lock(g_top_manager->lock_);
     tasks.swap(g_top_manager->stack_);
@@ -89,8 +89,7 @@
   ScopedAllowCrossThreadRefCountAccess allow_cross_thread_ref_count_access;
 
   while (!tasks.empty()) {
-    base::Closure task = tasks.top();
-    task.Run();
+    std::move(tasks.top()).Run();
     tasks.pop();
   }
 
diff --git a/base/at_exit.h b/base/at_exit.h
index 6ace3125..fa652ac 100644
--- a/base/at_exit.h
+++ b/base/at_exit.h
@@ -43,7 +43,7 @@
   static void RegisterCallback(AtExitCallbackType func, void* param);
 
   // Registers the specified task to be called at exit.
-  static void RegisterTask(base::Closure task);
+  static void RegisterTask(base::OnceClosure task);
 
   // Calls the functions registered with RegisterCallback in LIFO order. It
   // is possible to register new callbacks after calling this function.
@@ -63,7 +63,7 @@
  private:
   base::Lock lock_;
 
-  base::stack<base::Closure> stack_ GUARDED_BY(lock_);
+  base::stack<base::OnceClosure> stack_ GUARDED_BY(lock_);
 
 #if DCHECK_IS_ON()
   bool processing_callbacks_ GUARDED_BY(lock_) = false;
diff --git a/base/at_exit_unittest.cc b/base/at_exit_unittest.cc
index 3de061f..7c87111d 100644
--- a/base/at_exit_unittest.cc
+++ b/base/at_exit_unittest.cc
@@ -81,7 +81,7 @@
 
 TEST_F(AtExitTest, Task) {
   ZeroTestCounters();
-  base::AtExitManager::RegisterTask(base::Bind(&ExpectParamIsCounter,
-                                               &g_test_counter_1));
+  base::AtExitManager::RegisterTask(
+      base::BindOnce(&ExpectParamIsCounter, &g_test_counter_1));
   base::AtExitManager::ProcessCallbacksNow();
 }
diff --git a/base/callback_forward.h b/base/callback_forward.h
index f1851c4..d0f230c 100644
--- a/base/callback_forward.h
+++ b/base/callback_forward.h
@@ -16,8 +16,9 @@
 template <typename Signature>
 using Callback = RepeatingCallback<Signature>;
 
-// Syntactic sugar to make Callback<void()> easier to declare since it
-// will be used in a lot of APIs with delayed execution.
+// Syntactic sugar to make OnceClosure<void()> and RepeatingClosure<void()>
+// easier to declare since they will be used in a lot of APIs with delayed
+// execution.
 using OnceClosure = OnceCallback<void()>;
 using RepeatingClosure = RepeatingCallback<void()>;
 using Closure = Callback<void()>;
diff --git a/base/callback_list_unittest.cc b/base/callback_list_unittest.cc
index 6eb5ff7..a628287 100644
--- a/base/callback_list_unittest.cc
+++ b/base/callback_list_unittest.cc
@@ -61,7 +61,7 @@
     if (!added_) {
       added_ = true;
       subscription_ =
-          cb_reg_->Add(Bind(&Adder::IncrementTotal, Unretained(this)));
+          cb_reg_->Add(BindRepeating(&Adder::IncrementTotal, Unretained(this)));
     }
   }
   void IncrementTotal() { total_++; }
@@ -119,35 +119,38 @@
 
   CallbackList<void(int)> c1;
   std::unique_ptr<CallbackList<void(int)>::Subscription> subscription1 =
-      c1.Add(Bind(&Summer::AddOneParam, Unretained(&s)));
+      c1.Add(BindRepeating(&Summer::AddOneParam, Unretained(&s)));
 
   c1.Notify(1);
   EXPECT_EQ(1, s.value());
 
   CallbackList<void(int, int)> c2;
   std::unique_ptr<CallbackList<void(int, int)>::Subscription> subscription2 =
-      c2.Add(Bind(&Summer::AddTwoParam, Unretained(&s)));
+      c2.Add(BindRepeating(&Summer::AddTwoParam, Unretained(&s)));
 
   c2.Notify(1, 2);
   EXPECT_EQ(3, s.value());
 
   CallbackList<void(int, int, int)> c3;
   std::unique_ptr<CallbackList<void(int, int, int)>::Subscription>
-      subscription3 = c3.Add(Bind(&Summer::AddThreeParam, Unretained(&s)));
+      subscription3 =
+          c3.Add(BindRepeating(&Summer::AddThreeParam, Unretained(&s)));
 
   c3.Notify(1, 2, 3);
   EXPECT_EQ(6, s.value());
 
   CallbackList<void(int, int, int, int)> c4;
   std::unique_ptr<CallbackList<void(int, int, int, int)>::Subscription>
-      subscription4 = c4.Add(Bind(&Summer::AddFourParam, Unretained(&s)));
+      subscription4 =
+          c4.Add(BindRepeating(&Summer::AddFourParam, Unretained(&s)));
 
   c4.Notify(1, 2, 3, 4);
   EXPECT_EQ(10, s.value());
 
   CallbackList<void(int, int, int, int, int)> c5;
   std::unique_ptr<CallbackList<void(int, int, int, int, int)>::Subscription>
-      subscription5 = c5.Add(Bind(&Summer::AddFiveParam, Unretained(&s)));
+      subscription5 =
+          c5.Add(BindRepeating(&Summer::AddFiveParam, Unretained(&s)));
 
   c5.Notify(1, 2, 3, 4, 5);
   EXPECT_EQ(15, s.value());
@@ -155,7 +158,8 @@
   CallbackList<void(int, int, int, int, int, int)> c6;
   std::unique_ptr<
       CallbackList<void(int, int, int, int, int, int)>::Subscription>
-      subscription6 = c6.Add(Bind(&Summer::AddSixParam, Unretained(&s)));
+      subscription6 =
+          c6.Add(BindRepeating(&Summer::AddSixParam, Unretained(&s)));
 
   c6.Notify(1, 2, 3, 4, 5, 6);
   EXPECT_EQ(21, s.value());
@@ -168,9 +172,9 @@
   Listener a, b, c;
 
   std::unique_ptr<CallbackList<void(void)>::Subscription> a_subscription =
-      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a)));
+      cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
   std::unique_ptr<CallbackList<void(void)>::Subscription> b_subscription =
-      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
+      cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
 
   EXPECT_TRUE(a_subscription.get());
   EXPECT_TRUE(b_subscription.get());
@@ -183,7 +187,7 @@
   b_subscription.reset();
 
   std::unique_ptr<CallbackList<void(void)>::Subscription> c_subscription =
-      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&c)));
+      cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&c)));
 
   cb_reg.Notify();
 
@@ -203,9 +207,11 @@
   Listener a(1), b(-1), c(1);
 
   std::unique_ptr<CallbackList<void(int)>::Subscription> a_subscription =
-      cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&a)));
+      cb_reg.Add(BindRepeating(&Listener::IncrementByMultipleOfScaler,
+                               Unretained(&a)));
   std::unique_ptr<CallbackList<void(int)>::Subscription> b_subscription =
-      cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&b)));
+      cb_reg.Add(BindRepeating(&Listener::IncrementByMultipleOfScaler,
+                               Unretained(&b)));
 
   EXPECT_TRUE(a_subscription.get());
   EXPECT_TRUE(b_subscription.get());
@@ -218,7 +224,8 @@
   b_subscription.reset();
 
   std::unique_ptr<CallbackList<void(int)>::Subscription> c_subscription =
-      cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&c)));
+      cb_reg.Add(BindRepeating(&Listener::IncrementByMultipleOfScaler,
+                               Unretained(&c)));
 
   cb_reg.Notify(10);
 
@@ -239,15 +246,15 @@
   Remover remover_1, remover_2;
 
   std::unique_ptr<CallbackList<void(void)>::Subscription> remover_1_sub =
-      cb_reg.Add(
-          Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_1)));
+      cb_reg.Add(BindRepeating(&Remover::IncrementTotalAndRemove,
+                               Unretained(&remover_1)));
   std::unique_ptr<CallbackList<void(void)>::Subscription> remover_2_sub =
-      cb_reg.Add(
-          Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_2)));
+      cb_reg.Add(BindRepeating(&Remover::IncrementTotalAndRemove,
+                               Unretained(&remover_2)));
   std::unique_ptr<CallbackList<void(void)>::Subscription> a_subscription =
-      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a)));
+      cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
   std::unique_ptr<CallbackList<void(void)>::Subscription> b_subscription =
-      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
+      cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
 
   // |remover_1| will remove itself.
   remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
@@ -280,9 +287,9 @@
   Adder a(&cb_reg);
   Listener b;
   std::unique_ptr<CallbackList<void(void)>::Subscription> a_subscription =
-      cb_reg.Add(Bind(&Adder::AddCallback, Unretained(&a)));
+      cb_reg.Add(BindRepeating(&Adder::AddCallback, Unretained(&a)));
   std::unique_ptr<CallbackList<void(void)>::Subscription> b_subscription =
-      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
+      cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
 
   cb_reg.Notify();
 
@@ -307,7 +314,7 @@
   Counter remove_count;
   CallbackList<void(void)> cb_reg;
   cb_reg.set_removal_callback(
-      Bind(&Counter::Increment, Unretained(&remove_count)));
+      BindRepeating(&Counter::Increment, Unretained(&remove_count)));
 
   std::unique_ptr<CallbackList<void(void)>::Subscription> subscription =
       cb_reg.Add(DoNothing());
@@ -320,11 +327,11 @@
   // Configure two subscriptions to remove themselves.
   Remover remover_1, remover_2;
   std::unique_ptr<CallbackList<void(void)>::Subscription> remover_1_sub =
-      cb_reg.Add(
-          Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_1)));
+      cb_reg.Add(BindRepeating(&Remover::IncrementTotalAndRemove,
+                               Unretained(&remover_1)));
   std::unique_ptr<CallbackList<void(void)>::Subscription> remover_2_sub =
-      cb_reg.Add(
-          Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_2)));
+      cb_reg.Add(BindRepeating(&Remover::IncrementTotalAndRemove,
+                               Unretained(&remover_2)));
   remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
   remover_2.SetSubscriptionToRemove(std::move(remover_2_sub));
 
diff --git a/base/callback_list_unittest.nc b/base/callback_list_unittest.nc
index 7347f76..c6af89a 100644
--- a/base/callback_list_unittest.nc
+++ b/base/callback_list_unittest.nc
@@ -47,7 +47,7 @@
   FooListener f;
   CallbackList<void(std::unique_ptr<Foo>)> c1;
   std::unique_ptr<CallbackList<void(std::unique_ptr<Foo>)>::Subscription> sub =
-      c1.Add(Bind(&FooListener::GotAScopedFoo, Unretained(&f)));
+      c1.Add(BindRepeating(&FooListener::GotAScopedFoo, Unretained(&f)));
   c1.Notify(std::unique_ptr<Foo>(new Foo()));
 }
 
diff --git a/base/files/file_descriptor_watcher_posix.cc b/base/files/file_descriptor_watcher_posix.cc
index 3a8cd4bf..f4e885e9 100644
--- a/base/files/file_descriptor_watcher_posix.cc
+++ b/base/files/file_descriptor_watcher_posix.cc
@@ -153,7 +153,7 @@
 
 FileDescriptorWatcher::Controller::Controller(MessagePumpForIO::Mode mode,
                                               int fd,
-                                              const Closure& callback)
+                                              const RepeatingClosure& callback)
     : callback_(callback),
       io_thread_task_runner_(
           tls_fd_watcher.Get().Get()->io_thread_task_runner()),
@@ -252,12 +252,12 @@
 }
 
 std::unique_ptr<FileDescriptorWatcher::Controller>
-FileDescriptorWatcher::WatchReadable(int fd, const Closure& callback) {
+FileDescriptorWatcher::WatchReadable(int fd, const RepeatingClosure& callback) {
   return WrapUnique(new Controller(MessagePumpForIO::WATCH_READ, fd, callback));
 }
 
 std::unique_ptr<FileDescriptorWatcher::Controller>
-FileDescriptorWatcher::WatchWritable(int fd, const Closure& callback) {
+FileDescriptorWatcher::WatchWritable(int fd, const RepeatingClosure& callback) {
   return WrapUnique(
       new Controller(MessagePumpForIO::WATCH_WRITE, fd, callback));
 }
diff --git a/base/files/file_descriptor_watcher_posix.h b/base/files/file_descriptor_watcher_posix.h
index 3751cef5..3c2cb9d 100644
--- a/base/files/file_descriptor_watcher_posix.h
+++ b/base/files/file_descriptor_watcher_posix.h
@@ -48,7 +48,9 @@
 
     // Registers |callback| to be invoked when |fd| is readable or writable
     // without blocking (depending on |mode|).
-    Controller(MessagePumpForIO::Mode mode, int fd, const Closure& callback);
+    Controller(MessagePumpForIO::Mode mode,
+               int fd,
+               const RepeatingClosure& callback);
 
     // Starts watching the file descriptor.
     void StartWatching();
@@ -58,7 +60,7 @@
 
     // The callback to run when the watched file descriptor is readable or
     // writable without blocking.
-    Closure callback_;
+    RepeatingClosure callback_;
 
     // TaskRunner associated with the MessageLoopForIO that watches the file
     // descriptor.
@@ -100,10 +102,12 @@
   // must return true (these conditions are met at least on all ThreadPool
   // threads as well as on threads backed by a MessageLoopForIO). |fd| must
   // outlive the returned Controller.
-  static std::unique_ptr<Controller> WatchReadable(int fd,
-                                                   const Closure& callback);
-  static std::unique_ptr<Controller> WatchWritable(int fd,
-                                                   const Closure& callback);
+  static std::unique_ptr<Controller> WatchReadable(
+      int fd,
+      const RepeatingClosure& callback);
+  static std::unique_ptr<Controller> WatchWritable(
+      int fd,
+      const RepeatingClosure& callback);
 
   // Asserts that usage of this API is allowed on this thread.
   static void AssertAllowed()
diff --git a/base/files/file_descriptor_watcher_posix_unittest.cc b/base/files/file_descriptor_watcher_posix_unittest.cc
index b2191e35..22f0514 100644
--- a/base/files/file_descriptor_watcher_posix_unittest.cc
+++ b/base/files/file_descriptor_watcher_posix_unittest.cc
@@ -101,7 +101,7 @@
     std::unique_ptr<FileDescriptorWatcher::Controller> controller =
         FileDescriptorWatcher::WatchReadable(
             read_file_descriptor(),
-            Bind(&Mock::ReadableCallback, Unretained(&mock_)));
+            BindRepeating(&Mock::ReadableCallback, Unretained(&mock_)));
     EXPECT_TRUE(controller);
 
     // Unless read_file_descriptor() was readable before the callback was
@@ -117,7 +117,7 @@
     std::unique_ptr<FileDescriptorWatcher::Controller> controller =
         FileDescriptorWatcher::WatchWritable(
             write_file_descriptor(),
-            Bind(&Mock::WritableCallback, Unretained(&mock_)));
+            BindRepeating(&Mock::WritableCallback, Unretained(&mock_)));
     EXPECT_TRUE(controller);
     return controller;
   }
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h
index 9e29d0a9..0289334 100644
--- a/base/files/file_path_watcher.h
+++ b/base/files/file_path_watcher.h
@@ -35,7 +35,8 @@
   // Callback type for Watch(). |path| points to the file that was updated,
   // and |error| is true if the platform specific code detected an error. In
   // that case, the callback won't be invoked again.
-  typedef base::Callback<void(const FilePath& path, bool error)> Callback;
+  using Callback =
+      base::RepeatingCallback<void(const FilePath& path, bool error)>;
 
   // Used internally to encapsulate different members on different platforms.
   class PlatformDelegate {
diff --git a/base/files/file_path_watcher_kqueue.cc b/base/files/file_path_watcher_kqueue.cc
index fb17e45..84553ccc 100644
--- a/base/files/file_path_watcher_kqueue.cc
+++ b/base/files/file_path_watcher_kqueue.cc
@@ -276,8 +276,8 @@
   // callback cannot be invoked after |kqueue_watch_controller_| (which is a
   // member of |this|) has been deleted.
   kqueue_watch_controller_ = FileDescriptorWatcher::WatchReadable(
-      kqueue_,
-      Bind(&FilePathWatcherKQueue::OnKQueueReadable, Unretained(this)));
+      kqueue_, BindRepeating(&FilePathWatcherKQueue::OnKQueueReadable,
+                             Unretained(this)));
 
   return true;
 }
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc
index abc4bd44..eb1c1b36 100644
--- a/base/files/file_path_watcher_unittest.cc
+++ b/base/files/file_path_watcher_unittest.cc
@@ -218,9 +218,9 @@
                                      FilePathWatcher* watcher,
                                      TestDelegateBase* delegate,
                                      bool recursive_watch) {
-  return watcher->Watch(
-      target, recursive_watch,
-      base::Bind(&TestDelegateBase::OnFileChanged, delegate->AsWeakPtr()));
+  return watcher->Watch(target, recursive_watch,
+                        base::BindRepeating(&TestDelegateBase::OnFileChanged,
+                                            delegate->AsWeakPtr()));
 }
 
 // Basic test: Create the file and verify that we notice.
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
index 2a786be0..35f9056a 100644
--- a/base/files/file_util_unittest.cc
+++ b/base/files/file_util_unittest.cc
@@ -2392,7 +2392,7 @@
     FILE* file = OpenFile(file_path, mode);
     ASSERT_NE(nullptr, file);
     {
-      ScopedClosureRunner file_closer(Bind(IgnoreResult(&CloseFile), file));
+      ScopedClosureRunner file_closer(BindOnce(IgnoreResult(&CloseFile), file));
       bool is_inheritable = true;
       ASSERT_NO_FATAL_FAILURE(GetIsInheritable(file, &is_inheritable));
       EXPECT_FALSE(is_inheritable);
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
index 2c3a846..2a9ef4f93 100644
--- a/base/files/important_file_writer.cc
+++ b/base/files/important_file_writer.cc
@@ -280,7 +280,7 @@
   if (!timer().IsRunning()) {
     timer().Start(
         FROM_HERE, commit_interval_,
-        Bind(&ImportantFileWriter::DoScheduledWrite, Unretained(this)));
+        BindOnce(&ImportantFileWriter::DoScheduledWrite, Unretained(this)));
   }
 }
 
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
index 39e6308..d752287 100644
--- a/base/files/important_file_writer_unittest.cc
+++ b/base/files/important_file_writer_unittest.cc
@@ -93,10 +93,10 @@
 void WriteCallbacksObserver::ObserveNextWriteCallbacks(
     ImportantFileWriter* writer) {
   writer->RegisterOnNextWriteCallbacks(
-      base::Bind(&WriteCallbacksObserver::OnBeforeWrite,
-                 base::Unretained(this)),
-      base::Bind(&WriteCallbacksObserver::OnAfterWrite,
-                 base::Unretained(this)));
+      base::BindOnce(&WriteCallbacksObserver::OnBeforeWrite,
+                     base::Unretained(this)),
+      base::BindOnce(&WriteCallbacksObserver::OnAfterWrite,
+                     base::Unretained(this)));
 }
 
 WriteCallbackObservationState
diff --git a/base/i18n/streaming_utf8_validator_perftest.cc b/base/i18n/streaming_utf8_validator_perftest.cc
index b2e2a007..4f34138 100644
--- a/base/i18n/streaming_utf8_validator_perftest.cc
+++ b/base/i18n/streaming_utf8_validator_perftest.cc
@@ -151,7 +151,7 @@
 // is around 16MB.
 void RunSomeTests(
     const char format[],
-    base::Callback<std::string(size_t length)> construct_test_string,
+    base::RepeatingCallback<std::string(size_t length)> construct_test_string,
     const TestFunctionDescription* test_functions,
     size_t test_count) {
   for (auto length : kTestLengths) {
@@ -171,68 +171,61 @@
 }
 
 TEST(StreamingUtf8ValidatorPerfTest, OneByteRepeated) {
-  RunSomeTests("%s: bytes=1 repeated length=%d repeat=%d",
-               base::Bind(ConstructRepeatedTestString, kOneByteSeqRangeStart),
-               kTestFunctions,
-               3);
+  RunSomeTests(
+      "%s: bytes=1 repeated length=%d repeat=%d",
+      base::BindRepeating(ConstructRepeatedTestString, kOneByteSeqRangeStart),
+      kTestFunctions, 3);
 }
 
 TEST(StreamingUtf8ValidatorPerfTest, OneByteRange) {
   RunSomeTests("%s: bytes=1 ranged length=%d repeat=%d",
-               base::Bind(ConstructRangedTestString,
-                          kOneByteSeqRangeStart,
-                          kOneByteSeqRangeEnd),
-               kTestFunctions,
-               3);
+               base::BindRepeating(ConstructRangedTestString,
+                                   kOneByteSeqRangeStart, kOneByteSeqRangeEnd),
+               kTestFunctions, 3);
 }
 
 TEST(StreamingUtf8ValidatorPerfTest, TwoByteRepeated) {
-  RunSomeTests("%s: bytes=2 repeated length=%d repeat=%d",
-               base::Bind(ConstructRepeatedTestString, kTwoByteSeqRangeStart),
-               kTestFunctions,
-               2);
+  RunSomeTests(
+      "%s: bytes=2 repeated length=%d repeat=%d",
+      base::BindRepeating(ConstructRepeatedTestString, kTwoByteSeqRangeStart),
+      kTestFunctions, 2);
 }
 
 TEST(StreamingUtf8ValidatorPerfTest, TwoByteRange) {
   RunSomeTests("%s: bytes=2 ranged length=%d repeat=%d",
-               base::Bind(ConstructRangedTestString,
-                          kTwoByteSeqRangeStart,
-                          kTwoByteSeqRangeEnd),
-               kTestFunctions,
-               2);
+               base::BindRepeating(ConstructRangedTestString,
+                                   kTwoByteSeqRangeStart, kTwoByteSeqRangeEnd),
+               kTestFunctions, 2);
 }
 
 TEST(StreamingUtf8ValidatorPerfTest, ThreeByteRepeated) {
   RunSomeTests(
       "%s: bytes=3 repeated length=%d repeat=%d",
-      base::Bind(ConstructRepeatedTestString, kThreeByteSeqRangeStart),
-      kTestFunctions,
-      2);
+      base::BindRepeating(ConstructRepeatedTestString, kThreeByteSeqRangeStart),
+      kTestFunctions, 2);
 }
 
 TEST(StreamingUtf8ValidatorPerfTest, ThreeByteRange) {
-  RunSomeTests("%s: bytes=3 ranged length=%d repeat=%d",
-               base::Bind(ConstructRangedTestString,
-                          kThreeByteSeqRangeStart,
+  RunSomeTests(
+      "%s: bytes=3 ranged length=%d repeat=%d",
+      base::BindRepeating(ConstructRangedTestString, kThreeByteSeqRangeStart,
                           kThreeByteSeqRangeEnd),
-               kTestFunctions,
-               2);
+      kTestFunctions, 2);
 }
 
 TEST(StreamingUtf8ValidatorPerfTest, FourByteRepeated) {
-  RunSomeTests("%s: bytes=4 repeated length=%d repeat=%d",
-               base::Bind(ConstructRepeatedTestString, kFourByteSeqRangeStart),
-               kTestFunctions,
-               2);
+  RunSomeTests(
+      "%s: bytes=4 repeated length=%d repeat=%d",
+      base::BindRepeating(ConstructRepeatedTestString, kFourByteSeqRangeStart),
+      kTestFunctions, 2);
 }
 
 TEST(StreamingUtf8ValidatorPerfTest, FourByteRange) {
-  RunSomeTests("%s: bytes=4 ranged length=%d repeat=%d",
-               base::Bind(ConstructRangedTestString,
-                          kFourByteSeqRangeStart,
+  RunSomeTests(
+      "%s: bytes=4 ranged length=%d repeat=%d",
+      base::BindRepeating(ConstructRangedTestString, kFourByteSeqRangeStart,
                           kFourByteSeqRangeEnd),
-               kTestFunctions,
-               2);
+      kTestFunctions, 2);
 }
 
 }  // namespace
diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc
index 0abbf6e..1547af29 100644
--- a/base/message_loop/message_pump_libevent_unittest.cc
+++ b/base/message_loop/message_pump_libevent_unittest.cc
@@ -155,8 +155,8 @@
   OnLibeventNotification(pump.get(), &watcher);
 }
 
-void QuitMessageLoopAndStart(const Closure& quit_closure) {
-  quit_closure.Run();
+void QuitMessageLoopAndStart(OnceClosure quit_closure) {
+  std::move(quit_closure).Run();
 
   RunLoop runloop(RunLoop::Type::kNestableTasksAllowed);
   ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, runloop.QuitClosure());
@@ -196,18 +196,19 @@
 class QuitWatcher : public BaseWatcher {
  public:
   QuitWatcher(MessagePumpLibevent::FdWatchController* controller,
-              base::Closure quit_closure)
+              base::OnceClosure quit_closure)
       : BaseWatcher(controller), quit_closure_(std::move(quit_closure)) {}
 
   void OnFileCanReadWithoutBlocking(int /* fd */) override {
     // Post a fatal closure to the MessageLoop before we quit it.
     ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, BindOnce(&FatalClosure));
 
-    quit_closure_.Run();
+    if (quit_closure_)
+      std::move(quit_closure_).Run();
   }
 
  private:
-  base::Closure quit_closure_;
+  base::OnceClosure quit_closure_;
 };
 
 void WriteFDWrapper(const int fd,
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index 28773a1..53448b0 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -237,14 +237,13 @@
 }
 
 // static
-bool StatisticsRecorder::SetCallback(
-    const std::string& name,
-    const StatisticsRecorder::OnSampleCallback& cb) {
+bool StatisticsRecorder::SetCallback(const std::string& name,
+                                     StatisticsRecorder::OnSampleCallback cb) {
   DCHECK(!cb.is_null());
   const AutoLock auto_lock(lock_.Get());
   EnsureGlobalRecorderWhileLocked();
 
-  if (!top_->callbacks_.insert({name, cb}).second)
+  if (!top_->callbacks_.insert({name, std::move(cb)}).second)
     return false;
 
   const HistogramMap::const_iterator it = top_->histograms_.find(name);
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
index 87a9311..3ac9f45 100644
--- a/base/metrics/statistics_recorder.h
+++ b/base/metrics/statistics_recorder.h
@@ -143,7 +143,7 @@
                             HistogramBase::Flags required_flags,
                             HistogramSnapshotManager* snapshot_manager);
 
-  typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback;
+  using OnSampleCallback = base::RepeatingCallback<void(HistogramBase::Sample)>;
 
   // Sets the callback to notify when a new sample is recorded on the histogram
   // referred to by |histogram_name|. Can be called before or after the
@@ -151,7 +151,7 @@
   //
   // This method is thread safe.
   static bool SetCallback(const std::string& histogram_name,
-                          const OnSampleCallback& callback);
+                          OnSampleCallback callback);
 
   // Clears any callback set on the histogram referred to by |histogram_name|.
   //
diff --git a/base/metrics/user_metrics.h b/base/metrics/user_metrics.h
index 87fbd9ca..3de6f18d 100644
--- a/base/metrics/user_metrics.h
+++ b/base/metrics/user_metrics.h
@@ -56,7 +56,7 @@
 BASE_EXPORT void RecordComputedAction(const std::string& action);
 
 // Called with the action string.
-typedef Callback<void(const std::string&)> ActionCallback;
+using ActionCallback = RepeatingCallback<void(const std::string&)>;
 
 // Add/remove action callbacks (see above).
 // These functions must be called after the task runner has been set with
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
index aeeb4dd..5036ffc 100644
--- a/base/observer_list_threadsafe.h
+++ b/base/observer_list_threadsafe.h
@@ -155,9 +155,9 @@
   // delivery.
   template <typename Method, typename... Params>
   void Notify(const Location& from_here, Method m, Params&&... params) {
-    Callback<void(ObserverType*)> method =
-        Bind(&Dispatcher<ObserverType, Method>::Run, m,
-             std::forward<Params>(params)...);
+    RepeatingCallback<void(ObserverType*)> method =
+        BindRepeating(&Dispatcher<ObserverType, Method>::Run, m,
+                      std::forward<Params>(params)...);
 
     AutoLock lock(lock_);
     for (const auto& observer : observers_) {
@@ -174,11 +174,11 @@
   struct NotificationData : public NotificationDataBase {
     NotificationData(ObserverListThreadSafe* observer_list_in,
                      const Location& from_here_in,
-                     const Callback<void(ObserverType*)>& method_in)
+                     const RepeatingCallback<void(ObserverType*)>& method_in)
         : NotificationDataBase(observer_list_in, from_here_in),
           method(method_in) {}
 
-    Callback<void(ObserverType*)> method;
+    RepeatingCallback<void(ObserverType*)> method;
   };
 
   ~ObserverListThreadSafe() override = default;
diff --git a/base/one_shot_event_unittest.cc b/base/one_shot_event_unittest.cc
index b873336..f7e54fce 100644
--- a/base/one_shot_event_unittest.cc
+++ b/base/one_shot_event_unittest.cc
@@ -52,8 +52,8 @@
   scoped_refptr<base::TestSimpleTaskRunner> runner(
       new base::TestSimpleTaskRunner);
   int i = 0;
-  event.Post(FROM_HERE, base::Bind(&Increment, &i), runner);
-  event.Post(FROM_HERE, base::Bind(&Increment, &i), runner);
+  event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
+  event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
   EXPECT_EQ(0U, runner->NumPendingTasks());
   event.Signal();
 
@@ -69,8 +69,8 @@
   scoped_refptr<base::TestSimpleTaskRunner> runner(
       new base::TestSimpleTaskRunner);
   int i = 0;
-  event.Post(FROM_HERE, base::Bind(&Increment, &i), runner);
-  event.Post(FROM_HERE, base::Bind(&Increment, &i), runner);
+  event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
+  event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
   EXPECT_EQ(0U, runner->NumPendingTasks());
   event.Signal();
   ASSERT_EQ(2U, runner->NumPendingTasks());
@@ -87,7 +87,7 @@
   int i = 0;
 
   event.Signal();
-  event.Post(FROM_HERE, base::Bind(&Increment, &i), runner);
+  event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
   EXPECT_EQ(1U, runner->NumPendingTasks());
   EXPECT_EQ(0, i);
   runner->RunPendingTasks();
@@ -102,8 +102,8 @@
   int runner_i = 0;
   int loop_i = 0;
 
-  event.Post(FROM_HERE, base::Bind(&Increment, &runner_i), runner);
-  event.Post(FROM_HERE, base::Bind(&Increment, &loop_i));
+  event.Post(FROM_HERE, base::BindOnce(&Increment, &runner_i), runner);
+  event.Post(FROM_HERE, base::BindOnce(&Increment, &loop_i));
   event.Signal();
   EXPECT_EQ(1U, runner->NumPendingTasks());
   EXPECT_EQ(0, runner_i);
@@ -119,7 +119,7 @@
     const scoped_refptr<base::SingleThreadTaskRunner>& runner,
     int* i) {
   EXPECT_TRUE(event->is_signaled());
-  event->Post(FROM_HERE, base::Bind(&Increment, i), runner);
+  event->Post(FROM_HERE, base::BindOnce(&Increment, i), runner);
 }
 
 TEST(OneShotEventTest, IsSignaledAndPostsFromCallbackWork) {
@@ -129,7 +129,7 @@
   int i = 0;
 
   event.Post(FROM_HERE,
-             base::Bind(&CheckSignaledAndPostIncrement, &event, runner, &i),
+             base::BindOnce(&CheckSignaledAndPostIncrement, &event, runner, &i),
              runner);
   EXPECT_EQ(0, i);
   event.Signal();
diff --git a/base/pending_task.h b/base/pending_task.h
index e7b7c80..45ed675 100644
--- a/base/pending_task.h
+++ b/base/pending_task.h
@@ -58,6 +58,16 @@
   static constexpr size_t kTaskBacktraceLength = 4;
   std::array<const void*, kTaskBacktraceLength> task_backtrace = {};
 
+  // The context of the IPC message that was being handled when this task was
+  // posted. This is a program counter that is set within the scope of an IPC
+  // handler and when symbolized uniquely identifies the message being
+  // processed. This property is also propagated from one PendingTask to the
+  // next. For example, if pending task A was posted while handling an IPC,
+  // and pending task B was posted from within pending task A, then pending task
+  // B will inherit the |ipc_program_counter| of pending task A. In some sense
+  // this can be interpreted as a "root" task backtrace frame.
+  const void* ipc_program_counter = nullptr;
+
   // Secondary sort key for run time.
   int sequence_num = 0;
 
diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc
index 93a94c88..bf9db43 100644
--- a/base/profiler/stack_sampling_profiler_unittest.cc
+++ b/base/profiler/stack_sampling_profiler_unittest.cc
@@ -69,26 +69,6 @@
 
 namespace {
 
-// Configuration for the frames that appear on the stack.
-struct StackConfiguration {
-  enum Config { NORMAL, WITH_ALLOCA, WITH_OTHER_LIBRARY };
-
-  explicit StackConfiguration(Config config)
-      : StackConfiguration(config, nullptr) {
-    EXPECT_NE(config, WITH_OTHER_LIBRARY);
-  }
-
-  StackConfiguration(Config config, NativeLibrary library)
-      : config(config), library(library) {
-    EXPECT_TRUE(config != WITH_OTHER_LIBRARY || library);
-  }
-
-  Config config;
-
-  // Only used if config == WITH_OTHER_LIBRARY.
-  NativeLibrary library;
-};
-
 // Addresses near the start and end of a function.
 struct FunctionAddressRange {
   const void* start;
@@ -241,9 +221,14 @@
 NOINLINE FunctionAddressRange CallWithAlloca(const Closure& wait_for_sample) {
   const void* start_program_counter = GetProgramCounter();
 
-  const size_t alloca_size = 100;
-  // Memset to 0 to generate a clean failure.
-  std::memset(alloca(alloca_size), 0, alloca_size);
+  // Volatile to force a dynamic stack allocation.
+  const volatile size_t alloca_size = 100;
+  // Use the memory via volatile writes to prevent the allocation from being
+  // optimized out.
+  volatile char* const allocation =
+      const_cast<volatile char*>(static_cast<char*>(alloca(alloca_size)));
+  for (volatile char* p = allocation; p < allocation + alloca_size; ++p)
+    *p = '\0';
 
   if (!wait_for_sample.is_null())
     wait_for_sample.Run();
@@ -524,6 +509,33 @@
   WithTargetThread(&scenario, profile_function);
 }
 
+Frames SampleScenario(UnwindScenario* scenario, ModuleCache* module_cache) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(0);
+  params.samples_per_profile = 1;
+
+  Profile profile;
+  WithTargetThread(scenario, [&](PlatformThreadId target_thread_id) {
+    WaitableEvent sampling_thread_completed(
+        WaitableEvent::ResetPolicy::MANUAL,
+        WaitableEvent::InitialState::NOT_SIGNALED);
+    StackSamplingProfiler profiler(
+        target_thread_id, params,
+        std::make_unique<TestProfileBuilder>(
+            module_cache,
+            BindLambdaForTesting(
+                [&profile, &sampling_thread_completed](Profile result_profile) {
+                  profile = std::move(result_profile);
+                  sampling_thread_completed.Signal();
+                })));
+    profiler.Start();
+    sampling_thread_completed.Wait();
+  });
+
+  CHECK_EQ(1u, profile.frame_sets.size());
+  return profile.frame_sets[0];
+}
+
 struct TestProfilerInfo {
   TestProfilerInfo(PlatformThreadId thread_id,
                    const SamplingParams& params,
@@ -773,33 +785,8 @@
 #define MAYBE_Basic DISABLED_Basic
 #endif
 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_Basic) {
-  SamplingParams params;
-  params.sampling_interval = TimeDelta::FromMilliseconds(0);
-  params.samples_per_profile = 1;
-
   UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
-
-  Profile profile;
-  WithTargetThread(&scenario, [&](PlatformThreadId target_thread_id) {
-    WaitableEvent sampling_thread_completed(
-        WaitableEvent::ResetPolicy::MANUAL,
-        WaitableEvent::InitialState::NOT_SIGNALED);
-    StackSamplingProfiler profiler(
-        target_thread_id, params,
-        std::make_unique<TestProfileBuilder>(
-            module_cache(),
-            BindLambdaForTesting(
-                [&profile, &sampling_thread_completed](Profile result_profile) {
-                  profile = std::move(result_profile);
-                  sampling_thread_completed.Signal();
-                })));
-    profiler.Start();
-    sampling_thread_completed.Wait();
-  });
-
-  // Check that the size of the frame sets are correct.
-  ASSERT_EQ(1u, profile.frame_sets.size());
-  const Frames& frames = profile.frame_sets[0];
+  const Frames& frames = SampleScenario(&scenario, module_cache());
 
   // Check that all the modules are valid.
   for (const auto& frame : frames)
@@ -820,34 +807,8 @@
 #define MAYBE_Alloca DISABLED_Alloca
 #endif
 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_Alloca) {
-  SamplingParams params;
-  params.sampling_interval = TimeDelta::FromMilliseconds(0);
-  params.samples_per_profile = 1;
-
   UnwindScenario scenario(BindRepeating(&CallWithAlloca));
-
-  Profile profile;
-  WithTargetThread(
-      &scenario, [&](PlatformThreadId target_thread_id) {
-        WaitableEvent sampling_thread_completed(
-            WaitableEvent::ResetPolicy::MANUAL,
-            WaitableEvent::InitialState::NOT_SIGNALED);
-        StackSamplingProfiler profiler(
-            target_thread_id, params,
-            std::make_unique<TestProfileBuilder>(
-                module_cache(),
-                BindLambdaForTesting([&profile, &sampling_thread_completed](
-                                         Profile result_profile) {
-                  profile = std::move(result_profile);
-                  sampling_thread_completed.Signal();
-                })));
-        profiler.Start();
-        sampling_thread_completed.Wait();
-      });
-
-  // Look up the frames.
-  ASSERT_EQ(1u, profile.frame_sets.size());
-  const Frames& frames = profile.frame_sets[0];
+  const Frames& frames = SampleScenario(&scenario, module_cache());
 
   // The stack should contain a full unwind.
   ExpectStackContains(frames, {scenario.GetWaitForSampleAddressRange(),
@@ -855,6 +816,50 @@
                                scenario.GetOuterFunctionAddressRange()});
 }
 
+// Checks that a stack that runs through another library produces a stack with
+// the expected functions.
+// macOS ASAN is not yet supported - crbug.com/718628.
+#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
+#define MAYBE_OtherLibrary OtherLibrary
+#else
+#define MAYBE_OtherLibrary DISABLED_OtherLibrary
+#endif
+PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_OtherLibrary) {
+  ScopedNativeLibrary other_library(LoadOtherLibrary());
+  UnwindScenario scenario(
+      BindRepeating(&CallThroughOtherLibrary, Unretained(other_library.get())));
+  const Frames& frames = SampleScenario(&scenario, module_cache());
+
+  // The stack should contain a full unwind.
+  ExpectStackContains(frames, {scenario.GetWaitForSampleAddressRange(),
+                               scenario.GetSetupFunctionAddressRange(),
+                               scenario.GetOuterFunctionAddressRange()});
+}
+
+// Checks that a stack that runs through a library that is unloading produces a
+// stack, and doesn't crash.
+// Unloading is synchronous on the Mac, so this test is inapplicable.
+#if !defined(OS_MACOSX)
+#define MAYBE_UnloadingLibrary UnloadingLibrary
+#else
+#define MAYBE_UnloadingLibrary DISABLED_UnloadingLibrary
+#endif
+PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadingLibrary) {
+  TestLibraryUnload(false, module_cache());
+}
+
+// Checks that a stack that runs through a library that has been unloaded
+// produces a stack, and doesn't crash.
+// macOS ASAN is not yet supported - crbug.com/718628.
+#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
+#define MAYBE_UnloadedLibrary UnloadedLibrary
+#else
+#define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary
+#endif
+PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadedLibrary) {
+  TestLibraryUnload(true, module_cache());
+}
+
 // Checks that a profiler can stop/destruct without ever having started.
 PROFILER_TEST_F(StackSamplingProfilerTest, StopWithoutStarting) {
   WithTargetThread([this](PlatformThreadId target_thread_id) {
@@ -1309,76 +1314,6 @@
   });
 }
 
-// Checks that a stack that runs through another library produces a stack with
-// the expected functions.
-// macOS ASAN is not yet supported - crbug.com/718628.
-#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
-#define MAYBE_OtherLibrary OtherLibrary
-#else
-#define MAYBE_OtherLibrary DISABLED_OtherLibrary
-#endif
-PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_OtherLibrary) {
-  SamplingParams params;
-  params.sampling_interval = TimeDelta::FromMilliseconds(0);
-  params.samples_per_profile = 1;
-
-  Profile profile;
-
-  ScopedNativeLibrary other_library(LoadOtherLibrary());
-  UnwindScenario scenario(
-      BindRepeating(&CallThroughOtherLibrary, Unretained(other_library.get())));
-
-  WithTargetThread(&scenario, [&, this](PlatformThreadId target_thread_id) {
-    WaitableEvent sampling_thread_completed(
-        WaitableEvent::ResetPolicy::MANUAL,
-        WaitableEvent::InitialState::NOT_SIGNALED);
-    StackSamplingProfiler profiler(
-        target_thread_id, params,
-        std::make_unique<TestProfileBuilder>(
-            module_cache(),
-            BindLambdaForTesting(
-                [&profile, &sampling_thread_completed](Profile result_profile) {
-                  profile = std::move(result_profile);
-                  sampling_thread_completed.Signal();
-                })));
-    profiler.Start();
-    sampling_thread_completed.Wait();
-  });
-
-  // Look up the frames.
-  ASSERT_EQ(1u, profile.frame_sets.size());
-  const Frames& frames = profile.frame_sets[0];
-
-  // The stack should contain a full unwind.
-  ExpectStackContains(frames, {scenario.GetWaitForSampleAddressRange(),
-                               scenario.GetSetupFunctionAddressRange(),
-                               scenario.GetOuterFunctionAddressRange()});
-}
-
-// Checks that a stack that runs through a library that is unloading produces a
-// stack, and doesn't crash.
-// Unloading is synchronous on the Mac, so this test is inapplicable.
-#if !defined(OS_MACOSX)
-#define MAYBE_UnloadingLibrary UnloadingLibrary
-#else
-#define MAYBE_UnloadingLibrary DISABLED_UnloadingLibrary
-#endif
-PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadingLibrary) {
-  TestLibraryUnload(false, module_cache());
-}
-
-// Checks that a stack that runs through a library that has been unloaded
-// produces a stack, and doesn't crash.
-// macOS ASAN is not yet supported - crbug.com/718628.
-#if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
-#define MAYBE_UnloadedLibrary UnloadedLibrary
-#else
-#define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary
-#endif
-PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadedLibrary) {
-  TestLibraryUnload(true, module_cache());
-}
-
 // Checks that different threads can be sampled in parallel.
 PROFILER_TEST_F(StackSamplingProfilerTest, MultipleSampledThreads) {
   UnwindScenario scenario1(BindRepeating(&CallWithPlainFunction));
diff --git a/base/syslog_logging.cc b/base/syslog_logging.cc
index 2c44cd5..6d139b709 100644
--- a/base/syslog_logging.cc
+++ b/base/syslog_logging.cc
@@ -69,8 +69,8 @@
     return;
   }
 
-  base::ScopedClosureRunner auto_deregister(
-      base::Bind(base::IgnoreResult(&DeregisterEventSource), event_log_handle));
+  base::ScopedClosureRunner auto_deregister(base::BindOnce(
+      base::IgnoreResult(&DeregisterEventSource), event_log_handle));
   std::string message(log_message_.str());
   WORD log_type = EVENTLOG_ERROR_TYPE;
   switch (log_message_.severity()) {
diff --git a/base/task/cancelable_task_tracker.h b/base/task/cancelable_task_tracker.h
index 6d42e3ce..1ccd1fd 100644
--- a/base/task/cancelable_task_tracker.h
+++ b/base/task/cancelable_task_tracker.h
@@ -93,16 +93,18 @@
                  std::move(reply), Owned(result)));
   }
 
-  // Callback version of PostTaskWithTraitsAndReplyWithResult above.
+  // RepeatingCallback version of PostTaskWithTraitsAndReplyWithResult above.
   // Though RepeatingCallback is convertible to OnceCallback, we need this since
   // we can not use template deduction and object conversion at once on the
   // overload resolution.
-  // TODO(tzik): Update all callers of the Callback version to use OnceCallback.
+  // TODO(tzik): Update all callers of the RepeatingCallback version to use
+  // OnceCallback.
   template <typename TaskReturnType, typename ReplyArgType>
-  TaskId PostTaskAndReplyWithResult(TaskRunner* task_runner,
-                                    const Location& from_here,
-                                    Callback<TaskReturnType()> task,
-                                    Callback<void(ReplyArgType)> reply) {
+  TaskId PostTaskAndReplyWithResult(
+      TaskRunner* task_runner,
+      const Location& from_here,
+      RepeatingCallback<TaskReturnType()> task,
+      RepeatingCallback<void(ReplyArgType)> reply) {
     return PostTaskAndReplyWithResult(
         task_runner, from_here,
         static_cast<OnceCallback<TaskReturnType()>>(std::move(task)),
diff --git a/base/task/common/task_annotator.cc b/base/task/common/task_annotator.cc
index 76294de..b5b0873 100644
--- a/base/task/common/task_annotator.cc
+++ b/base/task/common/task_annotator.cc
@@ -8,6 +8,7 @@
 
 #include "base/debug/activity_tracker.h"
 #include "base/debug/alias.h"
+#include "base/memory/ptr_util.h"
 #include "base/no_destructor.h"
 #include "base/pending_task.h"
 #include "base/threading/thread_local.h"
@@ -19,19 +20,36 @@
 
 TaskAnnotator::ObserverForTesting* g_task_annotator_observer = nullptr;
 
+// Information about the context in which a PendingTask is currently being
+// executed.
+struct TaskAnnotatorThreadInfo {
+  // The pending task currently being executed.
+  const PendingTask* pending_task = nullptr;
+  // The pending task that was being executed when the |ipc_program_counter|
+  // was set. This is used to detect a nested message loop, in which case the
+  // global IPC decoration should not be applied.
+  const PendingTask* ipc_message_handler_task = nullptr;
+  // The program counter of the currently executing IPC message handler, if
+  // there is one.
+  const void* ipc_program_counter = nullptr;
+};
+
 // Returns the TLS slot that stores the PendingTask currently in progress on
 // each thread. Used to allow creating a breadcrumb of program counters on the
 // stack to help identify a task's origin in crashes.
-ThreadLocalPointer<const PendingTask>* GetTLSForCurrentPendingTask() {
-  static NoDestructor<ThreadLocalPointer<const PendingTask>>
-      tls_for_current_pending_task;
-  return tls_for_current_pending_task.get();
+TaskAnnotatorThreadInfo* GetTLSForCurrentPendingTask() {
+  static NoDestructor<ThreadLocalOwnedPointer<TaskAnnotatorThreadInfo>>
+      instance;
+  if (!instance->Get())
+    instance->Set(WrapUnique(new TaskAnnotatorThreadInfo));
+  auto* tls_info = instance->Get();
+  return tls_info;
 }
 
 }  // namespace
 
 const PendingTask* TaskAnnotator::CurrentTaskForThread() {
-  return GetTLSForCurrentPendingTask()->Get();
+  return GetTLSForCurrentPendingTask()->pending_task;
 }
 
 TaskAnnotator::TaskAnnotator() = default;
@@ -55,9 +73,21 @@
   if (pending_task->task_backtrace[0])
     return;
 
-  const PendingTask* parent_task = GetTLSForCurrentPendingTask()->Get();
+  // Inherit the currently executing IPC handler context only if not in a nested
+  // message loop.
+  const auto* tls_info = GetTLSForCurrentPendingTask();
+  if (tls_info->ipc_message_handler_task == tls_info->pending_task)
+    pending_task->ipc_program_counter = tls_info->ipc_program_counter;
+
+  const auto* parent_task = tls_info->pending_task;
   if (!parent_task)
     return;
+
+  // If an IPC message handler context wasn't explicitly set, then inherit the
+  // context from the parent task.
+  if (!pending_task->ipc_program_counter)
+    pending_task->ipc_program_counter = parent_task->ipc_program_counter;
+
   pending_task->task_backtrace[0] = parent_task->posted_from.program_counter();
   std::copy(parent_task->task_backtrace.begin(),
             parent_task->task_backtrace.end() - 1,
@@ -78,17 +108,21 @@
       TRACE_DISABLED_BY_DEFAULT("toplevel.flow"), trace_event_name,
       TRACE_ID_MANGLE(GetTaskTraceID(*pending_task)), TRACE_EVENT_FLAG_FLOW_IN);
 
-  // Before running the task, store the task backtrace with the chain of
-  // PostTasks that resulted in this call and deliberately alias it to ensure
-  // it is on the stack if the task crashes. Be careful not to assume that the
-  // variable itself will have the expected value when displayed by the
+  // Before running the task, store the IPC context and the task backtrace with
+  // the chain of PostTasks that resulted in this call and deliberately alias it
+  // to ensure it is on the stack if the task crashes. Be careful not to assume
+  // that the variable itself will have the expected value when displayed by the
   // optimizer in an optimized build. Look at a memory dump of the stack.
   static constexpr int kStackTaskTraceSnapshotSize =
-      PendingTask::kTaskBacktraceLength + 3;
+      PendingTask::kTaskBacktraceLength + 4;
   std::array<const void*, kStackTaskTraceSnapshotSize> task_backtrace;
 
   // Store a marker to locate |task_backtrace| content easily on a memory
-  // dump.
+  // dump. The layout is as follows:
+  //
+  // +------------ +----+---------+-----+-----------+--------+-------------+
+  // | Head Marker | PC | frame 0 | ... | frame N-1 | IPC PC | Tail Marker |
+  // +------------ +----+---------+-----+-----------+--------+-------------+
   //
   // Markers glossary (compliments of wez):
   //      cool code,do it dude!
@@ -101,19 +135,19 @@
   task_backtrace[1] = pending_task->posted_from.program_counter();
   std::copy(pending_task->task_backtrace.begin(),
             pending_task->task_backtrace.end(), task_backtrace.begin() + 2);
+  task_backtrace[kStackTaskTraceSnapshotSize - 2] =
+      pending_task->ipc_program_counter;
   debug::Alias(&task_backtrace);
 
-  ThreadLocalPointer<const PendingTask>* tls_for_current_pending_task =
-      GetTLSForCurrentPendingTask();
-  const PendingTask* previous_pending_task =
-      tls_for_current_pending_task->Get();
-  tls_for_current_pending_task->Set(pending_task);
+  auto* tls_info = GetTLSForCurrentPendingTask();
+  const auto* previous_pending_task = tls_info->pending_task;
+  tls_info->pending_task = pending_task;
 
   if (g_task_annotator_observer)
     g_task_annotator_observer->BeforeRunTask(pending_task);
   std::move(pending_task->task).Run();
 
-  tls_for_current_pending_task->Set(previous_pending_task);
+  tls_info->pending_task = previous_pending_task;
 }
 
 uint64_t TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
@@ -133,4 +167,19 @@
   g_task_annotator_observer = nullptr;
 }
 
+TaskAnnotator::ScopedSetIpcProgramCounter::ScopedSetIpcProgramCounter(
+    const void* program_counter) {
+  auto* tls_info = GetTLSForCurrentPendingTask();
+  old_ipc_message_handler_task_ = tls_info->ipc_message_handler_task;
+  old_ipc_program_counter_ = tls_info->ipc_program_counter;
+  tls_info->ipc_message_handler_task = tls_info->pending_task;
+  tls_info->ipc_program_counter = program_counter;
+}
+
+TaskAnnotator::ScopedSetIpcProgramCounter::~ScopedSetIpcProgramCounter() {
+  auto* tls_info = GetTLSForCurrentPendingTask();
+  tls_info->ipc_message_handler_task = old_ipc_message_handler_task_;
+  tls_info->ipc_program_counter = old_ipc_program_counter_;
+}
+
 }  // namespace base
diff --git a/base/task/common/task_annotator.h b/base/task/common/task_annotator.h
index 4a19cdfd..654ce984 100644
--- a/base/task/common/task_annotator.h
+++ b/base/task/common/task_annotator.h
@@ -14,7 +14,8 @@
 struct PendingTask;
 
 // Implements common debug annotations for posted tasks. This includes data
-// such as task origins, queueing durations and memory usage.
+// such as task origins, IPC message contexts, queueing durations and memory
+// usage.
 class BASE_EXPORT TaskAnnotator {
  public:
   class ObserverForTesting {
@@ -24,6 +25,10 @@
     virtual void BeforeRunTask(const PendingTask* pending_task) = 0;
   };
 
+  // This is used to set the |ipc_program_counter| field for PendingTasks. It is
+  // intended to be used only from within generated IPC handler dispatch code.
+  class ScopedSetIpcProgramCounter;
+
   static const PendingTask* CurrentTaskForThread();
 
   TaskAnnotator();
@@ -59,6 +64,18 @@
   DISALLOW_COPY_AND_ASSIGN(TaskAnnotator);
 };
 
+class BASE_EXPORT TaskAnnotator::ScopedSetIpcProgramCounter {
+ public:
+  explicit ScopedSetIpcProgramCounter(const void* program_counter);
+  ~ScopedSetIpcProgramCounter();
+
+ private:
+  const PendingTask* old_ipc_message_handler_task_ = nullptr;
+  const void* old_ipc_program_counter_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSetIpcProgramCounter);
+};
+
 }  // namespace base
 
 #endif  // BASE_TASK_COMMON_TASK_ANNOTATOR_H_
diff --git a/base/task/common/task_annotator_unittest.cc b/base/task/common/task_annotator_unittest.cc
index 901ab54..b2b6440 100644
--- a/base/task/common/task_annotator_unittest.cc
+++ b/base/task/common/task_annotator_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/post_task.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -61,6 +62,7 @@
     AutoLock auto_lock(on_before_run_task_lock_);
     last_posted_from_ = pending_task->posted_from;
     last_task_backtrace_ = pending_task->task_backtrace;
+    last_ipc_pc_ = pending_task->ipc_program_counter;
   }
 
   void SetUp() override { TaskAnnotator::RegisterObserverForTesting(this); }
@@ -71,6 +73,7 @@
                           const Location& posted_from,
                           const Location& next_from_here,
                           const ExpectedTrace& expected_trace,
+                          const void* expected_ipc_pc,
                           OnceClosure task) {
     SCOPED_TRACE(StringPrintf("Callback Depth: %zu", expected_trace.size()));
 
@@ -82,10 +85,24 @@
       else
         EXPECT_EQ(nullptr, last_task_backtrace_[i]);
     }
+    EXPECT_EQ(expected_ipc_pc, last_ipc_pc_);
 
     task_runner->PostTask(next_from_here, std::move(task));
   }
 
+  void VerifyTraceAndPostWithIpcContext(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      const Location& posted_from,
+      const Location& next_from_here,
+      const ExpectedTrace& expected_trace,
+      const void* expected_ipc_pc,
+      OnceClosure task,
+      const void* new_ipc_pc) {
+    TaskAnnotator::ScopedSetIpcProgramCounter scoped_ipc_pc(new_ipc_pc);
+    VerifyTraceAndPost(task_runner, posted_from, next_from_here, expected_trace,
+                       expected_ipc_pc, std::move(task));
+  }
+
   // Same as VerifyTraceAndPost() with the exception that it also posts a task
   // that will prevent |task| from running until |wait_before_next_task| is
   // signaled.
@@ -94,6 +111,7 @@
       const Location& posted_from,
       const Location& next_from_here,
       const ExpectedTrace& expected_trace,
+      const void* expected_ipc_pc,
       OnceClosure task,
       WaitableEvent* wait_before_next_task) {
     DCHECK(wait_before_next_task);
@@ -107,7 +125,7 @@
         FROM_HERE,
         BindOnce(&WaitableEvent::Wait, Unretained(wait_before_next_task)));
     VerifyTraceAndPost(task_runner, posted_from, next_from_here, expected_trace,
-                       std::move(task));
+                       expected_ipc_pc, std::move(task));
   }
 
  protected:
@@ -128,12 +146,15 @@
   std::array<const void*, PendingTask::kTaskBacktraceLength>
       last_task_backtrace_ = {};
 
+  const void* last_ipc_pc_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(TaskAnnotatorBacktraceIntegrationTest);
 };
 
 // Ensure the task backtrace populates correctly.
 TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedSimple) {
   test::ScopedTaskEnvironment scoped_task_environment;
+  const void* dummy_ipc_pc = &dummy_ipc_pc;
   const Location location0 = FROM_HERE;
   const Location location1 = FROM_HERE;
   const Location location2 = FROM_HERE;
@@ -143,6 +164,9 @@
 
   RunLoop run_loop;
 
+  // Task 0 executes with no IPC context. Task 1 executes under an explicitly
+  // set IPC context, and tasks 2-5 inherit that context.
+
   // Task 5 has tasks 4/3/2/1 as parents (task 0 isn't visible as only the
   // last 4 parents are kept).
   OnceClosure task5 = BindOnce(
@@ -150,7 +174,7 @@
       Unretained(this), ThreadTaskRunnerHandle::Get(), location5, FROM_HERE,
       ExpectedTrace({location4.program_counter(), location3.program_counter(),
                      location2.program_counter(), location1.program_counter()}),
-      run_loop.QuitClosure());
+      dummy_ipc_pc, run_loop.QuitClosure());
 
   // Task i=4/3/2/1/0 have tasks [0,i) as parents.
   OnceClosure task4 = BindOnce(
@@ -158,26 +182,27 @@
       Unretained(this), ThreadTaskRunnerHandle::Get(), location4, location5,
       ExpectedTrace({location3.program_counter(), location2.program_counter(),
                      location1.program_counter(), location0.program_counter()}),
-      std::move(task5));
+      dummy_ipc_pc, std::move(task5));
   OnceClosure task3 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
       Unretained(this), ThreadTaskRunnerHandle::Get(), location3, location4,
       ExpectedTrace({location2.program_counter(), location1.program_counter(),
                      location0.program_counter()}),
-      std::move(task4));
+      dummy_ipc_pc, std::move(task4));
   OnceClosure task2 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
       Unretained(this), ThreadTaskRunnerHandle::Get(), location2, location3,
       ExpectedTrace({location1.program_counter(), location0.program_counter()}),
-      std::move(task3));
+      dummy_ipc_pc, std::move(task3));
   OnceClosure task1 = BindOnce(
-      &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
+      &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPostWithIpcContext,
       Unretained(this), ThreadTaskRunnerHandle::Get(), location1, location2,
-      ExpectedTrace({location0.program_counter()}), std::move(task2));
+      ExpectedTrace({location0.program_counter()}), nullptr, std::move(task2),
+      dummy_ipc_pc);
   OnceClosure task0 =
       BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
                Unretained(this), ThreadTaskRunnerHandle::Get(), location0,
-               location1, ExpectedTrace({}), std::move(task1));
+               location1, ExpectedTrace({}), nullptr, std::move(task1));
 
   ThreadTaskRunnerHandle::Get()->PostTask(location0, std::move(task0));
 
@@ -224,6 +249,15 @@
   //                                \         \       /
   //  C:                            Wait........ TC0 /
 
+  // IPC contexts:
+  // TA0 and TA1 execute with no IPC context.
+  // TB0L is the first task to execute with an explicit IPC context.
+  // TB0F inherits no context.
+  // TC0 is posted with a new IPC context from TB0L.
+  // TA2 inherits that IPC context.
+  const void* dummy_ipc_pc0 = &dummy_ipc_pc0;
+  const void* dummy_ipc_pc1 = &dummy_ipc_pc1;
+
   // On task runner c, post a task back to main thread that verifies its trace
   // and terminates after one more self-post.
   OnceClosure task_a2 = BindOnce(
@@ -232,14 +266,14 @@
       ExpectedTrace(
           {location_c0.program_counter(), location_b0.program_counter(),
            location_a1.program_counter(), location_a0.program_counter()}),
-      run_loop.QuitClosure());
-  OnceClosure task_c0 =
-      BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-               Unretained(this), main_thread_a, location_c0, location_a2,
-               ExpectedTrace({location_b0.program_counter(),
-                              location_a1.program_counter(),
-                              location_a0.program_counter()}),
-               std::move(task_a2));
+      dummy_ipc_pc1, run_loop.QuitClosure());
+  OnceClosure task_c0 = BindOnce(
+      &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPostWithIpcContext,
+      Unretained(this), main_thread_a, location_c0, location_a2,
+      ExpectedTrace({location_b0.program_counter(),
+                     location_a1.program_counter(),
+                     location_a0.program_counter()}),
+      nullptr, std::move(task_a2), dummy_ipc_pc1);
 
   // On task runner b run two tasks that conceptually come from the same
   // location (managed via RunTwo().) One will post back to task runner b and
@@ -251,24 +285,25 @@
       Unretained(this), task_runner_c, location_b0, location_c0,
       ExpectedTrace(
           {location_a1.program_counter(), location_a0.program_counter()}),
-      std::move(task_c0), &lock_step);
-  OnceClosure task_b0_local =
-      BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-               Unretained(this), task_runner_b, location_b0, location_b1,
-               ExpectedTrace({location_a1.program_counter(),
-                              location_a0.program_counter()}),
-               BindOnce(&WaitableEvent::Signal, Unretained(&lock_step)));
+      nullptr, std::move(task_c0), &lock_step);
+  OnceClosure task_b0_local = BindOnce(
+      &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPostWithIpcContext,
+      Unretained(this), task_runner_b, location_b0, location_b1,
+      ExpectedTrace(
+          {location_a1.program_counter(), location_a0.program_counter()}),
+      nullptr, BindOnce(&WaitableEvent::Signal, Unretained(&lock_step)),
+      dummy_ipc_pc0);
 
   OnceClosure task_a1 =
       BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
                Unretained(this), task_runner_b, location_a1, location_b0,
-               ExpectedTrace({location_a0.program_counter()}),
+               ExpectedTrace({location_a0.program_counter()}), nullptr,
                BindOnce(&TaskAnnotatorBacktraceIntegrationTest::RunTwo,
                         std::move(task_b0_local), std::move(task_b0_fork)));
   OnceClosure task_a0 =
       BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
                Unretained(this), main_thread_a, location_a0, location_a1,
-               ExpectedTrace({}), std::move(task_a1));
+               ExpectedTrace({}), nullptr, std::move(task_a1));
 
   main_thread_a->PostTask(location_a0, std::move(task_a0));
 
@@ -278,6 +313,9 @@
 // Ensure nesting doesn't break the chain.
 TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedNested) {
   test::ScopedTaskEnvironment scoped_task_environment;
+  const void* dummy_ipc_pc = &dummy_ipc_pc;
+  const void* dummy_ipc_pc1 = &dummy_ipc_pc1;
+  const void* dummy_ipc_pc2 = &dummy_ipc_pc2;
   const Location location0 = FROM_HERE;
   const Location location1 = FROM_HERE;
   const Location location2 = FROM_HERE;
@@ -307,6 +345,10 @@
   //   tls_for_current_pending_task->Set(nullptr);
   // at the end of TaskAnnotator::RunTask() makes this test fail.
 
+  // This test also validates the IPC contexts are propagated appropriately, and
+  // then a context in an outer loop does not color tasks posted from a nested
+  // loop.
+
   RunLoop nested_run_loop1(RunLoop::Type::kNestableTasksAllowed);
 
   // Expectations are the same as in SingleThreadedSimple test despite the
@@ -317,19 +359,19 @@
       Unretained(this), ThreadTaskRunnerHandle::Get(), location5, FROM_HERE,
       ExpectedTrace({location4.program_counter(), location3.program_counter(),
                      location2.program_counter(), location1.program_counter()}),
-      run_loop.QuitClosure());
+      dummy_ipc_pc, run_loop.QuitClosure());
   OnceClosure task4 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
       Unretained(this), ThreadTaskRunnerHandle::Get(), location4, location5,
       ExpectedTrace({location3.program_counter(), location2.program_counter(),
                      location1.program_counter(), location0.program_counter()}),
-      std::move(task5));
+      dummy_ipc_pc, std::move(task5));
   OnceClosure task3 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
       Unretained(this), ThreadTaskRunnerHandle::Get(), location3, location4,
       ExpectedTrace({location2.program_counter(), location1.program_counter(),
                      location0.program_counter()}),
-      std::move(task4));
+      dummy_ipc_pc, std::move(task4));
 
   OnceClosure run_task_3_then_quit_nested_loop1 =
       BindOnce(&TaskAnnotatorBacktraceIntegrationTest::RunTwo, std::move(task3),
@@ -339,29 +381,41 @@
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
       Unretained(this), ThreadTaskRunnerHandle::Get(), location2, location3,
       ExpectedTrace({location1.program_counter(), location0.program_counter()}),
-      std::move(run_task_3_then_quit_nested_loop1));
+      dummy_ipc_pc, std::move(run_task_3_then_quit_nested_loop1));
 
   // Task 1 is custom. It enters another nested RunLoop, has it do work and exit
   // before posting the next task. This confirms that |task1| is restored as the
   // current task before posting |task2| after returning from the nested loop.
   RunLoop nested_run_loop2(RunLoop::Type::kNestableTasksAllowed);
   OnceClosure task1 = BindOnce(
-      [](RunLoop* nested_run_loop, const Location& location2,
-         OnceClosure task2) {
-        ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
-        nested_run_loop->RunUntilIdle();
+      BindLambdaForTesting([dummy_ipc_pc1](RunLoop* nested_run_loop,
+                                           const Location& location2,
+                                           OnceClosure task2) {
+        {
+          // Run the nested message loop with an explicitly set IPC context.
+          // This context should not leak out of the inner loop and color the
+          // tasks in the outer loop.
+          TaskAnnotator::ScopedSetIpcProgramCounter scoped_ipc_pc(
+              dummy_ipc_pc1);
+          ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
+          nested_run_loop->RunUntilIdle();
+        }
         ThreadTaskRunnerHandle::Get()->PostTask(location2, std::move(task2));
-      },
+      }),
       Unretained(&nested_run_loop2), location2, std::move(task2));
 
-  OnceClosure task0 =
-      BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-               Unretained(this), ThreadTaskRunnerHandle::Get(), location0,
-               location1, ExpectedTrace({}), std::move(task1));
+  OnceClosure task0 = BindOnce(
+      &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPostWithIpcContext,
+      Unretained(this), ThreadTaskRunnerHandle::Get(), location0, location1,
+      ExpectedTrace({}), nullptr, std::move(task1), dummy_ipc_pc);
 
   ThreadTaskRunnerHandle::Get()->PostTask(location0, std::move(task0));
-  ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, BindOnce(&RunLoop::Run, Unretained(&nested_run_loop1)));
+
+  {
+    TaskAnnotator::ScopedSetIpcProgramCounter scoped_ipc_pc(dummy_ipc_pc2);
+    ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, BindOnce(&RunLoop::Run, Unretained(&nested_run_loop1)));
+  }
 
   run_loop.Run();
 }
diff --git a/base/task/post_task.h b/base/task/post_task.h
index 0aff1ba1..c646cd5 100644
--- a/base/task/post_task.h
+++ b/base/task/post_task.h
@@ -102,15 +102,16 @@
       from_here, TaskTraits(), std::move(task), std::move(reply));
 }
 
-// Callback version of PostTaskAndReplyWithResult above.
+// RepeatingCallback version of PostTaskAndReplyWithResult above.
 // Though RepeatingCallback is convertible to OnceCallback, we need this since
 // we can not use template deduction and object conversion at once on the
 // overload resolution.
-// TODO(tzik): Update all callers of the Callback version to use OnceCallback.
+// TODO(tzik): Update all callers of the RepeatingCallback version to use
+// OnceCallback.
 template <typename TaskReturnType, typename ReplyArgType>
 bool PostTaskAndReplyWithResult(const Location& from_here,
-                                Callback<TaskReturnType()> task,
-                                Callback<void(ReplyArgType)> reply) {
+                                RepeatingCallback<TaskReturnType()> task,
+                                RepeatingCallback<void(ReplyArgType)> reply) {
   return PostTaskAndReplyWithResult(
       from_here, OnceCallback<TaskReturnType()>(std::move(task)),
       OnceCallback<void(ReplyArgType)>(std::move(reply)));
@@ -163,16 +164,18 @@
                std::move(reply), Owned(result)));
 }
 
-// Callback version of PostTaskWithTraitsAndReplyWithResult above.
+// RepeatingCallback version of PostTaskWithTraitsAndReplyWithResult above.
 // Though RepeatingCallback is convertible to OnceCallback, we need this since
 // we can not use template deduction and object conversion at once on the
 // overload resolution.
-// TODO(tzik): Update all callers of the Callback version to use OnceCallback.
+// TODO(tzik): Update all callers of the RepeatingCallback version to use
+// OnceCallback.
 template <typename TaskReturnType, typename ReplyArgType>
-bool PostTaskWithTraitsAndReplyWithResult(const Location& from_here,
-                                          const TaskTraits& traits,
-                                          Callback<TaskReturnType()> task,
-                                          Callback<void(ReplyArgType)> reply) {
+bool PostTaskWithTraitsAndReplyWithResult(
+    const Location& from_here,
+    const TaskTraits& traits,
+    RepeatingCallback<TaskReturnType()> task,
+    RepeatingCallback<void(ReplyArgType)> reply) {
   return PostTaskWithTraitsAndReplyWithResult(
       from_here, traits, OnceCallback<TaskReturnType()>(std::move(task)),
       OnceCallback<void(ReplyArgType)>(std::move(reply)));
diff --git a/base/task/thread_pool/platform_native_worker_pool.cc b/base/task/thread_pool/platform_native_worker_pool.cc
index 8df0b4d4..552369b 100644
--- a/base/task/thread_pool/platform_native_worker_pool.cc
+++ b/base/task/thread_pool/platform_native_worker_pool.cc
@@ -74,32 +74,32 @@
 #endif
 }
 
-void PlatformNativeWorkerPool::RunNextSequenceImpl() {
-  scoped_refptr<Sequence> sequence = GetWork();
+void PlatformNativeWorkerPool::RunNextTaskSourceImpl() {
+  scoped_refptr<TaskSource> task_source = GetWork();
 
-  if (sequence) {
+  if (task_source) {
     BindToCurrentThread();
-    sequence = task_tracker_->RunAndPopNextTask(std::move(sequence));
+    task_source = task_tracker_->RunAndPopNextTask(std::move(task_source));
     UnbindFromCurrentThread();
 
-    if (sequence) {
+    if (task_source) {
       ScopedWorkersExecutor workers_executor(this);
       ScopedReenqueueExecutor reenqueue_executor;
-      auto sequence_and_transaction =
-          SequenceAndTransaction::FromSequence(std::move(sequence));
+      auto task_source_and_transaction =
+          TaskSourceAndTransaction::FromTaskSource(std::move(task_source));
       AutoSchedulerLock auto_lock(lock_);
-      ReEnqueueSequenceLockRequired(&workers_executor, &reenqueue_executor,
-                                    std::move(sequence_and_transaction));
+      ReEnqueueTaskSourceLockRequired(&workers_executor, &reenqueue_executor,
+                                      std::move(task_source_and_transaction));
     }
   }
 }
 
-scoped_refptr<Sequence> PlatformNativeWorkerPool::GetWork() {
+scoped_refptr<TaskSource> PlatformNativeWorkerPool::GetWork() {
   AutoSchedulerLock auto_lock(lock_);
   DCHECK_GT(num_pending_threadpool_work_, 0U);
   --num_pending_threadpool_work_;
-  // There can be more pending threadpool work than Sequences in the
-  // PriorityQueue after RemoveSequence().
+  // There can be more pending threadpool work than TaskSources in the
+  // PriorityQueue after RemoveTaskSource().
   if (priority_queue_.IsEmpty())
     return nullptr;
 
@@ -107,31 +107,31 @@
   const TaskPriority priority = priority_queue_.PeekSortKey().priority();
   if (!task_tracker_->CanRunPriority(priority))
     return nullptr;
-  return priority_queue_.PopSequence();
+  return priority_queue_.PopTaskSource();
 }
 
 void PlatformNativeWorkerPool::UpdateSortKey(
-    SequenceAndTransaction sequence_and_transaction) {
+    TaskSourceAndTransaction task_source_and_transaction) {
   ScopedWorkersExecutor executor(this);
-  UpdateSortKeyImpl(&executor, std::move(sequence_and_transaction));
+  UpdateSortKeyImpl(&executor, std::move(task_source_and_transaction));
 }
 
-void PlatformNativeWorkerPool::PushSequenceAndWakeUpWorkers(
-    SequenceAndTransaction sequence_and_transaction) {
+void PlatformNativeWorkerPool::PushTaskSourceAndWakeUpWorkers(
+    TaskSourceAndTransaction task_source_and_transaction) {
   ScopedWorkersExecutor executor(this);
-  PushSequenceAndWakeUpWorkersImpl(&executor,
-                                   std::move(sequence_and_transaction));
+  PushTaskSourceAndWakeUpWorkersImpl(&executor,
+                                     std::move(task_source_and_transaction));
 }
 
 void PlatformNativeWorkerPool::EnsureEnoughWorkersLockRequired(
     BaseScopedWorkersExecutor* executor) {
   if (!started_)
     return;
-  // Ensure that there is at least one pending threadpool work per Sequence in
+  // Ensure that there is at least one pending threadpool work per TaskSource in
   // the PriorityQueue.
   const size_t desired_num_pending_threadpool_work =
-      GetNumQueuedCanRunBestEffortSequences() +
-      GetNumQueuedCanRunForegroundSequences();
+      GetNumQueuedCanRunBestEffortTaskSources() +
+      GetNumQueuedCanRunForegroundTaskSources();
 
   if (desired_num_pending_threadpool_work > num_pending_threadpool_work_) {
     static_cast<ScopedWorkersExecutor*>(executor)
diff --git a/base/task/thread_pool/platform_native_worker_pool.h b/base/task/thread_pool/platform_native_worker_pool.h
index efb65fa..149bdff 100644
--- a/base/task/thread_pool/platform_native_worker_pool.h
+++ b/base/task/thread_pool/platform_native_worker_pool.h
@@ -33,9 +33,9 @@
                            TrackedRef<Delegate> delegate,
                            SchedulerWorkerPool* predecessor_pool);
 
-  // Runs a task off the next sequence on the |priority_queue_|. Called by
+  // Runs a task off the next task source on the |priority_queue_|. Called by
   // callbacks posted to platform native thread pools.
-  void RunNextSequenceImpl();
+  void RunNextTaskSourceImpl();
 
   virtual void JoinImpl() = 0;
   virtual void StartImpl() = 0;
@@ -48,21 +48,22 @@
   class ScopedWorkersExecutor;
 
   // SchedulerWorkerPool:
-  void UpdateSortKey(SequenceAndTransaction sequence_and_transaction) override;
-  void PushSequenceAndWakeUpWorkers(
-      SequenceAndTransaction sequence_and_transaction) override;
+  void UpdateSortKey(
+      TaskSourceAndTransaction task_source_and_transaction) override;
+  void PushTaskSourceAndWakeUpWorkers(
+      TaskSourceAndTransaction task_source_and_transaction) override;
   void EnsureEnoughWorkersLockRequired(BaseScopedWorkersExecutor* executor)
       override EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
-  // Returns the top Sequence off the |priority_queue_|. Returns nullptr
+  // Returns the top TaskSource off the |priority_queue_|. Returns nullptr
   // if the |priority_queue_| is empty.
-  scoped_refptr<Sequence> GetWork();
+  scoped_refptr<TaskSource> GetWork();
 
   // Indicates whether the pool has been started yet.
   bool started_ GUARDED_BY(lock_) = false;
 
   // Number of threadpool work submitted to the pool which haven't popped a
-  // Sequence from the PriorityQueue yet.
+  // TaskSource from the PriorityQueue yet.
   size_t num_pending_threadpool_work_ GUARDED_BY(lock_) = 0;
 
 #if DCHECK_IS_ON()
diff --git a/base/task/thread_pool/platform_native_worker_pool_mac.h b/base/task/thread_pool/platform_native_worker_pool_mac.h
index 39d9959..01f080b5 100644
--- a/base/task/thread_pool/platform_native_worker_pool_mac.h
+++ b/base/task/thread_pool/platform_native_worker_pool_mac.h
@@ -47,6 +47,8 @@
   DISALLOW_COPY_AND_ASSIGN(PlatformNativeWorkerPoolMac);
 };
 
+using PlatformNativeWorkerPoolImpl = PlatformNativeWorkerPoolMac;
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/task/thread_pool/platform_native_worker_pool_mac.mm b/base/task/thread_pool/platform_native_worker_pool_mac.mm
index 3c08aa52..ec21eb2 100644
--- a/base/task/thread_pool/platform_native_worker_pool_mac.mm
+++ b/base/task/thread_pool/platform_native_worker_pool_mac.mm
@@ -33,7 +33,7 @@
   // TODO(adityakeerthi): Handle priorities by having multiple dispatch queues
   // with different qualities-of-service.
   dispatch_group_async(group_, queue_, ^{
-    RunNextSequenceImpl();
+    RunNextTaskSourceImpl();
   });
 }
 
diff --git a/base/task/thread_pool/platform_native_worker_pool_win.cc b/base/task/thread_pool/platform_native_worker_pool_win.cc
index 9b16a5e5..1ffbf0d 100644
--- a/base/task/thread_pool/platform_native_worker_pool_win.cc
+++ b/base/task/thread_pool/platform_native_worker_pool_win.cc
@@ -33,7 +33,7 @@
   ::SetThreadpoolThreadMinimum(pool_, 1);
   ::SetThreadpoolThreadMaximum(pool_, 256);
 
-  work_ = ::CreateThreadpoolWork(&RunNextSequence, this, &environment_);
+  work_ = ::CreateThreadpoolWork(&RunNextTaskSource, this, &environment_);
   DCHECK(work_) << "LastError: " << GetLastError();
   ::SetThreadpoolCallbackPool(&environment_, pool_);
 }
@@ -49,7 +49,7 @@
 }
 
 // static
-void CALLBACK PlatformNativeWorkerPoolWin::RunNextSequence(
+void CALLBACK PlatformNativeWorkerPoolWin::RunNextTaskSource(
     PTP_CALLBACK_INSTANCE,
     void* scheduler_worker_pool_windows_impl,
     PTP_WORK) {
@@ -63,7 +63,7 @@
   if (worker_pool->worker_environment_ == WorkerEnvironment::COM_MTA)
     com_initializer.emplace(win::ScopedCOMInitializer::kMTA);
 
-  worker_pool->RunNextSequenceImpl();
+  worker_pool->RunNextTaskSourceImpl();
 }
 
 }  // namespace internal
diff --git a/base/task/thread_pool/platform_native_worker_pool_win.h b/base/task/thread_pool/platform_native_worker_pool_win.h
index cb7fe7a..6e3a647 100644
--- a/base/task/thread_pool/platform_native_worker_pool_win.h
+++ b/base/task/thread_pool/platform_native_worker_pool_win.h
@@ -35,9 +35,10 @@
 
  private:
   // Callback that gets run by |pool_|.
-  static void CALLBACK RunNextSequence(PTP_CALLBACK_INSTANCE,
-                                       void* scheduler_worker_pool_windows_impl,
-                                       PTP_WORK);
+  static void CALLBACK
+  RunNextTaskSource(PTP_CALLBACK_INSTANCE,
+                    void* scheduler_worker_pool_windows_impl,
+                    PTP_WORK);
 
   // PlatformNativeWorkerPool:
   void JoinImpl() override;
@@ -51,14 +52,16 @@
   // work objects using this environment run on |pool_|.
   TP_CALLBACK_ENVIRON environment_ = {};
 
-  // Work object that executes RunNextSequence. It has a pointer to the current
-  // |PlatformNativeWorkerPoolWin| and a pointer to |environment_| bound to
-  // it.
+  // Work object that executes RunNextTaskSource. It has a pointer to the
+  // current |PlatformNativeWorkerPoolWin| and a pointer to |environment_| bound
+  // to it.
   PTP_WORK work_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(PlatformNativeWorkerPoolWin);
 };
 
+using PlatformNativeWorkerPoolImpl = PlatformNativeWorkerPoolWin;
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/task/thread_pool/priority_queue.cc b/base/task/thread_pool/priority_queue.cc
index f187a63..33d8b76 100644
--- a/base/task/thread_pool/priority_queue.cc
+++ b/base/task/thread_pool/priority_queue.cc
@@ -13,84 +13,86 @@
 namespace base {
 namespace internal {
 
-// A class combining a Sequence and the SequenceSortKey that determines its
-// position in a PriorityQueue. Instances are only mutable via take_sequence()
-// which can only be called once and renders its instance invalid after the
-// call.
-class PriorityQueue::SequenceAndSortKey {
+// A class combining a TaskSource and the SequenceSortKey that determines its
+// position in a PriorityQueue. Instances are only mutable via
+// take_task_source() which can only be called once and renders its instance
+// invalid after the call.
+class PriorityQueue::TaskSourceAndSortKey {
  public:
-  SequenceAndSortKey() = default;
-  SequenceAndSortKey(scoped_refptr<Sequence> sequence,
-                     const SequenceSortKey& sort_key)
-      : sequence_(std::move(sequence)), sort_key_(sort_key) {
-    DCHECK(sequence_);
+  TaskSourceAndSortKey() = default;
+  TaskSourceAndSortKey(scoped_refptr<TaskSource> task_source,
+                       const SequenceSortKey& sort_key)
+      : task_source_(std::move(task_source)), sort_key_(sort_key) {
+    DCHECK(task_source_);
   }
 
-  // Note: while |sequence_| should always be non-null post-move (i.e. we
-  // shouldn't be moving an invalid SequenceAndSortKey around), there can't be
-  // a DCHECK(sequence_) on moves as IntrusiveHeap moves elements on pop
-  // instead of overwriting them: resulting in the move of a SequenceAndSortKey
-  // with a null |sequence_| in Transaction::Pop()'s implementation.
-  SequenceAndSortKey(SequenceAndSortKey&& other) = default;
-  SequenceAndSortKey& operator=(SequenceAndSortKey&& other) = default;
+  // Note: while |task_source_| should always be non-null post-move (i.e. we
+  // shouldn't be moving an invalid TaskSourceAndSortKey around), there can't be
+  // a DCHECK(task_source_) on moves as IntrusiveHeap moves elements on pop
+  // instead of overwriting them: resulting in the move of a
+  // TaskSourceAndSortKey with a null |task_source_| in Transaction::Pop()'s
+  // implementation.
+  TaskSourceAndSortKey(TaskSourceAndSortKey&& other) = default;
+  TaskSourceAndSortKey& operator=(TaskSourceAndSortKey&& other) = default;
 
-  // Extracts |sequence_| from this object. This object is invalid after this
+  // Extracts |task_source_| from this object. This object is invalid after this
   // call.
-  scoped_refptr<Sequence> take_sequence() {
-    DCHECK(sequence_);
-    sequence_->ClearHeapHandle();
-    return std::move(sequence_);
+  scoped_refptr<TaskSource> take_task_source() {
+    DCHECK(task_source_);
+    task_source_->ClearHeapHandle();
+    return std::move(task_source_);
   }
 
-  // Compares this SequenceAndSortKey to |other| based on their respective
+  // Compares this TaskSourceAndSortKey to |other| based on their respective
   // |sort_key_|. Required by IntrusiveHeap.
-  bool operator<=(const SequenceAndSortKey& other) const {
+  bool operator<=(const TaskSourceAndSortKey& other) const {
     return sort_key_ <= other.sort_key_;
   }
 
   // Required by IntrusiveHeap.
   void SetHeapHandle(const HeapHandle& handle) {
-    DCHECK(sequence_);
-    sequence_->SetHeapHandle(handle);
+    DCHECK(task_source_);
+    task_source_->SetHeapHandle(handle);
   }
 
   // Required by IntrusiveHeap.
   void ClearHeapHandle() {
-    // Ensure |sequence_| is not nullptr, which may be the case if
-    // take_sequence() was called before this.
-    if (sequence_) {
-      sequence_->ClearHeapHandle();
+    // Ensure |task_source_| is not nullptr, which may be the case if
+    // take_task_source() was called before this.
+    if (task_source_) {
+      task_source_->ClearHeapHandle();
     }
   }
 
-  const Sequence* sequence() const { return sequence_.get(); }
+  const TaskSource* task_source() const { return task_source_.get(); }
 
   const SequenceSortKey& sort_key() const { return sort_key_; }
 
  private:
-  scoped_refptr<Sequence> sequence_;
+  scoped_refptr<TaskSource> task_source_;
   SequenceSortKey sort_key_;
 
-  DISALLOW_COPY_AND_ASSIGN(SequenceAndSortKey);
+  DISALLOW_COPY_AND_ASSIGN(TaskSourceAndSortKey);
 };
 
 PriorityQueue::PriorityQueue() = default;
 
 PriorityQueue::~PriorityQueue() {
-  if (!is_flush_sequences_on_destroy_enabled_)
+  if (!is_flush_task_sources_on_destroy_enabled_)
     return;
 
   while (!container_.empty()) {
-    PopSequence()->BeginTransaction().Clear();
+    PopTaskSource()->BeginTransaction().Clear();
   }
 }
 
 PriorityQueue& PriorityQueue::operator=(PriorityQueue&& other) = default;
 
-void PriorityQueue::Push(scoped_refptr<Sequence> sequence,
+void PriorityQueue::Push(scoped_refptr<TaskSource> task_source,
                          const SequenceSortKey& sequence_sort_key) {
-  container_.insert(SequenceAndSortKey(std::move(sequence), sequence_sort_key));
-  IncrementNumSequencesForPriority(sequence_sort_key.priority());
+  container_.insert(
+      TaskSourceAndSortKey(std::move(task_source), sequence_sort_key));
+  IncrementNumTaskSourcesForPriority(sequence_sort_key.priority());
 }
 
 const SequenceSortKey& PriorityQueue::PeekSortKey() const {
@@ -98,60 +100,64 @@
   return container_.Min().sort_key();
 }
 
-scoped_refptr<Sequence> PriorityQueue::PopSequence() {
+scoped_refptr<TaskSource> PriorityQueue::PopTaskSource() {
   DCHECK(!IsEmpty());
 
-  // The const_cast on Min() is okay since the SequenceAndSortKey is
+  // The const_cast on Min() is okay since the TaskSourceAndSortKey is
   // transactionally being popped from |container_| right after and taking its
-  // Sequence does not alter its sort order.
-  auto& sequence_and_sort_key =
-      const_cast<PriorityQueue::SequenceAndSortKey&>(container_.Min());
-  DecrementNumSequencesForPriority(sequence_and_sort_key.sort_key().priority());
-  scoped_refptr<Sequence> sequence = sequence_and_sort_key.take_sequence();
+  // TaskSource does not alter its sort order.
+  auto& task_source_and_sort_key =
+      const_cast<PriorityQueue::TaskSourceAndSortKey&>(container_.Min());
+  DecrementNumTaskSourcesForPriority(
+      task_source_and_sort_key.sort_key().priority());
+  scoped_refptr<TaskSource> task_source =
+      task_source_and_sort_key.take_task_source();
   container_.Pop();
-  return sequence;
+  return task_source;
 }
 
-bool PriorityQueue::RemoveSequence(scoped_refptr<Sequence> sequence) {
-  DCHECK(sequence);
+bool PriorityQueue::RemoveTaskSource(scoped_refptr<TaskSource> task_source) {
+  DCHECK(task_source);
 
   if (IsEmpty())
     return false;
 
-  const HeapHandle heap_handle = sequence->heap_handle();
+  const HeapHandle heap_handle = task_source->heap_handle();
   if (!heap_handle.IsValid())
     return false;
 
-  const SequenceAndSortKey& sequence_and_sort_key = container_.at(heap_handle);
-  DCHECK_EQ(sequence_and_sort_key.sequence(), sequence.get());
+  const TaskSourceAndSortKey& task_source_and_sort_key =
+      container_.at(heap_handle);
+  DCHECK_EQ(task_source_and_sort_key.task_source(), task_source.get());
 
-  DecrementNumSequencesForPriority(sequence_and_sort_key.sort_key().priority());
+  DecrementNumTaskSourcesForPriority(
+      task_source_and_sort_key.sort_key().priority());
   container_.erase(heap_handle);
   return true;
 }
 
 void PriorityQueue::UpdateSortKey(
-    SequenceAndTransaction sequence_and_transaction) {
-  DCHECK(sequence_and_transaction.sequence);
+    TaskSourceAndTransaction task_source_and_transaction) {
+  DCHECK(task_source_and_transaction.task_source);
 
   if (IsEmpty())
     return;
 
   const HeapHandle heap_handle =
-      sequence_and_transaction.sequence->heap_handle();
+      task_source_and_transaction.task_source->heap_handle();
   if (!heap_handle.IsValid())
     return;
 
   auto old_sort_key = container_.at(heap_handle).sort_key();
-  auto new_sort_key = sequence_and_transaction.transaction.GetSortKey();
+  auto new_sort_key = task_source_and_transaction.transaction.GetSortKey();
 
-  DecrementNumSequencesForPriority(old_sort_key.priority());
-  IncrementNumSequencesForPriority(new_sort_key.priority());
+  DecrementNumTaskSourcesForPriority(old_sort_key.priority());
+  IncrementNumTaskSourcesForPriority(new_sort_key.priority());
 
   container_.ChangeKey(
       heap_handle,
-      SequenceAndSortKey(std::move(sequence_and_transaction.sequence),
-                         new_sort_key));
+      TaskSourceAndSortKey(std::move(task_source_and_transaction.task_source),
+                           new_sort_key));
 }
 
 bool PriorityQueue::IsEmpty() const {
@@ -162,18 +168,18 @@
   return container_.size();
 }
 
-void PriorityQueue::EnableFlushSequencesOnDestroyForTesting() {
-  DCHECK(!is_flush_sequences_on_destroy_enabled_);
-  is_flush_sequences_on_destroy_enabled_ = true;
+void PriorityQueue::EnableFlushTaskSourcesOnDestroyForTesting() {
+  DCHECK(!is_flush_task_sources_on_destroy_enabled_);
+  is_flush_task_sources_on_destroy_enabled_ = true;
 }
 
-void PriorityQueue::DecrementNumSequencesForPriority(TaskPriority priority) {
-  DCHECK_GT(num_sequences_per_priority_[static_cast<int>(priority)], 0U);
-  --num_sequences_per_priority_[static_cast<int>(priority)];
+void PriorityQueue::DecrementNumTaskSourcesForPriority(TaskPriority priority) {
+  DCHECK_GT(num_task_sources_per_priority_[static_cast<int>(priority)], 0U);
+  --num_task_sources_per_priority_[static_cast<int>(priority)];
 }
 
-void PriorityQueue::IncrementNumSequencesForPriority(TaskPriority priority) {
-  ++num_sequences_per_priority_[static_cast<int>(priority)];
+void PriorityQueue::IncrementNumTaskSourcesForPriority(TaskPriority priority) {
+  ++num_task_sources_per_priority_[static_cast<int>(priority)];
 }
 
 }  // namespace internal
diff --git a/base/task/thread_pool/priority_queue.h b/base/task/thread_pool/priority_queue.h
index 0020045..1ec5c7d 100644
--- a/base/task/thread_pool/priority_queue.h
+++ b/base/task/thread_pool/priority_queue.h
@@ -12,13 +12,13 @@
 #include "base/memory/ref_counted.h"
 #include "base/task/common/intrusive_heap.h"
 #include "base/task/thread_pool/scheduler_lock.h"
-#include "base/task/thread_pool/sequence.h"
 #include "base/task/thread_pool/sequence_sort_key.h"
+#include "base/task/thread_pool/task_source.h"
 
 namespace base {
 namespace internal {
 
-// A PriorityQueue holds Sequences of Tasks. This class is not thread-safe
+// A PriorityQueue holds TaskSources of Tasks. This class is not thread-safe
 // (requires external synchronization).
 class BASE_EXPORT PriorityQueue {
  public:
@@ -27,11 +27,11 @@
 
   PriorityQueue& operator=(PriorityQueue&& other);
 
-  // Inserts |sequence| in the PriorityQueue with |sequence_sort_key|. Note:
+  // Inserts |task_source| in the PriorityQueue with |sequence_sort_key|. Note:
   // |sequence_sort_key| is required as a parameter instead of being extracted
-  // from |sequence| in Push() to avoid this Transaction having a lock
-  // interdependency with |sequence|.
-  void Push(scoped_refptr<Sequence> sequence,
+  // from |task_source| in Push() to avoid this Transaction having a lock
+  // interdependency with |task_source|.
+  void Push(scoped_refptr<TaskSource> task_source,
             const SequenceSortKey& sequence_sort_key);
 
   // Returns a reference to the SequenceSortKey representing the priority of
@@ -40,53 +40,53 @@
   // Cannot be called on an empty PriorityQueue.
   const SequenceSortKey& PeekSortKey() const;
 
-  // Removes and returns the highest priority Sequence in this PriorityQueue.
+  // Removes and returns the highest priority TaskSource in this PriorityQueue.
   // Cannot be called on an empty PriorityQueue.
-  scoped_refptr<Sequence> PopSequence();
+  scoped_refptr<TaskSource> PopTaskSource();
 
-  // Removes |sequence| from the PriorityQueue. Returns true if successful, or
-  // false if |sequence| is not currently in the PriorityQueue or the
+  // Removes |task_source| from the PriorityQueue. Returns true if successful,
+  // or false if |task_source| is not currently in the PriorityQueue or the
   // PriorityQueue is empty.
-  bool RemoveSequence(scoped_refptr<Sequence> sequence);
+  bool RemoveTaskSource(scoped_refptr<TaskSource> task_source);
 
-  // Updates the sort key of the Sequence in |sequence_and_transaction| to
-  // match its current traits. No-ops if the Sequence is not in the
+  // Updates the sort key of the TaskSource in |task_source_and_transaction| to
+  // match its current traits. No-ops if the TaskSource is not in the
   // PriorityQueue or the PriorityQueue is empty.
-  void UpdateSortKey(SequenceAndTransaction sequence_and_transaction);
+  void UpdateSortKey(TaskSourceAndTransaction task_source_and_transaction);
 
   // Returns true if the PriorityQueue is empty.
   bool IsEmpty() const;
 
-  // Returns the number of Sequences in the PriorityQueue.
+  // Returns the number of TaskSources in the PriorityQueue.
   size_t Size() const;
 
-  // Returns the number of Sequences with |priority|.
-  size_t GetNumSequencesWithPriority(TaskPriority priority) const {
-    return num_sequences_per_priority_[static_cast<int>(priority)];
+  // Returns the number of TaskSources with |priority|.
+  size_t GetNumTaskSourcesWithPriority(TaskPriority priority) const {
+    return num_task_sources_per_priority_[static_cast<int>(priority)];
   }
 
-  // Set the PriorityQueue to empty all its Sequences of Tasks when it is
+  // Set the PriorityQueue to empty all its TaskSources of Tasks when it is
   // destroyed; needed to prevent memory leaks caused by a reference cycle
-  // (Sequence -> Task -> TaskRunner -> Sequence...) during test teardown.
-  void EnableFlushSequencesOnDestroyForTesting();
+  // (TaskSource -> Task -> TaskRunner -> TaskSource...) during test teardown.
+  void EnableFlushTaskSourcesOnDestroyForTesting();
 
  private:
-  // A class combining a Sequence and the SequenceSortKey that determines its
+  // A class combining a TaskSource and the SequenceSortKey that determines its
   // position in a PriorityQueue.
-  class SequenceAndSortKey;
+  class TaskSourceAndSortKey;
 
-  using ContainerType = IntrusiveHeap<SequenceAndSortKey>;
+  using ContainerType = IntrusiveHeap<TaskSourceAndSortKey>;
 
-  void DecrementNumSequencesForPriority(TaskPriority priority);
-  void IncrementNumSequencesForPriority(TaskPriority priority);
+  void DecrementNumTaskSourcesForPriority(TaskPriority priority);
+  void IncrementNumTaskSourcesForPriority(TaskPriority priority);
 
   ContainerType container_;
 
   std::array<size_t, static_cast<int>(TaskPriority::HIGHEST) + 1>
-      num_sequences_per_priority_ = {};
+      num_task_sources_per_priority_ = {};
 
-  // Should only be enabled by EnableFlushSequencesOnDestroyForTesting().
-  bool is_flush_sequences_on_destroy_enabled_ = false;
+  // Should only be enabled by EnableFlushTaskSourcesOnDestroyForTesting().
+  bool is_flush_task_sources_on_destroy_enabled_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(PriorityQueue);
 };
diff --git a/base/task/thread_pool/priority_queue_unittest.cc b/base/task/thread_pool/priority_queue_unittest.cc
index f4de124..6cff85f 100644
--- a/base/task/thread_pool/priority_queue_unittest.cc
+++ b/base/task/thread_pool/priority_queue_unittest.cc
@@ -23,7 +23,7 @@
 
 namespace {
 
-scoped_refptr<Sequence> MakeSequenceWithTraitsAndTask(
+scoped_refptr<TaskSource> MakeSequenceWithTraitsAndTask(
     const TaskTraits& traits) {
   scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(
       traits, nullptr, TaskSourceExecutionMode::kParallel);
@@ -37,27 +37,27 @@
   void ExpectNumSequences(size_t num_best_effort,
                           size_t num_user_visible,
                           size_t num_user_blocking) {
-    EXPECT_EQ(pq.GetNumSequencesWithPriority(TaskPriority::BEST_EFFORT),
+    EXPECT_EQ(pq.GetNumTaskSourcesWithPriority(TaskPriority::BEST_EFFORT),
               num_best_effort);
-    EXPECT_EQ(pq.GetNumSequencesWithPriority(TaskPriority::USER_VISIBLE),
+    EXPECT_EQ(pq.GetNumTaskSourcesWithPriority(TaskPriority::USER_VISIBLE),
               num_user_visible);
-    EXPECT_EQ(pq.GetNumSequencesWithPriority(TaskPriority::USER_BLOCKING),
+    EXPECT_EQ(pq.GetNumTaskSourcesWithPriority(TaskPriority::USER_BLOCKING),
               num_user_blocking);
   }
 
-  scoped_refptr<Sequence> sequence_a =
+  scoped_refptr<TaskSource> sequence_a =
       MakeSequenceWithTraitsAndTask(TaskTraits(TaskPriority::USER_VISIBLE));
   SequenceSortKey sort_key_a = sequence_a->BeginTransaction().GetSortKey();
 
-  scoped_refptr<Sequence> sequence_b =
+  scoped_refptr<TaskSource> sequence_b =
       MakeSequenceWithTraitsAndTask(TaskTraits(TaskPriority::USER_BLOCKING));
   SequenceSortKey sort_key_b = sequence_b->BeginTransaction().GetSortKey();
 
-  scoped_refptr<Sequence> sequence_c =
+  scoped_refptr<TaskSource> sequence_c =
       MakeSequenceWithTraitsAndTask(TaskTraits(TaskPriority::USER_BLOCKING));
   SequenceSortKey sort_key_c = sequence_c->BeginTransaction().GetSortKey();
 
-  scoped_refptr<Sequence> sequence_d =
+  scoped_refptr<TaskSource> sequence_d =
       MakeSequenceWithTraitsAndTask(TaskTraits(TaskPriority::BEST_EFFORT));
   SequenceSortKey sort_key_d = sequence_d->BeginTransaction().GetSortKey();
 
@@ -96,24 +96,24 @@
 
   // Pop |sequence_b| from the PriorityQueue. |sequence_c| becomes the sequence
   // with the highest priority.
-  EXPECT_EQ(sequence_b, pq.PopSequence());
+  EXPECT_EQ(sequence_b, pq.PopTaskSource());
   EXPECT_EQ(sort_key_c, pq.PeekSortKey());
   ExpectNumSequences(1U, 1U, 1U);
 
   // Pop |sequence_c| from the PriorityQueue. |sequence_a| becomes the sequence
   // with the highest priority.
-  EXPECT_EQ(sequence_c, pq.PopSequence());
+  EXPECT_EQ(sequence_c, pq.PopTaskSource());
   EXPECT_EQ(sort_key_a, pq.PeekSortKey());
   ExpectNumSequences(1U, 1U, 0U);
 
   // Pop |sequence_a| from the PriorityQueue. |sequence_d| becomes the sequence
   // with the highest priority.
-  EXPECT_EQ(sequence_a, pq.PopSequence());
+  EXPECT_EQ(sequence_a, pq.PopTaskSource());
   EXPECT_EQ(sort_key_d, pq.PeekSortKey());
   ExpectNumSequences(1U, 0U, 0U);
 
   // Pop |sequence_d| from the PriorityQueue. It is now empty.
-  EXPECT_EQ(sequence_d, pq.PopSequence());
+  EXPECT_EQ(sequence_d, pq.PopTaskSource());
   EXPECT_TRUE(pq.IsEmpty());
   ExpectNumSequences(0U, 0U, 0U);
 }
@@ -132,34 +132,34 @@
 
   // Remove |sequence_a| from the PriorityQueue. |sequence_b| is still the
   // sequence with the highest priority.
-  EXPECT_TRUE(pq.RemoveSequence(sequence_a));
+  EXPECT_TRUE(pq.RemoveTaskSource(sequence_a));
   EXPECT_EQ(sort_key_b, pq.PeekSortKey());
   ExpectNumSequences(1U, 0U, 2U);
 
-  // RemoveSequence() should return false if called on a sequence not in the
+  // RemoveTaskSource() should return false if called on a sequence not in the
   // PriorityQueue.
-  EXPECT_FALSE(pq.RemoveSequence(sequence_a));
+  EXPECT_FALSE(pq.RemoveTaskSource(sequence_a));
   ExpectNumSequences(1U, 0U, 2U);
 
   // Remove |sequence_b| from the PriorityQueue. |sequence_c| becomes the
   // sequence with the highest priority.
-  EXPECT_TRUE(pq.RemoveSequence(sequence_b));
+  EXPECT_TRUE(pq.RemoveTaskSource(sequence_b));
   EXPECT_EQ(sort_key_c, pq.PeekSortKey());
   ExpectNumSequences(1U, 0U, 1U);
 
   // Remove |sequence_d| from the PriorityQueue. |sequence_c| is still the
   // sequence with the highest priority.
-  EXPECT_TRUE(pq.RemoveSequence(sequence_d));
+  EXPECT_TRUE(pq.RemoveTaskSource(sequence_d));
   EXPECT_EQ(sort_key_c, pq.PeekSortKey());
   ExpectNumSequences(0U, 0U, 1U);
 
   // Remove |sequence_c| from the PriorityQueue, making it empty.
-  EXPECT_TRUE(pq.RemoveSequence(sequence_c));
+  EXPECT_TRUE(pq.RemoveTaskSource(sequence_c));
   EXPECT_TRUE(pq.IsEmpty());
   ExpectNumSequences(0U, 0U, 0U);
 
-  // Return false if RemoveSequence() is called on an empty PriorityQueue.
-  EXPECT_FALSE(pq.RemoveSequence(sequence_c));
+  // Return false if RemoveTaskSource() is called on an empty PriorityQueue.
+  EXPECT_FALSE(pq.RemoveTaskSource(sequence_c));
   ExpectNumSequences(0U, 0U, 0U);
 }
 
@@ -179,7 +179,7 @@
     // Downgrade |sequence_b| from USER_BLOCKING to BEST_EFFORT. |sequence_c|
     // (USER_BLOCKING priority) becomes the sequence with the highest priority.
     auto sequence_b_and_transaction =
-        SequenceAndTransaction::FromSequence(sequence_b);
+        TaskSourceAndTransaction::FromTaskSource(sequence_b);
     sequence_b_and_transaction.transaction.UpdatePriority(
         TaskPriority::BEST_EFFORT);
 
@@ -193,7 +193,7 @@
     // |sequence_c| (USER_BLOCKING priority) is still the sequence with the
     // highest priority.
     auto sequence_c_and_transaction =
-        SequenceAndTransaction::FromSequence(sequence_c);
+        TaskSourceAndTransaction::FromTaskSource(sequence_c);
     sequence_c_and_transaction.transaction.UpdatePriority(
         TaskPriority::USER_BLOCKING);
 
@@ -203,7 +203,7 @@
     // Note: |sequence_c| is popped for comparison as |sort_key_c| becomes
     // obsolete. |sequence_a| (USER_VISIBLE priority) becomes the sequence with
     // the highest priority.
-    EXPECT_EQ(sequence_c, pq.PopSequence());
+    EXPECT_EQ(sequence_c, pq.PopTaskSource());
     EXPECT_EQ(sort_key_a, pq.PeekSortKey());
     ExpectNumSequences(2U, 1U, 0U);
   }
@@ -212,7 +212,7 @@
     // Upgrade |sequence_d| from BEST_EFFORT to USER_BLOCKING. |sequence_d|
     // becomes the sequence with the highest priority.
     auto sequence_d_and_transaction =
-        SequenceAndTransaction::FromSequence(sequence_d);
+        TaskSourceAndTransaction::FromTaskSource(sequence_d);
     sequence_d_and_transaction.transaction.UpdatePriority(
         TaskPriority::USER_BLOCKING);
 
@@ -221,7 +221,7 @@
 
     // Note: |sequence_d| is popped for comparison as |sort_key_d| becomes
     // obsolete.
-    EXPECT_EQ(sequence_d, pq.PopSequence());
+    EXPECT_EQ(sequence_d, pq.PopTaskSource());
     // No-op if UpdateSortKey() is called on a Sequence not in the
     // PriorityQueue.
     EXPECT_EQ(sort_key_a, pq.PeekSortKey());
@@ -230,20 +230,20 @@
 
   {
     auto sequence_d_and_transaction =
-        SequenceAndTransaction::FromSequence(sequence_d);
+        TaskSourceAndTransaction::FromTaskSource(sequence_d);
 
     pq.UpdateSortKey(std::move(sequence_d_and_transaction));
     ExpectNumSequences(1U, 1U, 0U);
-    EXPECT_EQ(sequence_a, pq.PopSequence());
+    EXPECT_EQ(sequence_a, pq.PopTaskSource());
     ExpectNumSequences(1U, 0U, 0U);
-    EXPECT_EQ(sequence_b, pq.PopSequence());
+    EXPECT_EQ(sequence_b, pq.PopTaskSource());
     ExpectNumSequences(0U, 0U, 0U);
   }
 
   {
     // No-op if UpdateSortKey() is called on an empty PriorityQueue.
     auto sequence_b_and_transaction =
-        SequenceAndTransaction::FromSequence(sequence_b);
+        TaskSourceAndTransaction::FromTaskSource(sequence_b);
     pq.UpdateSortKey(std::move(sequence_b_and_transaction));
     EXPECT_TRUE(pq.IsEmpty());
     ExpectNumSequences(0U, 0U, 0U);
diff --git a/base/task/thread_pool/scheduler_single_thread_task_runner_manager.cc b/base/task/thread_pool/scheduler_single_thread_task_runner_manager.cc
index 496cb9d..a72fd18 100644
--- a/base/task/thread_pool/scheduler_single_thread_task_runner_manager.cc
+++ b/base/task/thread_pool/scheduler_single_thread_task_runner_manager.cc
@@ -22,6 +22,7 @@
 #include "base/task/thread_pool/scheduler_worker.h"
 #include "base/task/thread_pool/sequence.h"
 #include "base/task/thread_pool/task.h"
+#include "base/task/thread_pool/task_source.h"
 #include "base/task/thread_pool/task_tracker.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
@@ -99,33 +100,33 @@
     PlatformThread::SetName(thread_name_);
   }
 
-  scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
+  scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) override {
     AutoSchedulerLock auto_lock(lock_);
     DCHECK(worker_awake_);
-    auto sequence = GetWorkLockRequired(worker);
-    if (sequence == nullptr) {
+    auto task_source = GetWorkLockRequired(worker);
+    if (task_source == nullptr) {
       // The worker will sleep after this returns nullptr.
       worker_awake_ = false;
     }
-    return sequence;
+    return task_source;
   }
 
-  void DidRunTask(scoped_refptr<Sequence> sequence) override {
-    if (sequence) {
-      EnqueueSequence(
-          SequenceAndTransaction::FromSequence(std::move(sequence)));
+  void DidRunTask(scoped_refptr<TaskSource> task_source) override {
+    if (task_source) {
+      EnqueueTaskSource(
+          TaskSourceAndTransaction::FromTaskSource(std::move(task_source)));
     }
   }
 
   TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); }
 
   void PostTaskNow(scoped_refptr<Sequence> sequence, Task task) {
-    auto sequence_and_transaction =
-        SequenceAndTransaction::FromSequence(std::move(sequence));
-    const bool task_source_should_be_queued =
-        sequence_and_transaction.transaction.PushTask(std::move(task));
-    if (task_source_should_be_queued) {
-      bool should_wakeup = EnqueueSequence(std::move(sequence_and_transaction));
+    auto transaction = sequence->BeginTransaction();
+    const bool sequence_should_be_queued =
+        transaction.PushTask(std::move(task));
+    if (sequence_should_be_queued) {
+      bool should_wakeup =
+          EnqueueTaskSource({std::move(sequence), std::move(transaction)});
       if (should_wakeup)
         worker_->WakeUp();
     }
@@ -143,7 +144,7 @@
     bool should_wakeup = false;
     {
       AutoSchedulerLock auto_lock(lock_);
-      if (!worker_awake_ && CanRunNextSequence()) {
+      if (!worker_awake_ && CanRunNextTaskSource()) {
         should_wakeup = true;
         worker_awake_ = true;
       }
@@ -152,18 +153,18 @@
       worker_->WakeUp();
   }
 
-  void EnableFlushPriorityQueueSequencesOnDestroyForTesting() {
+  void EnableFlushPriorityQueueTaskSourcesOnDestroyForTesting() {
     AutoSchedulerLock auto_lock(lock_);
-    priority_queue_.EnableFlushSequencesOnDestroyForTesting();
+    priority_queue_.EnableFlushTaskSourcesOnDestroyForTesting();
   }
 
  protected:
-  scoped_refptr<Sequence> GetWorkLockRequired(SchedulerWorker* worker)
+  scoped_refptr<TaskSource> GetWorkLockRequired(SchedulerWorker* worker)
       EXCLUSIVE_LOCKS_REQUIRED(lock_) {
-    if (!CanRunNextSequence()) {
+    if (!CanRunNextTaskSource()) {
       return nullptr;
     }
-    return priority_queue_.PopSequence();
+    return priority_queue_.PopTaskSource();
   }
 
   const TrackedRef<TaskTracker>& task_tracker() { return task_tracker_; }
@@ -172,21 +173,21 @@
   bool worker_awake_ GUARDED_BY(lock_) = false;
 
  private:
-  // Enqueues a sequence in this single-threaded worker's priority queue.
-  // Returns true iff the worker must wakeup, i.e. sequence is allowed to run
+  // Enqueues a task source in this single-threaded worker's priority queue.
+  // Returns true iff the worker must wakeup, i.e. task source is allowed to run
   // and the worker was not awake.
-  bool EnqueueSequence(SequenceAndTransaction sequence_and_transaction) {
+  bool EnqueueTaskSource(TaskSourceAndTransaction task_source_and_transaction) {
     AutoSchedulerLock auto_lock(lock_);
-    priority_queue_.Push(std::move(sequence_and_transaction.sequence),
-                         sequence_and_transaction.transaction.GetSortKey());
-    if (!worker_awake_ && CanRunNextSequence()) {
+    priority_queue_.Push(std::move(task_source_and_transaction.task_source),
+                         task_source_and_transaction.transaction.GetSortKey());
+    if (!worker_awake_ && CanRunNextTaskSource()) {
       worker_awake_ = true;
       return true;
     }
     return false;
   }
 
-  bool CanRunNextSequence() EXCLUSIVE_LOCKS_REQUIRED(lock_) {
+  bool CanRunNextTaskSource() EXCLUSIVE_LOCKS_REQUIRED(lock_) {
     return !priority_queue_.IsEmpty() &&
            task_tracker_->CanRunPriority(
                priority_queue_.PeekSortKey().priority());
@@ -229,43 +230,43 @@
     scoped_com_initializer_ = std::make_unique<win::ScopedCOMInitializer>();
   }
 
-  scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
+  scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) override {
     // This scheme below allows us to cover the following scenarios:
     // * Only SchedulerWorkerDelegate::GetWork() has work:
-    //   Always return the sequence from GetWork().
+    //   Always return the task source from GetWork().
     // * Only the Windows Message Queue has work:
-    //   Always return the sequence from GetWorkFromWindowsMessageQueue();
+    //   Always return the task source from GetWorkFromWindowsMessageQueue();
     // * Both SchedulerWorkerDelegate::GetWork() and the Windows Message Queue
     //   have work:
-    //   Process sequences from each source round-robin style.
+    //   Process task sources from each source round-robin style.
     AutoSchedulerLock auto_lock(lock_);
     DCHECK(worker_awake_);
-    scoped_refptr<Sequence> sequence;
+    scoped_refptr<TaskSource> task_source;
     if (get_work_first_) {
-      sequence = SchedulerWorkerDelegate::GetWorkLockRequired(worker);
-      if (sequence)
+      task_source = SchedulerWorkerDelegate::GetWorkLockRequired(worker);
+      if (task_source)
         get_work_first_ = false;
     }
 
-    if (!sequence) {
+    if (!task_source) {
       AutoSchedulerUnlock auto_unlock(lock_);
-      sequence = GetWorkFromWindowsMessageQueue();
-      if (sequence)
+      task_source = GetWorkFromWindowsMessageQueue();
+      if (task_source)
         get_work_first_ = true;
     }
 
-    if (!sequence && !get_work_first_) {
+    if (!task_source && !get_work_first_) {
       // This case is important if we checked the Windows Message Queue first
       // and found there was no work. We don't want to return null immediately
       // as that could cause the thread to go to sleep while work is waiting via
       // SchedulerWorkerDelegate::GetWork().
-      sequence = SchedulerWorkerDelegate::GetWorkLockRequired(worker);
+      task_source = SchedulerWorkerDelegate::GetWorkLockRequired(worker);
     }
-    if (sequence == nullptr) {
+    if (task_source == nullptr) {
       // The worker will sleep after this returns nullptr.
       worker_awake_ = false;
     }
-    return sequence;
+    return task_source;
   }
 
   void OnMainExit(SchedulerWorker* /* worker */) override {
@@ -287,7 +288,7 @@
   }
 
  private:
-  scoped_refptr<Sequence> GetWorkFromWindowsMessageQueue() {
+  scoped_refptr<TaskSource> GetWorkFromWindowsMessageQueue() {
     MSG msg;
     if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != FALSE) {
       Task pump_message_task(FROM_HERE,
@@ -580,7 +581,7 @@
 
   for (const auto& worker : local_workers) {
     static_cast<SchedulerWorkerDelegate*>(worker->delegate())
-        ->EnableFlushPriorityQueueSequencesOnDestroyForTesting();
+        ->EnableFlushPriorityQueueTaskSourcesOnDestroyForTesting();
     worker->JoinForTesting();
   }
 
diff --git a/base/task/thread_pool/scheduler_task_runner_delegate.h b/base/task/thread_pool/scheduler_task_runner_delegate.h
index e563fb31..42e3d19 100644
--- a/base/task/thread_pool/scheduler_task_runner_delegate.h
+++ b/base/task/thread_pool/scheduler_task_runner_delegate.h
@@ -9,6 +9,7 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool/sequence.h"
 #include "base/task/thread_pool/task.h"
+#include "base/task/thread_pool/task_source.h"
 
 namespace base {
 namespace internal {
@@ -42,7 +43,7 @@
   // implementation must update |sequence|'s priority to |priority|, then place
   // |sequence| in the correct priority-queue position within the appropriate
   // worker pool.
-  virtual void UpdatePriority(scoped_refptr<Sequence> sequence,
+  virtual void UpdatePriority(scoped_refptr<TaskSource> task_source,
                               TaskPriority priority) = 0;
 };
 
diff --git a/base/task/thread_pool/scheduler_worker.cc b/base/task/thread_pool/scheduler_worker.cc
index 3efb841..d105fb9c 100644
--- a/base/task/thread_pool/scheduler_worker.cc
+++ b/base/task/thread_pool/scheduler_worker.cc
@@ -324,9 +324,9 @@
 
     UpdateThreadPriority(GetDesiredThreadPriority());
 
-    // Get the sequence containing the next task to execute.
-    scoped_refptr<Sequence> sequence = delegate_->GetWork(this);
-    if (!sequence) {
+    // Get the task source containing the next task to execute.
+    scoped_refptr<TaskSource> task_source = delegate_->GetWork(this);
+    if (!task_source) {
       // Exit immediately if GetWork() resulted in detaching this worker.
       if (ShouldExit())
         break;
@@ -337,12 +337,12 @@
       continue;
     }
 
-    sequence = task_tracker_->RunAndPopNextTask(std::move(sequence));
+    task_source = task_tracker_->RunAndPopNextTask(std::move(task_source));
 
-    delegate_->DidRunTask(std::move(sequence));
+    delegate_->DidRunTask(std::move(task_source));
 
     // Calling WakeUp() guarantees that this SchedulerWorker will run Tasks from
-    // Sequences returned by the GetWork() method of |delegate_| until it
+    // TaskSources returned by the GetWork() method of |delegate_| until it
     // returns nullptr. Resetting |wake_up_event_| here doesn't break this
     // invariant and avoids a useless loop iteration before going to sleep if
     // WakeUp() is called while this SchedulerWorker is awake.
diff --git a/base/task/thread_pool/scheduler_worker.h b/base/task/thread_pool/scheduler_worker.h
index 68c46a45..e5f9eb9b 100644
--- a/base/task/thread_pool/scheduler_worker.h
+++ b/base/task/thread_pool/scheduler_worker.h
@@ -14,7 +14,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/scheduler_worker_params.h"
-#include "base/task/thread_pool/sequence.h"
+#include "base/task/thread_pool/task_source.h"
 #include "base/task/thread_pool/tracked_ref.h"
 #include "base/thread_annotations.h"
 #include "base/threading/platform_thread.h"
@@ -33,12 +33,12 @@
 
 class TaskTracker;
 
-// A worker that manages a single thread to run Tasks from Sequences returned
+// A worker that manages a single thread to run Tasks from TaskSources returned
 // by a delegate.
 //
 // A SchedulerWorker starts out sleeping. It is woken up by a call to WakeUp().
-// After a wake-up, a SchedulerWorker runs Tasks from Sequences returned by the
-// GetWork() method of its delegate as long as it doesn't return nullptr. It
+// After a wake-up, a SchedulerWorker runs Tasks from TaskSources returned by
+// the GetWork() method of its delegate as long as it doesn't return nullptr. It
 // also periodically checks with its TaskTracker whether shutdown has completed
 // and exits when it has.
 //
@@ -73,13 +73,13 @@
     // Called by |worker|'s thread when it enters its main function.
     virtual void OnMainEntry(const SchedulerWorker* worker) = 0;
 
-    // Called by |worker|'s thread to get a Sequence from which to run a Task.
-    virtual scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) = 0;
+    // Called by |worker|'s thread to get a TaskSource from which to run a Task.
+    virtual scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) = 0;
 
-    // Called by the SchedulerWorker after it ran a Task. If the Task's Sequence
-    // should be reenqueued, it is passed to |sequence|. Otherwise, |sequence|
-    // is nullptr.
-    virtual void DidRunTask(scoped_refptr<Sequence> sequence) = 0;
+    // Called by the SchedulerWorker after it ran a Task. If the Task's
+    // TaskSource should be reenqueued, it is passed to |task_source|.
+    // Otherwise, |task_source| is nullptr.
+    virtual void DidRunTask(scoped_refptr<TaskSource> task_source) = 0;
 
     // Called to determine how long to sleep before the next call to GetWork().
     // GetWork() may be called before this timeout expires if the worker's
@@ -99,7 +99,7 @@
     virtual void OnMainExit(SchedulerWorker* worker) {}
   };
 
-  // Creates a SchedulerWorker that runs Tasks from Sequences returned by
+  // Creates a SchedulerWorker that runs Tasks from TaskSources returned by
   // |delegate|. No actual thread will be created for this SchedulerWorker
   // before Start() is called. |priority_hint| is the preferred thread priority;
   // the actual thread priority depends on shutdown state and platform
@@ -124,9 +124,9 @@
   bool Start(SchedulerWorkerObserver* scheduler_worker_observer = nullptr);
 
   // Wakes up this SchedulerWorker if it wasn't already awake. After this is
-  // called, this SchedulerWorker will run Tasks from Sequences returned by the
-  // GetWork() method of its delegate until it returns nullptr. No-op if Start()
-  // wasn't called. DCHECKs if called after Start() has failed or after
+  // called, this SchedulerWorker will run Tasks from TaskSources returned by
+  // the GetWork() method of its delegate until it returns nullptr. No-op if
+  // Start() wasn't called. DCHECKs if called after Start() has failed or after
   // Cleanup() has been called.
   void WakeUp();
 
diff --git a/base/task/thread_pool/scheduler_worker_pool.cc b/base/task/thread_pool/scheduler_worker_pool.cc
index 01bf95a..dbb6e1b 100644
--- a/base/task/thread_pool/scheduler_worker_pool.cc
+++ b/base/task/thread_pool/scheduler_worker_pool.cc
@@ -32,19 +32,19 @@
 
 SchedulerWorkerPool::ScopedReenqueueExecutor::~ScopedReenqueueExecutor() {
   if (destination_pool_) {
-    destination_pool_->PushSequenceAndWakeUpWorkers(
-        std::move(sequence_and_transaction_.value()));
+    destination_pool_->PushTaskSourceAndWakeUpWorkers(
+        std::move(task_source_and_transaction_.value()));
   }
 }
 
 void SchedulerWorkerPool::ScopedReenqueueExecutor::
-    SchedulePushSequenceAndWakeUpWorkers(
-        SequenceAndTransaction sequence_and_transaction,
+    SchedulePushTaskSourceAndWakeUpWorkers(
+        TaskSourceAndTransaction task_source_and_transaction,
         SchedulerWorkerPool* destination_pool) {
   DCHECK(destination_pool);
   DCHECK(!destination_pool_);
-  DCHECK(!sequence_and_transaction_);
-  sequence_and_transaction_.emplace(std::move(sequence_and_transaction));
+  DCHECK(!task_source_and_transaction_);
+  task_source_and_transaction_.emplace(std::move(task_source_and_transaction));
   destination_pool_ = destination_pool;
 }
 
@@ -82,16 +82,18 @@
   // in the past).
   DCHECK_LE(task.delayed_run_time, TimeTicks::Now());
 
-  const bool task_source_should_be_queued =
+  const bool sequence_should_be_queued =
       sequence_and_transaction.transaction.PushTask(std::move(task));
-  if (task_source_should_be_queued) {
-    PushSequenceAndWakeUpWorkers(std::move(sequence_and_transaction));
+  if (sequence_should_be_queued) {
+    PushTaskSourceAndWakeUpWorkers(
+        {std::move(sequence_and_transaction.sequence),
+         std::move(sequence_and_transaction.transaction)});
   }
 }
 
-size_t SchedulerWorkerPool::GetNumQueuedCanRunBestEffortSequences() const {
+size_t SchedulerWorkerPool::GetNumQueuedCanRunBestEffortTaskSources() const {
   const size_t num_queued =
-      priority_queue_.GetNumSequencesWithPriority(TaskPriority::BEST_EFFORT);
+      priority_queue_.GetNumTaskSourcesWithPriority(TaskPriority::BEST_EFFORT);
   if (num_queued == 0 ||
       !task_tracker_->CanRunPriority(TaskPriority::BEST_EFFORT)) {
     return 0U;
@@ -99,10 +101,11 @@
   return num_queued;
 }
 
-size_t SchedulerWorkerPool::GetNumQueuedCanRunForegroundSequences() const {
-  const size_t num_queued =
-      priority_queue_.GetNumSequencesWithPriority(TaskPriority::USER_VISIBLE) +
-      priority_queue_.GetNumSequencesWithPriority(TaskPriority::USER_BLOCKING);
+size_t SchedulerWorkerPool::GetNumQueuedCanRunForegroundTaskSources() const {
+  const size_t num_queued = priority_queue_.GetNumTaskSourcesWithPriority(
+                                TaskPriority::USER_VISIBLE) +
+                            priority_queue_.GetNumTaskSourcesWithPriority(
+                                TaskPriority::USER_BLOCKING);
   if (num_queued == 0 ||
       !task_tracker_->CanRunPriority(TaskPriority::HIGHEST)) {
     return 0U;
@@ -110,51 +113,52 @@
   return num_queued;
 }
 
-bool SchedulerWorkerPool::RemoveSequence(scoped_refptr<Sequence> sequence) {
+bool SchedulerWorkerPool::RemoveTaskSource(
+    scoped_refptr<TaskSource> task_source) {
   AutoSchedulerLock auto_lock(lock_);
-  return priority_queue_.RemoveSequence(std::move(sequence));
+  return priority_queue_.RemoveTaskSource(std::move(task_source));
 }
 
-void SchedulerWorkerPool::ReEnqueueSequenceLockRequired(
+void SchedulerWorkerPool::ReEnqueueTaskSourceLockRequired(
     BaseScopedWorkersExecutor* workers_executor,
     ScopedReenqueueExecutor* reenqueue_executor,
-    SequenceAndTransaction sequence_and_transaction) {
-  // Decide in which pool the Sequence should be reenqueued.
+    TaskSourceAndTransaction task_source_and_transaction) {
+  // Decide in which pool the TaskSource should be reenqueued.
   SchedulerWorkerPool* destination_pool = delegate_->GetWorkerPoolForTraits(
-      sequence_and_transaction.transaction.traits());
+      task_source_and_transaction.transaction.traits());
 
   if (destination_pool == this) {
-    // If the Sequence should be reenqueued in the current pool, reenqueue it
+    // If the TaskSource should be reenqueued in the current pool, reenqueue it
     // inside the scope of the lock.
-    priority_queue_.Push(std::move(sequence_and_transaction.sequence),
-                         sequence_and_transaction.transaction.GetSortKey());
+    priority_queue_.Push(std::move(task_source_and_transaction.task_source),
+                         task_source_and_transaction.transaction.GetSortKey());
     EnsureEnoughWorkersLockRequired(workers_executor);
   } else {
     // Otherwise, schedule a reenqueue after releasing the lock.
-    reenqueue_executor->SchedulePushSequenceAndWakeUpWorkers(
-        std::move(sequence_and_transaction), destination_pool);
+    reenqueue_executor->SchedulePushTaskSourceAndWakeUpWorkers(
+        std::move(task_source_and_transaction), destination_pool);
   }
 }
 
 void SchedulerWorkerPool::UpdateSortKeyImpl(
     BaseScopedWorkersExecutor* executor,
-    SequenceAndTransaction sequence_and_transaction) {
+    TaskSourceAndTransaction task_source_and_transaction) {
   AutoSchedulerLock auto_lock(lock_);
-  priority_queue_.UpdateSortKey(std::move(sequence_and_transaction));
+  priority_queue_.UpdateSortKey(std::move(task_source_and_transaction));
   EnsureEnoughWorkersLockRequired(executor);
 }
 
-void SchedulerWorkerPool::PushSequenceAndWakeUpWorkersImpl(
+void SchedulerWorkerPool::PushTaskSourceAndWakeUpWorkersImpl(
     BaseScopedWorkersExecutor* executor,
-    SequenceAndTransaction sequence_and_transaction) {
+    TaskSourceAndTransaction task_source_and_transaction) {
   AutoSchedulerLock auto_lock(lock_);
   DCHECK(!replacement_pool_);
-  priority_queue_.Push(std::move(sequence_and_transaction.sequence),
-                       sequence_and_transaction.transaction.GetSortKey());
+  priority_queue_.Push(std::move(task_source_and_transaction.task_source),
+                       task_source_and_transaction.transaction.GetSortKey());
   EnsureEnoughWorkersLockRequired(executor);
 }
 
-void SchedulerWorkerPool::InvalidateAndHandoffAllSequencesToOtherPool(
+void SchedulerWorkerPool::InvalidateAndHandoffAllTaskSourcesToOtherPool(
     SchedulerWorkerPool* destination_pool) {
   AutoSchedulerLock current_pool_lock(lock_);
   AutoSchedulerLock destination_pool_lock(destination_pool->lock_);
diff --git a/base/task/thread_pool/scheduler_worker_pool.h b/base/task/thread_pool/scheduler_worker_pool.h
index eb82100..75c14071 100644
--- a/base/task/thread_pool/scheduler_worker_pool.h
+++ b/base/task/thread_pool/scheduler_worker_pool.h
@@ -11,6 +11,7 @@
 #include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/sequence.h"
 #include "base/task/thread_pool/task.h"
+#include "base/task/thread_pool/task_source.h"
 #include "base/task/thread_pool/tracked_ref.h"
 #include "build/build_config.h"
 
@@ -27,9 +28,9 @@
    public:
     virtual ~Delegate() = default;
 
-    // Invoked when the Sequence in |sequence_and_transaction| is non-empty
+    // Invoked when the TaskSource in |task_source_and_transaction| is non-empty
     // after the SchedulerWorkerPool has run a task from it. The implementation
-    // must return the pool in which the Sequence should be reenqueued.
+    // must return the pool in which the TaskSource should be reenqueued.
     virtual SchedulerWorkerPool* GetWorkerPoolForTraits(
         const TaskTraits& traits) = 0;
   };
@@ -61,34 +62,34 @@
   // Returns true if the worker pool is registered in TLS.
   bool IsBoundToCurrentThread() const;
 
-  // Removes |sequence| from |priority_queue_|. Returns true if successful, or
-  // false if |sequence| is not currently in |priority_queue_|, such as when a
-  // worker is running a task from it.
-  bool RemoveSequence(scoped_refptr<Sequence> sequence);
+  // Removes |task_source| from |priority_queue_|. Returns true if successful,
+  // or false if |task_source| is not currently in |priority_queue_|, such as
+  // when a worker is running a task from it.
+  bool RemoveTaskSource(scoped_refptr<TaskSource> task_source);
 
-  // Updates the position of the Sequence in |sequence_and_transaction| in
-  // this pool's PriorityQueue based on the Sequence's current traits.
+  // Updates the position of the TaskSource in |task_source_and_transaction| in
+  // this pool's PriorityQueue based on the TaskSource's current traits.
   //
   // Implementations should instantiate a concrete ScopedWorkersExecutor and
   // invoke UpdateSortKeyImpl().
   virtual void UpdateSortKey(
-      SequenceAndTransaction sequence_and_transaction) = 0;
+      TaskSourceAndTransaction task_source_and_transaction) = 0;
 
-  // Pushes the Sequence in |sequence_and_transaction| into this pool's
+  // Pushes the TaskSource in |task_source_and_transaction| into this pool's
   // PriorityQueue and wakes up workers as appropriate.
   //
   // Implementations should instantiate a concrete ScopedWorkersExecutor and
-  // invoke PushSequenceAndWakeUpWorkersImpl().
-  virtual void PushSequenceAndWakeUpWorkers(
-      SequenceAndTransaction sequence_and_transaction) = 0;
+  // invoke PushTaskSourceAndWakeUpWorkersImpl().
+  virtual void PushTaskSourceAndWakeUpWorkers(
+      TaskSourceAndTransaction task_source_and_transaction) = 0;
 
-  // Removes all sequences from this pool's PriorityQueue and enqueues them in
-  // another |destination_pool|. After this method is called, any sequences
-  // posted to this pool will be forwarded to |destination_pool|.
+  // Removes all task sources from this pool's PriorityQueue and enqueues them
+  // in another |destination_pool|. After this method is called, any task
+  // sources posted to this pool will be forwarded to |destination_pool|.
   //
   // TODO(crbug.com/756547): Remove this method once the UseNativeThreadPool
   // experiment is complete.
-  void InvalidateAndHandoffAllSequencesToOtherPool(
+  void InvalidateAndHandoffAllTaskSourcesToOtherPool(
       SchedulerWorkerPool* destination_pool);
 
   // Prevents new tasks from starting to run and waits for currently running
@@ -123,27 +124,27 @@
     DISALLOW_COPY_AND_ASSIGN(BaseScopedWorkersExecutor);
   };
 
-  // Allows a sequence to be pushed to a pool's PriorityQueue at the end of a
+  // Allows a task source to be pushed to a pool's PriorityQueue at the end of a
   // scope, when all locks have been released.
   class ScopedReenqueueExecutor {
    public:
     ScopedReenqueueExecutor();
     ~ScopedReenqueueExecutor();
 
-    void SchedulePushSequenceAndWakeUpWorkers(
-        SequenceAndTransaction sequence_and_transaction,
+    void SchedulePushTaskSourceAndWakeUpWorkers(
+        TaskSourceAndTransaction task_source_and_transaction,
         SchedulerWorkerPool* destination_pool);
 
    private:
-    // A SequenceAndTransaction and the pool in which it should be enqueued.
-    Optional<SequenceAndTransaction> sequence_and_transaction_;
+    // A TaskSourceAndTransaction and the pool in which it should be enqueued.
+    Optional<TaskSourceAndTransaction> task_source_and_transaction_;
     SchedulerWorkerPool* destination_pool_ = nullptr;
 
     DISALLOW_COPY_AND_ASSIGN(ScopedReenqueueExecutor);
   };
 
   // |predecessor_pool| is a pool whose lock can be acquired before the
-  // constructed pool's lock. This is necessary to move all sequences from
+  // constructed pool's lock. This is necessary to move all task sources from
   // |predecessor_pool| to the constructed pool and support the
   // UseNativeThreadPool experiment.
   //
@@ -156,35 +157,36 @@
   const TrackedRef<TaskTracker> task_tracker_;
   const TrackedRef<Delegate> delegate_;
 
-  // Returns the number of queued BEST_EFFORT sequences allowed to run by the
+  // Returns the number of queued BEST_EFFORT task sources allowed to run by the
   // current CanRunPolicy.
-  size_t GetNumQueuedCanRunBestEffortSequences() const
+  size_t GetNumQueuedCanRunBestEffortTaskSources() const
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
-  // Returns the number of queued USER_VISIBLE/USER_BLOCKING sequences allowed
-  // to run by the current CanRunPolicy.
-  size_t GetNumQueuedCanRunForegroundSequences() const
+  // Returns the number of queued USER_VISIBLE/USER_BLOCKING task sources
+  // allowed to run by the current CanRunPolicy.
+  size_t GetNumQueuedCanRunForegroundTaskSources() const
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
-  // Ensures that there are enough workers to run queued sequences. |executor|
-  // is forwarded from the one received in PushSequenceAndWakeUpWorkersImpl()
+  // Ensures that there are enough workers to run queued task sources.
+  // |executor| is forwarded from the one received in
+  // PushTaskSourceAndWakeUpWorkersImpl()
   virtual void EnsureEnoughWorkersLockRequired(
       BaseScopedWorkersExecutor* executor) EXCLUSIVE_LOCKS_REQUIRED(lock_) = 0;
 
-  // Reenqueues a |sequence_and_transaction| from which a Task just ran in the
-  // current pool into the appropriate pool.
-  void ReEnqueueSequenceLockRequired(
+  // Reenqueues a |task_source_and_transaction| from which a Task just ran in
+  // the current pool into the appropriate pool.
+  void ReEnqueueTaskSourceLockRequired(
       BaseScopedWorkersExecutor* workers_executor,
       ScopedReenqueueExecutor* reenqueue_executor,
-      SequenceAndTransaction sequence_and_transaction)
+      TaskSourceAndTransaction task_source_and_transaction)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Must be invoked by implementations of the corresponding non-Impl() methods.
   void UpdateSortKeyImpl(BaseScopedWorkersExecutor* executor,
-                         SequenceAndTransaction sequence_and_transaction);
-  void PushSequenceAndWakeUpWorkersImpl(
+                         TaskSourceAndTransaction task_source_and_transaction);
+  void PushTaskSourceAndWakeUpWorkersImpl(
       BaseScopedWorkersExecutor* executor,
-      SequenceAndTransaction sequence_and_transaction);
+      TaskSourceAndTransaction task_source_and_transaction);
 
   // Synchronizes accesses to all members of this class which are neither const,
   // atomic, nor immutable after start. Since this lock is a bottleneck to post
@@ -195,8 +197,8 @@
   // PriorityQueue from which all threads of this worker pool get work.
   PriorityQueue priority_queue_ GUARDED_BY(lock_);
 
-  // If |replacement_pool_| is non-null, this pool is invalid and all sequences
-  // should be scheduled on |replacement_pool_|. Used to support the
+  // If |replacement_pool_| is non-null, this pool is invalid and all task
+  // sources should be scheduled on |replacement_pool_|. Used to support the
   // UseNativeThreadPool experiment.
   SchedulerWorkerPool* replacement_pool_ = nullptr;
 
diff --git a/base/task/thread_pool/scheduler_worker_pool_impl.cc b/base/task/thread_pool/scheduler_worker_pool_impl.cc
index 989d5de..0da65e8 100644
--- a/base/task/thread_pool/scheduler_worker_pool_impl.cc
+++ b/base/task/thread_pool/scheduler_worker_pool_impl.cc
@@ -210,8 +210,8 @@
   // SchedulerWorker::Delegate:
   SchedulerWorker::ThreadLabel GetThreadLabel() const override;
   void OnMainEntry(const SchedulerWorker* worker) override;
-  scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override;
-  void DidRunTask(scoped_refptr<Sequence> sequence) override;
+  scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) override;
+  void DidRunTask(scoped_refptr<TaskSource> task_source) override;
   TimeDelta GetSleepTimeout() override;
   void OnMainExit(SchedulerWorker* worker) override;
 
@@ -272,7 +272,8 @@
     size_t num_tasks_since_last_detach = 0;
 
     // Whether the worker is currently running a task (i.e. GetWork() has
-    // returned a non-empty sequence and DidRunTask() hasn't been called yet).
+    // returned a non-empty task source and DidRunTask() hasn't been called
+    // yet).
     bool is_running_task = false;
 
 #if defined(OS_WIN)
@@ -435,16 +436,16 @@
 }
 
 void SchedulerWorkerPoolImpl::UpdateSortKey(
-    SequenceAndTransaction sequence_and_transaction) {
+    TaskSourceAndTransaction task_source_and_transaction) {
   ScopedWorkersExecutor executor(this);
-  UpdateSortKeyImpl(&executor, std::move(sequence_and_transaction));
+  UpdateSortKeyImpl(&executor, std::move(task_source_and_transaction));
 }
 
-void SchedulerWorkerPoolImpl::PushSequenceAndWakeUpWorkers(
-    SequenceAndTransaction sequence_and_transaction) {
+void SchedulerWorkerPoolImpl::PushTaskSourceAndWakeUpWorkers(
+    TaskSourceAndTransaction task_source_and_transaction) {
   ScopedWorkersExecutor executor(this);
-  PushSequenceAndWakeUpWorkersImpl(&executor,
-                                   std::move(sequence_and_transaction));
+  PushTaskSourceAndWakeUpWorkersImpl(&executor,
+                                     std::move(task_source_and_transaction));
 }
 
 size_t SchedulerWorkerPoolImpl::GetMaxConcurrentNonBlockedTasksDeprecated()
@@ -496,7 +497,7 @@
   decltype(workers_) workers_copy;
   {
     AutoSchedulerLock auto_lock(lock_);
-    priority_queue_.EnableFlushSequencesOnDestroyForTesting();
+    priority_queue_.EnableFlushTaskSourcesOnDestroyForTesting();
 
     DCHECK_GT(workers_.size(), size_t(0)) << "Joined an unstarted worker pool.";
 
@@ -592,7 +593,7 @@
   SetBlockingObserverForCurrentThread(this);
 }
 
-scoped_refptr<Sequence>
+scoped_refptr<TaskSource>
 SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::GetWork(
     SchedulerWorker* worker) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
@@ -645,12 +646,12 @@
               outer_->max_best_effort_tasks_);
   }
 
-  // Pop the Sequence from which to run a task from the PriorityQueue.
-  return outer_->priority_queue_.PopSequence();
+  // Pop the TaskSource from which to run a task from the PriorityQueue.
+  return outer_->priority_queue_.PopTaskSource();
 }
 
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::DidRunTask(
-    scoped_refptr<Sequence> sequence) {
+    scoped_refptr<TaskSource> task_source) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
   DCHECK(worker_only().is_running_task);
   DCHECK(read_worker().may_block_start_time.is_null());
@@ -658,13 +659,13 @@
   ++worker_only().num_tasks_since_last_wait;
   ++worker_only().num_tasks_since_last_detach;
 
-  // A transaction to the Sequence to reenqueue, if any. Instantiated here as
-  // |Sequence::lock_| is a UniversalPredecessor and must always be acquired
+  // A transaction to the TaskSource to reenqueue, if any. Instantiated here as
+  // |TaskSource::lock_| is a UniversalPredecessor and must always be acquired
   // prior to acquiring a second lock
-  Optional<SequenceAndTransaction> sequence_and_transaction;
-  if (sequence) {
-    sequence_and_transaction.emplace(
-        SequenceAndTransaction::FromSequence(std::move(sequence)));
+  Optional<TaskSourceAndTransaction> task_source_and_transaction;
+  if (task_source) {
+    task_source_and_transaction.emplace(
+        TaskSourceAndTransaction::FromTaskSource(std::move(task_source)));
   }
 
   ScopedWorkersExecutor workers_executor(outer_.get());
@@ -685,10 +686,10 @@
     write_worker().is_running_best_effort_task = false;
   }
 
-  if (sequence_and_transaction) {
-    outer_->ReEnqueueSequenceLockRequired(
+  if (task_source_and_transaction) {
+    outer_->ReEnqueueTaskSourceLockRequired(
         &workers_executor, &reenqueue_executor,
-        std::move(sequence_and_transaction.value()));
+        std::move(task_source_and_transaction.value()));
   }
 }
 
@@ -1020,27 +1021,28 @@
 }
 
 size_t SchedulerWorkerPoolImpl::GetDesiredNumAwakeWorkersLockRequired() const {
-  // Number of BEST_EFFORT sequences that are running or queued and allowed to
-  // run by the CanRunPolicy.
-  const size_t num_running_or_queued_can_run_best_effort_sequences =
-      num_running_best_effort_tasks_ + GetNumQueuedCanRunBestEffortSequences();
+  // Number of BEST_EFFORT task sources that are running or queued and allowed
+  // to run by the CanRunPolicy.
+  const size_t num_running_or_queued_can_run_best_effort_task_sources =
+      num_running_best_effort_tasks_ +
+      GetNumQueuedCanRunBestEffortTaskSources();
 
-  const size_t workers_for_best_effort_sequences =
-      std::max(std::min(num_running_or_queued_can_run_best_effort_sequences,
+  const size_t workers_for_best_effort_task_sources =
+      std::max(std::min(num_running_or_queued_can_run_best_effort_task_sources,
                         max_best_effort_tasks_),
                num_running_best_effort_tasks_);
 
-  // Number of USER_{VISIBLE|BLOCKING} sequences that are running or queued.
-  const size_t num_running_or_queued_foreground_sequences =
+  // Number of USER_{VISIBLE|BLOCKING} task sources that are running or queued.
+  const size_t num_running_or_queued_foreground_task_sources =
       (num_running_tasks_ - num_running_best_effort_tasks_) +
-      GetNumQueuedCanRunForegroundSequences();
+      GetNumQueuedCanRunForegroundTaskSources();
 
-  const size_t workers_for_foreground_sequences =
-      num_running_or_queued_foreground_sequences;
+  const size_t workers_for_foreground_task_sources =
+      num_running_or_queued_foreground_task_sources;
 
-  return std::min(
-      {workers_for_best_effort_sequences + workers_for_foreground_sequences,
-       max_tasks_, kMaxNumberOfWorkers});
+  return std::min({workers_for_best_effort_task_sources +
+                       workers_for_foreground_task_sources,
+                   max_tasks_, kMaxNumberOfWorkers});
 }
 
 void SchedulerWorkerPoolImpl::DidUpdateCanRunPolicy() {
@@ -1138,25 +1140,25 @@
 bool SchedulerWorkerPoolImpl::ShouldPeriodicallyAdjustMaxTasksLockRequired() {
   // AdjustMaxTasks() should be scheduled to periodically adjust |max_tasks_|
   // and |max_best_effort_tasks_| when (1) the concurrency limits are not large
-  // enough to accommodate all queued and running sequences and an idle worker
-  // and (2) there are unresolved MAY_BLOCK ScopedBlockingCalls.
+  // enough to accommodate all queued and running task sources and an idle
+  // worker and (2) there are unresolved MAY_BLOCK ScopedBlockingCalls.
   // - When (1) is false: No worker would be created or woken up if the
   //   concurrency limits were increased, so there is no hurry to increase them.
   // - When (2) is false: The concurrency limits could not be increased by
   //   AdjustMaxTasks().
 
-  const size_t num_running_or_queued_best_effort_sequences =
+  const size_t num_running_or_queued_best_effort_task_sources =
       num_running_best_effort_tasks_ +
-      priority_queue_.GetNumSequencesWithPriority(TaskPriority::BEST_EFFORT);
-  if (num_running_or_queued_best_effort_sequences > max_best_effort_tasks_ &&
+      priority_queue_.GetNumTaskSourcesWithPriority(TaskPriority::BEST_EFFORT);
+  if (num_running_or_queued_best_effort_task_sources > max_best_effort_tasks_ &&
       num_unresolved_best_effort_may_block_ > 0) {
     return true;
   }
 
-  const size_t num_running_or_queued_sequences =
+  const size_t num_running_or_queued_task_sources =
       num_running_tasks_ + priority_queue_.Size();
   constexpr size_t kIdleWorker = 1;
-  return num_running_or_queued_sequences + kIdleWorker > max_tasks_ &&
+  return num_running_or_queued_task_sources + kIdleWorker > max_tasks_ &&
          num_unresolved_may_block_ > 0;
 }
 
diff --git a/base/task/thread_pool/scheduler_worker_pool_impl.h b/base/task/thread_pool/scheduler_worker_pool_impl.h
index e2310c6..7af46ef 100644
--- a/base/task/thread_pool/scheduler_worker_pool_impl.h
+++ b/base/task/thread_pool/scheduler_worker_pool_impl.h
@@ -26,8 +26,8 @@
 #include "base/task/thread_pool/scheduler_worker.h"
 #include "base/task/thread_pool/scheduler_worker_pool.h"
 #include "base/task/thread_pool/scheduler_worker_stack.h"
-#include "base/task/thread_pool/sequence.h"
 #include "base/task/thread_pool/task.h"
+#include "base/task/thread_pool/task_source.h"
 #include "base/task/thread_pool/tracked_ref.h"
 #include "base/task_runner.h"
 #include "base/time/time.h"
@@ -145,9 +145,10 @@
                            ThreadBlockUnblockPremature);
 
   // SchedulerWorkerPool:
-  void UpdateSortKey(SequenceAndTransaction sequence_and_transaction) override;
-  void PushSequenceAndWakeUpWorkers(
-      SequenceAndTransaction sequence_and_transaction) override;
+  void UpdateSortKey(
+      TaskSourceAndTransaction task_source_and_transaction) override;
+  void PushTaskSourceAndWakeUpWorkers(
+      TaskSourceAndTransaction task_source_and_transaction) override;
   void EnsureEnoughWorkersLockRequired(BaseScopedWorkersExecutor* executor)
       override EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
diff --git a/base/task/thread_pool/scheduler_worker_stack_unittest.cc b/base/task/thread_pool/scheduler_worker_stack_unittest.cc
index 24004ca3..a9f6625 100644
--- a/base/task/thread_pool/scheduler_worker_stack_unittest.cc
+++ b/base/task/thread_pool/scheduler_worker_stack_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/task/thread_pool/scheduler_worker.h"
-#include "base/task/thread_pool/sequence.h"
+#include "base/task/thread_pool/task_source.h"
 #include "base/task/thread_pool/task_tracker.h"
 #include "base/test/gtest_util.h"
 #include "base/threading/platform_thread.h"
@@ -25,10 +25,10 @@
     return SchedulerWorker::ThreadLabel::DEDICATED;
   }
   void OnMainEntry(const SchedulerWorker* worker) override {}
-  scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
+  scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) override {
     return nullptr;
   }
-  void DidRunTask(scoped_refptr<Sequence> sequence) override {
+  void DidRunTask(scoped_refptr<TaskSource> task_source) override {
     ADD_FAILURE() << "Unexpected call to DidRunTask()";
   }
   TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); }
diff --git a/base/task/thread_pool/scheduler_worker_unittest.cc b/base/task/thread_pool/scheduler_worker_unittest.cc
index 6d0e3f4..a43da7e 100644
--- a/base/task/thread_pool/scheduler_worker_unittest.cc
+++ b/base/task/thread_pool/scheduler_worker_unittest.cc
@@ -57,10 +57,10 @@
     return SchedulerWorker::ThreadLabel::DEDICATED;
   }
   void OnMainEntry(const SchedulerWorker* worker) override {}
-  scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
+  scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) override {
     return nullptr;
   }
-  void DidRunTask(scoped_refptr<Sequence> sequence) override {
+  void DidRunTask(scoped_refptr<TaskSource> sequence) override {
     ADD_FAILURE() << "Unexpected call to DidRunTask()";
   }
   TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); }
@@ -117,12 +117,12 @@
     return num_run_tasks_;
   }
 
-  std::vector<scoped_refptr<Sequence>> CreatedSequences() {
+  std::vector<scoped_refptr<TaskSource>> CreatedTaskSources() {
     AutoSchedulerLock auto_lock(lock_);
     return created_sequences_;
   }
 
-  std::vector<scoped_refptr<Sequence>> DidRunTaskSequences() {
+  std::vector<scoped_refptr<TaskSource>> DidRunTaskSequences() {
     AutoSchedulerLock auto_lock(lock_);
     return did_run_task_sequences_;
   }
@@ -151,7 +151,7 @@
       outer_->main_entry_called_.Signal();
     }
 
-    scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
+    scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) override {
       EXPECT_FALSE(IsCallToDidRunTaskExpected());
       EXPECT_EQ(outer_->worker_.get(), worker);
 
@@ -200,7 +200,7 @@
     // and adds it to |did_run_task_sequences_|. Unlike a normal DidRunTask()
     // implementation, it doesn't add |sequence| to a queue for further
     // execution.
-    void DidRunTask(scoped_refptr<Sequence> sequence) override {
+    void DidRunTask(scoped_refptr<TaskSource> sequence) override {
       {
         AutoSchedulerLock auto_lock(expect_did_run_task_lock_);
         EXPECT_TRUE(expect_did_run_task_);
@@ -282,10 +282,10 @@
   std::unique_ptr<ConditionVariable> num_get_work_cv_;
 
   // Sequences created by GetWork().
-  std::vector<scoped_refptr<Sequence>> created_sequences_;
+  std::vector<scoped_refptr<TaskSource>> created_sequences_;
 
   // Sequences passed to DidRunTask().
-  std::vector<scoped_refptr<Sequence>> did_run_task_sequences_;
+  std::vector<scoped_refptr<TaskSource>> did_run_task_sequences_;
 
   // Number of times that RunTaskCallback() has been called.
   size_t num_run_tasks_ = 0;
@@ -322,7 +322,7 @@
   // empty after the worker pops Tasks from them and thus should be returned to
   // DidRunTask().
   if (TasksPerSequence() > 1)
-    EXPECT_EQ(CreatedSequences(), DidRunTaskSequences());
+    EXPECT_EQ(CreatedTaskSources(), DidRunTaskSequences());
   else
     EXPECT_TRUE(DidRunTaskSequences().empty());
 }
@@ -353,7 +353,7 @@
     // aren't empty after the worker pops Tasks from them and thus should be
     // returned to DidRunTask().
     if (TasksPerSequence() > 1)
-      EXPECT_EQ(CreatedSequences(), DidRunTaskSequences());
+      EXPECT_EQ(CreatedTaskSources(), DidRunTaskSequences());
     else
       EXPECT_TRUE(DidRunTaskSequences().empty());
   }
@@ -424,7 +424,7 @@
 
   ~ControllableCleanupDelegate() override { controls_->destroyed_.Signal(); }
 
-  scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
+  scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) override {
     EXPECT_TRUE(controls_->expect_get_work_);
 
     // Sends one item of work to signal |work_processed_|. On subsequent calls,
@@ -459,7 +459,7 @@
     return sequence;
   }
 
-  void DidRunTask(scoped_refptr<Sequence>) override {}
+  void DidRunTask(scoped_refptr<TaskSource>) override {}
 
   void OnMainExit(SchedulerWorker* worker) override {
     controls_->exited_.Signal();
@@ -702,7 +702,7 @@
   void OnMainEntry(const SchedulerWorker* worker) override {
     VerifyThreadPriority();
   }
-  scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
+  scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) override {
     VerifyThreadPriority();
     priority_verified_in_get_work_event_.Signal();
     return nullptr;
@@ -821,7 +821,7 @@
  public:
   CoInitializeDelegate() = default;
 
-  scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
+  scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) override {
     EXPECT_FALSE(get_work_returned_.IsSignaled());
     EXPECT_EQ(E_UNEXPECTED, coinitialize_hresult_);
 
diff --git a/base/task/thread_pool/task_tracker.cc b/base/task/thread_pool/task_tracker.cc
index ceffb8e8..88cec79 100644
--- a/base/task/thread_pool/task_tracker.cc
+++ b/base/task/thread_pool/task_tracker.cc
@@ -402,29 +402,31 @@
   return false;
 }
 
-scoped_refptr<Sequence> TaskTracker::RunAndPopNextTask(
-    scoped_refptr<Sequence> sequence) {
-  DCHECK(sequence);
+scoped_refptr<TaskSource> TaskTracker::RunAndPopNextTask(
+    scoped_refptr<TaskSource> task_source) {
+  DCHECK(task_source);
 
-  // Run the next task in |sequence|.
+  // Run the next task in |task_source|.
   Optional<Task> task;
   TaskTraits traits;
   {
-    Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
-    task = sequence_transaction.TakeTask();
+    TaskSource::Transaction task_source_transaction(
+        task_source->BeginTransaction());
+    task = task_source_transaction.TakeTask();
     // TODO(fdoray): Support TakeTask() returning null. https://crbug.com/783309
     DCHECK(task);
 
-    traits = sequence_transaction.traits();
+    traits = task_source_transaction.traits();
   }
 
   const TaskShutdownBehavior effective_shutdown_behavior =
-      GetEffectiveShutdownBehavior(sequence->shutdown_behavior(),
+      GetEffectiveShutdownBehavior(task_source->shutdown_behavior(),
                                    !task->delayed_run_time.is_null());
 
   const bool can_run_task = BeforeRunTask(effective_shutdown_behavior);
 
-  RunOrSkipTask(std::move(task.value()), sequence.get(), traits, can_run_task);
+  RunOrSkipTask(std::move(task.value()), task_source.get(), traits,
+                can_run_task);
   if (can_run_task) {
     IncrementNumTasksRun();
     AfterRunTask(effective_shutdown_behavior);
@@ -433,13 +435,13 @@
   if (task->delayed_run_time.is_null())
     DecrementNumIncompleteUndelayedTasks();
 
-  const bool sequence_must_be_queued =
-      sequence->BeginTransaction().DidRunTask();
+  const bool task_source_must_be_queued =
+      task_source->BeginTransaction().DidRunTask();
 
-  // The sequence should be reenqueued iff requested by DidRunTask().
-  if (!sequence_must_be_queued)
+  // The task source should be reenqueued iff requested by DidRunTask().
+  if (!task_source_must_be_queued)
     return nullptr;
-  return sequence;
+  return task_source;
 }
 
 bool TaskTracker::HasShutdownStarted() const {
@@ -493,14 +495,14 @@
 }
 
 void TaskTracker::RunOrSkipTask(Task task,
-                                Sequence* sequence,
+                                TaskSource* task_source,
                                 const TaskTraits& traits,
                                 bool can_run_task) {
-  DCHECK(sequence);
+  DCHECK(task_source);
   RecordLatencyHistogram(LatencyHistogramType::TASK_LATENCY, traits,
                          task.queue_time);
 
-  const auto environment = sequence->GetExecutionEnvironment();
+  const auto environment = task_source->GetExecutionEnvironment();
 
   const bool previous_singleton_allowed =
       ThreadRestrictions::SetSingletonAllowed(
@@ -532,18 +534,18 @@
     // Set up TaskRunnerHandle as expected for the scope of the task.
     Optional<SequencedTaskRunnerHandle> sequenced_task_runner_handle;
     Optional<ThreadTaskRunnerHandle> single_thread_task_runner_handle;
-    switch (sequence->execution_mode()) {
+    switch (task_source->execution_mode()) {
       case TaskSourceExecutionMode::kParallel:
         break;
       case TaskSourceExecutionMode::kSequenced:
-        DCHECK(sequence->task_runner());
+        DCHECK(task_source->task_runner());
         sequenced_task_runner_handle.emplace(
-            static_cast<SequencedTaskRunner*>(sequence->task_runner()));
+            static_cast<SequencedTaskRunner*>(task_source->task_runner()));
         break;
       case TaskSourceExecutionMode::kSingleThread:
-        DCHECK(sequence->task_runner());
+        DCHECK(task_source->task_runner());
         single_thread_task_runner_handle.emplace(
-            static_cast<SingleThreadTaskRunner*>(sequence->task_runner()));
+            static_cast<SingleThreadTaskRunner*>(task_source->task_runner()));
         break;
     }
 
@@ -557,7 +559,7 @@
                    std::make_unique<TaskTracingInfo>(
                        traits,
                        kExecutionModeString[static_cast<size_t>(
-                           sequence->execution_mode())],
+                           task_source->execution_mode())],
                        environment.token));
 
       RunTaskWithShutdownBehavior(traits.shutdown_behavior(), &task);
diff --git a/base/task/thread_pool/task_tracker.h b/base/task/thread_pool/task_tracker.h
index 9c4073c..91701e8 100644
--- a/base/task/thread_pool/task_tracker.h
+++ b/base/task/thread_pool/task_tracker.h
@@ -23,8 +23,8 @@
 #include "base/task/common/task_annotator.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool/scheduler_lock.h"
-#include "base/task/thread_pool/sequence.h"
 #include "base/task/thread_pool/task.h"
+#include "base/task/thread_pool/task_source.h"
 #include "base/task/thread_pool/tracked_ref.h"
 
 namespace base {
@@ -45,9 +45,9 @@
 };
 
 // TaskTracker enforces policies that determines whether:
-// - A task can be added to a sequence (WillPostTask).
+// - A task can be added to a task source (WillPostTask).
 // - Tasks for a given priority can run (CanRunPriority).
-// - The next task in a scheduled sequence can run (RunAndPopNextTask).
+// - The next task in a scheduled task source can run (RunAndPopNextTask).
 // TaskTracker also sets up the environment to run a task (RunAndPopNextTask)
 // and records metrics and trace events. This class is thread-safe.
 class BASE_EXPORT TaskTracker {
@@ -90,7 +90,7 @@
   // tasks that are allowed to run by the new policy can be scheduled.
   void SetCanRunPolicy(CanRunPolicy can_run_policy);
 
-  // Informs this TaskTracker that |task| from a |shutdown_behavior| sequence
+  // Informs this TaskTracker that |task| from a |shutdown_behavior| task source
   // is about to be posted. Returns true if this operation is allowed (|task|
   // should be posted if-and-only-if it is). This method may also modify
   // metadata on |task| if desired.
@@ -99,12 +99,14 @@
   // Returns true if a task with |priority| can run under to the current policy.
   bool CanRunPriority(TaskPriority priority) const;
 
-  // Runs the next task in |sequence| unless the current shutdown state prevents
-  // that. Then, pops the task from |sequence| (even if it didn't run). Returns
-  // |sequence| if non-empty after popping a task from it (which indicates that
-  // it should be reenqueued). WillPostTask() must have allowed the task in
-  // front of |sequence| to be posted before this is called.
-  scoped_refptr<Sequence> RunAndPopNextTask(scoped_refptr<Sequence> sequence);
+  // Runs the next task in |task_source| unless the current shutdown state
+  // prevents that. Then, pops the task from |task_source| (even if it didn't
+  // run). Returns |task_source| if non-empty after popping a task from it
+  // (which indicates that it should be reenqueued). WillPostTask() must have
+  // allowed the task in front of |task_source| to be posted before this is
+  // called.
+  scoped_refptr<TaskSource> RunAndPopNextTask(
+      scoped_refptr<TaskSource> task_source);
 
   // Returns true once shutdown has started (StartShutdown() was called).
   // Note: sequential consistency with the thread calling StartShutdown() isn't
@@ -148,12 +150,12 @@
  protected:
   // Runs and deletes |task| if |can_run_task| is true. Otherwise, just deletes
   // |task|. |task| is always deleted in the environment where it runs or would
-  // have run. |sequence| is the sequence from which |task| was extracted.
-  // |traits| are the traits of |sequence|. An override is expected to call its
-  // parent's implementation but is free to perform extra work before and after
-  // doing so.
+  // have run. |task_source| is the task source from which |task| was extracted.
+  // |traits| are the traits of |task_source|. An override is expected to call
+  // its parent's implementation but is free to perform extra work before and
+  // after doing so.
   virtual void RunOrSkipTask(Task task,
-                             Sequence* sequence,
+                             TaskSource* task_source,
                              const TaskTraits& traits,
                              bool can_run_task);
 
diff --git a/base/task/thread_pool/task_tracker_posix.cc b/base/task/thread_pool/task_tracker_posix.cc
index 210ab34..ded8ce1c 100644
--- a/base/task/thread_pool/task_tracker_posix.cc
+++ b/base/task/thread_pool/task_tracker_posix.cc
@@ -16,12 +16,13 @@
 TaskTrackerPosix::~TaskTrackerPosix() = default;
 
 void TaskTrackerPosix::RunOrSkipTask(Task task,
-                                     Sequence* sequence,
+                                     TaskSource* task_source,
                                      const TaskTraits& traits,
                                      bool can_run_task) {
   DCHECK(io_thread_task_runner_);
   FileDescriptorWatcher file_descriptor_watcher(io_thread_task_runner_);
-  TaskTracker::RunOrSkipTask(std::move(task), sequence, traits, can_run_task);
+  TaskTracker::RunOrSkipTask(std::move(task), task_source, traits,
+                             can_run_task);
 }
 
 }  // namespace internal
diff --git a/base/task/thread_pool/task_tracker_posix.h b/base/task/thread_pool/task_tracker_posix.h
index 14ed817..0d9c227 100644
--- a/base/task/thread_pool/task_tracker_posix.h
+++ b/base/task/thread_pool/task_tracker_posix.h
@@ -41,7 +41,7 @@
  protected:
   // TaskTracker:
   void RunOrSkipTask(Task task,
-                     Sequence* sequence,
+                     TaskSource* task_source,
                      const TaskTraits& traits,
                      bool can_run_task) override;
 
diff --git a/base/task/thread_pool/test_utils.cc b/base/task/thread_pool/test_utils.cc
index f3f5ccd..649ee80 100644
--- a/base/task/thread_pool/test_utils.cc
+++ b/base/task/thread_pool/test_utils.cc
@@ -149,12 +149,12 @@
 }
 
 void MockSchedulerTaskRunnerDelegate::UpdatePriority(
-    scoped_refptr<Sequence> sequence,
+    scoped_refptr<TaskSource> task_source,
     TaskPriority priority) {
-  auto sequence_and_transaction =
-      SequenceAndTransaction::FromSequence(std::move(sequence));
-  sequence_and_transaction.transaction.UpdatePriority(priority);
-  worker_pool_->UpdateSortKey(std::move(sequence_and_transaction));
+  auto task_source_and_transaction =
+      TaskSourceAndTransaction::FromTaskSource(std::move(task_source));
+  task_source_and_transaction.transaction.UpdatePriority(priority);
+  worker_pool_->UpdateSortKey(std::move(task_source_and_transaction));
 }
 
 void MockSchedulerTaskRunnerDelegate::SetWorkerPool(
diff --git a/base/task/thread_pool/test_utils.h b/base/task/thread_pool/test_utils.h
index 484a48d2..eb48c3eb 100644
--- a/base/task/thread_pool/test_utils.h
+++ b/base/task/thread_pool/test_utils.h
@@ -57,7 +57,7 @@
   bool PostTaskWithSequence(Task task,
                             scoped_refptr<Sequence> sequence) override;
   bool IsRunningPoolWithTraits(const TaskTraits& traits) const override;
-  void UpdatePriority(scoped_refptr<Sequence> sequence,
+  void UpdatePriority(scoped_refptr<TaskSource> task_source,
                       TaskPriority priority) override;
 
   void SetWorkerPool(SchedulerWorkerPool* worker_pool);
diff --git a/base/task/thread_pool/thread_pool_impl.cc b/base/task/thread_pool/thread_pool_impl.cc
index d7b9106..ec5fe520 100644
--- a/base/task/thread_pool/thread_pool_impl.cc
+++ b/base/task/thread_pool/thread_pool_impl.cc
@@ -21,14 +21,23 @@
 #include "base/task/task_features.h"
 #include "base/task/thread_pool/scheduler_parallel_task_runner.h"
 #include "base/task/thread_pool/scheduler_sequenced_task_runner.h"
+#include "base/task/thread_pool/scheduler_worker_pool_impl.h"
 #include "base/task/thread_pool/scheduler_worker_pool_params.h"
-#include "base/task/thread_pool/sequence.h"
 #include "base/task/thread_pool/sequence_sort_key.h"
 #include "base/task/thread_pool/service_thread.h"
 #include "base/task/thread_pool/task.h"
+#include "base/task/thread_pool/task_source.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 
+#if defined(OS_WIN)
+#include "base/task/thread_pool/platform_native_worker_pool_win.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "base/task/thread_pool/platform_native_worker_pool_mac.h"
+#endif
+
 namespace base {
 namespace internal {
 
@@ -68,7 +77,7 @@
       tracked_ref_factory_(this) {
   DCHECK(!histogram_label.empty());
 
-  foreground_pool_.emplace(
+  foreground_pool_ = std::make_unique<SchedulerWorkerPoolImpl>(
       JoinString(
           {histogram_label, kForegroundPoolEnvironmentParams.name_suffix}, "."),
       kForegroundPoolEnvironmentParams.name_suffix,
@@ -76,7 +85,7 @@
       task_tracker_->GetTrackedRef(), tracked_ref_factory_.GetTrackedRef());
 
   if (CanUseBackgroundPriorityForSchedulerWorker()) {
-    background_pool_.emplace(
+    background_pool_ = std::make_unique<SchedulerWorkerPoolImpl>(
         JoinString(
             {histogram_label, kBackgroundPoolEnvironmentParams.name_suffix},
             "."),
@@ -94,9 +103,6 @@
   // Reset worker pools to release held TrackedRefs, which block teardown.
   foreground_pool_.reset();
   background_pool_.reset();
-#if defined(OS_WIN) || defined(OS_MACOSX)
-  native_foreground_pool_.reset();
-#endif
 }
 
 void ThreadPoolImpl::Start(const ThreadPool::InitParams& init_params,
@@ -113,11 +119,11 @@
 
 #if defined(OS_WIN) || defined(OS_MACOSX)
   if (FeatureList::IsEnabled(kUseNativeThreadPool)) {
-    native_foreground_pool_.emplace(task_tracker_->GetTrackedRef(),
-                                    tracked_ref_factory_.GetTrackedRef(),
-                                    &foreground_pool_.value());
-    foreground_pool_->InvalidateAndHandoffAllSequencesToOtherPool(
-        &native_foreground_pool_.value());
+    std::unique_ptr<SchedulerWorkerPool> pool = std::move(foreground_pool_);
+    foreground_pool_ = std::make_unique<PlatformNativeWorkerPoolImpl>(
+        task_tracker_->GetTrackedRef(), tracked_ref_factory_.GetTrackedRef(),
+        pool.get());
+    pool->InvalidateAndHandoffAllTaskSourcesToOtherPool(foreground_pool_.get());
   }
 #endif
 
@@ -158,8 +164,9 @@
 #endif
 
 #if defined(OS_WIN) || defined(OS_MACOSX)
-  if (native_foreground_pool_) {
-    native_foreground_pool_->Start(worker_environment);
+  if (FeatureList::IsEnabled(kUseNativeThreadPool)) {
+    static_cast<PlatformNativeWorkerPool*>(foreground_pool_.get())
+        ->Start(worker_environment);
   } else
 #endif
   {
@@ -172,13 +179,14 @@
     const int max_best_effort_tasks_in_foreground_pool = std::max(
         1, std::min(init_params.background_worker_pool_params.max_tasks(),
                     init_params.foreground_worker_pool_params.max_tasks() / 2));
-    foreground_pool_->Start(init_params.foreground_worker_pool_params,
-                            max_best_effort_tasks_in_foreground_pool,
-                            service_thread_task_runner,
-                            scheduler_worker_observer, worker_environment);
+    static_cast<SchedulerWorkerPoolImpl*>(foreground_pool_.get())
+        ->Start(init_params.foreground_worker_pool_params,
+                max_best_effort_tasks_in_foreground_pool,
+                service_thread_task_runner, scheduler_worker_observer,
+                worker_environment);
   }
 
-  if (background_pool_.has_value()) {
+  if (background_pool_) {
     background_pool_->Start(
         init_params.background_worker_pool_params,
         init_params.background_worker_pool_params.max_tasks(),
@@ -281,8 +289,8 @@
   // https://crbug.com/771701.
   service_thread_->Stop();
   single_thread_task_runner_manager_.JoinForTesting();
-  GetForegroundWorkerPool()->JoinForTesting();
-  if (background_pool_.has_value())
+  foreground_pool_->JoinForTesting();
+  if (background_pool_)
     background_pool_->JoinForTesting();
 #if DCHECK_IS_ON()
   join_for_testing_returned_.Set();
@@ -347,29 +355,29 @@
   return GetWorkerPoolForTraits(traits)->IsBoundToCurrentThread();
 }
 
-void ThreadPoolImpl::UpdatePriority(scoped_refptr<Sequence> sequence,
+void ThreadPoolImpl::UpdatePriority(scoped_refptr<TaskSource> task_source,
                                     TaskPriority priority) {
-  auto sequence_and_transaction =
-      SequenceAndTransaction::FromSequence(std::move(sequence));
+  auto task_source_and_transaction =
+      TaskSourceAndTransaction::FromTaskSource(std::move(task_source));
 
   SchedulerWorkerPool* const current_worker_pool =
-      GetWorkerPoolForTraits(sequence_and_transaction.transaction.traits());
-  sequence_and_transaction.transaction.UpdatePriority(priority);
+      GetWorkerPoolForTraits(task_source_and_transaction.transaction.traits());
+  task_source_and_transaction.transaction.UpdatePriority(priority);
   SchedulerWorkerPool* const new_worker_pool =
-      GetWorkerPoolForTraits(sequence_and_transaction.transaction.traits());
+      GetWorkerPoolForTraits(task_source_and_transaction.transaction.traits());
 
   if (new_worker_pool == current_worker_pool) {
-    // |sequence|'s position needs to be updated within its current pool.
-    current_worker_pool->UpdateSortKey(std::move(sequence_and_transaction));
+    // |task_source|'s position needs to be updated within its current pool.
+    current_worker_pool->UpdateSortKey(std::move(task_source_and_transaction));
   } else {
-    // |sequence| is changing pools; remove it from its current pool and
+    // |task_source| is changing pools; remove it from its current pool and
     // reenqueue it.
-    const bool sequence_was_found =
-        current_worker_pool->RemoveSequence(sequence_and_transaction.sequence);
-    if (sequence_was_found) {
-      DCHECK(sequence_and_transaction.sequence);
-      new_worker_pool->PushSequenceAndWakeUpWorkers(
-          std::move(sequence_and_transaction));
+    const bool task_source_was_found = current_worker_pool->RemoveTaskSource(
+        task_source_and_transaction.task_source);
+    if (task_source_was_found) {
+      DCHECK(task_source_and_transaction.task_source);
+      new_worker_pool->PushTaskSourceAndWakeUpWorkers(
+          std::move(task_source_and_transaction));
     }
   }
 }
@@ -381,25 +389,11 @@
 
 SchedulerWorkerPool* ThreadPoolImpl::GetWorkerPoolForTraits(
     const TaskTraits& traits) {
-  if (traits.priority() == TaskPriority::BEST_EFFORT &&
-      background_pool_.has_value()) {
-    return &background_pool_.value();
+  if (traits.priority() == TaskPriority::BEST_EFFORT && background_pool_) {
+    return background_pool_.get();
   }
 
-  return GetForegroundWorkerPool();
-}
-
-const SchedulerWorkerPool* ThreadPoolImpl::GetForegroundWorkerPool() const {
-  return const_cast<ThreadPoolImpl*>(this)->GetForegroundWorkerPool();
-}
-
-SchedulerWorkerPool* ThreadPoolImpl::GetForegroundWorkerPool() {
-#if defined(OS_WIN) || defined(OS_MACOSX)
-  if (native_foreground_pool_) {
-    return &native_foreground_pool_.value();
-  }
-#endif
-  return &foreground_pool_.value();
+  return foreground_pool_.get();
 }
 
 void ThreadPoolImpl::UpdateCanRunPolicy() {
@@ -410,7 +404,7 @@
                                        : CanRunPolicy::kForegroundOnly)
                : CanRunPolicy::kNone;
   task_tracker_->SetCanRunPolicy(can_run_policy);
-  GetForegroundWorkerPool()->DidUpdateCanRunPolicy();
+  foreground_pool_->DidUpdateCanRunPolicy();
   if (background_pool_)
     background_pool_->DidUpdateCanRunPolicy();
   single_thread_task_runner_manager_.DidUpdateCanRunPolicy();
@@ -424,8 +418,8 @@
 }
 
 void ThreadPoolImpl::ReportHeartbeatMetrics() const {
-  GetForegroundWorkerPool()->ReportHeartbeatMetrics();
-  if (background_pool_.has_value())
+  foreground_pool_->ReportHeartbeatMetrics();
+  if (background_pool_)
     background_pool_->ReportHeartbeatMetrics();
 }
 
diff --git a/base/task/thread_pool/thread_pool_impl.h b/base/task/thread_pool/thread_pool_impl.h
index 26effdc..a6e272c 100644
--- a/base/task/thread_pool/thread_pool_impl.h
+++ b/base/task/thread_pool/thread_pool_impl.h
@@ -23,6 +23,7 @@
 #include "base/task/thread_pool/environment_config.h"
 #include "base/task/thread_pool/scheduler_single_thread_task_runner_manager.h"
 #include "base/task/thread_pool/scheduler_task_runner_delegate.h"
+#include "base/task/thread_pool/scheduler_worker_pool.h"
 #include "base/task/thread_pool/scheduler_worker_pool_impl.h"
 #include "base/task/thread_pool/task_tracker.h"
 #include "base/task/thread_pool/thread_pool.h"
@@ -34,14 +35,9 @@
 #endif
 
 #if defined(OS_WIN)
-#include "base/task/thread_pool/platform_native_worker_pool_win.h"
 #include "base/win/com_init_check_hook.h"
 #endif
 
-#if defined(OS_MACOSX)
-#include "base/task/thread_pool/platform_native_worker_pool_mac.h"
-#endif
-
 namespace base {
 
 class Thread;
@@ -114,10 +110,6 @@
 
   void ReportHeartbeatMetrics() const;
 
-  // Returns the thread pool responsible for foreground execution.
-  const SchedulerWorkerPool* GetForegroundWorkerPool() const;
-  SchedulerWorkerPool* GetForegroundWorkerPool();
-
   const SchedulerWorkerPool* GetWorkerPoolForTraits(
       const TaskTraits& traits) const;
 
@@ -129,7 +121,7 @@
   bool PostTaskWithSequence(Task task,
                             scoped_refptr<Sequence> sequence) override;
   bool IsRunningPoolWithTraits(const TaskTraits& traits) const override;
-  void UpdatePriority(scoped_refptr<Sequence> sequence,
+  void UpdatePriority(scoped_refptr<TaskSource> task_source,
                       TaskPriority priority) override;
 
   const std::unique_ptr<TaskTrackerImpl> task_tracker_;
@@ -145,8 +137,8 @@
   // TODO(fdoray): Remove after experiment. https://crbug.com/757022
   AtomicFlag all_tasks_user_blocking_;
 
-  Optional<SchedulerWorkerPoolImpl> foreground_pool_;
-  Optional<SchedulerWorkerPoolImpl> background_pool_;
+  std::unique_ptr<SchedulerWorkerPool> foreground_pool_;
+  std::unique_ptr<SchedulerWorkerPoolImpl> background_pool_;
 
   // Whether this TaskScheduler was started. Access controlled by
   // |sequence_checker_|.
@@ -157,12 +149,6 @@
   bool can_run_ = true;
   bool can_run_best_effort_;
 
-#if defined(OS_WIN)
-  Optional<PlatformNativeWorkerPoolWin> native_foreground_pool_;
-#elif defined(OS_MACOSX)
-  Optional<PlatformNativeWorkerPoolMac> native_foreground_pool_;
-#endif
-
 #if DCHECK_IS_ON()
   // Set once JoinForTesting() has returned.
   AtomicFlag join_for_testing_returned_;
diff --git a/base/task_runner_util.h b/base/task_runner_util.h
index 7ae085b..14c536d 100644
--- a/base/task_runner_util.h
+++ b/base/task_runner_util.h
@@ -48,17 +48,17 @@
                std::move(reply), Owned(result)));
 }
 
-// Callback version of PostTaskAndReplyWithResult above.
+// RepeatingCallback version of PostTaskAndReplyWithResult above.
 // Though RepeatingCallback is convertible to OnceCallback, we need this since
 // we cannot use template deduction and object conversion at once on the
 // overload resolution.
-// TODO(crbug.com/714018): Update all callers of the Callback version to use
-// OnceCallback.
+// TODO(crbug.com/714018): Update all callers of the RepeatingCallback version
+// to use OnceCallback.
 template <typename TaskReturnType, typename ReplyArgType>
 bool PostTaskAndReplyWithResult(TaskRunner* task_runner,
                                 const Location& from_here,
-                                Callback<TaskReturnType()> task,
-                                Callback<void(ReplyArgType)> reply) {
+                                RepeatingCallback<TaskReturnType()> task,
+                                RepeatingCallback<void(ReplyArgType)> reply) {
   return PostTaskAndReplyWithResult(
       task_runner, from_here, OnceCallback<TaskReturnType()>(std::move(task)),
       OnceCallback<void(ReplyArgType)>(std::move(reply)));
diff --git a/base/test/bind_test_util.h b/base/test/bind_test_util.h
index 10b4289..f545159 100644
--- a/base/test/bind_test_util.h
+++ b/base/test/bind_test_util.h
@@ -26,7 +26,7 @@
 
 }  // namespace internal
 
-// A variant of Bind() that can bind capturing lambdas for testing.
+// A variant of BindRepeating() that can bind capturing lambdas for testing.
 // This doesn't support extra arguments binding as the lambda itself can do.
 template <typename F>
 decltype(auto) BindLambdaForTesting(F&& f) {
diff --git a/base/test/scoped_task_environment.cc b/base/test/scoped_task_environment.cc
index 76811d1..2c8b093 100644
--- a/base/test/scoped_task_environment.cc
+++ b/base/test/scoped_task_environment.cc
@@ -4,6 +4,8 @@
 
 #include "base/test/scoped_task_environment.h"
 
+#include <memory>
+
 #include "base/bind_helpers.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
@@ -293,7 +295,7 @@
 
   // internal::ThreadPoolImpl::TaskTrackerImpl:
   void RunOrSkipTask(internal::Task task,
-                     internal::Sequence* sequence,
+                     internal::TaskSource* sequence,
                      const TaskTraits& traits,
                      bool can_run_task) override;
 
@@ -317,12 +319,13 @@
 
 ScopedTaskEnvironment::ScopedTaskEnvironment(
     MainThreadType main_thread_type,
-    ExecutionMode execution_control_mode,
+    ThreadPoolExecutionMode thread_pool_execution_mode,
     NowSource now_source,
+    ThreadingMode threading_mode,
     bool subclass_creates_default_taskrunner,
     trait_helpers::NotATraitTag)
     : main_thread_type_(main_thread_type),
-      execution_control_mode_(execution_control_mode),
+      thread_pool_execution_mode_(thread_pool_execution_mode),
       subclass_creates_default_taskrunner_(subclass_creates_default_taskrunner),
       sequence_manager_(
           CreateSequenceManagerForMainThreadType(main_thread_type)),
@@ -333,7 +336,6 @@
       mock_clock_(mock_time_domain_ ? std::make_unique<TickClockBasedClock>(
                                           mock_time_domain_.get())
                                     : nullptr),
-      task_tracker_(new TestTaskTracker()),
       scoped_lazy_task_runner_list_for_testing_(
           std::make_unique<internal::ScopedLazyTaskRunnerListForTesting>()),
       // TODO(https://crbug.com/918724): Enable Run() timeouts even for
@@ -368,6 +370,16 @@
     CompleteInitialization();
   }
 
+  if (threading_mode != ThreadingMode::MAIN_THREAD_ONLY)
+    InitializeThreadPool();
+
+  if (thread_pool_execution_mode_ == ThreadPoolExecutionMode::QUEUED &&
+      task_tracker_) {
+    CHECK(task_tracker_->DisallowRunTasks());
+  }
+}
+
+void ScopedTaskEnvironment::InitializeThreadPool() {
   // Instantiate a ThreadPool with 4 workers per pool. Having multiple
   // threads prevents deadlocks should some blocking APIs not use
   // ScopedBlockingCall. It also allows enough concurrency to allow TSAN to spot
@@ -376,8 +388,10 @@
   const TimeDelta kSuggestedReclaimTime = TimeDelta::Max();
   const SchedulerWorkerPoolParams worker_pool_params(kMaxThreads,
                                                      kSuggestedReclaimTime);
+  auto task_tracker = std::make_unique<TestTaskTracker>();
+  task_tracker_ = task_tracker.get();
   ThreadPool::SetInstance(std::make_unique<internal::ThreadPoolImpl>(
-      "ScopedTaskEnvironment", WrapUnique(task_tracker_)));
+      "ScopedTaskEnvironment", std::move(task_tracker)));
   thread_pool_ = ThreadPool::GetInstance();
   ThreadPool::GetInstance()->Start({
     worker_pool_params, worker_pool_params
@@ -397,9 +411,6 @@
         ThreadPool::InitParams::SharedWorkerPoolEnvironment::COM_MTA
 #endif
   });
-
-  if (execution_control_mode_ == ExecutionMode::QUEUED)
-    CHECK(task_tracker_->DisallowRunTasks());
 }
 
 void ScopedTaskEnvironment::CompleteInitialization() {
@@ -418,7 +429,14 @@
   // If we've been moved then bail out.
   if (!owns_instance_)
     return;
+  DestroyThreadPool();
+  task_queue_ = nullptr;
+  NotifyDestructionObserversAndReleaseSequenceManager();
+}
 
+void ScopedTaskEnvironment::DestroyThreadPool() {
+  if (!thread_pool_)
+    return;
   // Ideally this would RunLoop().RunUntilIdle() here to catch any errors or
   // infinite post loop in the remaining work but this isn't possible right now
   // because base::~MessageLoop() didn't use to do this and adding it here would
@@ -435,8 +453,6 @@
   // on their main thread.
   ScopedAllowBaseSyncPrimitivesForTesting allow_waits_to_destroy_task_tracker;
   ThreadPool::SetInstance(nullptr);
-  task_queue_ = nullptr;
-  NotifyDestructionObserversAndReleaseSequenceManager();
 }
 
 sequence_manager::TimeDomain* ScopedTaskEnvironment::GetTimeDomain() const {
@@ -568,8 +584,9 @@
   }
 
   // The above loop always ends with running tasks being disallowed. Re-enable
-  // parallel execution before returning unless in ExecutionMode::QUEUED.
-  if (execution_control_mode_ != ExecutionMode::QUEUED)
+  // parallel execution before returning unless in
+  // ThreadPoolExecutionMode::QUEUED.
+  if (thread_pool_execution_mode_ != ThreadPoolExecutionMode::QUEUED)
     task_tracker_->AllowRunTasks();
 
   if (mock_time_domain_)
@@ -658,7 +675,7 @@
 
 void ScopedTaskEnvironment::TestTaskTracker::RunOrSkipTask(
     internal::Task task,
-    internal::Sequence* sequence,
+    internal::TaskSource* sequence,
     const TaskTraits& traits,
     bool can_run_task) {
   {
diff --git a/base/test/scoped_task_environment.h b/base/test/scoped_task_environment.h
index 2e17d0ce..55e7323b 100644
--- a/base/test/scoped_task_environment.h
+++ b/base/test/scoped_task_environment.h
@@ -20,7 +20,6 @@
 
 namespace base {
 
-
 class Clock;
 class FileDescriptorWatcher;
 class ThreadPool;
@@ -40,9 +39,9 @@
 // the thread where the ScopedTaskEnvironment lives.
 //
 // Tasks posted through base/task/post_task.h run on dedicated threads. If
-// ExecutionMode is QUEUED, they run when RunUntilIdle() or
-// ~ScopedTaskEnvironment is called. If ExecutionMode is ASYNC, they run as they
-// are posted.
+// ThreadPoolExecutionMode is QUEUED, they run when RunUntilIdle() or
+// ~ScopedTaskEnvironment is called. If ThreadPoolExecutionMode is ASYNC, they
+// run as they are posted.
 //
 // All methods of ScopedTaskEnvironment must be called from the same thread.
 //
@@ -100,15 +99,23 @@
     IO_MOCK_TIME,
   };
 
-  enum class ExecutionMode {
-    // Tasks are queued and only executed when RunUntilIdle() is explicitly
+  // Note that this is irrelevant (and ignored) under
+  // ThreadingMode::MAIN_THREAD_ONLY
+  enum class ThreadPoolExecutionMode {
+    // Thread pool tasks are queued and only executed when RunUntilIdle() is
+    // explicitly
     // called.
     QUEUED,
-    // Tasks run as they are posted. RunUntilIdle() can still be used to block
+    // Thread pool tasks run as they are posted. RunUntilIdle() can still be
+    // used to block
     // until done.
     ASYNC,
+    DEFAULT = ASYNC
   };
 
+  // TODO(carlscab): Deprecated. Migrate all uses and remove.
+  using ExecutionMode = ThreadPoolExecutionMode;
+
   enum class NowSource {
     // base::Time::Now() and base::TimeTicks::Now() are real time.
     REAL_TIME,
@@ -126,12 +133,23 @@
     MAIN_THREAD_MOCK_TIME,
   };
 
+  enum class ThreadingMode {
+    // ThreadPool will be initialized, thus adding support for multi-threaded
+    // tests.
+    MULTIPLE_THREADS,
+    // No thread pool will be initialized. Useful for tests that want to run
+    // single threaded.
+    MAIN_THREAD_ONLY,
+    DEFAULT = MULTIPLE_THREADS
+  };
+
   // List of traits that are valid inputs for the constructor below.
   struct ValidTrait {
     ValidTrait(MainThreadType);
-    ValidTrait(ExecutionMode);
+    ValidTrait(ThreadPoolExecutionMode);
     ValidTrait(NowSource);
     ValidTrait(SubclassCreatesDefaultTaskRunner);
+    ValidTrait(ThreadingMode);
   };
 
   // Constructor accepts zero or more traits which customize the testing
@@ -143,9 +161,11 @@
       : ScopedTaskEnvironment(
             trait_helpers::GetEnum<MainThreadType, MainThreadType::DEFAULT>(
                 args...),
-            trait_helpers::GetEnum<ExecutionMode, ExecutionMode::ASYNC>(
-                args...),
+            trait_helpers::GetEnum<ThreadPoolExecutionMode,
+                                   ThreadPoolExecutionMode::DEFAULT>(args...),
             trait_helpers::GetEnum<NowSource, NowSource::REAL_TIME>(args...),
+            trait_helpers::GetEnum<ThreadingMode, ThreadingMode::DEFAULT>(
+                args...),
             trait_helpers::HasTrait<SubclassCreatesDefaultTaskRunner>(args...),
             trait_helpers::NotATraitTag()) {}
 
@@ -229,8 +249,8 @@
     return main_thread_type_;
   }
 
-  constexpr ExecutionMode execution_control_mode() const {
-    return execution_control_mode_;
+  constexpr ThreadPoolExecutionMode thread_pool_execution_mode() const {
+    return thread_pool_execution_mode_;
   }
 
   // Returns the TimeDomain driving this ScopedTaskEnvironment.
@@ -251,18 +271,22 @@
   class MockTimeDomain;
   class TestTaskTracker;
 
+  void InitializeThreadPool();
+  void DestroyThreadPool();
+
   void CompleteInitialization();
 
   // The template constructor has to be in the header but it delegates to this
   // constructor to initialize all other members out-of-line.
   ScopedTaskEnvironment(MainThreadType main_thread_type,
-                        ExecutionMode execution_control_mode,
+                        ThreadPoolExecutionMode thread_pool_execution_mode,
                         NowSource now_source,
+                        ThreadingMode threading_mode,
                         bool subclass_creates_default_taskrunner,
                         trait_helpers::NotATraitTag tag);
 
   const MainThreadType main_thread_type_;
-  const ExecutionMode execution_control_mode_;
+  const ThreadPoolExecutionMode thread_pool_execution_mode_;
   const bool subclass_creates_default_taskrunner_;
 
   std::unique_ptr<sequence_manager::SequenceManager> sequence_manager_;
@@ -282,7 +306,7 @@
   const ThreadPool* thread_pool_ = nullptr;
 
   // Owned by |thread_pool_|.
-  TestTaskTracker* const task_tracker_;
+  TestTaskTracker* task_tracker_ = nullptr;
 
   // Ensures destruction of lazy TaskRunners when this is destroyed.
   std::unique_ptr<internal::ScopedLazyTaskRunnerListForTesting>
diff --git a/base/test/scoped_task_environment_unittest.cc b/base/test/scoped_task_environment_unittest.cc
index 73ef2f6..96d4ff2e 100644
--- a/base/test/scoped_task_environment_unittest.cc
+++ b/base/test/scoped_task_environment_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/task/post_task.h"
 #include "base/task/sequence_manager/time_domain.h"
+#include "base/task/thread_pool/thread_pool.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/mock_callback.h"
 #include "base/test/test_timeouts.h"
@@ -33,6 +34,7 @@
 
 #if defined(OS_POSIX)
 #include <unistd.h>
+
 #include "base/files/file_descriptor_watcher_posix.h"
 #endif  // defined(OS_POSIX)
 
@@ -41,6 +43,8 @@
 
 namespace {
 
+using ::testing::IsNull;
+
 class ScopedTaskEnvironmentForTest : public ScopedTaskEnvironment {
  public:
   template <
@@ -67,10 +71,10 @@
 
 void RunUntilIdleTest(
     ScopedTaskEnvironment::MainThreadType main_thread_type,
-    ScopedTaskEnvironment::ExecutionMode execution_control_mode) {
+    ScopedTaskEnvironment::ThreadPoolExecutionMode thread_pool_execution_mode) {
   AtomicFlag run_until_idle_returned;
   ScopedTaskEnvironment scoped_task_environment(main_thread_type,
-                                                execution_control_mode);
+                                                thread_pool_execution_mode);
 
   AtomicFlag first_main_thread_task_ran;
   ThreadTaskRunnerHandle::Get()->PostTask(
@@ -105,18 +109,20 @@
 }  // namespace
 
 TEST_P(ScopedTaskEnvironmentTest, QueuedRunUntilIdle) {
-  RunUntilIdleTest(GetParam(), ScopedTaskEnvironment::ExecutionMode::QUEUED);
+  RunUntilIdleTest(GetParam(),
+                   ScopedTaskEnvironment::ThreadPoolExecutionMode::QUEUED);
 }
 
 TEST_P(ScopedTaskEnvironmentTest, AsyncRunUntilIdle) {
-  RunUntilIdleTest(GetParam(), ScopedTaskEnvironment::ExecutionMode::ASYNC);
+  RunUntilIdleTest(GetParam(),
+                   ScopedTaskEnvironment::ThreadPoolExecutionMode::ASYNC);
 }
 
-// Verify that tasks posted to an ExecutionMode::QUEUED ScopedTaskEnvironment do
-// not run outside of RunUntilIdle().
+// Verify that tasks posted to an ThreadPoolExecutionMode::QUEUED
+// ScopedTaskEnvironment do not run outside of RunUntilIdle().
 TEST_P(ScopedTaskEnvironmentTest, QueuedTasksDoNotRunOutsideOfRunUntilIdle) {
   ScopedTaskEnvironment scoped_task_environment(
-      GetParam(), ScopedTaskEnvironment::ExecutionMode::QUEUED);
+      GetParam(), ScopedTaskEnvironment::ThreadPoolExecutionMode::QUEUED);
 
   AtomicFlag run_until_idle_called;
   PostTask(FROM_HERE, BindOnce(
@@ -139,11 +145,11 @@
   scoped_task_environment.RunUntilIdle();
 }
 
-// Verify that a task posted to an ExecutionMode::ASYNC ScopedTaskEnvironment
-// can run without a call to RunUntilIdle().
+// Verify that a task posted to an ThreadPoolExecutionMode::ASYNC
+// ScopedTaskEnvironment can run without a call to RunUntilIdle().
 TEST_P(ScopedTaskEnvironmentTest, AsyncTasksRunAsTheyArePosted) {
   ScopedTaskEnvironment scoped_task_environment(
-      GetParam(), ScopedTaskEnvironment::ExecutionMode::ASYNC);
+      GetParam(), ScopedTaskEnvironment::ThreadPoolExecutionMode::ASYNC);
 
   WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL,
                          WaitableEvent::InitialState::NOT_SIGNALED);
@@ -153,13 +159,13 @@
   task_ran.Wait();
 }
 
-// Verify that a task posted to an ExecutionMode::ASYNC ScopedTaskEnvironment
-// after a call to RunUntilIdle() can run without another call to
-// RunUntilIdle().
+// Verify that a task posted to an ThreadPoolExecutionMode::ASYNC
+// ScopedTaskEnvironment after a call to RunUntilIdle() can run without another
+// call to RunUntilIdle().
 TEST_P(ScopedTaskEnvironmentTest,
        AsyncTasksRunAsTheyArePostedAfterRunUntilIdle) {
   ScopedTaskEnvironment scoped_task_environment(
-      GetParam(), ScopedTaskEnvironment::ExecutionMode::ASYNC);
+      GetParam(), ScopedTaskEnvironment::ThreadPoolExecutionMode::ASYNC);
 
   scoped_task_environment.RunUntilIdle();
 
@@ -175,7 +181,7 @@
   // Use a QUEUED execution-mode environment, so that no tasks are actually
   // executed until RunUntilIdle()/FastForwardBy() are invoked.
   ScopedTaskEnvironment scoped_task_environment(
-      GetParam(), ScopedTaskEnvironment::ExecutionMode::QUEUED);
+      GetParam(), ScopedTaskEnvironment::ThreadPoolExecutionMode::QUEUED);
 
   subtle::Atomic32 counter = 0;
 
@@ -265,18 +271,24 @@
 // Regression test for https://crbug.com/824770.
 TEST_P(ScopedTaskEnvironmentTest, SupportsSequenceLocalStorageOnMainThread) {
   ScopedTaskEnvironment scoped_task_environment(
-      GetParam(), ScopedTaskEnvironment::ExecutionMode::ASYNC);
+      GetParam(), ScopedTaskEnvironment::ThreadPoolExecutionMode::ASYNC);
 
   SequenceLocalStorageSlot<int> sls_slot;
   sls_slot.Set(5);
   EXPECT_EQ(5, sls_slot.Get());
 }
 
+TEST_P(ScopedTaskEnvironmentTest, SingleThreadShouldNotInitializeThreadPool) {
+  ScopedTaskEnvironmentForTest scoped_task_environment(
+      ScopedTaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY);
+  EXPECT_THAT(ThreadPool::GetInstance(), IsNull());
+}
+
 #if defined(OS_POSIX)
 TEST_F(ScopedTaskEnvironmentTest, SupportsFileDescriptorWatcherOnIOMainThread) {
   ScopedTaskEnvironment scoped_task_environment(
       ScopedTaskEnvironment::MainThreadType::IO,
-      ScopedTaskEnvironment::ExecutionMode::ASYNC);
+      ScopedTaskEnvironment::ThreadPoolExecutionMode::ASYNC);
 
   int pipe_fds_[2];
   ASSERT_EQ(0, pipe(pipe_fds_));
@@ -300,7 +312,7 @@
   // executed until RunUntilIdle()/FastForwardBy() are invoked.
   ScopedTaskEnvironment scoped_task_environment(
       ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
-      ScopedTaskEnvironment::ExecutionMode::QUEUED);
+      ScopedTaskEnvironment::ThreadPoolExecutionMode::QUEUED);
 
   constexpr base::TimeDelta kShortTaskDelay = TimeDelta::FromDays(1);
   ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, base::DoNothing(),
@@ -565,7 +577,7 @@
 
 TEST_P(ScopedTaskEnvironmentMockedTime, Basic) {
   ScopedTaskEnvironment scoped_task_environment(
-      GetParam(), ScopedTaskEnvironment::ExecutionMode::QUEUED);
+      GetParam(), ScopedTaskEnvironment::ThreadPoolExecutionMode::QUEUED);
 
   int counter = 0;
 
@@ -618,7 +630,7 @@
 
 TEST_P(ScopedTaskEnvironmentMockedTime, RunLoopDriveable) {
   ScopedTaskEnvironment scoped_task_environment(
-      GetParam(), ScopedTaskEnvironment::ExecutionMode::QUEUED);
+      GetParam(), ScopedTaskEnvironment::ThreadPoolExecutionMode::QUEUED);
 
   int counter = 0;
   ThreadTaskRunnerHandle::Get()->PostTask(
@@ -720,7 +732,7 @@
 
 TEST_P(ScopedTaskEnvironmentMockedTime, CancelPendingTask) {
   ScopedTaskEnvironment scoped_task_environment(
-      GetParam(), ScopedTaskEnvironment::ExecutionMode::QUEUED);
+      GetParam(), ScopedTaskEnvironment::ThreadPoolExecutionMode::QUEUED);
 
   CancelableOnceClosure task1(BindOnce([]() {}));
   ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, task1.callback(),
@@ -769,7 +781,7 @@
 
 TEST_P(ScopedTaskEnvironmentMockedTime, NoFastForwardToCancelledTask) {
   ScopedTaskEnvironment scoped_task_environment(
-      GetParam(), ScopedTaskEnvironment::ExecutionMode::QUEUED);
+      GetParam(), ScopedTaskEnvironment::ThreadPoolExecutionMode::QUEUED);
 
   TimeTicks start_time = scoped_task_environment.NowTicks();
   CancelableClosure task(BindRepeating([]() {}));
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index abe4e54..6ccd773 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -486,7 +486,7 @@
     SuppressErrorDialogs();
     debug::SetSuppressDebugUI(true);
     assert_handler_ = std::make_unique<logging::ScopedLogAssertHandler>(
-        Bind(&TestSuite::UnitTestAssertHandler, Unretained(this)));
+        BindRepeating(&TestSuite::UnitTestAssertHandler, Unretained(this)));
   }
 
   test::InitializeICUForTesting();
diff --git a/base/threading/thread.h b/base/threading/thread.h
index 94e260cc..b019154 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -72,7 +72,8 @@
   };
 
   struct BASE_EXPORT Options {
-    typedef Callback<std::unique_ptr<MessagePump>()> MessagePumpFactory;
+    using MessagePumpFactory =
+        RepeatingCallback<std::unique_ptr<MessagePump>()>;
 
     Options();
     Options(MessageLoop::Type type, size_t size);
diff --git a/base/trace_event/trace_buffer.cc b/base/trace_event/trace_buffer.cc
index 7357289..d62c8c9 100644
--- a/base/trace_event/trace_buffer.cc
+++ b/base/trace_event/trace_buffer.cc
@@ -303,7 +303,7 @@
 
 TraceResultBuffer::OutputCallback
 TraceResultBuffer::SimpleOutput::GetCallback() {
-  return Bind(&SimpleOutput::Append, Unretained(this));
+  return BindRepeating(&SimpleOutput::Append, Unretained(this));
 }
 
 void TraceResultBuffer::SimpleOutput::Append(
@@ -315,9 +315,8 @@
 
 TraceResultBuffer::~TraceResultBuffer() = default;
 
-void TraceResultBuffer::SetOutputCallback(
-    const OutputCallback& json_chunk_callback) {
-  output_callback_ = json_chunk_callback;
+void TraceResultBuffer::SetOutputCallback(OutputCallback json_chunk_callback) {
+  output_callback_ = std::move(json_chunk_callback);
 }
 
 void TraceResultBuffer::Start() {
diff --git a/base/trace_event/trace_buffer.h b/base/trace_event/trace_buffer.h
index 3d6465f..664a0cd 100644
--- a/base/trace_event/trace_buffer.h
+++ b/base/trace_event/trace_buffer.h
@@ -85,7 +85,7 @@
 // to JSON output.
 class BASE_EXPORT TraceResultBuffer {
  public:
-  typedef base::Callback<void(const std::string&)> OutputCallback;
+  using OutputCallback = base::RepeatingCallback<void(const std::string&)>;
 
   // If you don't need to stream JSON chunks out efficiently, and just want to
   // get a complete JSON string after calling Finish, use this struct to collect
@@ -106,7 +106,7 @@
   // JSON output and during AddFragment and Finish with following JSON output
   // chunks. The callback target must live past the last calls to
   // TraceResultBuffer::Start/AddFragment/Finish.
-  void SetOutputCallback(const OutputCallback& json_chunk_callback);
+  void SetOutputCallback(OutputCallback json_chunk_callback);
 
   // Start JSON output. This resets all internal state, so you can reuse
   // the TraceResultBuffer by calling Start.
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py
index 3766bbbb..3f2f5df 100755
--- a/build/android/gyp/compile_resources.py
+++ b/build/android/gyp/compile_resources.py
@@ -15,7 +15,6 @@
 import argparse
 import collections
 import contextlib
-import filecmp
 import multiprocessing.pool
 import os
 import re
@@ -65,20 +64,20 @@
 
   input_opts.add_argument(
       '--aapt2-path', required=True, help='Path to the Android aapt2 tool.')
+  input_opts.add_argument('--android-manifest', required=True,
+                          help='AndroidManifest.xml path')
   input_opts.add_argument(
-      '--android-manifest', required=True, help='AndroidManifest.xml path.')
-  group = input_opts.add_mutually_exclusive_group()
-  group.add_argument(
       '--shared-resources',
       action='store_true',
       help='Make all resources in R.java non-final and allow the resource IDs '
-      'to be reset to a different package index when the apk is loaded by '
-      'another application at runtime.')
-  group.add_argument(
+           'to be reset to a different package index when the apk is loaded by '
+           'another application at runtime.')
+
+  input_opts.add_argument(
       '--app-as-shared-lib',
       action='store_true',
       help='Same as --shared-resources, but also ensures all resource IDs are '
-      'directly usable from the APK loaded as an application.')
+           'directly usable from the APK loaded as an application.')
 
   input_opts.add_argument(
       '--package-id',
@@ -95,8 +94,7 @@
       help='Package name that will be used to determine package ID.')
 
   input_opts.add_argument(
-      '--arsc-package-name',
-      help='Package name to use for resources.arsc file.')
+      '--arsc-package-name', help='Package name to use for resources.arsc file')
 
   input_opts.add_argument(
       '--shared-resources-whitelist',
@@ -114,22 +112,27 @@
 
   input_opts.add_argument(
       '--use-resource-ids-path',
-      help='Use resource IDs generated by aapt --emit-ids.')
+      help='Use resource IDs generated by aapt --emit-ids')
 
-  input_opts.add_argument(
-      '--support-zh-hk',
-      action='store_true',
-      help='Use zh-rTW resources for zh-rHK.')
+  input_opts.add_argument('--proto-format', action='store_true',
+                          help='Compile resources to protocol buffer format.')
 
-  input_opts.add_argument(
-      '--debuggable',
-      action='store_true',
-      help='Whether to add android:debuggable="true".')
+  input_opts.add_argument('--support-zh-hk', action='store_true',
+                          help='Use zh-rTW resources for zh-rHK.')
+
+  input_opts.add_argument('--debuggable',
+                          action='store_true',
+                          help='Whether to add android:debuggable="true"')
 
   input_opts.add_argument('--version-code', help='Version code for apk.')
   input_opts.add_argument('--version-name', help='Version name for apk.')
 
   input_opts.add_argument(
+      '--no-compress',
+      help='disables compression for the given comma-separated list of '
+           'extensions')
+
+  input_opts.add_argument(
       '--locale-whitelist',
       default='[]',
       help='GN list of languages to include. All other language configs will '
@@ -151,25 +154,21 @@
   input_opts.add_argument('--webp-binary', default='',
                           help='Path to the cwebp binary.')
 
-  input_opts.add_argument(
-      '--no-xml-namespaces',
-      action='store_true',
-      help='Whether to strip xml namespaces from processed xml resources.')
-
-  output_opts.add_argument('--arsc-path', help='Apk output for arsc format.')
-  output_opts.add_argument('--proto-path', help='Apk output for proto format.')
-  group = input_opts.add_mutually_exclusive_group()
-  group.add_argument(
-      '--optimized-arsc-path',
-      help='Output for `aapt2 optimize` for arsc format (enables the step).')
-  group.add_argument(
-      '--optimized-proto-path',
-      help='Output for `aapt2 optimize` for proto format (enables the step).')
+  input_opts.add_argument('--no-xml-namespaces',
+                          action='store_true',
+                          help='Whether to strip xml namespaces from processed '
+                               'xml resources')
   input_opts.add_argument(
       '--resources-config-path', help='Path to aapt2 resources config file.')
+  input_opts.add_argument(
+      '--optimized-resources-path',
+      help='Output for `aapt2 optimize` (also enables the step).')
 
-  output_opts.add_argument(
-      '--info-path', help='Path to output info file for the partial apk.')
+  output_opts.add_argument('--apk-path', required=True,
+                           help='Path to output (partial) apk.')
+
+  output_opts.add_argument('--apk-info-path', required=True,
+                           help='Path to output info file for the partial apk.')
 
   output_opts.add_argument('--srcjar-out',
                            help='Path to srcjar to contain generated R.java.')
@@ -177,15 +176,17 @@
   output_opts.add_argument('--r-text-out',
                            help='Path to store the generated R.txt file.')
 
-  output_opts.add_argument(
-      '--proguard-file', help='Path to proguard.txt generated file.')
+  output_opts.add_argument('--proguard-file',
+                           help='Path to proguard.txt generated file')
 
   output_opts.add_argument(
       '--proguard-file-main-dex',
-      help='Path to proguard.txt generated file for main dex.')
+      help='Path to proguard.txt generated file for main dex')
 
   output_opts.add_argument(
-      '--emit-ids-out', help='Path to file produced by aapt2 --emit-ids.')
+      '--emit-ids-out',
+      help=
+      'Path to file produced by aapt2 --emit-ids (for use with --stable-ids)')
 
   options = parser.parse_args(args)
 
@@ -197,12 +198,9 @@
   options.resource_blacklist_exceptions = build_utils.ParseGnList(
       options.resource_blacklist_exceptions)
 
-  if options.optimized_proto_path and not options.proto_path:
-    # We could write to a temp file, but it's simpler to require it.
-    parser.error('--optimized-proto-path requires --proto-path')
-
-  if not options.arsc_path and not options.proto_path:
-    parser.error('One of --arsc-path or --proto-path is required.')
+  if options.shared_resources and options.app_as_shared_lib:
+    raise Exception('Only one of --app-as-shared-lib or --shared-resources '
+                    'can be used.')
 
   if options.package_name_to_id_mapping:
     package_names_list = build_utils.ParseGnList(
@@ -374,6 +372,54 @@
   return package_id
 
 
+def _CreateLinkApkArgs(options):
+  """Create command-line arguments list to invoke 'aapt2 link'.
+
+  Args:
+    options: The command-line options tuple.
+  Returns:
+    A list of strings corresponding to the command-line invokation for
+    the command, matching the arguments from |options|.
+  """
+  link_command = [
+    options.aapt2_path,
+    'link',
+    '--version-code', options.version_code,
+    '--version-name', options.version_name,
+    '--auto-add-overlay',
+    '--no-version-vectors',
+  ]
+
+  for j in options.include_resources:
+    link_command += ['-I', j]
+  if options.proguard_file:
+    link_command += ['--proguard', options.proguard_file]
+  if options.proguard_file_main_dex:
+    link_command += ['--proguard-main-dex', options.proguard_file_main_dex]
+  if options.emit_ids_out:
+    link_command += ['--emit-ids', options.emit_ids_out]
+
+  if options.no_compress:
+    for ext in options.no_compress.split(','):
+      link_command += ['-0', ext]
+
+  # Note: only one of --proto-format, --shared-lib or --app-as-shared-lib
+  #       can be used with recent versions of aapt2.
+  if options.proto_format:
+    link_command.append('--proto-format')
+  elif options.shared_resources:
+    link_command.append('--shared-lib')
+
+  if options.no_xml_namespaces:
+    link_command.append('--no-xml-namespaces')
+
+  package_id = _PackageIdFromOptions(options)
+  if package_id is not None:
+    link_command += ['--package-id', package_id, '--allow-reserved-package-id']
+
+  return link_command
+
+
 def _FixManifest(options, temp_dir):
   """Fix the APK's AndroidManifest.xml.
 
@@ -387,7 +433,7 @@
   Returns:
     Tuple of:
      * Manifest path within |temp_dir|.
-     * Original package_name.
+     * Original package_name (if different from arsc_package_name).
   """
   def maybe_extract_version(j):
     try:
@@ -536,7 +582,8 @@
   return partials
 
 
-def _CreateResourceInfoFile(renamed_paths, info_path, dependencies_res_zips):
+def _CreateResourceInfoFile(
+    renamed_paths, apk_info_path, dependencies_res_zips):
   lines = set()
   for zip_file in dependencies_res_zips:
     zip_info_file_path = zip_file + '.info'
@@ -545,7 +592,7 @@
         lines.update(zip_info_file.readlines())
   for dest, source in renamed_paths.iteritems():
     lines.add('Rename:{},{}\n'.format(dest, source))
-  with open(info_path, 'w') as info_file:
+  with build_utils.AtomicOutput(apk_info_path) as info_file:
     info_file.writelines(sorted(lines))
 
 
@@ -614,15 +661,19 @@
           path, lambda x: x not in shared_names_whitelist)
 
 
-def _PackageApk(options, build):
-  """Compile and link resources with aapt2.
+def _PackageApk(options, dep_subdirs, temp_dir, gen_dir, r_txt_path):
+  """Compile resources with aapt2 and generate intermediate .ap_ file.
 
   Args:
-    options: The command-line options.
-    build: BuildContext object.
+    options: The command-line options tuple. E.g. the generated apk
+      will be written to |options.apk_path|.
+    dep_subdirs: The list of directories where dependency resource zips
+      were extracted (its content will be altered by this function).
+    temp_dir: A temporary directory.
+    gen_dir: Another temp directory where some intermediate files are
+      generated.
+    r_txt_path: The path where the R.txt file will written to.
   """
-  dep_subdirs = resource_utils.ExtractDeps(options.dependencies_res_zips,
-                                           build.deps_dir)
   renamed_paths = dict()
   renamed_paths.update(_DuplicateZhResources(dep_subdirs))
   renamed_paths.update(_RenameLocaleResourceDirs(dep_subdirs))
@@ -647,89 +698,47 @@
   for directory in dep_subdirs:
     renamed_paths.update(_MoveImagesToNonMdpiFolders(directory))
 
-  _CreateResourceInfoFile(renamed_paths, build.info_path,
-                          options.dependencies_res_zips)
+  link_command = _CreateLinkApkArgs(options)
+  # TODO(digit): Is this below actually required for R.txt generation?
+  link_command += ['--java', gen_dir]
 
-  link_command = [
-      options.aapt2_path,
-      'link',
-      '--version-code',
-      options.version_code,
-      '--version-name',
-      options.version_name,
-      '--auto-add-overlay',
-      '--no-version-vectors',
-  ]
-
-  for j in options.include_resources:
-    link_command += ['-I', j]
-  if options.proguard_file:
-    link_command += ['--proguard', build.proguard_path]
-  if options.proguard_file_main_dex:
-    link_command += ['--proguard-main-dex', build.proguard_main_dex_path]
-  if options.emit_ids_out:
-    link_command += ['--emit-ids', build.emit_ids_path]
-  if options.r_text_in:
-    shutil.copyfile(options.r_text_in, build.r_txt_path)
-  else:
-    link_command += ['--output-text-symbols', build.r_txt_path]
-
-  # Note: only one of --proto-format, --shared-lib or --app-as-shared-lib
-  #       can be used with recent versions of aapt2.
-  if options.shared_resources and not options.proto_path:
-    link_command.append('--shared-lib')
-
-  if options.no_xml_namespaces:
-    link_command.append('--no-xml-namespaces')
-
-  package_id = _PackageIdFromOptions(options)
-  if package_id is not None:
-    link_command += ['--package-id', package_id, '--allow-reserved-package-id']
-
-  fixed_manifest, orig_package = _FixManifest(options, build.temp_dir)
+  fixed_manifest, orig_package = _FixManifest(options, temp_dir)
   link_command += [
       '--manifest', fixed_manifest, '--rename-manifest-package', orig_package
   ]
 
-  # Creates a .zip with AndroidManifest.xml, resources.arsc, res/*
-  # Also creates R.txt
-  if options.use_resource_ids_path:
-    _CreateStableIdsFile(options.use_resource_ids_path, build.stable_ids_path,
-                         orig_package)
-    link_command += ['--stable-ids', build.stable_ids_path]
-
-  partials = _CompileDeps(options.aapt2_path, dep_subdirs, build.temp_dir)
+  partials = _CompileDeps(options.aapt2_path, dep_subdirs, temp_dir)
   for partial in partials:
     link_command += ['-R', partial]
 
-  if options.proto_path:
-    link_command += ['--proto-format', '-o', build.proto_path]
-  else:
-    link_command += ['-o', build.arsc_path]
+  # Creates a .zip with AndroidManifest.xml, resources.arsc, res/*
+  # Also creates R.txt
+  with build_utils.AtomicOutput(options.apk_path) as unoptimized, \
+      build_utils.AtomicOutput(r_txt_path) as r_txt, \
+      _MaybeCreateStableIdsFile(options) as stable_ids:
+    if stable_ids:
+      link_command += ['--stable-ids', stable_ids.name]
+    link_command += ['-o', unoptimized.name]
+    link_command += ['--output-text-symbols', r_txt.name]
+    build_utils.CheckOutput(
+        link_command, print_stdout=False, print_stderr=False)
 
-  build_utils.CheckOutput(link_command, print_stdout=False, print_stderr=False)
+    if options.optimized_resources_path:
+      with build_utils.AtomicOutput(options.optimized_resources_path) as opt:
+        _OptimizeApk(opt.name, options, temp_dir, unoptimized.name, r_txt.name)
 
-  if options.proto_path and options.arsc_path:
-    build_utils.CheckOutput([
-        options.aapt2_path, 'convert', '-o', build.arsc_path, build.proto_path
-    ])
-
-  if options.optimized_proto_path:
-    _OptimizeApk(build.optimized_proto_path, options, build.temp_dir,
-                 build.proto_path, build.r_txt_path)
-  elif options.optimized_arsc_path:
-    _OptimizeApk(build.optimized_arsc_path, options, build.temp_dir,
-                 build.arsc_path, build.r_txt_path)
+  _CreateResourceInfoFile(
+      renamed_paths, options.apk_info_path, options.dependencies_res_zips)
 
 
-def _OptimizeApk(output, options, temp_dir, unoptimized_path, r_txt_path):
+def _OptimizeApk(output, options, temp_dir, unoptimized_apk_path, r_txt_path):
   """Optimize intermediate .ap_ file with aapt2.
 
   Args:
     output: Path to write to.
     options: The command-line options.
     temp_dir: A temporary directory.
-    unoptimized_path: path of the apk to optimize.
+    unoptimized_apk_path: path of the apk to optimize.
     r_txt_path: path to the R.txt file of the unoptimized apk.
   """
   # Resources of type ID are references to UI elements/views. They are used by
@@ -754,7 +763,7 @@
       output,
       '--resources-config-path',
       gen_config_path,
-      unoptimized_path,
+      unoptimized_apk_path,
   ]
   build_utils.CheckOutput(
       optimize_command, print_stdout=False, print_stderr=False)
@@ -778,7 +787,7 @@
 
 
 @contextlib.contextmanager
-def _CreateStableIdsFile(in_path, out_path, package_name):
+def _MaybeCreateStableIdsFile(options):
   """Transforms a file generated by --emit-ids from another package.
 
   --stable-ids is generally meant to be used by different versions of the same
@@ -788,35 +797,55 @@
   Note: This will fail if the package ID of the resources in
   |options.use_resource_ids_path| does not match the package ID of the
   resources being linked.
+
+  Args:
+    options: The command-line options
+  Yields:
+    Path to the transformed resource IDs file (lines formatted like
+      package:type/name = 0xPPTTEEEE) or None
   """
-  with open(in_path) as stable_ids_file:
-    with open(out_path, 'w') as output_ids_file:
-      output_stable_ids = re.sub(
-          r'^.*?:',
-          package_name + ':',
-          stable_ids_file.read(),
-          flags=re.MULTILINE)
-      output_ids_file.write(output_stable_ids)
+  if options.use_resource_ids_path:
+    package_name = options.package_name
+    if not package_name:
+      package_name = resource_utils.ExtractPackageFromManifest(
+          options.android_manifest)
+    with open(options.use_resource_ids_path) as stable_ids_file:
+      with tempfile.NamedTemporaryFile() as output_ids_file:
+        output_stable_ids = re.sub(
+            r'^.*?:',
+            package_name + ':',
+            stable_ids_file.read(),
+            flags=re.MULTILINE)
+        output_ids_file.write(output_stable_ids)
+        output_ids_file.flush()
+        yield output_ids_file
+  else:
+    yield None
 
 
-def _WriteOutputs(options, build):
-  possible_outputs = [
-      (options.srcjar_out, build.srcjar_path),
-      (options.r_text_out, build.r_txt_path),
-      (options.arsc_path, build.arsc_path),
-      (options.proto_path, build.proto_path),
-      (options.optimized_arsc_path, build.optimized_arsc_path),
-      (options.optimized_proto_path, build.optimized_proto_path),
-      (options.proguard_file, build.proguard_path),
-      (options.proguard_file_main_dex, build.proguard_main_dex_path),
-      (options.emit_ids_out, build.emit_ids_path),
-      (options.info_path, build.info_path),
-  ]
+def _WriteFinalRTxtFile(options, aapt_r_txt_path):
+  """Determine final R.txt and return its location.
 
-  for final, temp in possible_outputs:
-    # Write file only if it's changed.
-    if final and not (os.path.exists(final) and filecmp.cmp(final, temp)):
-      shutil.move(temp, final)
+  This handles --r-text-in and --r-text-out options at the same time.
+
+  Args:
+    options: The command-line options tuple.
+    aapt_r_txt_path: The path to the R.txt generated by aapt.
+  Returns:
+    Path to the final R.txt file.
+  """
+  if options.r_text_in:
+    r_txt_file = options.r_text_in
+  else:
+    # When an empty res/ directory is passed, aapt does not write an R.txt.
+    r_txt_file = aapt_r_txt_path
+    if not os.path.exists(r_txt_file):
+      build_utils.Touch(r_txt_file)
+
+  if options.r_text_out:
+    shutil.copyfile(r_txt_file, options.r_text_out)
+
+  return r_txt_file
 
 
 def main(args):
@@ -826,12 +855,18 @@
   debug_temp_resources_dir = os.environ.get(_ENV_DEBUG_VARIABLE)
   if debug_temp_resources_dir:
     debug_temp_resources_dir = os.path.join(debug_temp_resources_dir,
-                                            os.path.basename(options.arsc_path))
+                                            os.path.basename(options.apk_path))
     build_utils.DeleteDirectory(debug_temp_resources_dir)
     build_utils.MakeDirectory(debug_temp_resources_dir)
 
   with resource_utils.BuildContext(debug_temp_resources_dir) as build:
-    _PackageApk(options, build)
+    dep_subdirs = resource_utils.ExtractDeps(options.dependencies_res_zips,
+                                             build.deps_dir)
+
+    _PackageApk(options, dep_subdirs, build.temp_dir, build.gen_dir,
+                build.r_txt_path)
+
+    r_txt_path = _WriteFinalRTxtFile(options, build.r_txt_path)
 
     # If --shared-resources-whitelist is used, the all resources listed in
     # the corresponding R.txt file will be non-final, and an onResourcesLoaded()
@@ -852,30 +887,27 @@
       rjava_build_options.GenerateOnResourcesLoaded()
 
     resource_utils.CreateRJavaFiles(
-        build.srcjar_dir, None, build.r_txt_path, options.extra_res_packages,
+        build.srcjar_dir, None, r_txt_path, options.extra_res_packages,
         options.extra_r_text_files, rjava_build_options)
 
     if options.srcjar_out:
-      build_utils.ZipDir(build.srcjar_path, build.srcjar_dir)
+      build_utils.ZipDir(options.srcjar_out, build.srcjar_dir)
 
     # Sanity check that the created resources have the expected package ID.
     expected_id = _PackageIdFromOptions(options)
     if expected_id is None:
       expected_id = '0x00' if options.shared_resources else '0x7f'
     expected_id = int(expected_id, 16)
-    _, package_id = resource_utils.ExtractArscPackage(
-        options.aapt2_path,
-        build.arsc_path if options.arsc_path else build.proto_path)
+    _, package_id = resource_utils.ExtractArscPackage(options.aapt2_path,
+                                                      options.apk_path)
     if package_id != expected_id:
       raise Exception(
           'Invalid package ID 0x%x (expected 0x%x)' % (package_id, expected_id))
 
-    _WriteOutputs(options, build)
-
   if options.depfile:
     build_utils.WriteDepfile(
         options.depfile,
-        options.arsc_path or options.proto_path,
+        options.apk_path,
         inputs=options.dependencies_res_zips + options.extra_r_text_files,
         add_pydeps=False)
 
diff --git a/build/android/gyp/create_size_info_files.py b/build/android/gyp/create_size_info_files.py
index 381a23b..5b248e4 100755
--- a/build/android/gyp/create_size_info_files.py
+++ b/build/android/gyp/create_size_info_files.py
@@ -127,10 +127,11 @@
       action='append',
       help='Same as --assets, except disables compression.')
   parser.add_argument(
-      '--in-res-info-path',
+      '--resource-apk',
+      dest='resource_apks',
       required=True,
       action='append',
-      help='Paths to .ap_.info files')
+      help='An .ap_ file built using aapt')
 
   options = parser.parse_args(args)
 
@@ -142,7 +143,7 @@
   jar_inputs = _FindJarInputs(set(options.jar_files))
   pak_inputs = _PakInfoPathsForAssets(options.assets +
                                       options.uncompressed_assets)
-  res_inputs = options.in_res_info_path
+  res_inputs = [p + '.info' for p in options.resource_apks]
 
   # Don't bother re-running if no .info files have changed (saves ~250ms).
   md5_check.CallAndRecordIfStale(
diff --git a/build/android/gyp/util/resource_utils.py b/build/android/gyp/util/resource_utils.py
index fc6249a..61a4f3c 100644
--- a/build/android/gyp/util/resource_utils.py
+++ b/build/android/gyp/util/resource_utils.py
@@ -599,21 +599,11 @@
     # A location to place aapt-generated files.
     self.gen_dir = os.path.join(self.temp_dir, 'gen')
     os.mkdir(self.gen_dir)
+    # Location of the generated R.txt file.
+    self.r_txt_path = os.path.join(self.gen_dir, 'R.txt')
     # A location to place generated R.java files.
     self.srcjar_dir = os.path.join(self.temp_dir, 'java')
     os.mkdir(self.srcjar_dir)
-    # Temporary file locacations.
-    self.r_txt_path = os.path.join(self.gen_dir, 'R.txt')
-    self.srcjar_path = os.path.join(self.temp_dir, 'R.srcjar')
-    self.info_path = os.path.join(self.temp_dir, 'size.info')
-    self.stable_ids_path = os.path.join(self.temp_dir, 'in_ids.txt')
-    self.emit_ids_path = os.path.join(self.temp_dir, 'out_ids.txt')
-    self.proguard_path = os.path.join(self.temp_dir, 'keeps.flags')
-    self.proguard_main_dex_path = os.path.join(self.temp_dir, 'maindex.flags')
-    self.arsc_path = os.path.join(self.temp_dir, 'out.ap_')
-    self.proto_path = os.path.join(self.temp_dir, 'out.proto.ap_')
-    self.optimized_arsc_path = os.path.join(self.temp_dir, 'out.opt.ap_')
-    self.optimized_proto_path = os.path.join(self.temp_dir, 'out.opt.proto.ap_')
 
   def Close(self):
     """Close the context and destroy all temporary files."""
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index a0cd13f..68dfac4 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -924,7 +924,6 @@
   parser.add_option('--final-dex-path',
                     help='Path to final input classes.dex (or classes.zip) to '
                     'use in final apk.')
-  parser.add_option('--res-size-info', help='Path to .ap_.info')
   parser.add_option('--apk-proto-resources',
                     help='Path to resources compiled in protocol buffer format '
                          ' for this apk.')
@@ -963,7 +962,7 @@
       'android_apk': ['build_config', 'dex_path', 'final_dex_path'] + \
           jar_path_options,
       'android_app_bundle_module': ['build_config', 'dex_path',
-          'final_dex_path', 'res_size_info'] + jar_path_options,
+          'final_dex_path'] + jar_path_options,
       'android_assets': ['build_config'],
       'android_resources': ['build_config', 'resources_zip'],
       'dist_aar': ['build_config'],
@@ -1278,8 +1277,6 @@
     if options.type == 'android_apk' and options.tested_apk_config:
       config['resources']['arsc_package_name'] = (
           tested_apk_config['package_name'])
-    if options.res_size_info:
-      config['resources']['size_info'] = options.res_size_info
 
   if is_apk_or_module_target:
     deps_dex_files = [c['dex_path'] for c in all_library_deps]
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index e77a245..264514a 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -313,21 +313,18 @@
         rebase_path(invoker.r_text, root_build_dir),
       ]
     }
-    if (defined(invoker.res_size_info_path)) {
-      args += [
-        "--res-size-info",
-        rebase_path(invoker.res_size_info_path, root_build_dir),
-      ]
-    }
+
     if (defined(invoker.resource_dirs)) {
       resource_dirs = rebase_path(invoker.resource_dirs, root_build_dir)
       args += [ "--resource-dirs=$resource_dirs" ]
     }
+
     if (defined(invoker.proto_resources_path)) {
       _rebased_proto_resources =
           rebase_path(invoker.proto_resources_path, root_build_dir)
       args += [ "--apk-proto-resources=$_rebased_proto_resources" ]
     }
+
     if (defined(invoker.module_rtxt_path)) {
       _rebased_rtxt_path = rebase_path(invoker.module_rtxt_path, root_build_dir)
       args += [ "--module-rtxt-path=$_rebased_rtxt_path" ]
@@ -2079,6 +2076,9 @@
   #
   #   post_process_script: (optional)
   #
+  #   proto_format: (optional). If true, compiles resources into protocol
+  #     buffer format.
+  #
   #   package_name: (optional)
   #     Name of the package for the purpose of assigning package ID.
   #
@@ -2097,13 +2097,7 @@
   #     used in AndroidManifest.xml.
   #
   # Output variables:
-  #   arsc_output: Path to output .ap_ file (optional).
-  #
-  #   proto_output: Path to output .proto.ap_ file (optional).
-  #
-  #   optimized_arsc_output: Path to optimized .ap_ file (optional).
-  #
-  #   optimized_proto_output: Path to optimized .proto.ap_ file (optional).
+  #   output:  Path to a zip file containing the compiled resources.
   #
   #   r_text_out_path: (optional):
   #       Path for the corresponding generated R.txt file.
@@ -2117,30 +2111,24 @@
   #
   #   proguard_file_main_dex: (optional)
   #
+  #
   template("compile_resources") {
     _compile_resources_target_name = target_name
-    if (defined(invoker.arsc_output)) {
-      _arsc_output = invoker.arsc_output
-    }
-    if (defined(invoker.optimized_arsc_output)) {
-      _optimized_arsc_output = invoker.optimized_arsc_output
-    }
+    _compiled_resources_path = invoker.output
+
     if (defined(invoker.srcjar_path)) {
       _srcjar_path = invoker.srcjar_path
     }
     if (defined(invoker.post_process_script)) {
       _compile_resources_target_name = "${target_name}__intermediate"
+      _compiled_resources_path =
+          get_path_info(_compiled_resources_path, "dir") + "/" +
+          get_path_info(_compiled_resources_path, "name") + ".intermediate.ap_"
       _srcjar_path = "${_srcjar_path}.intermediate.srcjar"
-      _intermediate_path =
-          get_path_info(_arsc_output, "dir") + "/" +
-          get_path_info(_arsc_output, "name") + ".intermediate.ap_"
-      if (defined(_optimized_arsc_output)) {
-        _optimized_arsc_output = _intermediate_path
-      } else {
-        _arsc_output = _intermediate_path
-      }
     }
 
+    _proto_format = defined(invoker.proto_format) && invoker.proto_format
+
     # NOTE: Regarding the names of the depfiles used by this template:
     #       They all have the same prefix, related to invoker.target_name,
     #       instead of $target_name, so it is important they have different
@@ -2150,6 +2138,7 @@
     #
     #       _1.d for the unprocessed compiled resources.
     #       _2.d for the optional processed compiled resources.
+    #       _3.d for the proto-compiled resources.
 
     action_with_pydeps(_compile_resources_target_name) {
       set_sources_assignment_filter([])
@@ -2164,9 +2153,16 @@
       depfile = "$target_gen_dir/${invoker.target_name}_1.d"
       outputs = []
 
+      _android_aapt_path = android_default_aapt_path
+      _android_aapt2_path = android_sdk_tools_bundle_aapt2
+      if (_proto_format) {
+        depfile = "$target_gen_dir/${invoker.target_name}_3.d"
+      }
+
       inputs = [
         invoker.build_config,
-        android_sdk_tools_bundle_aapt2,
+        _android_aapt_path,
+        _android_aapt2_path,
       ]
 
       _rebased_build_config = rebase_path(invoker.build_config, root_build_dir)
@@ -2176,7 +2172,7 @@
         rebase_path(depfile, root_build_dir),
         "--include-resources=@FileArg($_rebased_build_config:android:sdk_jars)",
         "--aapt2-path",
-        rebase_path(android_sdk_tools_bundle_aapt2, root_build_dir),
+        rebase_path(_android_aapt2_path, root_build_dir),
         "--dependencies-res-zips=@FileArg($_rebased_build_config:resources:dependency_zips)",
         "--extra-res-packages=@FileArg($_rebased_build_config:resources:extra_package_names)",
         "--extra-r-text-files=@FileArg($_rebased_build_config:resources:extra_r_text_files)",
@@ -2187,9 +2183,11 @@
         "--android-manifest",
         rebase_path(invoker.android_manifest, root_build_dir),
       ]
+
       if (defined(invoker.no_xml_namespaces) && invoker.no_xml_namespaces) {
         args += [ "--no-xml-namespaces" ]
       }
+
       if (defined(invoker.version_code)) {
         args += [
           "--version-code",
@@ -2202,47 +2200,34 @@
           invoker.version_name,
         ]
       }
-      if (defined(_arsc_output)) {
-        outputs += [ _arsc_output ]
+      if (defined(_compiled_resources_path)) {
+        _info_path = invoker.output + ".info"
+        outputs += [
+          _compiled_resources_path,
+          _info_path,
+        ]
         args += [
-          "--arsc-path",
-          rebase_path(_arsc_output, root_build_dir),
+          "--apk-path",
+          rebase_path(_compiled_resources_path, root_build_dir),
+          "--apk-info-path",
+          rebase_path(_info_path, root_build_dir),
         ]
       }
-      if (defined(invoker.proto_output)) {
-        outputs += [ invoker.proto_output ]
+
+      if (defined(invoker.optimized_resources_path)) {
         args += [
-          "--proto-path",
-          rebase_path(invoker.proto_output, root_build_dir),
+          "--optimized-resources-path",
+          rebase_path(invoker.optimized_resources_path, root_build_dir),
         ]
-      }
-      if (defined(invoker.size_info_path)) {
-        outputs += [ invoker.size_info_path ]
-        args += [
-          "--info-path",
-          rebase_path(invoker.size_info_path, root_build_dir),
-        ]
-      }
-      if (defined(_optimized_arsc_output)) {
-        outputs += [ _optimized_arsc_output ]
-        args += [
-          "--optimized-arsc-path",
-          rebase_path(_optimized_arsc_output, root_build_dir),
-        ]
-      }
-      if (defined(invoker.optimized_proto_output)) {
-        outputs += [ invoker.optimized_proto_output ]
-        args += [
-          "--optimized-proto-path",
-          rebase_path(invoker.optimized_proto_output, root_build_dir),
-        ]
-      }
-      if (defined(invoker.resources_config_path)) {
-        inputs += [ invoker.resources_config_path ]
-        args += [
-          "--resources-config-path",
-          rebase_path(invoker.resources_config_path, root_build_dir),
-        ]
+        outputs += [ invoker.optimized_resources_path ]
+
+        if (defined(invoker.resources_config_path)) {
+          inputs += [ invoker.resources_config_path ]
+          args += [
+            "--resources-config-path",
+            rebase_path(invoker.resources_config_path, root_build_dir),
+          ]
+        }
       }
 
       # Useful to have android:debuggable in the manifest even for Release
@@ -2274,6 +2259,10 @@
         ]
       }
 
+      if (_proto_format) {
+        args += [ "--proto-format" ]
+      }
+
       # Define the flags related to shared resources.
       #
       # Note the small sanity check to ensure that the package ID of the
@@ -2393,24 +2382,15 @@
         args = [
           "--depfile",
           rebase_path(depfile, root_build_dir),
+          "--apk-path",
+          rebase_path(_compiled_resources_path, root_build_dir),
+          "--output",
+          rebase_path(invoker.output, root_build_dir),
           "--srcjar-in",
           rebase_path(_srcjar_path, root_build_dir),
           "--srcjar-out",
           rebase_path(invoker.srcjar_path, root_build_dir),
         ]
-        if (defined(_optimized_arsc_output)) {
-          _input_apk = _optimized_arsc_output
-          _output_apk = invoker.optimized_arsc_output
-        } else {
-          _input_apk = _arsc_output
-          _output_apk = invoker.arsc_output
-        }
-        args += [
-          "--apk-path",
-          rebase_path(_input_apk, root_build_dir),
-          "--output",
-          rebase_path(_output_apk, root_build_dir),
-        ]
         if (defined(invoker.shared_resources_whitelist)) {
           args += [
             "--r-text-whitelist",
@@ -2420,14 +2400,14 @@
           ]
         }
         inputs = [
-          _input_apk,
           _srcjar_path,
+          _compiled_resources_path,
         ]
         if (defined(invoker.post_process_script_inputs)) {
           inputs += invoker.post_process_script_inputs
         }
         outputs = [
-          _output_apk,
+          invoker.output,
           invoker.srcjar_path,
         ]
         public_deps = [
@@ -2443,7 +2423,7 @@
   #   build_config: Path to APK's build config file. Used to extract the
   #       list of input .jar files from its dependencies.
   #   name: Name of the apk or app bundle (e.g. "Foo.apk").
-  #   res_size_info_path: Path to input .ap_.info file (for apks).
+  #   packaged_resources_path: Path to .ap_ file.
   #
   template("create_size_info_files") {
     action_with_pydeps(target_name) {
@@ -2480,7 +2460,7 @@
           args += [
             "--jar-files=@FileArg($_rebased_build_config:deps_info:unprocessed_jar_path)",
             "--jar-files=@FileArg($_rebased_build_config:deps_info:javac_full_classpath)",
-            "--in-res-info-path=@FileArg($_rebased_build_config:resources:size_info)",
+            "--resource-apk=@FileArg($_rebased_build_config:deps_info:proto_resources_path)",
             "--assets=@FileArg($_rebased_build_config:assets)",
             "--uncompressed-assets=@FileArg($_rebased_build_config:uncompressed_assets)",
           ]
@@ -2488,15 +2468,15 @@
       } else {
         inputs = [
           invoker.build_config,
-          invoker.res_size_info_path,
+          invoker.packaged_resources_path,
         ]
         _rebased_build_config =
             rebase_path(invoker.build_config, root_build_dir)
         args += [
           "--jar-files=@FileArg($_rebased_build_config:deps_info:jar_path)",
           "--jar-files=@FileArg($_rebased_build_config:deps_info:javac_full_classpath)",
-          "--in-res-info-path",
-          rebase_path(invoker.res_size_info_path, root_build_dir),
+          "--resource-apk",
+          rebase_path(invoker.packaged_resources_path, root_build_dir),
           "--assets=@FileArg($_rebased_build_config:assets)",
           "--uncompressed-assets=@FileArg($_rebased_build_config:uncompressed_assets)",
         ]
@@ -3361,7 +3341,6 @@
               "extra_shared_libraries",
               "final_dex_path",
               "native_lib_placeholders",
-              "res_size_info_path",
               "secondary_abi_shared_libraries_runtime_deps_file",
               "secondary_native_lib_placeholders",
               "shared_libraries_runtime_deps_file",
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index d309275..f0f1b5f 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2070,10 +2070,7 @@
 
     _is_bundle_module =
         defined(invoker.is_bundle_module) && invoker.is_bundle_module
-    if (_is_bundle_module) {
-      _is_base_module =
-          defined(invoker.is_base_module) && invoker.is_base_module
-    }
+    _is_base_module = defined(invoker.is_base_module) && invoker.is_base_module
 
     _enable_multidex =
         !defined(invoker.enable_multidex) || invoker.enable_multidex
@@ -2087,36 +2084,34 @@
     if (!_is_bundle_module) {
       _final_rtxt_path = "${_final_apk_path}.R.txt"
     }
-    _res_size_info_path = "$target_out_dir/$target_name.ap_.info"
     _final_apk_path_no_ext_list =
         process_file_template([ _final_apk_path ],
                               "{{source_dir}}/{{source_name_part}}")
     _final_apk_path_no_ext = _final_apk_path_no_ext_list[0]
     assert(_final_apk_path_no_ext != "")  # Mark as used.
 
-    _optimize_resources =
-        defined(invoker.optimize_resources) && invoker.optimize_resources
-
     # Non-base bundle modules create only proto resources.
     if (!_is_bundle_module || _is_base_module) {
-      _arsc_resources_path = "$target_out_dir/$target_name.ap_"
+      _packaged_resources_path = "$target_out_dir/$target_name.ap_"
     }
     if (_is_bundle_module) {
       # Path to the intermediate proto-format resources zip file.
-      _proto_resources_path = "$target_out_dir/$target_name.proto.ap_"
-      if (_optimize_resources) {
-        _optimized_proto_resources_path =
-            "$target_out_dir/$target_name.optimized.proto.ap_"
-      }
+      _proto_resources_path = "$target_gen_dir/$target_name.proto.ap_"
     } else {
       # resource_sizes.py needs to be able to find the unpacked resources.arsc
       # file based on apk name to compute normatlized size.
       _resource_sizes_arsc_path =
           "$root_out_dir/arsc/" +
           rebase_path(_final_apk_path_no_ext, root_build_dir) + ".ap_"
-      if (_optimize_resources) {
-        _optimized_arsc_resources_path =
-            "$target_out_dir/$target_name.optimized.ap_"
+    }
+    _optimize_resources =
+        defined(invoker.optimize_resources) && invoker.optimize_resources
+    if (_optimize_resources) {
+      _optimized_resources_path = "$target_out_dir/$_template_name.optimized."
+      if (_is_bundle_module) {
+        _optimized_resources_path += ".proto.ap_"
+      } else {
+        _optimized_resources_path += ".ap_"
       }
     }
 
@@ -2363,7 +2358,6 @@
       srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
       r_text_out_path = _compile_resources_rtxt_out
       emit_ids_out_path = _compile_resources_emit_ids_out
-      size_info_path = _res_size_info_path
       proguard_file = _generated_proguard_config
       if (_enable_main_dex_list) {
         proguard_file_main_dex = _generated_proguard_main_dex_config
@@ -2388,37 +2382,28 @@
         assert(!defined(resource_ids_provider_dep))
         resource_ids_provider_dep = invoker.apk_under_test
 
+        deps += [ "${invoker.apk_under_test}__compile_resources" ]
         include_resource =
             get_label_info(invoker.apk_under_test, "target_out_dir") + "/" +
             get_label_info(invoker.apk_under_test, "name") + ".ap_"
-        _link_against = invoker.apk_under_test
       }
 
       if (_is_bundle_module) {
-        proto_output = _proto_resources_path
-        if (_optimize_resources) {
-          optimized_proto_output = _optimized_proto_resources_path
-        }
+        proto_format = true
+        output = _proto_resources_path
 
         if (defined(invoker.base_module_target)) {
+          deps += [ "${invoker.base_module_target}__compile_arsc_resources" ]
           include_resource =
               get_label_info(invoker.base_module_target, "target_out_dir") +
               "/" + get_label_info(invoker.base_module_target, "name") + ".ap_"
-          _link_against = invoker.base_module_target
         }
-      } else if (_optimize_resources) {
-        optimized_arsc_output = _optimized_arsc_resources_path
+      } else {
+        output = _packaged_resources_path
       }
 
-      if (defined(_link_against)) {
-        deps += [ "${_link_against}__compile_resources" ]
-        include_resource = get_label_info(_link_against, "target_out_dir") +
-                           "/" + get_label_info(_link_against, "name") + ".ap_"
-      }
-
-      # Bundle modules have to reference resources from the base module.
-      if (!_is_bundle_module || _is_base_module) {
-        arsc_output = _arsc_resources_path
+      if (_optimize_resources) {
+        optimized_resources_path = _optimized_resources_path
       }
 
       if (defined(invoker.shared_resources_whitelist_target)) {
@@ -2437,7 +2422,7 @@
 
         # resource_sizes.py doesn't care if it gets the optimized .arsc.
         sources = [
-          _arsc_resources_path,
+          _packaged_resources_path,
         ]
         outputs = [
           _resource_sizes_arsc_path,
@@ -2468,6 +2453,38 @@
       _final_deps += [ ":$_copy_rtxt_target" ]
     }
 
+    if (_is_base_module && _is_bundle_module) {
+      # Bundle modules have to reference resources from the base module.
+      # However, to compile the bundle module's resources we have to give it an
+      # arsc resource to link against (aapt2 fails with proto resources). Thus,
+      # add an arsc resource compilation step to make the bundle module's link
+      # step work.
+      compile_resources("${_template_name}__compile_arsc_resources") {
+        forward_variables_from(invoker,
+                               [
+                                 "support_zh_hk",
+                                 "aapt_locale_whitelist",
+                                 "resource_blacklist_regex",
+                                 "resource_blacklist_exceptions",
+                                 "png_to_webp",
+                                 "no_xml_namespaces",
+                               ])
+        android_manifest = _android_manifest
+        version_code = _version_code
+        version_name = _version_name
+
+        proto_format = false
+        output = _packaged_resources_path
+
+        build_config = _build_config
+        deps = _deps + [
+                 ":$_merge_manifest_target",
+                 ":$_build_config_target",
+                 _android_sdk_dep,
+               ]
+      }
+    }
+
     _srcjar_deps += [ ":$_compile_resources_target" ]
 
     if (_native_libs_deps != [] || _secondary_abi_native_libs_deps != []) {
@@ -2625,7 +2642,6 @@
                              ])
       if (_is_bundle_module) {
         type = "android_app_bundle_module"
-        res_size_info_path = _res_size_info_path
       } else {
         type = "android_apk"
       }
@@ -2801,7 +2817,7 @@
           create_size_info_files(_size_info_target) {
             name = "${invoker.name}.apk"
             build_config = _build_config
-            res_size_info_path = _res_size_info_path
+            packaged_resources_path = _packaged_resources_path
             deps = _deps + [
                      ":$_build_config_target",
                      ":$_compile_resources_target",
@@ -2836,12 +2852,9 @@
                                  "write_asset_list",
                                  "uncompress_dex",
                                ])
-        packaged_resources_path = _arsc_resources_path
-
-        if (_optimize_resources && _is_bundle_module) {
-          optimized_resources_path = _optimized_proto_resources_path
-        } else if (_optimize_resources) {
-          optimized_resources_path = _optimized_arsc_resources_path
+        packaged_resources_path = _packaged_resources_path
+        if (_optimize_resources) {
+          optimized_resources_path = _optimized_resources_path
         }
 
         apk_path = _final_apk_path
diff --git a/build/fuchsia/fidlgen_js/runtime/zircon.cc b/build/fuchsia/fidlgen_js/runtime/zircon.cc
index 6dd1b19..4f1dc5c 100644
--- a/build/fuchsia/fidlgen_js/runtime/zircon.cc
+++ b/build/fuchsia/fidlgen_js/runtime/zircon.cc
@@ -243,7 +243,7 @@
   uint32_t data_size;
   uint32_t num_handles;
   zx_status_t status =
-      ch->rea2(0, nullptr, nullptr, 0, 0, &data_size, &num_handles);
+      ch->read(0, nullptr, nullptr, 0, 0, &data_size, &num_handles);
   DCHECK_EQ(status, ZX_ERR_BUFFER_TOO_SMALL);
 
   std::vector<zx_handle_t> handles;
@@ -252,7 +252,7 @@
   v8::Local<v8::ArrayBuffer> buf =
       v8::ArrayBuffer::New(args->isolate(), data_size);
   uint32_t actual_bytes, actual_handles;
-  status = ch->rea2(0, buf->GetContents().Data(), handles.data(), data_size,
+  status = ch->read(0, buf->GetContents().Data(), handles.data(), data_size,
                     handles.size(), &actual_bytes, &actual_handles);
   DCHECK_EQ(actual_bytes, data_size);
   DCHECK_EQ(actual_handles, num_handles);
diff --git a/build/fuchsia/fidlgen_js/test/fidlgen_js_unittest.cc b/build/fuchsia/fidlgen_js/test/fidlgen_js_unittest.cc
index ed025c8..c033f28 100644
--- a/build/fuchsia/fidlgen_js/test/fidlgen_js_unittest.cc
+++ b/build/fuchsia/fidlgen_js/test/fidlgen_js_unittest.cc
@@ -544,7 +544,7 @@
   zx_handle_t handles[1];
   uint32_t actual_bytes, actual_handles;
   ASSERT_EQ(
-      helper.server().rea2(0, data, handles, base::size(data),
+      helper.server().read(0, data, handles, base::size(data),
                            base::size(handles), &actual_bytes, &actual_handles),
       ZX_OK);
   EXPECT_EQ(actual_bytes, 16u);
@@ -577,7 +577,7 @@
   zx_handle_t handles[1];
   uint32_t actual_bytes, actual_handles;
   ASSERT_EQ(
-      helper.server().rea2(0, data, handles, base::size(data),
+      helper.server().read(0, data, handles, base::size(data),
                            base::size(handles), &actual_bytes, &actual_handles),
       ZX_OK);
   // 24 rather than 20 because everything's 8 aligned.
@@ -611,7 +611,7 @@
   zx_handle_t handles[1];
   uint32_t actual_bytes, actual_handles;
   ASSERT_EQ(
-      helper.server().rea2(0, data, handles, base::size(data),
+      helper.server().read(0, data, handles, base::size(data),
                            base::size(handles), &actual_bytes, &actual_handles),
       ZX_OK);
   EXPECT_EQ(actual_handles, 0u);
@@ -643,7 +643,7 @@
   zx_handle_t handles[1];
   uint32_t actual_bytes, actual_handles;
   ASSERT_EQ(
-      helper.server().rea2(0, data, handles, base::size(data),
+      helper.server().read(0, data, handles, base::size(data),
                            base::size(handles), &actual_bytes, &actual_handles),
       ZX_OK);
   EXPECT_EQ(actual_handles, 0u);
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 6ca5f9c8..8a8e0bfc 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8915340996931770800
\ No newline at end of file
+8915282786790925936
\ No newline at end of file
diff --git a/cc/layers/painted_scrollbar_layer_impl_unittest.cc b/cc/layers/painted_scrollbar_layer_impl_unittest.cc
index bef40d67..d2d4c6af 100644
--- a/cc/layers/painted_scrollbar_layer_impl_unittest.cc
+++ b/cc/layers/painted_scrollbar_layer_impl_unittest.cc
@@ -80,8 +80,10 @@
     const viz::DrawQuad* thumb_draw_quad = impl.quad_list().ElementAt(0);
     const viz::DrawQuad* track_draw_quad = impl.quad_list().ElementAt(1);
 
-    EXPECT_EQ(viz::DrawQuad::TEXTURE_CONTENT, thumb_draw_quad->material);
-    EXPECT_EQ(viz::DrawQuad::TEXTURE_CONTENT, track_draw_quad->material);
+    EXPECT_EQ(viz::DrawQuad::Material::kTextureContent,
+              thumb_draw_quad->material);
+    EXPECT_EQ(viz::DrawQuad::Material::kTextureContent,
+              track_draw_quad->material);
 
     const viz::TextureDrawQuad* thumb_quad =
         viz::TextureDrawQuad::MaterialCast(thumb_draw_quad);
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 1ecd3df..d98fed6 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -1508,7 +1508,7 @@
   active_layer()->DidDraw(nullptr);
 
   ASSERT_EQ(1u, render_pass->quad_list.size());
-  EXPECT_EQ(viz::DrawQuad::PICTURE_CONTENT,
+  EXPECT_EQ(viz::DrawQuad::Material::kPictureContent,
             render_pass->quad_list.front()->material);
   EXPECT_EQ(render_pass->quad_list.front()->rect, layer_rect);
   EXPECT_FALSE(render_pass->quad_list.front()->needs_blending);
@@ -1545,7 +1545,7 @@
   gfx::Rect quad_visible = gfx::IntersectRects(scaled_visible, scaled_recorded);
 
   ASSERT_EQ(1U, render_pass->quad_list.size());
-  EXPECT_EQ(viz::DrawQuad::PICTURE_CONTENT,
+  EXPECT_EQ(viz::DrawQuad::Material::kPictureContent,
             render_pass->quad_list.front()->material);
   const viz::DrawQuad* quad = render_pass->quad_list.front();
   EXPECT_EQ(quad_visible, quad->rect);
@@ -1621,7 +1621,7 @@
       last_height = draw_quad->rect.height();
     }
     EXPECT_LT(last_y, 5000);
-    EXPECT_EQ(draw_quad->material, viz::DrawQuad::TILED_CONTENT);
+    EXPECT_EQ(draw_quad->material, viz::DrawQuad::Material::kTiledContent);
 
     auto transform = [draw_quad](const gfx::Rect& rect) {
       gfx::RectF result(rect);
@@ -1699,7 +1699,7 @@
       last_height = draw_quad->rect.height();
     }
     EXPECT_LT(last_y, 5000);
-    EXPECT_EQ(draw_quad->material, viz::DrawQuad::SOLID_COLOR);
+    EXPECT_EQ(draw_quad->material, viz::DrawQuad::Material::kSolidColor);
 
     auto transform = [draw_quad](const gfx::Rect& rect) {
       gfx::RectF result(rect);
@@ -3931,9 +3931,9 @@
   // Even when OOM, quads should be produced, and should be different material
   // from quads with resource.
   EXPECT_LT(max_tiles, render_pass->quad_list.size());
-  EXPECT_EQ(viz::DrawQuad::Material::TILED_CONTENT,
+  EXPECT_EQ(viz::DrawQuad::Material::kTiledContent,
             render_pass->quad_list.front()->material);
-  EXPECT_EQ(viz::DrawQuad::Material::SOLID_COLOR,
+  EXPECT_EQ(viz::DrawQuad::Material::kSolidColor,
             render_pass->quad_list.back()->material);
 }
 
@@ -4657,8 +4657,8 @@
     EXPECT_EQ(4u, render_pass->quad_list.size());
 
   viz::DrawQuad::Material expected =
-      test_for_solid ? viz::DrawQuad::Material::SOLID_COLOR
-                     : viz::DrawQuad::Material::TILED_CONTENT;
+      test_for_solid ? viz::DrawQuad::Material::kSolidColor
+                     : viz::DrawQuad::Material::kTiledContent;
   EXPECT_EQ(expected, render_pass->quad_list.front()->material);
 }
 
@@ -5283,7 +5283,7 @@
   active_layer->DidDraw(nullptr);
 
   ASSERT_FALSE(render_pass->quad_list.empty());
-  EXPECT_EQ(viz::DrawQuad::TILED_CONTENT,
+  EXPECT_EQ(viz::DrawQuad::Material::kTiledContent,
             render_pass->quad_list.front()->material);
 
   // Tiles are ready at correct scale, so should not set had_incomplete_tile.
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc
index ea81934..546f68d 100644
--- a/cc/layers/render_surface_impl.cc
+++ b/cc/layers/render_surface_impl.cc
@@ -573,7 +573,7 @@
 
     constexpr float backdrop_filter_quality = 1.0;
     switch (temp_quad->material) {
-      case viz::DrawQuad::TILED_CONTENT: {
+      case viz::DrawQuad::Material::kTiledContent: {
         DCHECK_EQ(1U, temp_quad->resources.count);
         // When the |temp_quad| is actually a texture, we need to calculate
         // |mask_uv_rect|. The |mask_uv_rect| is the normalized sub-rect for
@@ -622,7 +622,7 @@
                      !layer_tree_impl_->settings().enable_edge_anti_aliasing,
                      backdrop_filter_quality);
       } break;
-      case viz::DrawQuad::SOLID_COLOR: {
+      case viz::DrawQuad::Material::kSolidColor: {
         SkColor temp_color =
             viz::SolidColorDrawQuad::MaterialCast(temp_quad)->color;
         // Check the alpha channel of the color. We apply the mask by
@@ -642,7 +642,7 @@
                      !layer_tree_impl_->settings().enable_edge_anti_aliasing,
                      backdrop_filter_quality);
       } break;
-      case viz::DrawQuad::DEBUG_BORDER:
+      case viz::DrawQuad::Material::kDebugBorder:
         NOTIMPLEMENTED();
         break;
       default:
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index c46e3ee..d4b4a4b 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -582,7 +582,7 @@
 
     const auto& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material);
     EXPECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect);
   }
 
@@ -597,7 +597,7 @@
 
     const auto& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material);
     EXPECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect);
   }
 
@@ -612,7 +612,7 @@
 
     const auto& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material);
     EXPECT_EQ(gfx::Rect(1, 0, 98, 3), quads.front()->rect);
   }
 }
@@ -669,7 +669,7 @@
 
     const auto& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material);
     EXPECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect);
   }
 }
diff --git a/cc/layers/video_layer_impl_unittest.cc b/cc/layers/video_layer_impl_unittest.cc
index a8ba9a7..e70372f 100644
--- a/cc/layers/video_layer_impl_unittest.cc
+++ b/cc/layers/video_layer_impl_unittest.cc
@@ -328,7 +328,7 @@
 
   EXPECT_EQ(1u, impl.quad_list().size());
   const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
-  ASSERT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material);
+  ASSERT_EQ(viz::DrawQuad::Material::kYuvVideoContent, draw_quad->material);
 
   const auto* yuv_draw_quad =
       static_cast<const viz::YUVVideoDrawQuad*>(draw_quad);
@@ -366,7 +366,7 @@
 
   EXPECT_EQ(1u, impl.quad_list().size());
   const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
-  ASSERT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material);
+  ASSERT_EQ(viz::DrawQuad::Material::kYuvVideoContent, draw_quad->material);
 
   const auto* yuv_draw_quad =
       static_cast<const viz::YUVVideoDrawQuad*>(draw_quad);
@@ -408,7 +408,7 @@
 
   EXPECT_EQ(1u, impl.quad_list().size());
   const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
-  ASSERT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material);
+  ASSERT_EQ(viz::DrawQuad::Material::kYuvVideoContent, draw_quad->material);
 
   const auto* yuv_draw_quad =
       static_cast<const viz::YUVVideoDrawQuad*>(draw_quad);
@@ -451,7 +451,7 @@
 
   EXPECT_EQ(1u, impl.quad_list().size());
   const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
-  ASSERT_EQ(viz::DrawQuad::TEXTURE_CONTENT, draw_quad->material);
+  ASSERT_EQ(viz::DrawQuad::Material::kTextureContent, draw_quad->material);
 
   const viz::TextureDrawQuad* texture_draw_quad =
       viz::TextureDrawQuad::MaterialCast(draw_quad);
diff --git a/cc/layers/viewport.cc b/cc/layers/viewport.cc
index 98bc146f..c8985f2 100644
--- a/cc/layers/viewport.cc
+++ b/cc/layers/viewport.cc
@@ -287,6 +287,9 @@
 gfx::ScrollOffset Viewport::TotalScrollOffset() const {
   gfx::ScrollOffset offset;
 
+  if (!InnerScrollNode())
+    return offset;
+
   offset += scroll_tree().current_scroll_offset(InnerScrollNode()->element_id);
 
   if (auto* outer_node = OuterScrollNode())
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index e797e6db..f5945a7 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -40,37 +40,6 @@
 // a tile is of solid color.
 const bool kUseColorEstimator = true;
 
-DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER(
-    ScopedSoftwareRasterTaskTimer,
-    "Compositing.%s.RasterTask.RasterUs.Software",
-    "Compositing.%s.RasterTask.RasterPixelsPerMs2.Software")
-
-DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER(
-    ScopedGpuRasterTaskTimer,
-    "Compositing.%s.RasterTask.RasterUs.Gpu",
-    "Compositing.%s.RasterTask.RasterPixelsPerMs2.Gpu")
-
-class ScopedRasterTaskTimer {
- public:
-  explicit ScopedRasterTaskTimer(bool use_gpu_rasterization) {
-    if (use_gpu_rasterization)
-      gpu_timer_.emplace();
-    else
-      software_timer_.emplace();
-  }
-
-  void SetArea(int area) {
-    if (software_timer_)
-      software_timer_->SetArea(area);
-    if (gpu_timer_)
-      gpu_timer_->SetArea(area);
-  }
-
- private:
-  base::Optional<ScopedSoftwareRasterTaskTimer> software_timer_;
-  base::Optional<ScopedGpuRasterTaskTimer> gpu_timer_;
-};
-
 // This class is wrapper for both ImageProvider and PaintWorkletImageProvider,
 // which is used in RasterSource::PlaybackSettings. It looks at the draw image
 // and decides which one of the two providers to dispatch the request to.
@@ -132,7 +101,6 @@
         tile_tracing_id_(static_cast<void*>(tile)),
         new_content_id_(tile->id()),
         source_frame_number_(tile->source_frame_number()),
-        is_gpu_rasterization_(is_gpu_rasterization),
         raster_buffer_(std::move(raster_buffer)),
         image_provider_(std::move(image_provider)),
         url_(std::move(url)) {
@@ -152,8 +120,6 @@
 
     frame_viewer_instrumentation::ScopedRasterTask raster_task(
         tile_tracing_id_, tile_resolution_, source_frame_number_, layer_id_);
-    ScopedRasterTaskTimer timer(is_gpu_rasterization_);
-    timer.SetArea(content_rect_.size().GetArea());
 
     DCHECK(raster_source_);
 
@@ -203,7 +169,6 @@
   void* tile_tracing_id_;
   uint64_t new_content_id_;
   int source_frame_number_;
-  bool is_gpu_rasterization_;
   std::unique_ptr<RasterBuffer> raster_buffer_;
   DispatchingImageProvider image_provider_;
   GURL url_;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index f9e0cb0c..95fb1b6 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1389,7 +1389,7 @@
 
     // Remove orphan viz::RenderPassDrawQuads.
     for (auto it = pass->quad_list.begin(); it != pass->quad_list.end();) {
-      if (it->material != viz::DrawQuad::RENDER_PASS) {
+      if (it->material != viz::DrawQuad::Material::kRenderPass) {
         ++it;
         continue;
       }
@@ -1437,7 +1437,7 @@
       continue;
 
     for (auto it = pass->quad_list.begin(); it != pass->quad_list.end(); ++it) {
-      if (it->material != viz::DrawQuad::RENDER_PASS)
+      if (it->material != viz::DrawQuad::Material::kRenderPass)
         continue;
       const viz::RenderPassDrawQuad* quad =
           viz::RenderPassDrawQuad::MaterialCast(*it);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 6aebee8..6f226bb 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -7918,6 +7918,18 @@
   }
 }
 
+// The SetSynchronousInputHandlerRootScrollOffset API can be called while there
+// is no inner viewport set. This test passes if we don't crash.
+TEST_F(LayerTreeHostImplTest, SetRootScrollOffsetNoViewportCrash) {
+  host_impl_->active_tree()->ClearViewportLayers();
+  host_impl_->active_tree()->DidBecomeActive();
+
+  auto* inner_scroll = host_impl_->active_tree()->InnerViewportScrollLayer();
+  ASSERT_FALSE(inner_scroll);
+  gfx::ScrollOffset scroll_offset(25.f, 30.f);
+  host_impl_->SetSynchronousInputHandlerRootScrollOffset(scroll_offset);
+}
+
 TEST_F(LayerTreeHostImplTest, OverscrollRoot) {
   InputHandlerScrollResult scroll_result;
   SetupScrollAndContentsLayers(gfx::Size(100, 100));
@@ -9221,7 +9233,7 @@
 class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
  protected:
   LayerTreeHostImplViewportCoveredTest()
-      : gutter_quad_material_(viz::DrawQuad::SOLID_COLOR),
+      : gutter_quad_material_(viz::DrawQuad::Material::kSolidColor),
         child_(nullptr),
         did_activate_pending_tree_(false) {}
 
@@ -9415,7 +9427,7 @@
   // Make sure that the texture coordinates match their expectations.
   void ValidateTextureDrawQuads(const viz::QuadList& quad_list) {
     for (auto* quad : quad_list) {
-      if (quad->material != viz::DrawQuad::TEXTURE_CONTENT)
+      if (quad->material != viz::DrawQuad::Material::kTextureContent)
         continue;
       const viz::TextureDrawQuad* texture_quad =
           viz::TextureDrawQuad::MaterialCast(quad);
@@ -9731,7 +9743,7 @@
   {
     const auto& root_pass = frame.render_passes.back();
     ASSERT_EQ(1u, root_pass->quad_list.size());
-    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+    EXPECT_EQ(viz::DrawQuad::Material::kSolidColor,
               root_pass->quad_list.front()->material);
   }
   host_impl_->DrawLayers(&frame);
@@ -12879,15 +12891,15 @@
 
   // Add a quad to each pass so they aren't empty.
   auto* color_quad = pass1->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
-  color_quad->material = viz::DrawQuad::SOLID_COLOR;
+  color_quad->material = viz::DrawQuad::Material::kSolidColor;
   color_quad = pass2->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
-  color_quad->material = viz::DrawQuad::SOLID_COLOR;
+  color_quad->material = viz::DrawQuad::Material::kSolidColor;
   color_quad = pass3->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
-  color_quad->material = viz::DrawQuad::SOLID_COLOR;
+  color_quad->material = viz::DrawQuad::Material::kSolidColor;
 
   // pass3 is referenced by pass2.
   auto* rpdq = pass2->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>();
-  rpdq->material = viz::DrawQuad::RENDER_PASS;
+  rpdq->material = viz::DrawQuad::Material::kRenderPass;
   rpdq->render_pass_id = pass3->id;
 
   // But pass2 is not referenced by pass1. So pass2 and pass3 should be culled.
@@ -12914,16 +12926,16 @@
 
   // pass1 is not empty, but pass2 and pass3 are.
   auto* color_quad = pass1->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
-  color_quad->material = viz::DrawQuad::SOLID_COLOR;
+  color_quad->material = viz::DrawQuad::Material::kSolidColor;
 
   // pass3 is referenced by pass2.
   auto* rpdq = pass2->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>();
-  rpdq->material = viz::DrawQuad::RENDER_PASS;
+  rpdq->material = viz::DrawQuad::Material::kRenderPass;
   rpdq->render_pass_id = pass3->id;
 
   // pass2 is referenced by pass1.
   rpdq = pass1->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>();
-  rpdq->material = viz::DrawQuad::RENDER_PASS;
+  rpdq->material = viz::DrawQuad::Material::kRenderPass;
   rpdq->render_pass_id = pass2->id;
 
   // Since pass3 is empty it should be removed. Then pass2 is empty too, and
@@ -12936,7 +12948,7 @@
   EXPECT_EQ(1u, frame.render_passes[0]->id);
   // The viz::RenderPassDrawQuad should be removed from pass1.
   EXPECT_EQ(1u, pass1->quad_list.size());
-  EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+  EXPECT_EQ(viz::DrawQuad::Material::kSolidColor,
             pass1->quad_list.ElementAt(0)->material);
 }
 
@@ -12955,12 +12967,12 @@
 
   // pass3 is referenced by pass2.
   auto* rpdq = pass2->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>();
-  rpdq->material = viz::DrawQuad::RENDER_PASS;
+  rpdq->material = viz::DrawQuad::Material::kRenderPass;
   rpdq->render_pass_id = pass3->id;
 
   // pass2 is referenced by pass1.
   rpdq = pass1->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>();
-  rpdq->material = viz::DrawQuad::RENDER_PASS;
+  rpdq->material = viz::DrawQuad::Material::kRenderPass;
   rpdq->render_pass_id = pass2->id;
 
   // Since pass3 is empty it should be removed. Then pass2 is empty too, and
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 6afc9c9..da5520b 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -7095,7 +7095,7 @@
     viz::RenderPass* root_pass = frame_data->render_passes.back().get();
     for (auto* draw_quad : root_pass->quad_list) {
       // Checkerboards mean an incomplete frame.
-      if (draw_quad->material != viz::DrawQuad::TILED_CONTENT)
+      if (draw_quad->material != viz::DrawQuad::Material::kTiledContent)
         return 0.f;
       const viz::TileDrawQuad* quad =
           viz::TileDrawQuad::MaterialCast(draw_quad);
diff --git a/cc/trees/layer_tree_host_unittest_masks.cc b/cc/trees/layer_tree_host_unittest_masks.cc
index d0dfd9b9..b0a8b0c9 100644
--- a/cc/trees/layer_tree_host_unittest_masks.cc
+++ b/cc/trees/layer_tree_host_unittest_masks.cc
@@ -77,10 +77,10 @@
     EXPECT_EQ(2u, root_pass->quad_list.size());
 
     // There's a solid color quad under everything.
-    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+    EXPECT_EQ(viz::DrawQuad::Material::kSolidColor,
               root_pass->quad_list.back()->material);
 
-    EXPECT_EQ(viz::DrawQuad::RENDER_PASS,
+    EXPECT_EQ(viz::DrawQuad::Material::kRenderPass,
               root_pass->quad_list.front()->material);
     const viz::RenderPassDrawQuad* render_pass_quad =
         viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
@@ -209,11 +209,11 @@
     EXPECT_EQ(2u, root_pass->quad_list.size());
 
     // There's a solid color quad under everything.
-    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+    EXPECT_EQ(viz::DrawQuad::Material::kSolidColor,
               root_pass->quad_list.back()->material);
 
     // The surface is clipped to 10x20.
-    EXPECT_EQ(viz::DrawQuad::RENDER_PASS,
+    EXPECT_EQ(viz::DrawQuad::Material::kRenderPass,
               root_pass->quad_list.front()->material);
     const viz::RenderPassDrawQuad* render_pass_quad =
         viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
@@ -355,12 +355,12 @@
     EXPECT_EQ(2u, root_pass->quad_list.size());
 
     // There's a solid color quad under everything.
-    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+    EXPECT_EQ(viz::DrawQuad::Material::kSolidColor,
               root_pass->quad_list.back()->material);
 
     // The surface is clipped to 10x20, and then scaled by 2, which ends up
     // being 20x40.
-    EXPECT_EQ(viz::DrawQuad::RENDER_PASS,
+    EXPECT_EQ(viz::DrawQuad::Material::kRenderPass,
               root_pass->quad_list.front()->material);
     const viz::RenderPassDrawQuad* render_pass_quad =
         viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
@@ -488,10 +488,10 @@
     EXPECT_EQ(2u, root_pass->quad_list.size());
 
     // There's a solid color quad under everything.
-    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+    EXPECT_EQ(viz::DrawQuad::Material::kSolidColor,
               root_pass->quad_list.back()->material);
 
-    EXPECT_EQ(viz::DrawQuad::RENDER_PASS,
+    EXPECT_EQ(viz::DrawQuad::Material::kRenderPass,
               root_pass->quad_list.front()->material);
     const viz::RenderPassDrawQuad* render_pass_quad =
         viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
@@ -619,11 +619,11 @@
     EXPECT_EQ(2u, root_pass->quad_list.size());
 
     // There's a solid color quad under everything.
-    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+    EXPECT_EQ(viz::DrawQuad::Material::kSolidColor,
               root_pass->quad_list.back()->material);
 
     // The surface is 100x100
-    EXPECT_EQ(viz::DrawQuad::RENDER_PASS,
+    EXPECT_EQ(viz::DrawQuad::Material::kRenderPass,
               root_pass->quad_list.front()->material);
     const viz::RenderPassDrawQuad* render_pass_quad =
         viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 338b5d8..cc61f0a 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -329,6 +329,7 @@
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoUpdateWithTest.java",
+  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPayerDetailChangeTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppCanMakePaymentQueryTest.java",
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_assistive.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_assistive.xml
new file mode 100644
index 0000000..8322402d
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_assistive.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+<org.chromium.chrome.browser.autofill_assistant.carousel.ButtonView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    style="@style/AssistiveChip"
+    app:cornerRadius="40dp"/>
+
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java
index 569c666..dcee81e 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java
@@ -28,8 +28,8 @@
         ButtonView view = null;
         switch (viewType % AssistantChip.Type.NUM_ENTRIES) {
             case AssistantChip.Type.CHIP_ASSISTIVE:
-                view = new ButtonView(
-                        parent.getContext(), org.chromium.chrome.R.style.AssistiveChip);
+                view = (ButtonView) layoutInflater.inflate(
+                        R.layout.autofill_assistant_button_assistive, /* root= */ null);
                 break;
             case AssistantChip.Type.BUTTON_FILLED_BLUE:
                 view = (ButtonView) layoutInflater.inflate(
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantSuggestionsCarouselCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantSuggestionsCarouselCoordinator.java
index 55794d0..3e34d2c9 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantSuggestionsCarouselCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantSuggestionsCarouselCoordinator.java
@@ -9,7 +9,6 @@
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.util.TypedValue;
 import android.view.View;
 
 import org.chromium.base.ThreadUtils;
@@ -95,11 +94,9 @@
         private final int mOuterSpacePx;
 
         SpaceItemDecoration(Context context) {
-            mInnerSpacePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    context.getResources().getDimensionPixelSize(
-                            R.dimen.autofill_assistant_carousel_chips_spacing)
-                            / 2,
-                    context.getResources().getDisplayMetrics());
+            mInnerSpacePx = context.getResources().getDimensionPixelSize(
+                                    R.dimen.autofill_assistant_carousel_chips_spacing)
+                    / 2;
             mOuterSpacePx = context.getResources().getDimensionPixelSize(
                     R.dimen.autofill_assistant_bottombar_horizontal_spacing);
         }
diff --git a/chrome/android/java/AndroidManifest_trichrome_library.xml b/chrome/android/java/AndroidManifest_trichrome_library.xml
index 8e06286..09c2af3 100644
--- a/chrome/android/java/AndroidManifest_trichrome_library.xml
+++ b/chrome/android/java/AndroidManifest_trichrome_library.xml
@@ -19,7 +19,7 @@
 
     <!-- TODO(torne): we should specify an icon, roundIcon, and label from resources. -->
     <application
-        android:label="Trichrome Library"
+        android:label="{{ application_label|default('Trichrome Library') }}"
         android:icon="@drawable/icon_webview"
         android:multiArch="true"
         android:extractNativeLibs="false">
diff --git a/chrome/android/java/res/layout/explore_sites_tile_view_condensed.xml b/chrome/android/java/res/layout/explore_sites_tile_view_condensed.xml
index a15b8c4..ab6748e 100644
--- a/chrome/android/java/res/layout/explore_sites_tile_view_condensed.xml
+++ b/chrome/android/java/res/layout/explore_sites_tile_view_condensed.xml
@@ -59,5 +59,6 @@
             android:gravity="center_horizontal"
             android:lines="2"
             android:lineSpacingMultiplier="1.17"
+            android:layout_marginBottom="@dimen/explore_sites_tile_view_text_margin_bottom_condensed"
             android:textAppearance="@style/TextAppearance.BlackCaptionDefault" />
 </org.chromium.chrome.browser.explore_sites.ExploreSitesTileView>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 42eedeb5..ecbe8a6 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -386,6 +386,7 @@
     <dimen name="explore_sites_tile_view_title_margin_top_condensed">51dp</dimen>
     <dimen name="explore_sites_tile_view_width_condensed">72dp</dimen>
     <dimen name="explore_sites_tile_view_icon_padding_horizontal_condensed">4dp</dimen>
+    <dimen name="explore_sites_tile_view_text_margin_bottom_condensed">4dp</dimen>
 
     <!-- Recent tabs page -->
     <dimen name="recent_tabs_visible_separator_padding">8dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClearDataDialogResultRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClearDataDialogResultRecorder.java
index 626c5a4..133eb89 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClearDataDialogResultRecorder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClearDataDialogResultRecorder.java
@@ -4,8 +4,8 @@
 
 package org.chromium.chrome.browser.browserservices;
 
-import static org.chromium.chrome.browser.preferences.ChromePreferenceManager.TWA_DIALOG_NUMBER_OF_DIMSISSALS_ON_CLEAR_DATA;
-import static org.chromium.chrome.browser.preferences.ChromePreferenceManager.TWA_DIALOG_NUMBER_OF_DIMSISSALS_ON_UNINSTALL;
+import static org.chromium.chrome.browser.preferences.ChromePreferenceManager.TWA_DIALOG_NUMBER_OF_DISMISSALS_ON_CLEAR_DATA;
+import static org.chromium.chrome.browser.preferences.ChromePreferenceManager.TWA_DIALOG_NUMBER_OF_DISMISSALS_ON_UNINSTALL;
 
 import org.chromium.base.StrictModeContext;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
@@ -47,8 +47,8 @@
         } else {
             // Avoid loading native just for the sake of recording. Save the info and record
             // on next Chrome launch.
-            String key = triggeredByUninstall ? TWA_DIALOG_NUMBER_OF_DIMSISSALS_ON_UNINSTALL
-                    : TWA_DIALOG_NUMBER_OF_DIMSISSALS_ON_CLEAR_DATA;
+            String key = triggeredByUninstall ? TWA_DIALOG_NUMBER_OF_DISMISSALS_ON_UNINSTALL
+                                              : TWA_DIALOG_NUMBER_OF_DISMISSALS_ON_CLEAR_DATA;
 
             try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
                 mPrefsManager.get().writeInt(key, mPrefsManager.get().readInt(key) + 1);
@@ -61,8 +61,8 @@
      */
     public void makeDeferredRecordings() {
         try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-            recordDismissals(TWA_DIALOG_NUMBER_OF_DIMSISSALS_ON_UNINSTALL, true);
-            recordDismissals(TWA_DIALOG_NUMBER_OF_DIMSISSALS_ON_CLEAR_DATA, false);
+            recordDismissals(TWA_DIALOG_NUMBER_OF_DISMISSALS_ON_UNINSTALL, true);
+            recordDismissals(TWA_DIALOG_NUMBER_OF_DISMISSALS_ON_CLEAR_DATA, false);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index 4e9b9aa..19ceeced 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -622,7 +622,10 @@
         if (tab.getWebContents() == null) return defaultValue;
 
         String stringValue = getStringFromNavigationEntry(tab, key);
-
+        if (stringValue == null || stringValue.isEmpty()) {
+            return RecyclerView.NO_POSITION;
+        }
+        
         try {
             return Integer.parseInt(stringValue);
         } catch (NumberFormatException e) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 57f281e..94403e5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -875,11 +875,12 @@
             return;
         }
 
-        if (!mRequestShipping) {
+        if (!mRequestShipping && !mRequestPayerName && !mRequestPayerEmail && !mRequestPayerPhone) {
             mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER);
             disconnectFromClientWithDebugMessage(
                     "PaymentRequestUpdateEvent.updateWith() called without passing a promise into "
-                    + "PaymentRequest.show() and without requestShipping:true");
+                    + "PaymentRequest.show() and without payment options "
+                    + "(e.g. requestShipping: true)");
             return;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
index 10dd1e6a..d0f8604 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -285,9 +285,9 @@
      * Keys for deferred recording of the outcomes of showing the clear data dialog after
      * Trusted Web Activity client apps are uninstalled or have their data cleared.
      */
-    public static final String TWA_DIALOG_NUMBER_OF_DIMSISSALS_ON_UNINSTALL =
+    public static final String TWA_DIALOG_NUMBER_OF_DISMISSALS_ON_UNINSTALL =
             "twa_dialog_number_of_dismissals_on_uninstall";
-    public static final String TWA_DIALOG_NUMBER_OF_DIMSISSALS_ON_CLEAR_DATA =
+    public static final String TWA_DIALOG_NUMBER_OF_DISMISSALS_ON_CLEAR_DATA =
             "twa_dialog_number_of_dismissals_on_clear_data";
 
     /** Key for deferred recording of WebAPK uninstalls. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPayerDetailChangeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPayerDetailChangeTest.java
new file mode 100644
index 0000000..e5cb4ba
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPayerDetailChangeTest.java
@@ -0,0 +1,103 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.payments;
+
+import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.HAVE_INSTRUMENTS;
+import static org.chromium.chrome.browser.payments.PaymentRequestTestRule.IMMEDIATE_RESPONSE;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
+import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
+import org.chromium.ui.modaldialog.ModalDialogProperties;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A payment integration test for a merchant that retries payment request with payment validation.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+        PaymentRequestTestRule.ENABLE_EXPERIMENTAL_WEB_PLATFORM_FEATURES})
+public class PaymentRequestPayerDetailChangeTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
+    @Rule
+    public PaymentRequestTestRule mPaymentRequestTestRule =
+            new PaymentRequestTestRule("payment_request_onpayerdetailchange.html", this);
+
+    @Override
+    public void onMainActivityStarted()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        AutofillTestHelper helper = new AutofillTestHelper();
+
+        String billing_address_id = helper.setProfile(new AutofillProfile("", "https://example.com",
+                true, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "",
+                "US", "333-333-3333", "jon.doe@gmail.com", "en-US"));
+        helper.setCreditCard(new CreditCard("", "https://example.com", true /* isLocal */,
+                true /* isCached */, "Jon Doe", "5555555555554444", "" /* obfuscatedNumber */, "12",
+                "2050", "mastercard", R.drawable.mc_card, CardType.UNKNOWN, billing_address_id,
+                "" /* serverId */));
+
+        mPaymentRequestTestRule.installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
+    }
+
+    /**
+     * Test for onpayerdetailchange event.
+     */
+    @Test
+    @MediumTest
+    @Feature({"Payments"})
+    public void testPayerDetailChangeEvent()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput());
+        mPaymentRequestTestRule.clickAndWait(
+                R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput());
+        mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait(
+                R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask());
+        mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
+                ModalDialogProperties.ButtonType.POSITIVE,
+                mPaymentRequestTestRule.getPaymentResponseReady());
+
+        mPaymentRequestTestRule.retryPaymentRequest("{}", mPaymentRequestTestRule.getReadyToPay());
+
+        mPaymentRequestTestRule.clickInContactInfoAndWait(
+                R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
+        mPaymentRequestTestRule.clickInContactInfoAndWait(
+                R.id.payments_open_editor_pencil_button, mPaymentRequestTestRule.getReadyToEdit());
+        mPaymentRequestTestRule.setTextInEditorAndWait(
+                new String[] {"Jane Doe", "650-253-0000", "jane.doe@gmail.com"},
+                mPaymentRequestTestRule.getEditorTextUpdate());
+        mPaymentRequestTestRule.clickInEditorAndWait(
+                R.id.editor_dialog_done_button, mPaymentRequestTestRule.getReadyToPay());
+
+        mPaymentRequestTestRule.clickAndWait(
+                R.id.button_primary, mPaymentRequestTestRule.getReadyForUnmaskInput());
+        mPaymentRequestTestRule.setTextInCardUnmaskDialogAndWait(
+                R.id.card_unmask_input, "123", mPaymentRequestTestRule.getReadyToUnmask());
+        mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
+                ModalDialogProperties.ButtonType.POSITIVE, mPaymentRequestTestRule.getDismissed());
+
+        mPaymentRequestTestRule.expectResultContains(
+                new String[] {"Jane Doe", "6502530000", "jane.doe@gmail.com"});
+    }
+}
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 8f38b22..575d19f 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1188,6 +1188,10 @@
       <message name="IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR" desc="The separator between a result in the autocomplete popup and its description.">
         ''' - '''
       </message>
+      <message name="IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR_ALTERNATE"
+               desc="An experimental separator used in the autocomplete popup instead of IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR if an experimental flag is on.">
+        ''' | '''
+      </message>
       <if expr="not use_titlecase">
         <message name="IDS_EDIT_SEARCH_ENGINES"
                  desc="Title of the popup menu item for editing search engines">
diff --git a/chrome/app/generated_resources_grd/IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR_ALTERNATE.png.sha1 b/chrome/app/generated_resources_grd/IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR_ALTERNATE.png.sha1
new file mode 100644
index 0000000..e051de7
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR_ALTERNATE.png.sha1
@@ -0,0 +1 @@
+5593061efaa974c571e25dab47b85428789a512b
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 6eb815e..d8742092 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2192,11 +2192,6 @@
      flag_descriptions::kPerMethodCanMakePaymentQuotaDescription, kOsAll,
      FEATURE_VALUE_TYPE(
          payments::features::kWebPaymentsPerMethodCanMakePaymentQuota)},
-#if defined(OS_CHROMEOS)
-    {"disable-eol-notification", flag_descriptions::kEolNotificationName,
-     flag_descriptions::kEolNotificationDescription, kOsCrOS,
-     SINGLE_DISABLE_VALUE_TYPE(chromeos::switches::kDisableEolNotification)},
-#endif  // OS_CHROMEOS
     {"fill-on-account-select", flag_descriptions::kFillOnAccountSelectName,
      flag_descriptions::kFillOnAccountSelectDescription, kOsAll,
      FEATURE_VALUE_TYPE(password_manager::features::kFillOnAccountSelect)},
diff --git a/chrome/browser/android/compositor/compositor_view.cc b/chrome/browser/android/compositor/compositor_view.cc
index a42d8f6..9a31e594e8 100644
--- a/chrome/browser/android/compositor/compositor_view.cc
+++ b/chrome/browser/android/compositor/compositor_view.cc
@@ -92,11 +92,14 @@
   root_layer_->SetIsDrawable(true);
   root_layer_->SetBackgroundColor(SK_ColorWHITE);
 
-  surface_control_feature_checker_ = content::GpuFeatureChecker::Create(
+  // It is safe to not keep a ref on the feature checker because it adds one
+  // internally in CheckGpuFeatureAvailability and unrefs after the callback is
+  // dispatched.
+  auto surface_control_feature_checker = content::GpuFeatureChecker::Create(
       gpu::GpuFeatureType::GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL,
       base::Bind(&CompositorView::OnSurfaceControlFeatureStatusUpdate,
                  weak_factory_.GetWeakPtr()));
-  surface_control_feature_checker_->CheckGpuFeatureAvailability();
+  surface_control_feature_checker->CheckGpuFeatureAvailability();
 }
 
 CompositorView::~CompositorView() {
@@ -155,8 +158,6 @@
     JNIEnv* env = base::android::AttachCurrentThread();
     Java_CompositorView_notifyWillUseSurfaceControl(env, obj_);
   }
-
-  surface_control_feature_checker_.reset();
 }
 
 void CompositorView::SurfaceCreated(JNIEnv* env,
diff --git a/chrome/browser/android/compositor/compositor_view.h b/chrome/browser/android/compositor/compositor_view.h
index c15e33b5..086b3858 100644
--- a/chrome/browser/android/compositor/compositor_view.h
+++ b/chrome/browser/android/compositor/compositor_view.h
@@ -119,8 +119,6 @@
   int content_height_;
   bool overlay_video_mode_;
 
-  scoped_refptr<content::GpuFeatureChecker> surface_control_feature_checker_;
-
   base::WeakPtrFactory<CompositorView> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CompositorView);
diff --git a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc
index fcdd67b..6f9c87b 100644
--- a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc
+++ b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc
@@ -311,25 +311,25 @@
 
 // Callback function for mojom::BluetoothInstance::RequestGattRead
 void OnGattServerRead(
-    const BluetoothLocalGattService::Delegate::ValueCallback& success_callback,
-    const BluetoothLocalGattService::Delegate::ErrorCallback& error_callback,
+    BluetoothLocalGattService::Delegate::ValueCallback success_callback,
+    BluetoothLocalGattService::Delegate::ErrorCallback error_callback,
     arc::mojom::BluetoothGattStatus status,
     const std::vector<uint8_t>& value) {
   if (status == arc::mojom::BluetoothGattStatus::GATT_SUCCESS)
-    success_callback.Run(value);
+    std::move(success_callback).Run(value);
   else
-    error_callback.Run();
+    std::move(error_callback).Run();
 }
 
 // Callback function for mojom::BluetoothInstance::RequestGattWrite
 void OnGattServerWrite(
-    const base::Closure& success_callback,
-    const BluetoothLocalGattService::Delegate::ErrorCallback& error_callback,
+    base::OnceClosure success_callback,
+    BluetoothLocalGattService::Delegate::ErrorCallback error_callback,
     arc::mojom::BluetoothGattStatus status) {
   if (status == arc::mojom::BluetoothGattStatus::GATT_SUCCESS)
-    success_callback.Run();
+    std::move(success_callback).Run();
   else
-    error_callback.Run();
+    std::move(error_callback).Run();
 }
 
 bool IsGattOffsetValid(int offset) {
@@ -771,13 +771,13 @@
     const LocalGattAttribute* attribute,
     int offset,
     mojom::BluetoothGattDBAttributeType attribute_type,
-    const ValueCallback& success_callback,
-    const ErrorCallback& error_callback) {
+    ValueCallback success_callback,
+    ErrorCallback error_callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   auto* bluetooth_instance = ARC_GET_INSTANCE_FOR_METHOD(
       arc_bridge_service_->bluetooth(), RequestGattRead);
   if (!bluetooth_instance || !IsGattOffsetValid(offset)) {
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
@@ -787,32 +787,39 @@
       mojom::BluetoothAddress::From(device->GetAddress()),
       gatt_handle_[attribute->GetIdentifier()], offset, false /* is_long */,
       attribute_type,
-      base::BindOnce(&OnGattServerRead, success_callback, error_callback));
+      base::BindOnce(&OnGattServerRead, std::move(success_callback),
+                     std::move(error_callback)));
 }
 
 void ArcBluetoothBridge::OnGattServerPrepareWrite(
     mojom::BluetoothAddressPtr addr,
     bool has_subsequent_write,
-    const base::Closure& success_callback,
-    const ErrorCallback& error_callback,
+    base::OnceClosure success_callback,
+    ErrorCallback error_callback,
     mojom::BluetoothGattStatus status) {
   bool success = (status == mojom::BluetoothGattStatus::GATT_SUCCESS);
-  const base::Closure& callback = (success ? success_callback : error_callback);
   if (success && has_subsequent_write) {
-    callback.Run();
+    std::move(success_callback).Run();
     return;
   }
 
   auto* bluetooth_instance = ARC_GET_INSTANCE_FOR_METHOD(
       arc_bridge_service_->bluetooth(), RequestGattExecuteWrite);
   if (bluetooth_instance == nullptr) {
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
+  base::RepeatingClosure repeating_sucess_callback =
+      base::AdaptCallbackForRepeating(std::move(success_callback));
+  base::RepeatingClosure repeating_error_callback =
+      base::AdaptCallbackForRepeating(std::move(error_callback));
+  if (!success)
+    repeating_sucess_callback = repeating_error_callback;
   bluetooth_instance->RequestGattExecuteWrite(
       std::move(addr), success,
-      base::BindOnce(&OnGattServerWrite, callback, error_callback));
+      base::BindOnce(&OnGattServerWrite, repeating_sucess_callback,
+                     repeating_error_callback));
 }
 
 template <class LocalGattAttribute>
@@ -824,24 +831,25 @@
     mojom::BluetoothGattDBAttributeType attribute_type,
     bool is_prepare,
     bool has_subsequent_write,
-    const base::Closure& success_callback,
-    const ErrorCallback& error_callback) {
+    base::OnceClosure success_callback,
+    ErrorCallback error_callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   auto* bluetooth_instance = ARC_GET_INSTANCE_FOR_METHOD(
       arc_bridge_service_->bluetooth(), RequestGattWrite);
   if (!bluetooth_instance || !IsGattOffsetValid(offset)) {
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   GattStatusCallback callback =
-      is_prepare ? base::BindOnce(
-                       &ArcBluetoothBridge::OnGattServerPrepareWrite,
-                       weak_factory_.GetWeakPtr(),
-                       mojom::BluetoothAddress::From(device->GetAddress()),
-                       has_subsequent_write, success_callback, error_callback)
-                 : base::BindOnce(&OnGattServerWrite, success_callback,
-                                  error_callback);
+      is_prepare
+          ? base::BindOnce(&ArcBluetoothBridge::OnGattServerPrepareWrite,
+                           weak_factory_.GetWeakPtr(),
+                           mojom::BluetoothAddress::From(device->GetAddress()),
+                           has_subsequent_write, std::move(success_callback),
+                           std::move(error_callback))
+          : base::BindOnce(&OnGattServerWrite, std::move(success_callback),
+                           std::move(error_callback));
   DCHECK(gatt_handle_.find(attribute->GetIdentifier()) != gatt_handle_.end());
   bluetooth_instance->RequestGattWrite(
       mojom::BluetoothAddress::From(device->GetAddress()),
@@ -853,12 +861,12 @@
     const BluetoothDevice* device,
     const BluetoothLocalGattCharacteristic* characteristic,
     int offset,
-    const ValueCallback& callback,
-    const ErrorCallback& error_callback) {
+    ValueCallback callback,
+    ErrorCallback error_callback) {
   OnGattAttributeReadRequest(
       device, characteristic, offset,
-      mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC, callback,
-      error_callback);
+      mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
+      std::move(callback), std::move(error_callback));
 }
 
 void ArcBluetoothBridge::OnCharacteristicWriteRequest(
@@ -866,13 +874,13 @@
     const BluetoothLocalGattCharacteristic* characteristic,
     const std::vector<uint8_t>& value,
     int offset,
-    const base::Closure& callback,
-    const ErrorCallback& error_callback) {
+    base::OnceClosure callback,
+    ErrorCallback error_callback) {
   OnGattAttributeWriteRequest(
       device, characteristic, value, offset,
       mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
-      /* is_prepare = */ false, /* has_subsequent_write, = */ false, callback,
-      error_callback);
+      /* is_prepare = */ false, /* has_subsequent_write, = */ false,
+      std::move(callback), std::move(error_callback));
 }
 
 void ArcBluetoothBridge::OnCharacteristicPrepareWriteRequest(
@@ -881,24 +889,25 @@
     const std::vector<uint8_t>& value,
     int offset,
     bool has_subsequent_write,
-    const base::Closure& callback,
-    const ErrorCallback& error_callback) {
+    base::OnceClosure callback,
+    ErrorCallback error_callback) {
   OnGattAttributeWriteRequest(
       device, characteristic, value, offset,
       mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
-      /* is_prepare = */ true, has_subsequent_write, callback, error_callback);
+      /* is_prepare = */ true, has_subsequent_write, std::move(callback),
+      std::move(error_callback));
 }
 
 void ArcBluetoothBridge::OnDescriptorReadRequest(
     const BluetoothDevice* device,
     const BluetoothLocalGattDescriptor* descriptor,
     int offset,
-    const ValueCallback& callback,
-    const ErrorCallback& error_callback) {
+    ValueCallback callback,
+    ErrorCallback error_callback) {
   OnGattAttributeReadRequest(
       device, descriptor, offset,
-      mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR, callback,
-      error_callback);
+      mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR,
+      std::move(callback), std::move(error_callback));
 }
 
 void ArcBluetoothBridge::OnDescriptorWriteRequest(
@@ -906,13 +915,13 @@
     const BluetoothLocalGattDescriptor* descriptor,
     const std::vector<uint8_t>& value,
     int offset,
-    const base::Closure& callback,
-    const ErrorCallback& error_callback) {
+    base::OnceClosure callback,
+    ErrorCallback error_callback) {
   OnGattAttributeWriteRequest(
       device, descriptor, value, offset,
       mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR,
-      /* is_prepare = */ false, /* has_subsequent_write = */ false, callback,
-      error_callback);
+      /* is_prepare = */ false, /* has_subsequent_write = */ false,
+      std::move(callback), std::move(error_callback));
 }
 
 void ArcBluetoothBridge::OnNotificationsStart(
diff --git a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.h b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.h
index 19fba2d8..72598f5 100644
--- a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.h
+++ b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.h
@@ -151,16 +151,16 @@
       const device::BluetoothDevice* device,
       const device::BluetoothLocalGattCharacteristic* characteristic,
       int offset,
-      const ValueCallback& callback,
-      const ErrorCallback& error_callback) override;
+      ValueCallback callback,
+      ErrorCallback error_callback) override;
 
   void OnCharacteristicWriteRequest(
       const device::BluetoothDevice* device,
       const device::BluetoothLocalGattCharacteristic* characteristic,
       const std::vector<uint8_t>& value,
       int offset,
-      const base::Closure& callback,
-      const ErrorCallback& error_callback) override;
+      base::OnceClosure callback,
+      ErrorCallback error_callback) override;
 
   void OnCharacteristicPrepareWriteRequest(
       const device::BluetoothDevice* device,
@@ -168,23 +168,23 @@
       const std::vector<uint8_t>& value,
       int offset,
       bool has_subsequent_write,
-      const base::Closure& callback,
-      const ErrorCallback& error_callback) override;
+      base::OnceClosure callback,
+      ErrorCallback error_callback) override;
 
   void OnDescriptorReadRequest(
       const device::BluetoothDevice* device,
       const device::BluetoothLocalGattDescriptor* descriptor,
       int offset,
-      const ValueCallback& callback,
-      const ErrorCallback& error_callback) override;
+      ValueCallback callback,
+      ErrorCallback error_callback) override;
 
   void OnDescriptorWriteRequest(
       const device::BluetoothDevice* device,
       const device::BluetoothLocalGattDescriptor* descriptor,
       const std::vector<uint8_t>& value,
       int offset,
-      const base::Closure& callback,
-      const ErrorCallback& error_callback) override;
+      base::OnceClosure callback,
+      ErrorCallback error_callback) override;
 
   void OnNotificationsStart(
       const device::BluetoothDevice* device,
@@ -420,8 +420,8 @@
       const LocalGattAttribute* attribute,
       int offset,
       mojom::BluetoothGattDBAttributeType attribute_type,
-      const ValueCallback& success_callback,
-      const ErrorCallback& error_callback);
+      ValueCallback success_callback,
+      ErrorCallback error_callback);
 
   // Common code for OnCharacteristicWriteRequest and OnDescriptorWriteRequest
   // |is_prepare| is only set when a local characteristic receives a prepare
@@ -436,8 +436,8 @@
       mojom::BluetoothGattDBAttributeType attribute_type,
       bool is_prepare,
       bool has_subsequent_write,
-      const base::Closure& success_callback,
-      const ErrorCallback& error_callback);
+      base::OnceClosure success_callback,
+      ErrorCallback error_callback);
 
   void OnSetDiscoverable(bool discoverable, bool success, uint32_t timeout);
   void SetDiscoverable(bool discoverable, uint32_t timeout);
@@ -499,8 +499,8 @@
 
   void OnGattServerPrepareWrite(mojom::BluetoothAddressPtr addr,
                                 bool has_subsequent_write,
-                                const base::Closure& success_callback,
-                                const ErrorCallback& error_callback,
+                                base::OnceClosure success_callback,
+                                ErrorCallback error_callback,
                                 mojom::BluetoothGattStatus status);
 
   void SendDevice(const device::BluetoothDevice* device) const;
diff --git a/chrome/browser/chromeos/eol_notification.cc b/chrome/browser/chromeos/eol_notification.cc
index de36459..d0e0819 100644
--- a/chrome/browser/chromeos/eol_notification.cc
+++ b/chrome/browser/chromeos/eol_notification.cc
@@ -16,7 +16,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/update_engine_client.h"
 #include "components/prefs/pref_service.h"
@@ -82,11 +81,6 @@
 
 // static
 bool EolNotification::ShouldShowEolNotification() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kDisableEolNotification)) {
-    return false;
-  }
-
   // Do not show end of life notification if this device is managed by
   // enterprise user.
   if (g_browser_process->platform_part()
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
index 381761a6..9d4644e8 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
@@ -85,19 +85,22 @@
                  BrightnessMonitor* brightness_monitor,
                  Modeller* modeller,
                  ModelConfigLoader* model_config_loader,
-                 MetricsReporter* metrics_reporter,
-                 chromeos::PowerManagerClient* power_manager_client)
+                 MetricsReporter* metrics_reporter)
     : Adapter(profile,
               als_reader,
               brightness_monitor,
               modeller,
               model_config_loader,
               metrics_reporter,
-              power_manager_client,
               base::DefaultTickClock::GetInstance()) {}
 
 Adapter::~Adapter() = default;
 
+void Adapter::Init() {
+  // Deferred to Init() because it can result in a virtual method being called.
+  power_manager_client_observer_.Add(PowerManagerClient::Get());
+}
+
 void Adapter::OnAmbientLightUpdated(int lux) {
   // Ambient light data is only used when adapter is initialized to success.
   // |log_als_values_| may not be available to use when adapter is being
@@ -278,6 +281,11 @@
   UpdateStatus();
 }
 
+void Adapter::PowerManagerBecameAvailable(bool service_is_ready) {
+  power_manager_service_available_ = service_is_ready;
+  UpdateStatus();
+}
+
 void Adapter::SuspendDone(const base::TimeDelta& /* sleep_duration */) {
   // We skip this notification if adapter hasn't been initialised (because its
   // |params_| may change), or, if adapter is disabled (because adapter won't
@@ -332,11 +340,10 @@
     Modeller* modeller,
     ModelConfigLoader* model_config_loader,
     MetricsReporter* metrics_reporter,
-    chromeos::PowerManagerClient* power_manager_client,
     const base::TickClock* tick_clock) {
-  return base::WrapUnique(new Adapter(
-      profile, als_reader, brightness_monitor, modeller, model_config_loader,
-      metrics_reporter, power_manager_client, tick_clock));
+  return base::WrapUnique(new Adapter(profile, als_reader, brightness_monitor,
+                                      modeller, model_config_loader,
+                                      metrics_reporter, tick_clock));
 }
 
 Adapter::Adapter(Profile* profile,
@@ -345,34 +352,20 @@
                  Modeller* modeller,
                  ModelConfigLoader* model_config_loader,
                  MetricsReporter* metrics_reporter,
-                 chromeos::PowerManagerClient* power_manager_client,
                  const base::TickClock* tick_clock)
     : profile_(profile),
-      als_reader_observer_(this),
-      brightness_monitor_observer_(this),
-      modeller_observer_(this),
-      model_config_loader_observer_(this),
-      power_manager_client_observer_(this),
       metrics_reporter_(metrics_reporter),
-      power_manager_client_(power_manager_client),
-      tick_clock_(tick_clock),
-      weak_ptr_factory_(this) {
+      tick_clock_(tick_clock) {
   DCHECK(profile);
   DCHECK(als_reader);
   DCHECK(brightness_monitor);
   DCHECK(modeller);
   DCHECK(model_config_loader);
-  DCHECK(power_manager_client);
 
   als_reader_observer_.Add(als_reader);
   brightness_monitor_observer_.Add(brightness_monitor);
   modeller_observer_.Add(modeller);
   model_config_loader_observer_.Add(model_config_loader);
-  power_manager_client_observer_.Add(power_manager_client);
-
-  power_manager_client_->WaitForServiceToBeAvailable(
-      base::BindOnce(&Adapter::OnPowerManagerServiceAvailable,
-                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void Adapter::InitParams(const ModelConfig& model_config) {
@@ -439,11 +432,6 @@
                             params_.user_adjustment_effect);
 }
 
-void Adapter::OnPowerManagerServiceAvailable(bool service_is_ready) {
-  power_manager_service_available_ = service_is_ready;
-  UpdateStatus();
-}
-
 void Adapter::UpdateStatus() {
   if (adapter_status_ != Status::kInitializing)
     return;
@@ -605,7 +593,7 @@
   request.set_transition(
       power_manager::SetBacklightBrightnessRequest_Transition_GRADUAL);
   request.set_cause(power_manager::SetBacklightBrightnessRequest_Cause_MODEL);
-  power_manager_client_->SetScreenBrightness(request);
+  PowerManagerClient::Get()->SetScreenBrightness(request);
 
   const base::TimeTicks brightness_change_time = tick_clock_->NowTicks();
   if (!latest_model_brightness_change_time_.is_null()) {
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
index c4f695e..cfcca71 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
@@ -167,10 +167,12 @@
           BrightnessMonitor* brightness_monitor,
           Modeller* modeller,
           ModelConfigLoader* model_config_loader,
-          MetricsReporter* metrics_reporter,
-          chromeos::PowerManagerClient* power_manager_client);
+          MetricsReporter* metrics_reporter);
   ~Adapter() override;
 
+  // Must be called before the Adapter is used.
+  void Init();
+
   // AlsReader::Observer overrides:
   void OnAmbientLightUpdated(int lux) override;
   void OnAlsReaderInitialized(AlsReader::AlsInitStatus status) override;
@@ -191,6 +193,7 @@
   void OnModelConfigLoaded(base::Optional<ModelConfig> model_config) override;
 
   // chromeos::PowerManagerClient::Observer overrides:
+  void PowerManagerBecameAvailable(bool service_is_ready) override;
   void SuspendDone(const base::TimeDelta& sleep_duration) override;
 
   Status GetStatusForTesting() const;
@@ -217,7 +220,6 @@
       Modeller* modeller,
       ModelConfigLoader* model_config_loader,
       MetricsReporter* metrics_reporter,
-      chromeos::PowerManagerClient* power_manager_client,
       const base::TickClock* tick_clock);
 
  private:
@@ -227,7 +229,6 @@
           Modeller* modeller,
           ModelConfigLoader* model_config_loader,
           MetricsReporter* metrics_reporter,
-          chromeos::PowerManagerClient* power_manager_client,
           const base::TickClock* tick_clock);
 
   // Called by |OnModelConfigLoaded|. It will initialize all params used by
@@ -235,9 +236,6 @@
   // any param is invalid, it will disable the adapter.
   void InitParams(const ModelConfig& model_config);
 
-  // Called when powerd becomes available.
-  void OnPowerManagerServiceAvailable(bool service_is_ready);
-
   // Called to update |adapter_status_| when there's some status change from
   // AlsReader, BrightnessMonitor, Modeller, power manager and after
   // |InitParams|.
@@ -291,23 +289,21 @@
 
   Profile* const profile_;
 
-  ScopedObserver<AlsReader, AlsReader::Observer> als_reader_observer_;
+  ScopedObserver<AlsReader, AlsReader::Observer> als_reader_observer_{this};
   ScopedObserver<BrightnessMonitor, BrightnessMonitor::Observer>
-      brightness_monitor_observer_;
-  ScopedObserver<Modeller, Modeller::Observer> modeller_observer_;
+      brightness_monitor_observer_{this};
+  ScopedObserver<Modeller, Modeller::Observer> modeller_observer_{this};
 
   ScopedObserver<ModelConfigLoader, ModelConfigLoader::Observer>
-      model_config_loader_observer_;
+      model_config_loader_observer_{this};
 
   ScopedObserver<chromeos::PowerManagerClient,
                  chromeos::PowerManagerClient::Observer>
-      power_manager_client_observer_;
+      power_manager_client_observer_{this};
 
   // Used to report daily metrics to UMA. This may be null in unit tests.
   MetricsReporter* metrics_reporter_;
 
-  chromeos::PowerManagerClient* const power_manager_client_;
-
   Params params_;
 
   // This will be replaced by a mock tick clock during tests.
@@ -386,8 +382,6 @@
   // Used to record number of model-triggered brightness changes.
   int model_brightness_change_counter_ = 1;
 
-  base::WeakPtrFactory<Adapter> weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(Adapter);
 };
 
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
index 7ff355d..15ccecbd 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
@@ -210,8 +210,8 @@
     adapter_ = Adapter::CreateForTesting(
         profile_.get(), &fake_als_reader_, &fake_brightness_monitor_,
         &fake_modeller_, &fake_model_config_loader_,
-        nullptr /* metrics_reporter */, chromeos::PowerManagerClient::Get(),
-        thread_bundle_.GetMockTickClock());
+        nullptr /* metrics_reporter */, thread_bundle_.GetMockTickClock());
+    adapter_->Init();
     thread_bundle_.RunUntilIdle();
   }
 
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.cc b/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.cc
index b244272..169d35f 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.cc
@@ -24,14 +24,10 @@
 
 constexpr base::TimeDelta BrightnessMonitorImpl::kBrightnessSampleDelay;
 
-BrightnessMonitorImpl::BrightnessMonitorImpl() {
-  power_manager_client_observer_.Add(chromeos::PowerManagerMojoClient::Get());
+BrightnessMonitorImpl::BrightnessMonitorImpl() = default;
+BrightnessMonitorImpl::~BrightnessMonitorImpl() = default;
 
-  // TODO(estade): use Mojo.
-  chromeos::PowerManagerClient::Get()->WaitForServiceToBeAvailable(
-      base::BindOnce(&BrightnessMonitorImpl::OnPowerManagerServiceAvailable,
-                     weak_ptr_factory_.GetWeakPtr()));
-
+void BrightnessMonitorImpl::Init() {
   const int brightness_sample_delay_seconds = GetFieldTrialParamByFeatureAsInt(
       features::kAutoScreenBrightness, "brightness_sample_delay_seconds",
       kBrightnessSampleDelay.InSeconds());
@@ -40,9 +36,9 @@
       brightness_sample_delay_seconds < 0
           ? kBrightnessSampleDelay
           : base::TimeDelta::FromSeconds(brightness_sample_delay_seconds);
-}
 
-BrightnessMonitorImpl::~BrightnessMonitorImpl() = default;
+  power_manager_client_observer_.Add(PowerManagerMojoClient::Get());
+}
 
 void BrightnessMonitorImpl::AddObserver(
     BrightnessMonitor::Observer* const observer) {
@@ -60,6 +56,18 @@
   observers_.RemoveObserver(observer);
 }
 
+void BrightnessMonitorImpl::PowerManagerBecameAvailable(
+    const bool service_is_ready) {
+  if (!service_is_ready) {
+    brightness_monitor_status_ = Status::kDisabled;
+    OnInitializationComplete();
+    return;
+  }
+  PowerManagerMojoClient::Get()->GetScreenBrightnessPercent(
+      base::BindOnce(&BrightnessMonitorImpl::OnReceiveInitialBrightnessPercent,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
 void BrightnessMonitorImpl::ScreenBrightnessChanged(
     const power_manager::BacklightBrightnessChange& change) {
   if (brightness_monitor_status_ != Status::kSuccess) {
@@ -105,18 +113,6 @@
   return brightness_sample_delay_;
 }
 
-void BrightnessMonitorImpl::OnPowerManagerServiceAvailable(
-    const bool service_is_ready) {
-  if (!service_is_ready) {
-    brightness_monitor_status_ = Status::kDisabled;
-    OnInitializationComplete();
-    return;
-  }
-  chromeos::PowerManagerMojoClient::Get()->GetScreenBrightnessPercent(
-      base::BindOnce(&BrightnessMonitorImpl::OnReceiveInitialBrightnessPercent,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
 void BrightnessMonitorImpl::OnReceiveInitialBrightnessPercent(
     const base::Optional<double> brightness_percent) {
   DCHECK_EQ(brightness_monitor_status_, Status::kInitializing);
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.h b/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.h
index f9300230..0d232d5c 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl.h
@@ -37,18 +37,21 @@
   BrightnessMonitorImpl();
   ~BrightnessMonitorImpl() override;
 
+  // Must be called before the BrightnessMonitorImpl is used.
+  void Init();
+
   // BrightnessMonitor overrides:
   void AddObserver(BrightnessMonitor::Observer* observer) override;
   void RemoveObserver(BrightnessMonitor::Observer* observer) override;
 
   // chromeos::PowerManagerClient::Observer overrides:
+  void PowerManagerBecameAvailable(bool service_is_ready) override;
   void ScreenBrightnessChanged(
       const power_manager::BacklightBrightnessChange& change) override;
 
   base::TimeDelta GetBrightnessSampleDelayForTesting() const;
 
  private:
-  void OnPowerManagerServiceAvailable(bool service_is_ready);
 
   // Sets initial brightness obtained from powerd. If nullopt is received from
   // powerd, the monitor status will be set to kDisabled.
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl_unittest.cc
index 3a41332..60c64ee8 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor_impl_unittest.cc
@@ -102,6 +102,7 @@
     }
 
     monitor_ = std::make_unique<BrightnessMonitorImpl>();
+    monitor_->Init();
     test_observer_ = std::make_unique<TestObserver>();
     monitor_->AddObserver(test_observer_.get());
     scoped_task_environment_.RunUntilIdle();
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/controller.cc b/chrome/browser/chromeos/power/auto_screen_brightness/controller.cc
index 0fefe21..ff4e87cb 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/controller.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/controller.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 
 namespace chromeos {
 namespace power {
@@ -34,6 +33,7 @@
   als_reader_->Init();
 
   brightness_monitor_ = std::make_unique<BrightnessMonitorImpl>();
+  brightness_monitor_->Init();
 
   model_config_loader_ = std::make_unique<ModelConfigLoaderImpl>();
 
@@ -50,8 +50,8 @@
 
   adapter_ = std::make_unique<Adapter>(
       profile, als_reader_.get(), brightness_monitor_.get(), modeller_.get(),
-      model_config_loader_.get(), metrics_reporter_.get(),
-      power_manager_client);
+      model_config_loader_.get(), metrics_reporter_.get());
+  adapter_->Init();
 }
 
 Controller::~Controller() = default;
diff --git a/chrome/browser/chromeos/printing/printers_sync_bridge.cc b/chrome/browser/chromeos/printing/printers_sync_bridge.cc
index 487d104..c2d47d8 100644
--- a/chrome/browser/chromeos/printing/printers_sync_bridge.cc
+++ b/chrome/browser/chromeos/printing/printers_sync_bridge.cc
@@ -289,7 +289,7 @@
   // If the local printer doesn't exist, it must have been deleted. In this
   // case, use the remote one.
   if (iter == all_data_.end()) {
-    return ConflictResolution::UseRemote();
+    return ConflictResolution::kUseRemote;
   }
   const sync_pb::PrinterSpecifics& local_printer = *iter->second;
 
@@ -297,10 +297,10 @@
       remote_data.specifics.printer();
 
   if (local_printer.updated_timestamp() > remote_printer.updated_timestamp()) {
-    return ConflictResolution::UseLocal();
+    return ConflictResolution::kUseLocal;
   }
 
-  return ConflictResolution::UseRemote();
+  return ConflictResolution::kUseRemote;
 }
 
 void PrintersSyncBridge::AddPrinter(
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index a1c3e5b..8274e48e 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -515,11 +515,6 @@
     "expiry_milestone": 75
   },
   {
-    "name": "disable-eol-notification",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "disable-explicit-dma-fences",
     "owners": [ "chromeos-gfx@google.com" ],
     // This flag is used for QA & debugging on ChromeOS, which has no way to
@@ -1007,7 +1002,7 @@
   {
     "name": "enable-desktop-pwas-omnibox-install",
     "owners": [ "desktop-pwas-team@google.com" ],
-    "expiry_milestone": 77
+    "expiry_milestone": 79
   },
   {
     "name": "enable-devtools-experiments",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 5e65f8b..4002606 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3129,10 +3129,6 @@
     "Enable Zero State Suggestions feature in Launcher, which will show "
     "suggestions when launcher search box is active with an empty query";
 
-const char kEolNotificationName[] = "Disable Device End of Life notification.";
-const char kEolNotificationDescription[] =
-    "Disable Notifcation when Device is End of Life.";
-
 const char kExperimentalAccessibilityChromeVoxLanguageSwitchingName[] =
     "Enable experimental ChromeVox language switching.";
 const char kExperimentalAccessibilityChromeVoxLanguageSwitchingDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 29a17eb..4c8bddaa 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1888,9 +1888,6 @@
 extern const char kEnableZeroStateSuggestionsName[];
 extern const char kEnableZeroStateSuggestionsDescription[];
 
-extern const char kEolNotificationName[];
-extern const char kEolNotificationDescription[];
-
 extern const char kExperimentalAccessibilityChromeVoxLanguageSwitchingName[];
 extern const char
     kExperimentalAccessibilityChromeVoxLanguageSwitchingDescription[];
diff --git a/chrome/browser/resources/PRESUBMIT.py b/chrome/browser/resources/PRESUBMIT.py
index b57bdba..b502dbb 100644
--- a/chrome/browser/resources/PRESUBMIT.py
+++ b/chrome/browser/resources/PRESUBMIT.py
@@ -100,6 +100,20 @@
   return input_api.canned_checks.RunUnitTests(input_api, output_api, tests)
 
 
+def _CheckSvgsOptimized(input_api, output_api):
+  results = []
+  try:
+    import sys
+    old_sys_path = sys.path[:]
+    cwd = input_api.PresubmitLocalPath()
+    sys.path += [input_api.os_path.join(cwd, '..', '..', '..', 'tools')]
+    from resources import svgo_presubmit
+    results += svgo_presubmit.CheckOptimized(input_api, output_api)
+  finally:
+    sys.path = old_sys_path
+  return results
+
+
 def _CheckWebDevStyle(input_api, output_api):
   results = []
 
@@ -108,8 +122,8 @@
     old_sys_path = sys.path[:]
     cwd = input_api.PresubmitLocalPath()
     sys.path += [input_api.os_path.join(cwd, '..', '..', '..', 'tools')]
-    import web_dev_style.presubmit_support
-    results += web_dev_style.presubmit_support.CheckStyle(input_api, output_api)
+    from web_dev_style import presubmit_support
+    results += presubmit_support.CheckStyle(input_api, output_api)
   finally:
     sys.path = old_sys_path
 
@@ -126,6 +140,7 @@
   affected_files = [input_api.os_path.basename(f.LocalPath()) for f in affected]
   if webui_sources.intersection(set(affected_files)):
     results += RunOptimizeWebUiTests(input_api, output_api)
+  results += _CheckSvgsOptimized(input_api, output_api)
   results += _CheckWebDevStyle(input_api, output_api)
   results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api,
                                                          check_js=True)
diff --git a/chrome/browser/resources/chromeos/switch_access/BUILD.gn b/chrome/browser/resources/chromeos/switch_access/BUILD.gn
index 094fc4f..24a2a83b 100644
--- a/chrome/browser/resources/chromeos/switch_access/BUILD.gn
+++ b/chrome/browser/resources/chromeos/switch_access/BUILD.gn
@@ -18,6 +18,7 @@
     ":switch_access_copied_files",
     ":switch_access_guest_manifest",
     ":switch_access_manifest",
+    "strings:switch_access_strings",
   ]
 }
 
diff --git a/chrome/browser/resources/chromeos/switch_access/manifest.json.jinja2 b/chrome/browser/resources/chromeos/switch_access/manifest.json.jinja2
index 804493c..5301ca3 100644
--- a/chrome/browser/resources/chromeos/switch_access/manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/switch_access/manifest.json.jinja2
@@ -3,9 +3,9 @@
   "key": "{{key}}",
 {% endif %}
   "manifest_version": 2,
-  "name": "TODO: Translated Switch access name",
+  "name": "__MSG_SWITCH_ACCESS_NAME__",
   "version": "{{set_version}}",
-  "description": "TODO: Translated Switch access description",
+  "description": "__MSG_SWITCH_ACCESS_DESCRIPTION__",
 {% if is_guest_manifest == '1' %}
   "incognito": "split",
 {% endif %}
@@ -36,5 +36,6 @@
   "automation": {
     "desktop": true
   },
+  "default_locale": "en",
   "options_page": "options.html"
 }
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/BUILD.gn b/chrome/browser/resources/chromeos/switch_access/strings/BUILD.gn
new file mode 100644
index 0000000..1808267
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/BUILD.gn
@@ -0,0 +1,73 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//chrome/common/features.gni")
+import("//tools/grit/grit_rule.gni")
+
+switch_access_out_dir = "$root_out_dir/resources/chromeos/switch_access"
+
+grit("switch_access_strings") {
+  source = "switch_access_strings.grd"
+  defines = chrome_grit_defines
+  outputs = [
+    "_locales/am/messages.json",
+    "_locales/ar/messages.json",
+    "_locales/bg/messages.json",
+    "_locales/bn/messages.json",
+    "_locales/ca/messages.json",
+    "_locales/cs/messages.json",
+    "_locales/da/messages.json",
+    "_locales/de/messages.json",
+    "_locales/el/messages.json",
+    "_locales/en_GB/messages.json",
+    "_locales/en/messages.json",
+    "_locales/es/messages.json",
+    "_locales/es_419/messages.json",
+    "_locales/et/messages.json",
+    "_locales/fa/messages.json",
+    "_locales/fi/messages.json",
+    "_locales/fil/messages.json",
+    "_locales/fr/messages.json",
+    "_locales/gu/messages.json",
+    "_locales/he/messages.json",
+    "_locales/hi/messages.json",
+    "_locales/hr/messages.json",
+    "_locales/hu/messages.json",
+    "_locales/id/messages.json",
+    "_locales/it/messages.json",
+    "_locales/ja/messages.json",
+    "_locales/kn/messages.json",
+    "_locales/ko/messages.json",
+    "_locales/lt/messages.json",
+    "_locales/lv/messages.json",
+    "_locales/ml/messages.json",
+    "_locales/mr/messages.json",
+    "_locales/ms/messages.json",
+    "_locales/nl/messages.json",
+    "_locales/nb/messages.json",
+    "_locales/pl/messages.json",
+    "_locales/pt_BR/messages.json",
+    "_locales/pt_PT/messages.json",
+    "_locales/ro/messages.json",
+    "_locales/ru/messages.json",
+    "_locales/sk/messages.json",
+    "_locales/sl/messages.json",
+    "_locales/sr/messages.json",
+    "_locales/sv/messages.json",
+    "_locales/sw/messages.json",
+    "_locales/ta/messages.json",
+    "_locales/te/messages.json",
+    "_locales/th/messages.json",
+    "_locales/tr/messages.json",
+    "_locales/uk/messages.json",
+    "_locales/vi/messages.json",
+    "_locales/zh_CN/messages.json",
+    "_locales/zh_TW/messages.json",
+  ]
+  output_dir = switch_access_out_dir
+
+  # Don't pollute the extension directory with stamp and .d files.
+  depfile_dir = target_out_dir
+  resource_ids = ""
+}
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings.grd b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings.grd
new file mode 100644
index 0000000..ce211b2
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings.grd
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<grit base_dir="." current_release="1" latest_public_release="0"
+      output_all_resource_defines="false" enc_check="möl" source_lang_id="en">
+  <outputs>
+    <output filename="_locales/am/messages.json" type="chrome_messages_json" lang="am"/>
+    <output filename="_locales/ar/messages.json" type="chrome_messages_json" lang="ar"/>
+    <output filename="_locales/bg/messages.json" type="chrome_messages_json" lang="bg"/>
+    <output filename="_locales/bn/messages.json" type="chrome_messages_json" lang="bn"/>
+    <output filename="_locales/ca/messages.json" type="chrome_messages_json" lang="ca"/>
+    <output filename="_locales/cs/messages.json" type="chrome_messages_json" lang="cs"/>
+    <output filename="_locales/da/messages.json" type="chrome_messages_json" lang="da"/>
+    <output filename="_locales/de/messages.json" type="chrome_messages_json" lang="de"/>
+    <output filename="_locales/el/messages.json" type="chrome_messages_json" lang="el"/>
+    <output filename="_locales/en_GB/messages.json" type="chrome_messages_json" lang="en-GB"/>
+    <output filename="_locales/en/messages.json" type="chrome_messages_json" lang="en"/>
+    <output filename="_locales/es/messages.json" type="chrome_messages_json" lang="es"/>
+    <output filename="_locales/es_419/messages.json" type="chrome_messages_json" lang="es-419"/>
+    <output filename="_locales/et/messages.json" type="chrome_messages_json" lang="et"/>
+    <output filename="_locales/fa/messages.json" type="chrome_messages_json" lang="fa"/>
+    <output filename="_locales/fi/messages.json" type="chrome_messages_json" lang="fi"/>
+    <output filename="_locales/fil/messages.json" type="chrome_messages_json" lang="fil"/>
+    <output filename="_locales/fr/messages.json" type="chrome_messages_json" lang="fr"/>
+    <output filename="_locales/gu/messages.json" type="chrome_messages_json" lang="gu"/>
+    <output filename="_locales/he/messages.json" type="chrome_messages_json" lang="he"/>
+    <output filename="_locales/hi/messages.json" type="chrome_messages_json" lang="hi"/>
+    <output filename="_locales/hr/messages.json" type="chrome_messages_json" lang="hr"/>
+    <output filename="_locales/hu/messages.json" type="chrome_messages_json" lang="hu"/>
+    <output filename="_locales/id/messages.json" type="chrome_messages_json" lang="id"/>
+    <output filename="_locales/it/messages.json" type="chrome_messages_json" lang="it"/>
+    <output filename="_locales/ja/messages.json" type="chrome_messages_json" lang="ja"/>
+    <output filename="_locales/kn/messages.json" type="chrome_messages_json" lang="kn"/>
+    <output filename="_locales/ko/messages.json" type="chrome_messages_json" lang="ko"/>
+    <output filename="_locales/lt/messages.json" type="chrome_messages_json" lang="lt"/>
+    <output filename="_locales/lv/messages.json" type="chrome_messages_json" lang="lv"/>
+    <output filename="_locales/ml/messages.json" type="chrome_messages_json" lang="ml"/>
+    <output filename="_locales/mr/messages.json" type="chrome_messages_json" lang="mr"/>
+    <output filename="_locales/ms/messages.json" type="chrome_messages_json" lang="ms"/>
+    <output filename="_locales/nl/messages.json" type="chrome_messages_json" lang="nl"/>
+    <output filename="_locales/nb/messages.json" type="chrome_messages_json" lang="no"/>
+    <output filename="_locales/pl/messages.json" type="chrome_messages_json" lang="pl"/>
+    <output filename="_locales/pt_BR/messages.json" type="chrome_messages_json" lang="pt-BR"/>
+    <output filename="_locales/pt_PT/messages.json" type="chrome_messages_json" lang="pt-PT"/>
+    <output filename="_locales/ro/messages.json" type="chrome_messages_json" lang="ro"/>
+    <output filename="_locales/ru/messages.json" type="chrome_messages_json" lang="ru"/>
+    <output filename="_locales/sk/messages.json" type="chrome_messages_json" lang="sk"/>
+    <output filename="_locales/sl/messages.json" type="chrome_messages_json" lang="sl"/>
+    <output filename="_locales/sr/messages.json" type="chrome_messages_json" lang="sr"/>
+    <output filename="_locales/sv/messages.json" type="chrome_messages_json" lang="sv"/>
+    <output filename="_locales/sw/messages.json" type="chrome_messages_json" lang="sw"/>
+    <output filename="_locales/ta/messages.json" type="chrome_messages_json" lang="ta"/>
+    <output filename="_locales/te/messages.json" type="chrome_messages_json" lang="te"/>
+    <output filename="_locales/th/messages.json" type="chrome_messages_json" lang="th"/>
+    <output filename="_locales/tr/messages.json" type="chrome_messages_json" lang="tr"/>
+    <output filename="_locales/uk/messages.json" type="chrome_messages_json" lang="uk"/>
+    <output filename="_locales/vi/messages.json" type="chrome_messages_json" lang="vi"/>
+    <output filename="_locales/zh_CN/messages.json" type="chrome_messages_json" lang="zh-CN"/>
+    <output filename="_locales/zh_TW/messages.json" type="chrome_messages_json" lang="zh-TW"/>
+  </outputs>
+  <translations>
+  <file path="switch_access_strings_am.xtb" lang="am" />
+    <file path="switch_access_strings_ar.xtb" lang="ar" />
+    <file path="switch_access_strings_bg.xtb" lang="bg" />
+    <file path="switch_access_strings_bn.xtb" lang="bn" />
+    <file path="switch_access_strings_ca.xtb" lang="ca" />
+    <file path="switch_access_strings_cs.xtb" lang="cs" />
+    <file path="switch_access_strings_da.xtb" lang="da" />
+    <file path="switch_access_strings_de.xtb" lang="de" />
+    <file path="switch_access_strings_el.xtb" lang="el" />
+    <file path="switch_access_strings_en-GB.xtb" lang="en-GB" />
+    <file path="switch_access_strings_es.xtb" lang="es" />
+    <file path="switch_access_strings_es-419.xtb" lang="es-419" />
+    <file path="switch_access_strings_et.xtb" lang="et" />
+    <file path="switch_access_strings_fa.xtb" lang="fa" />
+    <file path="switch_access_strings_fi.xtb" lang="fi" />
+    <file path="switch_access_strings_fil.xtb" lang="fil" />
+    <file path="switch_access_strings_fr.xtb" lang="fr" />
+    <file path="switch_access_strings_gu.xtb" lang="gu" />
+    <file path="switch_access_strings_hi.xtb" lang="hi" />
+    <file path="switch_access_strings_hr.xtb" lang="hr" />
+    <file path="switch_access_strings_hu.xtb" lang="hu" />
+    <file path="switch_access_strings_id.xtb" lang="id" />
+    <file path="switch_access_strings_it.xtb" lang="it" />
+    <!-- The translation console uses 'iw' for Hebrew, but we use 'he'. -->
+    <file path="switch_access_strings_iw.xtb" lang="he" />
+    <file path="switch_access_strings_ja.xtb" lang="ja" />
+    <file path="switch_access_strings_kn.xtb" lang="kn" />
+    <file path="switch_access_strings_ko.xtb" lang="ko" />
+    <file path="switch_access_strings_lt.xtb" lang="lt" />
+    <file path="switch_access_strings_lv.xtb" lang="lv" />
+    <file path="switch_access_strings_ml.xtb" lang="ml" />
+    <file path="switch_access_strings_mr.xtb" lang="mr" />
+    <file path="switch_access_strings_ms.xtb" lang="ms" />
+    <file path="switch_access_strings_nl.xtb" lang="nl" />
+    <file path="switch_access_strings_no.xtb" lang="no" />
+    <file path="switch_access_strings_pl.xtb" lang="pl" />
+    <file path="switch_access_strings_pt-BR.xtb" lang="pt-BR" />
+    <file path="switch_access_strings_pt-PT.xtb" lang="pt-PT" />
+    <file path="switch_access_strings_ro.xtb" lang="ro" />
+    <file path="switch_access_strings_ru.xtb" lang="ru" />
+    <file path="switch_access_strings_sk.xtb" lang="sk" />
+    <file path="switch_access_strings_sl.xtb" lang="sl" />
+    <file path="switch_access_strings_sr.xtb" lang="sr" />
+    <file path="switch_access_strings_sv.xtb" lang="sv" />
+    <file path="switch_access_strings_sw.xtb" lang="sw" />
+    <file path="switch_access_strings_ta.xtb" lang="ta" />
+    <file path="switch_access_strings_te.xtb" lang="te" />
+    <file path="switch_access_strings_th.xtb" lang="th" />
+    <file path="switch_access_strings_tr.xtb" lang="tr" />
+    <file path="switch_access_strings_uk.xtb" lang="uk" />
+    <file path="switch_access_strings_vi.xtb" lang="vi" />
+    <file path="switch_access_strings_zh-CN.xtb" lang="zh-CN" />
+    <file path="switch_access_strings_zh-TW.xtb" lang="zh-TW" />
+  </translations>
+  <release allow_pseudo="false" seq="1">
+    <messages fallback_to_english="true">
+      <message desc="The product name for Switch Access." name="IDS_SWITCH_ACCESS_NAME">
+        Switch Access
+      </message>
+      <message desc="The description for Switch Access." name="IDS_SWITCH_ACCESS_DESCRIPTION">
+        Control the device with just 1 or 2 switches.
+      </message>
+    </messages>
+  </release>
+</grit>
+
+
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_am.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_am.xtb
new file mode 100644
index 0000000..6c985cb8
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_am.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="am">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ar.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ar.xtb
new file mode 100644
index 0000000..e8b5562
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ar.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ar">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_bg.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_bg.xtb
new file mode 100644
index 0000000..ebab473
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_bg.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="bg">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_bn.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_bn.xtb
new file mode 100644
index 0000000..a66cc1fc
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_bn.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="bn">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ca.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ca.xtb
new file mode 100644
index 0000000..1438d89
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ca.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ca">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_cs.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_cs.xtb
new file mode 100644
index 0000000..2d95130
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_cs.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="cs">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_da.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_da.xtb
new file mode 100644
index 0000000..751fa4a8
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_da.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="da">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_de.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_de.xtb
new file mode 100644
index 0000000..91de7f51
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_de.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="de">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_el.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_el.xtb
new file mode 100644
index 0000000..6e5e7d8
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_el.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="el">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_en-GB.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_en-GB.xtb
new file mode 100644
index 0000000..0fb2133
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_en-GB.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="en-GB">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_es-419.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_es-419.xtb
new file mode 100644
index 0000000..2fe4770
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_es-419.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es-419">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_es.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_es.xtb
new file mode 100644
index 0000000..64022ec
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_es.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_et.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_et.xtb
new file mode 100644
index 0000000..5244dfd
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_et.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="et">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fa.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fa.xtb
new file mode 100644
index 0000000..18626f8
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fa.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fa">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fi.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fi.xtb
new file mode 100644
index 0000000..4691cd5
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fi.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fi">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fil.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fil.xtb
new file mode 100644
index 0000000..443630e7
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fil.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fil">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fr.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fr.xtb
new file mode 100644
index 0000000..63026a3
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_fr.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fr">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_gu.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_gu.xtb
new file mode 100644
index 0000000..7d8a4df1
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_gu.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="gu">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_hi.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_hi.xtb
new file mode 100644
index 0000000..a6ddd5d
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_hi.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hi">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_hr.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_hr.xtb
new file mode 100644
index 0000000..26f99d0
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_hr.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hr">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_hu.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_hu.xtb
new file mode 100644
index 0000000..7ef9a5e0
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_hu.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hu">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_id.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_id.xtb
new file mode 100644
index 0000000..aa34783
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_id.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="id">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_it.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_it.xtb
new file mode 100644
index 0000000..a6ac8d46
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_it.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="it">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_iw.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_iw.xtb
new file mode 100644
index 0000000..86b5533
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_iw.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="iw">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ja.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ja.xtb
new file mode 100644
index 0000000..23139e6
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ja.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ja">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_kn.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_kn.xtb
new file mode 100644
index 0000000..cc3643a2
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_kn.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="kn">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ko.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ko.xtb
new file mode 100644
index 0000000..e0fc370
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ko.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ko">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_lt.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_lt.xtb
new file mode 100644
index 0000000..5804ae2a
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_lt.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lt">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_lv.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_lv.xtb
new file mode 100644
index 0000000..a0a1c477
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_lv.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lv">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ml.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ml.xtb
new file mode 100644
index 0000000..f7db315
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ml.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ml">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_mr.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_mr.xtb
new file mode 100644
index 0000000..098d29c
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_mr.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="mr">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ms.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ms.xtb
new file mode 100644
index 0000000..1fb470a
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ms.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ms">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_nl.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_nl.xtb
new file mode 100644
index 0000000..e782410
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_nl.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="nl">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_no.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_no.xtb
new file mode 100644
index 0000000..913638b
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_no.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="no">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_pl.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_pl.xtb
new file mode 100644
index 0000000..4519e3d
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_pl.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pl">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_pt-BR.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_pt-BR.xtb
new file mode 100644
index 0000000..e95eb56b
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_pt-BR.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-BR">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_pt-PT.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_pt-PT.xtb
new file mode 100644
index 0000000..1dcf557a
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_pt-PT.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-PT">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ro.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ro.xtb
new file mode 100644
index 0000000..9e43493
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ro.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ro">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ru.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ru.xtb
new file mode 100644
index 0000000..c4a621b
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ru.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ru">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sk.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sk.xtb
new file mode 100644
index 0000000..00750d31
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sk.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sk">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sl.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sl.xtb
new file mode 100644
index 0000000..489b7e46
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sl.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sl">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sr.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sr.xtb
new file mode 100644
index 0000000..38f6f35
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sr.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sr">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sv.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sv.xtb
new file mode 100644
index 0000000..ddea3dc
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sv.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sv">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sw.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sw.xtb
new file mode 100644
index 0000000..b7750886
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_sw.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sw">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ta.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ta.xtb
new file mode 100644
index 0000000..ef90687
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_ta.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ta">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_te.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_te.xtb
new file mode 100644
index 0000000..48c714b
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_te.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="te">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_th.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_th.xtb
new file mode 100644
index 0000000..fae31966
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_th.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="th">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_tr.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_tr.xtb
new file mode 100644
index 0000000..9a29951
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_tr.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="tr">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_uk.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_uk.xtb
new file mode 100644
index 0000000..f0db52c
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_uk.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="uk">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_vi.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_vi.xtb
new file mode 100644
index 0000000..b2957da
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_vi.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="vi">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_zh-CN.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_zh-CN.xtb
new file mode 100644
index 0000000..26e8b40
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_zh-CN.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-CN">
+</translationbundle>
diff --git a/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_zh-TW.xtb b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_zh-TW.xtb
new file mode 100644
index 0000000..935ef485
--- /dev/null
+++ b/chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings_zh-TW.xtb
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-TW">
+</translationbundle>
diff --git a/chrome/browser/resources/downloads/item.js b/chrome/browser/resources/downloads/item.js
index 516c3a7..921f573 100644
--- a/chrome/browser/resources/downloads/item.js
+++ b/chrome/browser/resources/downloads/item.js
@@ -307,14 +307,8 @@
 
       // Wait for dom-if to switch to true, in case the text has just changed
       // from empty.
-      // TODO (rbpotter): Remove this conditional when Polymer 2 migration is
-      // complete.
-      if (Polymer.DomIf) {
-        Polymer.RenderStatus.beforeNextRender(
-            this, () => this.toggleButtonClass_());
-      } else {
-        this.async(() => this.toggleButtonClass_());
-      }
+      Polymer.RenderStatus.beforeNextRender(
+          this, () => this.toggleButtonClass_());
     },
 
     /**
diff --git a/chrome/browser/resources/downloads/manager.js b/chrome/browser/resources/downloads/manager.js
index 8f409a5..2bbf5ae 100644
--- a/chrome/browser/resources/downloads/manager.js
+++ b/chrome/browser/resources/downloads/manager.js
@@ -102,12 +102,6 @@
         this.mojoEventTarget_.updateItem.addListener(
             this.updateItem_.bind(this)),
       ];
-
-      // TODO(aee): Remove this conditional when the Polymer 2 migration
-      // is completed. Polymer.DomIf exists in Polymer 2 and not in Polymer 1.
-      if (typeof Polymer.DomIf == 'undefined') {
-        this.$.downloadsList.preserveFocus = false;
-      }
     },
 
     /** @override */
@@ -323,19 +317,7 @@
       this.items_[index] = data;
       this.updateHideDates_(index, index);
 
-      // TODO(aee): Remove this conditional when the Polymer 2 migration
-      // is completed. Polymer.DomIf exists in Polymer 2 and not in Polymer 1.
-      if (Polymer.DomIf) {
-        this.notifyPath(`items_.${index}`);
-      } else {
-        this.notifySplices('items_', [{
-                             index: index,
-                             addedCount: 0,
-                             object: this.items_,
-                             type: 'splice',
-                             removed: [],
-                           }]);
-      }
+      this.notifyPath(`items_.${index}`);
       this.async(() => {
         const list = /** @type {!IronListElement} */ (this.$.downloadsList);
         list.updateSizeForIndex(index);
diff --git a/chrome/browser/resources/history/history.js b/chrome/browser/resources/history/history.js
index cf0f547..72403e4 100644
--- a/chrome/browser/resources/history/history.js
+++ b/chrome/browser/resources/history/history.js
@@ -22,13 +22,7 @@
 function waitForAppUpgrade() {
   if (!upgradePromise) {
     upgradePromise = new Promise(function(resolve, reject) {
-      // TODO(dpapad): Need to update this to work with Polymer 2.
-      if (window.Polymer && Polymer.isInstance &&
-          Polymer.isInstance($('history-app'))) {
-        resolve();
-      } else {
-        $('bundle').addEventListener('load', resolve);
-      }
+      $('bundle').addEventListener('load', resolve);
     });
   }
   return upgradePromise;
diff --git a/chrome/browser/resources/net_internals/chromeos_view.html b/chrome/browser/resources/net_internals/chromeos_view.html
index b3b55b90..ad1a965 100644
--- a/chrome/browser/resources/net_internals/chromeos_view.html
+++ b/chrome/browser/resources/net_internals/chromeos_view.html
@@ -47,9 +47,6 @@
                value="Cellular"
                id="chromeos-view-network-debugging-cellular">
         <input type="button"
-               value="WiMAX"
-               id="chromeos-view-network-debugging-wimax">
-        <input type="button"
                name="subsystem"
                value="None"
                id="chromeos-view-network-debugging-none">
diff --git a/chrome/browser/resources/net_internals/chromeos_view.js b/chrome/browser/resources/net_internals/chromeos_view.js
index 5999e6a..a83105a 100644
--- a/chrome/browser/resources/net_internals/chromeos_view.js
+++ b/chrome/browser/resources/net_internals/chromeos_view.js
@@ -187,9 +187,6 @@
     $(CrosView.DEBUG_CELLULAR_ID).addEventListener('click', function(event) {
       setNetworkDebugMode_('cellular');
     }, false);
-    $(CrosView.DEBUG_WIMAX_ID).addEventListener('click', function(event) {
-      setNetworkDebugMode_('wimax');
-    }, false);
     $(CrosView.DEBUG_NONE_ID).addEventListener('click', function(event) {
       setNetworkDebugMode_('none');
     }, false);
@@ -251,7 +248,6 @@
   CrosView.DEBUG_WIFI_ID = 'chromeos-view-network-debugging-wifi';
   CrosView.DEBUG_ETHERNET_ID = 'chromeos-view-network-debugging-ethernet';
   CrosView.DEBUG_CELLULAR_ID = 'chromeos-view-network-debugging-cellular';
-  CrosView.DEBUG_WIMAX_ID = 'chromeos-view-network-debugging-wimax';
   CrosView.DEBUG_NONE_ID = 'chromeos-view-network-debugging-none';
   CrosView.DEBUG_STATUS_ID = 'chromeos-view-network-debugging-status';
 
diff --git a/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js b/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js
index e357009..3970e0ff 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js
+++ b/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js
@@ -110,15 +110,9 @@
 
   /** @override */
   attached: function() {
-    // TODO (rbpotter): Remove this conditional when the migration to Polymer 2
-    // is completed.
-    if (Polymer.DomIf) {
-      Polymer.RenderStatus.beforeNextRender(this, () => {
-        this.updateExpandedStateAndFinishAnimations_();
-      });
-    } else {
+    Polymer.RenderStatus.beforeNextRender(this, () => {
       this.updateExpandedStateAndFinishAnimations_();
-    }
+    });
   },
 
   /**
diff --git a/chrome/browser/resources/print_preview/new/destination_settings.js b/chrome/browser/resources/print_preview/new/destination_settings.js
index 29cf07d0..0c7d7f1 100644
--- a/chrome/browser/resources/print_preview/new/destination_settings.js
+++ b/chrome/browser/resources/print_preview/new/destination_settings.js
@@ -466,17 +466,9 @@
       return;
     }
 
-    // TODO (rbpotter): Remove this conditional when the Polymer 2 migration
-    // is completed.
-    if (Polymer.DomIf) {
-      Polymer.RenderStatus.beforeNextRender(this.$.destinationSelect, () => {
-        this.$.destinationSelect.updateDestination();
-      });
-    } else {
-      this.$.destinationSelect.async(() => {
-        this.$.destinationSelect.updateDestination();
-      });
-    }
+    Polymer.RenderStatus.beforeNextRender(this.$.destinationSelect, () => {
+      this.$.destinationSelect.updateDestination();
+    });
   },
 });
 })();
diff --git a/chrome/browser/resources/search_header.css b/chrome/browser/resources/search_header.css
deleted file mode 100644
index 2974894..0000000
--- a/chrome/browser/resources/search_header.css
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Copyright 2014 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-/* This is a common file for pages that have a title and search box as their
- * header. This visually looks like:
- * _____________________________________________________________________________
- * |                                                                           |
- * |  I Am So Great!                                  [ Search greatness... ]  |
- * |___________________________________________________________________________|
- * | Summary (90235 things currently great)                      _Great links_ |
- *
- * The title expands to fill any space it needs and the search bar is locked to
- * the end of the header (e.g., right in LTR, left in RTL). */
-
-header,
-.summary {
-  min-width: 400px;
-}
-
-header {
-  align-items: center;
-  display: flex;
-  padding: 0 12px;
-}
-
-header h1 {
-  flex: 1;
-  /* TODO(dbeam): reconcile font/line-height/margin with chrome_shared.css */
-  font-size: 1.5em;
-  font-weight: normal;
-  line-height: 1;
-  margin: 15px 0;
-}
-
-header > :-webkit-any(form, input[type='search']) {
-  flex: none;
-}
-
-.summary {
-  background-color: rgb(235, 239, 249);
-  border-top: 1px solid rgb(156, 194, 239);
-  display: flex;
-  padding: 5px 10px;
-  white-space: nowrap;
-}
-
-.summary > * {
-  flex: none;
-}
-
-.summary > :first-child {
-  flex: 1;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
diff --git a/chrome/browser/resources/settings/autofill_page/autofill_section.js b/chrome/browser/resources/settings/autofill_page/autofill_section.js
index 423ae7f..530dcf0 100644
--- a/chrome/browser/resources/settings/autofill_page/autofill_section.js
+++ b/chrome/browser/resources/settings/autofill_page/autofill_section.js
@@ -160,11 +160,7 @@
    */
   onAddressMenuTap_: function(e) {
     const menuEvent = /** @type {!{model: !{item: !Object}}} */ (e);
-
-    // TODO(dpapad): The [dataHost][dataHost] workaround is only necessary for
-    // Polymer 1. Remove once migration to Polymer 2 has completed.
-    const item = Polymer.DomIf ? menuEvent.model.item :
-                                 menuEvent.model['dataHost']['dataHost'].item;
+    const item = menuEvent.model.item;
 
     // Copy item so dialog won't update model on cancel.
     this.activeAddress = /** @type {!chrome.autofillPrivate.AddressEntry} */ (
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.js b/chrome/browser/resources/settings/basic_page/basic_page.js
index 3082d22d..f407faf 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.js
+++ b/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -273,21 +273,15 @@
    * @private
    */
   advancedToggleExpandedChanged_: function() {
-    if (this.advancedToggleExpanded) {
-      // In Polymer2, async() does not wait long enough for layout to complete.
-      // Polymer.RenderStatus.beforeNextRender() must be used instead.
-      // TODO (rbpotter): Remove conditional when migration to Polymer 2 is
-      // completed.
-      if (Polymer.DomIf) {
-        Polymer.RenderStatus.beforeNextRender(this, () => {
-          this.$$('#advancedPageTemplate').get();
-        });
-      } else {
-        this.async(() => {
-          this.$$('#advancedPageTemplate').get();
-        });
-      }
+    if (!this.advancedToggleExpanded) {
+      return;
     }
+
+    // In Polymer2, async() does not wait long enough for layout to complete.
+    // Polymer.RenderStatus.beforeNextRender() must be used instead.
+    Polymer.RenderStatus.beforeNextRender(this, () => {
+      this.$$('#advancedPageTemplate').get();
+    });
   },
 
   advancedToggleClicked_: function() {
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
index cb850b8..ed6547fc 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
@@ -193,16 +193,6 @@
     this.saveScroll(this.$.pairedDevices);
     this.saveScroll(this.$.unpairedDevices);
 
-    // In Polymer 1, default values for |pairedDeviceList_| and
-    // |unpairedDeviceList_| might not have been set yet by the time
-    // |deviceList_| changes.
-    if (this.pairedDeviceList_ === undefined) {
-      this.pairedDeviceList_ = [];
-    }
-    if (this.unpairedDeviceList_ === undefined) {
-      this.unpairedDeviceList_ = [];
-    }
-
     this.pairedDeviceList_ = this.getUpdatedDeviceList_(
       this.pairedDeviceList_,
       this.deviceList_.filter(d => d.paired || d.connecting));
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.js b/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.js
index 5b79332..8799139 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.js
@@ -65,12 +65,7 @@
     },
 
     /** @private */
-    showingSubpage_: {
-      type: Boolean,
-      // TODO(dpapad): Initial value only needed for Polymer 1, remove once
-      // Polymer 2 migration is done.
-      value: false,
-    },
+    showingSubpage_: Boolean,
 
     toolbarSpinnerActive: {
       type: Boolean,
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.js b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.js
index 5cb70006..024e64d 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.js
@@ -271,21 +271,15 @@
    * @private
    */
   advancedToggleExpandedChanged_: function() {
-    if (this.advancedToggleExpanded) {
-      // In Polymer2, async() does not wait long enough for layout to complete.
-      // Polymer.RenderStatus.beforeNextRender() must be used instead.
-      // TODO (rbpotter): Remove conditional when migration to Polymer 2 is
-      // completed.
-      if (Polymer.DomIf) {
-        Polymer.RenderStatus.beforeNextRender(this, () => {
-          this.$$('#advancedPageTemplate').get();
-        });
-      } else {
-        this.async(() => {
-          this.$$('#advancedPageTemplate').get();
-        });
-      }
+    if (!this.advancedToggleExpanded) {
+      return;
     }
+
+    // In Polymer2, async() does not wait long enough for layout to complete.
+    // Polymer.RenderStatus.beforeNextRender() must be used instead.
+    Polymer.RenderStatus.beforeNextRender(this, () => {
+      this.$$('#advancedPageTemplate').get();
+    });
   },
 
   advancedToggleClicked_: function() {
diff --git a/chrome/browser/resources/settings/controls/settings_dropdown_menu.js b/chrome/browser/resources/settings/controls/settings_dropdown_menu.js
index 2c6f212..b4187b59 100644
--- a/chrome/browser/resources/settings/controls/settings_dropdown_menu.js
+++ b/chrome/browser/resources/settings/controls/settings_dropdown_menu.js
@@ -34,15 +34,9 @@
   properties: {
     /**
      * List of options for the drop-down menu.
-     * @type {?DropdownMenuOptionList}
+     * @type {!DropdownMenuOptionList}
      */
-    menuOptions: {
-      type: Array,
-      // TODO(dpapad): This seems unnecessary in Polymer 2, since any
-      // bindings/observers will execute anyway, even if this is undefined.
-      // Consider removing once migration is done.
-      value: null,
-    },
+    menuOptions: Array,
 
     /** Whether the dropdown menu should be disabled. */
     disabled: {
@@ -115,7 +109,7 @@
       return;
     }
 
-    if (this.menuOptions === null || !this.menuOptions.length) {
+    if (!this.menuOptions.length) {
       return;
     }
 
@@ -174,6 +168,6 @@
    */
   shouldDisableMenu_: function() {
     return this.disabled || this.isPrefEnforced() ||
-        this.menuOptions === null || this.menuOptions.length == 0;
+        this.menuOptions === undefined || this.menuOptions.length == 0;
   },
 });
diff --git a/chrome/browser/resources/settings/controls/settings_idle_load.js b/chrome/browser/resources/settings/controls/settings_idle_load.js
index 97d776a..21f1c0b 100644
--- a/chrome/browser/resources/settings/controls/settings_idle_load.js
+++ b/chrome/browser/resources/settings/controls/settings_idle_load.js
@@ -72,28 +72,6 @@
   },
 
   /**
-   * TODO(dpapad): Delete this method once migration to Polymer 2 has finished.
-   * @param {string} prop
-   * @param {Object} value
-   */
-  _forwardParentProp: function(prop, value) {
-    if (this.child_) {
-      this.child_._templateInstance[prop] = value;
-    }
-  },
-
-  /**
-   * TODO(dpapad): Delete this method once migration to Polymer 2 has finished.
-   * @param {string} path
-   * @param {Object} value
-   */
-  _forwardParentPath: function(path, value) {
-    if (this.child_) {
-      this.child_._templateInstance.notifyPath(path, value, true);
-    }
-  },
-
-  /**
    * @param {string} prop
    * @param {Object} value
    */
diff --git a/chrome/browser/resources/settings/page_visibility.js b/chrome/browser/resources/settings/page_visibility.js
index c475e67..19eb861 100644
--- a/chrome/browser/resources/settings/page_visibility.js
+++ b/chrome/browser/resources/settings/page_visibility.js
@@ -12,7 +12,7 @@
  *   appearance: (boolean|undefined|AppearancePageVisibility),
  *   autofill: (boolean|undefined),
  *   bluetooth: (boolean|undefined),
- *   dateTime: (boolean|undefined|DateTimePageVisibility),
+ *   dateTime: (boolean|undefined),
  *   defaultBrowser: (boolean|undefined),
  *   device: (boolean|undefined),
  *   downloads: (boolean|undefined|DownloadsPageVisibility),
@@ -39,13 +39,6 @@
 
 /**
  * @typedef {{
- *   timeZoneSelector: boolean,
- * }}
- */
-let DateTimePageVisibility;
-
-/**
- * @typedef {{
  *   googleDrive: boolean
  * }}
  */
@@ -101,6 +94,7 @@
       },
       device: showOSSettings,
       advancedSettings: true,
+      dateTime: showOSSettings,
       privacy: {
         searchPrediction: false,
         networkPrediction: false,
@@ -124,7 +118,7 @@
       onStartup: true,
       reset: true,
       appearance: {
-        setWallpaper: true,
+        setWallpaper: showOSSettings,
         setTheme: true,
         homeButton: true,
         bookmarksBar: true,
@@ -132,6 +126,7 @@
       },
       device: showOSSettings,
       advancedSettings: true,
+      dateTime: showOSSettings,
       privacy: {
         searchPrediction: true,
         networkPrediction: true,
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.js b/chrome/browser/resources/settings/settings_main/settings_main.js
index 28986af..bf40b02 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.js
+++ b/chrome/browser/resources/settings/settings_main/settings_main.js
@@ -65,12 +65,7 @@
     },
 
     /** @private */
-    showingSubpage_: {
-      type: Boolean,
-      // TODO(dpapad): Initial value only needed for Polymer 1, remove once
-      // Polymer 2 migration is done.
-      value: false,
-    },
+    showingSubpage_: Boolean,
 
     toolbarSpinnerActive: {
       type: Boolean,
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index 63e6257..d836c95 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -170,7 +170,7 @@
         <iron-selector id="subMenu" selectable="a" attr-for-selected="href"
             role="navigation" on-click="onLinkClick_">
 <if expr="chromeos">
-          <a href="/dateTime">
+          <a href="/dateTime" hidden="[[!pageVisibility.dateTime]]">
             <iron-icon icon="settings:access-time"></iron-icon>
             $i18n{dateTimePageTitle}
           </a>
diff --git a/chrome/browser/resources/settings/settings_page/BUILD.gn b/chrome/browser/resources/settings/settings_page/BUILD.gn
index b47302b..f6f20fe 100644
--- a/chrome/browser/resources/settings/settings_page/BUILD.gn
+++ b/chrome/browser/resources/settings/settings_page/BUILD.gn
@@ -33,6 +33,7 @@
     "//ui/webui/resources/js:util",
     "//ui/webui/resources/js/cr/ui:focus_without_ink",
   ]
+  externs_list = [ "$externs_path/pending.js" ]
 }
 
 js_library("settings_section") {
diff --git a/chrome/browser/resources/settings/settings_page/main_page_behavior.js b/chrome/browser/resources/settings/settings_page/main_page_behavior.js
index 761e23c..301eb75 100644
--- a/chrome/browser/resources/settings/settings_page/main_page_behavior.js
+++ b/chrome/browser/resources/settings/settings_page/main_page_behavior.js
@@ -160,11 +160,8 @@
         return Promise.resolve(section);
       }
 
-      // TODO(dpapad): Remove condition when Polymer 2 migration is complete.
       // The function to use to wait for <dom-if>s to render.
-      const waitFn = Polymer.DomIf ?
-          Polymer.RenderStatus.beforeNextRender.bind(null, this) :
-          requestAnimationFrame;
+      const waitFn = Polymer.RenderStatus.beforeNextRender.bind(null, this);
 
       return new Promise(resolve => {
         if (this.shouldExpandAdvanced_(route)) {
diff --git a/chrome/browser/resources/settings/settings_page/settings_animated_pages.js b/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
index 4f0bd12..e857c8d3a 100644
--- a/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
+++ b/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
@@ -189,25 +189,17 @@
    */
   ensureSubpageInstance_: function() {
     const routePath = settings.getCurrentRoute().path;
-    /* TODO(dpapad): Remove conditional logic once migration to Polymer 2 is
-     * completed. */
-    const domIf = this.querySelector(
-        (Polymer.DomIf ? 'dom-if' : 'template') +
-        `[route-path='${routePath}']`);
+    const domIf = this.querySelector(`dom-if[route-path='${routePath}']`);
 
-    // Nothing to do if the subpage isn't wrapped in a <dom-if>
-    // (or <template is="dom-if" for Poylmer 1) or the template is already
-    // stamped.
+    // Nothing to do if the subpage isn't wrapped in a <dom-if> or the template
+    // is already stamped.
     if (!domIf || domIf.if) {
       return;
     }
 
     // Set the subpage's id for use by neon-animated-pages.
-    // TODO(dpapad): Remove conditional logic once migration to Polymer 2 is
-    // completed.
-    const content = Polymer.DomIf ?
-        Polymer.DomIf._contentForTemplate(domIf.firstElementChild) :
-        /** @type {{_content: DocumentFragment}} */ (domIf)._content;
+    const content = Polymer.DomIf._contentForTemplate(
+        /** @type {!HTMLTemplateElement} */ (domIf.firstElementChild));
     const subpage = content.querySelector('settings-subpage');
     subpage.setAttribute('route-path', routePath);
 
diff --git a/chrome/browser/resources/usb_internals/descriptor_panel.js b/chrome/browser/resources/usb_internals/descriptor_panel.js
index 2f03c52..be52a08 100644
--- a/chrome/browser/resources/usb_internals/descriptor_panel.js
+++ b/chrome/browser/resources/usb_internals/descriptor_panel.js
@@ -10,16 +10,23 @@
 cr.define('descriptor_panel', function() {
   // Standard USB requests and descriptor types:
   const GET_DESCRIPTOR_REQUEST = 0x06;
+
   const DEVICE_DESCRIPTOR_TYPE = 0x01;
   const CONFIGURATION_DESCRIPTOR_TYPE = 0x02;
   const STRING_DESCRIPTOR_TYPE = 0x03;
   const INTERFACE_DESCRIPTOR_TYPE = 0x04;
   const ENDPOINT_DESCRIPTOR_TYPE = 0x05;
+  const BOS_DESCRIPTOR_TYPE = 0x0F;
+
+  const DEVICE_CAPABILITY_DESCRIPTOR_TYPE_PLATFORM = 0x05;
 
   const DEVICE_DESCRIPTOR_LENGTH = 18;
   const CONFIGURATION_DESCRIPTOR_LENGTH = 9;
   const INTERFACE_DESCRIPTOR_LENGTH = 9;
   const ENDPOINT_DESCRIPTOR_LENGTH = 7;
+  const BOS_DESCRIPTOR_LENGTH = 5;
+  const MAX_STRING_DESCRIPTOR_LENGTH = 0xFF;
+  const MAX_URL_DESCRIPTOR_LENGTH = 0xFF;
 
   const CONTROL_TRANSFER_TIMEOUT_MS = 2000;  // 2 seconds
 
@@ -27,6 +34,18 @@
   // https://docs.microsoft.com/en-us/windows/desktop/intl/language-identifier-constants-and-strings
   const LANGUAGE_CODE_EN_US = 0x0409;
 
+  // These constants are defined by the WebUSB specification:
+  // http://wicg.github.io/webusb/
+  const WEB_USB_DESCRIPTOR_LENGTH = 24;
+
+  const GET_URL_REQUEST = 0x02;
+
+  const WEB_USB_CAPABILITY_UUID = [
+    // Little-endian encoding of {3408b638-09a9-47a0-8bfd-a0768815b665}.
+    0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76,
+    0x88, 0x15, 0xB6, 0x65
+  ];
+
   class DescriptorPanel {
     /**
      * @param {!device.mojom.UsbDeviceInterface} usbDeviceProxy
@@ -105,8 +124,8 @@
         const item = customTreeItem(
             `${field.label}${field.formatter(rawData, offset)}`, className);
 
-        if (field.isIndex) {
-          this.renderIndexItem_(rawData[offset], item, field.label);
+        if (field.extraTreeItemFormatter) {
+          field.extraTreeItemFormatter(rawData, offset, item, field.label);
         }
 
         for (let i = 0; i < field.size; i++) {
@@ -128,11 +147,13 @@
      * Renders a get string descriptor button for the String Descriptor Index
      * field, and adds an autocomplete value to the index input area in string
      * descriptor panel.
-     * @param {number} index
-     * @param {cr.ui.TreeItem} item
+     * @param {!Uint8Array} rawData
+     * @param {number} offset
+     * @param {!cr.ui.TreeItem} item
      * @param {string} fieldLabel
      */
-    renderIndexItem_(index, item, fieldLabel) {
+    renderIndexItem_(rawData, offset, item, fieldLabel) {
+      const index = rawData[offset];
       if (index > 0) {
         if (!this.stringDescriptorPanel_.stringDescriptorIndexes.has(index)) {
           const optionElement = cr.doc.createElement('option');
@@ -165,7 +186,31 @@
     }
 
     /**
-     * Checks the if the status of a descriptor read indicates success.
+     * Renders a URL descriptor item for the URL Descriptor Index and
+     * adds it to the String Descriptor Index item.
+     * @param {!Uint8Array} rawData
+     * @param {number} offset
+     * @param {!cr.ui.TreeItem} item
+     * @param {string} fieldLabel Not used in this function, but used to match
+     *     other extraTreeItemFormatter.
+     */
+    async renderLandingPageItem_(rawData, offset, item, fieldLabel) {
+      // The second to last byte Byte is the vendor code used to query URL
+      // descriptor. Last byte is index of url descriptor. These are defined by
+      // the WebUSB specification: http://wicg.github.io/webusb/
+      const vendorCode = rawData[offset - 1];
+      const urlIndex = rawData[offset];
+      const url = await this.getUrlDescriptor_(vendorCode, urlIndex);
+
+      const landingPageItem = customTreeItem(url);
+      item.add(landingPageItem);
+
+      landingPageItem.querySelector('.tree-label')
+          .addEventListener('click', () => window.open(url, '_blank'));
+    }
+
+    /**
+     * Checks if the status of a descriptor read indicates success.
      * @param {number} status
      * @param {string} defaultMessage
      * @private
@@ -237,13 +282,10 @@
       usbControlTransferParams.request = GET_DESCRIPTOR_REQUEST;
       usbControlTransferParams.value = (DEVICE_DESCRIPTOR_TYPE << 8);
       usbControlTransferParams.index = 0;
-      const length = DEVICE_DESCRIPTOR_LENGTH;
-      const timeout = CONTROL_TRANSFER_TIMEOUT_MS;
-
-      await this.usbDeviceProxy_.open();
 
       const response = await this.usbDeviceProxy_.controlTransferIn(
-          usbControlTransferParams, length, timeout);
+          usbControlTransferParams, DEVICE_DESCRIPTOR_LENGTH,
+          CONTROL_TRANSFER_TIMEOUT_MS);
 
       this.checkDescriptorGetSuccess_(
           response.status, 'Failed to read the device descriptor.');
@@ -258,10 +300,13 @@
     async renderDeviceDescriptor() {
       let rawData;
       try {
+        await this.usbDeviceProxy_.open();
         rawData = await this.getDeviceDescriptor_();
       } catch (e) {
         // Stop rendering if failed to read the device descriptor.
         return;
+      } finally {
+        await this.usbDeviceProxy_.close();
       }
 
       const fields = [
@@ -319,19 +364,19 @@
           label: 'Manufacturer String Index: ',
           size: 1,
           formatter: formatByte,
-          isIndex: true,
+          extraTreeItemFormatter: this.renderIndexItem_.bind(this),
         },
         {
           label: 'Product String Index: ',
           size: 1,
           formatter: formatByte,
-          isIndex: true,
+          extraTreeItemFormatter: this.renderIndexItem_.bind(this),
         },
         {
           label: 'Serial Number Index: ',
           size: 1,
           formatter: formatByte,
-          isIndex: true,
+          extraTreeItemFormatter: this.renderIndexItem_.bind(this),
         },
         {
           label: 'Number of Configurations: ',
@@ -374,13 +419,10 @@
       usbControlTransferParams.request = GET_DESCRIPTOR_REQUEST;
       usbControlTransferParams.value = (CONFIGURATION_DESCRIPTOR_TYPE << 8);
       usbControlTransferParams.index = 0;
-      let length = CONFIGURATION_DESCRIPTOR_LENGTH;
-      const timeout = CONTROL_TRANSFER_TIMEOUT_MS;
-
-      await this.usbDeviceProxy_.open();
 
       let response = await this.usbDeviceProxy_.controlTransferIn(
-          usbControlTransferParams, length, timeout);
+          usbControlTransferParams, CONFIGURATION_DESCRIPTOR_LENGTH,
+          CONTROL_TRANSFER_TIMEOUT_MS);
 
       this.checkDescriptorGetSuccess_(
           response.status,
@@ -388,10 +430,10 @@
               'the total descriptor length.');
 
       const data = new DataView(new Uint8Array(response.data).buffer);
-      length = data.getUint16(2, true);
+      const length = data.getUint16(2, true);
       // Re-gets the data use the full length.
       response = await this.usbDeviceProxy_.controlTransferIn(
-          usbControlTransferParams, length, timeout);
+          usbControlTransferParams, length, CONTROL_TRANSFER_TIMEOUT_MS);
 
       this.checkDescriptorGetSuccess_(
           response.status,
@@ -407,10 +449,13 @@
     async renderConfigurationDescriptor() {
       let rawData;
       try {
+        await this.usbDeviceProxy_.open();
         rawData = await this.getConfigurationDescriptor_();
       } catch (e) {
         // Stop rendering if failed to read the configuration descriptor.
         return;
+      } finally {
+        await this.usbDeviceProxy_.close();
       }
 
       const fields = [
@@ -443,7 +488,7 @@
           label: 'Configuration String Index: ',
           size: 1,
           formatter: formatByte,
-          isIndex: true,
+          extraTreeItemFormatter: this.renderIndexItem_.bind(this),
         },
         {
           label: 'Attribute Bitmap: ',
@@ -481,8 +526,11 @@
       let indexUnknown = 0;
       let expectNumEndpoints = 0;
 
+      // Continue parsing while there are still unparsed interface, endpoint,
+      // or endpoint companion descriptors. Stop if accessing the descriptor
+      // type (rawData[offset + 1]) would cause us to read past the end of the
+      // buffer.
       while ((offset + 1) < rawData.length) {
-        // The descriptor length and type byte still exists.
         switch (rawData[offset + 1]) {
           case INTERFACE_DESCRIPTOR_TYPE:
             [offset, expectNumEndpoints] = this.renderInterfaceDescriptor_(
@@ -594,7 +642,7 @@
           label: 'Interface String Index: ',
           size: 1,
           formatter: formatByte,
-          isIndex: true,
+          extraTreeItemFormatter: this.renderIndexItem_.bind(this),
         },
       ];
 
@@ -757,13 +805,14 @@
       usbControlTransferParams.request = GET_DESCRIPTOR_REQUEST;
       usbControlTransferParams.value = (STRING_DESCRIPTOR_TYPE << 8);
       usbControlTransferParams.index = 0;
-      const length = 0xFF;
-      const timeout = CONTROL_TRANSFER_TIMEOUT_MS;
 
       await this.usbDeviceProxy_.open();
 
       const response = await this.usbDeviceProxy_.controlTransferIn(
-          usbControlTransferParams, length, timeout);
+          usbControlTransferParams, MAX_STRING_DESCRIPTOR_LENGTH,
+          CONTROL_TRANSFER_TIMEOUT_MS);
+
+      await this.usbDeviceProxy_.close();
 
       try {
         this.checkDescriptorGetSuccess_(
@@ -802,14 +851,12 @@
 
     /**
      * Gets string descriptor of current device with index and language code.
-     * @param {number}
-     * @param {number}
+     * @param {number} index
+     * @param {number} languageCode
      * @return {{languageCode:string,rawData:!Uint8Array}}
      * @private
      */
     async getStringDescriptorForLanguageCode_(index, languageCode) {
-      await this.usbDeviceProxy_.open();
-
       /** @type {device.mojom.UsbControlTransferParams} */
       const usbControlTransferParams = {};
       usbControlTransferParams.type =
@@ -817,15 +864,14 @@
       usbControlTransferParams.recipient =
           device.mojom.UsbControlTransferRecipient.DEVICE;
       usbControlTransferParams.request = GET_DESCRIPTOR_REQUEST;
-      const length = 0xFF;
-      const timeout = CONTROL_TRANSFER_TIMEOUT_MS;
 
       usbControlTransferParams.index = languageCode;
 
       usbControlTransferParams.value = (STRING_DESCRIPTOR_TYPE << 8) | index;
 
       const response = await this.usbDeviceProxy_.controlTransferIn(
-          usbControlTransferParams, length, timeout);
+          usbControlTransferParams, MAX_DESCRIPTOR_LENGTH,
+          CONTROL_TRANSFER_TIMEOUT_MS);
 
       const languageCodeStr = parseLanguageCode(languageCode);
       this.checkDescriptorGetSuccess_(
@@ -851,11 +897,14 @@
 
       let rawDataMap;
       try {
+        await this.usbDeviceProxy_.open();
         rawDataMap =
             await this.getStringDescriptorForLanguageCode_(index, languageCode);
       } catch (e) {
         // Stop rendering if failed to read the string descriptor.
         return;
+      } finally {
+        await this.usbDeviceProxy_.close();
       }
 
       const languageStr = rawDataMap.languageCodeStr;
@@ -897,12 +946,14 @@
       /** @type {!HTMLElement} */
       const rawDataByteElement = displayElement.rawDataByteElement;
 
+      // The first two elements of rawData are length and descriptor type.
+      const stringDescriptor = decodeUtf16Array(rawData.slice(2));
       const stringDescriptorItem = customTreeItem(
-          `${languageStr}: ${decodeArray(rawData)}`,
+          `${languageStr}: ${stringDescriptor}`,
           `descriptor-string-${index}-language-code-${languageStr}`);
       rawDataTreeRoot.add(stringDescriptorItem);
       if (treeItem) {
-        treeItem.add(customTreeItem(`${languageStr}: ${decodeArray(rawData)}`));
+        treeItem.add(customTreeItem(`${languageStr}: ${stringDescriptor}`));
         treeItem.expanded = true;
       }
 
@@ -1007,6 +1058,333 @@
       }
       return true;
     }
+
+    /**
+     * Gets the Binary device Object Store (BOS) descriptor of the current
+     * device, which contains the WebUSB descriptor and Microsoft OS 2.0
+     * descriptor.
+     * @return {!Uint8Array}
+     * @private
+     */
+    async getBosDescriptor_() {
+      /** @type {device.mojom.UsbControlTransferParams} */
+      const usbControlTransferParams = {};
+      usbControlTransferParams.type =
+          device.mojom.UsbControlTransferType.STANDARD;
+      usbControlTransferParams.recipient =
+          device.mojom.UsbControlTransferRecipient.DEVICE;
+      usbControlTransferParams.request = GET_DESCRIPTOR_REQUEST;
+      usbControlTransferParams.value = (BOS_DESCRIPTOR_TYPE << 8);
+      usbControlTransferParams.index = 0;
+
+      let response = await this.usbDeviceProxy_.controlTransferIn(
+          usbControlTransferParams, BOS_DESCRIPTOR_LENGTH,
+          CONTROL_TRANSFER_TIMEOUT_MS);
+
+      this.checkDescriptorGetSuccess_(
+          response.status,
+          'Failed to read the device BOS descriptor to determine ' +
+              'the total descriptor length.');
+
+      const data = new DataView(new Uint8Array(response.data).buffer);
+      const length = data.getUint16(2, true);
+
+      // Re-gets the data use the full length.
+      response = await this.usbDeviceProxy_.controlTransferIn(
+          usbControlTransferParams, length, CONTROL_TRANSFER_TIMEOUT_MS);
+
+      this.checkDescriptorGetSuccess_(
+          response.status, 'Failed to read the complete BOS descriptor.');
+
+      return new Uint8Array(response.data);
+    }
+
+    /**
+     * Renders a view to display BOS descriptor hex data in both tree view
+     * and raw form.
+     */
+    async renderBosDescriptor() {
+      let rawData;
+      try {
+        await this.usbDeviceProxy_.open();
+        rawData = await this.getBosDescriptor_();
+      } catch (e) {
+        // Stop rendering if failed to read the BOS descriptor.
+        return;
+      } finally {
+        await this.usbDeviceProxy_.close();
+      }
+
+      const fields = [
+        {
+          'label': 'Length: ',
+          'size': 1,
+          'formatter': formatByte,
+        },
+        {
+          'label': 'Descriptor Type: ',
+          'size': 1,
+          'formatter': formatDescriptorType,
+        },
+        {
+          'label': 'Total Length: ',
+          'size': 2,
+          'formatter': formatShort,
+        },
+        {
+          'label': 'Number of Device Capability Descriptors: ',
+          'size': 1,
+          'formatter': formatByte,
+        },
+      ];
+
+      const displayElement = this.addNewDescriptorDisplayElement_();
+      /** @type {!cr.ui.Tree} */
+      const rawDataTreeRoot = displayElement.rawDataTreeRoot;
+      /** @type {!HTMLElement} */
+      const rawDataByteElement = displayElement.rawDataByteElement;
+
+      renderRawDataBytes(rawDataByteElement, rawData);
+
+      let offset = 0;
+      offset = this.renderRawDataTree_(
+          rawDataTreeRoot, rawDataByteElement, fields, rawData, offset);
+
+      if (offset != BOS_DESCRIPTOR_LENGTH) {
+        this.showError_(
+            'An error occurred while rendering BOS descriptor header.');
+      }
+
+      let indexWebUsb = 0;
+      let indexUnknownBos = 0;
+      // Continue parsing while there are still unparsed device capability
+      // descriptors. Stop if accessing the device capability type
+      // (rawData[offset + 2]) would cause us to read past the end of the
+      // buffer.
+      while ((offset + 2) < rawData.length) {
+        switch (rawData[offset + 2]) {
+          case DEVICE_CAPABILITY_DESCRIPTOR_TYPE_PLATFORM:
+            if (isSameUUID(rawData, offset, WEB_USB_CAPABILITY_UUID)) {
+              offset = this.renderWebUsbDescriptor_(
+                  rawDataTreeRoot, rawDataByteElement, rawData, offset,
+                  indexWebUsb);
+              indexWebUsb++;
+              break;
+            }
+          default:
+            offset = this.renderUnknownBosDescriptor_(
+                rawDataTreeRoot, rawDataByteElement, rawData, offset,
+                indexUnknownBos);
+            indexUnknownBos++;
+        }
+      }
+
+      const expectNumBosDescriptors = rawData[5];
+      const encounteredNumBosDescriptors = indexWebUsb + indexUnknownBos;
+      if (encounteredNumBosDescriptors === expectNumBosDescriptors) {
+        this.showError_(`Expected to find \
+            ${expectNumBosDescriptors} interface descriptors \
+            but only encountered ${encounteredNumBosDescriptors}.`);
+      }
+
+      assert(
+          offset === rawData.length, 'Complete BOS Descriptor Rendering Error');
+
+      addMappingAction(rawDataTreeRoot, rawDataByteElement);
+    }
+
+    /**
+     * Renders a tree item to display WebUSB descriptor at index
+     * indexWebUsb.
+     * @param {!cr.ui.Tree} rawDataTreeRoot
+     * @param {!HTMLElement} rawDataByteElement
+     * @param {!Uint8Array} rawData
+     * @param {number} originalOffset
+     * @param {number} indexWebUsb
+     * @return {!Array<number>}
+     * @private
+     */
+    renderWebUsbDescriptor_(
+        rawDataTreeRoot, rawDataByteElement, rawData, originalOffset,
+        indexWebUsb) {
+      if (originalOffset + WEB_USB_DESCRIPTOR_LENGTH > rawData.length) {
+        this.showError_(`Failed to read the WebUSB descriptor\
+          at index ${indexWebUsb}.`);
+      }
+
+      const webUsbItem = customTreeItem(
+          `WebUSB Descriptor`, `descriptor-webusb-${indexWebUsb}`);
+      rawDataTreeRoot.add(webUsbItem);
+
+      const fields = [
+        {
+          label: 'Length: ',
+          size: 1,
+          formatter: formatByte,
+        },
+        {
+          label: 'Descriptor Type: ',
+          size: 1,
+          formatter: formatDescriptorType,
+        },
+        {
+          label: 'Device Capability Descriptor Type: ',
+          size: 1,
+          formatter: formatByte,
+        },
+        {
+          label: 'Reserved (Should be Zero): ',
+          size: 1,
+          formatter: formatByte,
+        },
+        {
+          label: 'UUID: ',
+          size: 16,
+          formatter: formatUUID,
+        },
+        {
+          label: 'Protocol version supported (should be 1.0.0): ',
+          size: 2,
+          formatter: formatUsbVersion,
+        },
+        {
+          label: 'Vendor Code: ',
+          size: 1,
+          formatter: formatByte,
+        },
+        {
+          label: 'Landing Page: ',
+          size: 1,
+          formatter: formatByte,
+          extraTreeItemFormatter: this.renderLandingPageItem_.bind(this),
+        },
+      ];
+
+      let offset = originalOffset;
+
+      offset = this.renderRawDataTree_(
+          webUsbItem, rawDataByteElement, fields, rawData, offset,
+          `descriptor-webusb-${indexWebUsb}`);
+
+      if (offset != originalOffset + WEB_USB_DESCRIPTOR_LENGTH) {
+        this.showError_(
+            `An error occurred while rendering WebUSB descriptor at \
+            index ${indexWebUsb}.`);
+      }
+
+      return offset;
+    }
+
+    /**
+     * Renders a tree item to display unknown BOS descriptor at indexUnknownBos
+     * @param {!cr.ui.Tree} rawDataTreeRoot
+     * @param {!HTMLElement} rawDataByteElement
+     * @param {!Uint8Array} rawData
+     * @param {number} originalOffset
+     * @param {number} indexUnknownBos
+     * @return {!Array<number>}
+     * @private
+     */
+    renderUnknownBosDescriptor_(
+        rawDataTreeRoot, rawDataByteElement, rawData, originalOffset,
+        indexUnknownBos) {
+      const length = rawData[originalOffset];
+
+      const unknownBosItem = customTreeItem(
+          `Unknown BOS Descriptor`, `descriptor-unknownbos-${indexUnknownBos}`);
+      rawDataTreeRoot.add(unknownBosItem);
+
+      const fields = [
+        {
+          label: 'Length: ',
+          size: 1,
+          formatter: formatByte,
+        },
+        {
+          label: 'Descriptor Type: ',
+          size: 1,
+          formatter: formatDescriptorType,
+        },
+        {
+          label: 'Device Capability Descriptor Type: ',
+          size: 1,
+          formatter: formatByte,
+        },
+      ];
+
+      let offset = originalOffset;
+      offset = this.renderRawDataTree_(
+          unknownBosItem, rawDataByteElement, fields, rawData, offset,
+          `descriptor-unknownbos-${indexUnknownBos}`);
+
+      const rawDataByteElements = rawDataByteElement.querySelectorAll('span');
+
+      for (; offset < originalOffset + length; offset++) {
+        rawDataByteElements[offset].classList.add(`field-offset-${offset}`);
+        rawDataByteElements[offset].classList.add(
+            `descriptor-unknownbos-${indexUnknownBos}`);
+      }
+
+      return originalOffset + length;
+    }
+
+    /**
+     * Gets the URL Descriptor, and returns the parsed URL.
+     * @param {number} vendorCode
+     * @param {number} urlIndex
+     * @return {string}
+     * @private
+     */
+    async getUrlDescriptor_(vendorCode, urlIndex) {
+      /** @type {device.mojom.UsbControlTransferParams} */
+      const usbControlTransferParams = {};
+      usbControlTransferParams.recipient =
+          device.mojom.UsbControlTransferRecipient.DEVICE;
+      // These constants are defined by the WebUSB specification:
+      // http://wicg.github.io/webusb/
+      usbControlTransferParams.type =
+          device.mojom.UsbControlTransferType.VENDOR;
+      usbControlTransferParams.request = vendorCode;
+      usbControlTransferParams.value = urlIndex;
+      usbControlTransferParams.index = GET_URL_REQUEST;
+
+      await this.usbDeviceProxy_.open();
+
+      // Gets the URL descriptor.
+      const urlResponse = await this.usbDeviceProxy_.controlTransferIn(
+          usbControlTransferParams, MAX_URL_DESCRIPTOR_LENGTH,
+          CONTROL_TRANSFER_TIMEOUT_MS);
+
+      await this.usbDeviceProxy_.close();
+
+      try {
+        this.checkDescriptorGetSuccess_(
+            urlResponse.status, 'Failed to read the device URL descriptor.');
+      } catch (e) {
+        // Stops parsing to string format URL.
+        return;
+      }
+
+      let urlDescriptor;
+      // URL Prefixes are defined by Chapter 4.3.1 of the WebUSB specification:
+      // http://wicg.github.io/webusb/
+      switch (urlResponse.data[2]) {
+        case 0:
+          urlDescriptor = 'http://';
+          break;
+        case 1:
+          urlDescriptor = 'https://';
+          break;
+        case 255:
+        default:
+          urlDescriptor = '';
+      }
+      // The first three elements of urlResponse.data are length, descriptor
+      // type and URL scheme prefix.
+      urlDescriptor +=
+          decodeUtf8Array(new Uint8Array(urlResponse.data.slice(3)));
+      return urlDescriptor;
+    }
   }
 
   /**
@@ -1148,16 +1526,28 @@
    * @param {!Uint8Array} arr
    * @return {string}
    */
-  function decodeArray(arr) {
+  function decodeUtf16Array(arr) {
     let str = '';
-    // The first two elements are length and descriptor type.
-    for (let i = 2; i < arr.length; i += 2) {
+    for (let i = 0; i < arr.length; i += 2) {
       str += formatLetter(arr, i);
     }
     return str;
   }
 
   /**
+   * Parses UTF-8 array to string.
+   * @param {!Uint8Array} arr
+   * @return {string}
+   */
+  function decodeUtf8Array(arr) {
+    let str = '';
+    for (let i = 0; i < arr.length; i++) {
+      str += String.fromCodePoint(arr[i]);
+    }
+    return str;
+  }
+
+  /**
    * Parses one byte to decimal number string.
    * @param {!Uint8Array} rawData
    * @param {number} offset
@@ -1242,6 +1632,38 @@
   }
 
   /**
+   * Parses UUID field.
+   * @param {!Uint8Array} rawData
+   * @param {number} offset
+   * @return {string}
+   */
+  function formatUUID(rawData, offset) {
+    // UUID is 16 bytes (Section 9.6.2.4 of Universal Serial Bus 3.1
+    // Specification).
+    // Additional reference: IETF RFC 4122. https://tools.ietf.org/html/rfc4122
+    let uuidStr = '';
+    const data = new DataView(rawData.buffer);
+
+    uuidStr += toHex(data.getUint32(offset, true), 8);
+    uuidStr += '-';
+    uuidStr += toHex(data.getUint16(offset + 4, true), 4);
+    uuidStr += '-';
+    uuidStr += toHex(data.getUint16(offset + 6, true), 4);
+    uuidStr += '-';
+    uuidStr += toHex(data.getUint8(offset + 8), 2);
+    uuidStr += toHex(data.getUint8(offset + 9), 2);
+    uuidStr += '-';
+    uuidStr += toHex(data.getUint8(offset + 10), 2);
+    uuidStr += toHex(data.getUint8(offset + 11), 2);
+    uuidStr += toHex(data.getUint8(offset + 12), 2);
+    uuidStr += toHex(data.getUint8(offset + 13), 2);
+    uuidStr += toHex(data.getUint8(offset + 14), 2);
+    uuidStr += toHex(data.getUint8(offset + 15), 2);
+
+    return uuidStr;
+  }
+
+  /**
    * Parses language code to readable language name.
    * @param {number} languageCode
    * @return {string}
@@ -1255,6 +1677,27 @@
     }
   }
 
+  /**
+   * Checks if two UUIDs are same.
+   * @param {!Uint8Array} rawData
+   * @param {number} offset
+   * @param {!Array<number>} uuidArr
+   */
+  function isSameUUID(rawData, offset, uuidArr) {
+    // Validate the Platform Capability Descriptor
+    if (offset + 20 > rawData.length) {
+      return false;
+    }
+    // UUID is from index 4 to index 19 (Section 9.6.2.4 of Universal Serial
+    // Bus 3.1 Specification).
+    for (const [i, num] of rawData.slice(offset + 4, offset + 20).entries()) {
+      if (num !== uuidArr[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   return {
     DescriptorPanel,
   };
diff --git a/chrome/browser/resources/usb_internals/devices_page.js b/chrome/browser/resources/usb_internals/devices_page.js
index e09e3af..a218d88 100644
--- a/chrome/browser/resources/usb_internals/devices_page.js
+++ b/chrome/browser/resources/usb_internals/devices_page.js
@@ -195,6 +195,23 @@
         }
       });
 
+      const getBosDescriptorButton =
+          tabPanelClone.querySelector('#bos-descriptor-button');
+      const bosDescriptorElement =
+          tabPanelClone.querySelector('.bos-descriptor-panel');
+      const bosDescriptorPanel = new descriptor_panel.DescriptorPanel(
+          usbDeviceProxy, bosDescriptorElement);
+      getBosDescriptorButton.addEventListener('click', () => {
+        bosDescriptorElement.hidden = !bosDescriptorElement.hidden;
+
+        // Clear the panel before rendering new data.
+        bosDescriptorPanel.clearView();
+
+        if (!bosDescriptorElement.hidden) {
+          bosDescriptorPanel.renderBosDescriptor();
+        }
+      });
+
       tabPanels.appendChild(tabPanelClone);
       cr.ui.decorate('tabpanel', cr.ui.TabPanel);
     }
diff --git a/chrome/browser/resources/usb_internals/usb_internals.css b/chrome/browser/resources/usb_internals/usb_internals.css
index 2dc7995..42957da 100644
--- a/chrome/browser/resources/usb_internals/usb_internals.css
+++ b/chrome/browser/resources/usb_internals/usb_internals.css
@@ -3,12 +3,12 @@
  * found in the LICENSE file.
  */
 
- tabs {
-   position: sticky;
-   top: 0;
-   /* selected treeItem is 2 */
-   z-index: 3;
- }
+tabs {
+  position: sticky;
+  top: 0;
+  /* selected treeItem is 2 */
+  z-index: 3;
+}
 
 /* Devices Tab */
 table.styled-table {
@@ -106,6 +106,7 @@
 }
 
 #raw-data-byte-view div span {
+  font-family: monospace;
   padding-inline-end: .5em;
   padding-inline-start: .5em;
 }
diff --git a/chrome/browser/resources/usb_internals/usb_internals.html b/chrome/browser/resources/usb_internals/usb_internals.html
index ddc0fdb..66cf6a6 100644
--- a/chrome/browser/resources/usb_internals/usb_internals.html
+++ b/chrome/browser/resources/usb_internals/usb_internals.html
@@ -152,14 +152,20 @@
         <button id="string-descriptor-button">Get String Descriptor</button>
       </div>
       <div class="string-descriptor-panel" hidden>
-        String Descriptor Index: 
+        String Descriptor Index:
         <input id="index-input" type="number" min="1" list="indexes">
         <datalist id="indexes"></datalist>
-        Language Code: 
+        Language Code:
         <input id="language-code-input" list="languages">
         <datalist id="languages"></datalist>
         <button>GET</button>
       </div>
+      <div class="descriptor-button">
+        <button id="bos-descriptor-button">
+          Get WebUSB & Microsoft OS 2.0 Descriptors
+        </button>
+      </div>
+      <div class="bos-descriptor-panel" hidden></div>
     </tabpanel>
   </template>
 
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/nux_ntp_background.js b/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/nux_ntp_background.js
index 79cb40f..99e37a65 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/nux_ntp_background.js
+++ b/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/nux_ntp_background.js
@@ -180,7 +180,7 @@
       direction *= -1;  // Reverse direction if RTL.
     }
 
-    const buttons = this.root.querySelectorAll('.ntp-background-grid-button');
+    const buttons = this.root.querySelectorAll('.option');
     const targetIndex = Array.prototype.indexOf.call(buttons, element);
 
     const oldFocus = buttons[targetIndex];
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index 2a537e7..8b2c60fc 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -32,7 +32,6 @@
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
-#include "chrome/browser/ui/dark_mode_observer.h"
 #include "chrome/browser/ui/webui/favicon_source.h"
 #include "chrome/browser/ui/webui/theme_source.h"
 #include "chrome/common/chrome_paths.h"
@@ -53,6 +52,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/url_data_source.h"
 #include "ui/gfx/color_utils.h"
+#include "ui/native_theme/dark_mode_observer.h"
 
 namespace {
 
@@ -761,7 +761,7 @@
 }
 
 void InstantService::CreateDarkModeObserver(ui::NativeTheme* theme) {
-  dark_mode_observer_ = std::make_unique<DarkModeObserver>(
+  dark_mode_observer_ = std::make_unique<ui::DarkModeObserver>(
       theme, base::BindRepeating(&InstantService::OnDarkModeChanged,
                                  weak_ptr_factory_.GetWeakPtr()));
   dark_mode_observer_->Start();
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index 83cf546..319bab81 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -32,7 +32,6 @@
 #error "Instant is only used on desktop";
 #endif
 
-class DarkModeObserver;
 class InstantIOContext;
 class InstantServiceObserver;
 class NtpBackgroundService;
@@ -44,6 +43,10 @@
 class RenderProcessHost;
 }  // namespace content
 
+namespace ui {
+class DarkModeObserver;
+}  // namespace ui
+
 // Tracks render process host IDs that are associated with Instant, i.e.
 // processes that are used to render an NTP. Also responsible for keeping
 // necessary information (most visited tiles and theme info) updated in those
@@ -254,7 +257,7 @@
   PrefService* pref_service_;
 
   // Keeps track of any changes to system dark mode.
-  std::unique_ptr<DarkModeObserver> dark_mode_observer_;
+  std::unique_ptr<ui::DarkModeObserver> dark_mode_observer_;
 
   NtpBackgroundService* background_service_;
 
diff --git a/chrome/browser/sync/test/integration/sync_auth_test.cc b/chrome/browser/sync/test/integration/sync_auth_test.cc
index 49d5c79..12da831 100644
--- a/chrome/browser/sync/test/integration/sync_auth_test.cc
+++ b/chrome/browser/sync/test/integration/sync_auth_test.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
 #include "components/sync/driver/profile_sync_service.h"
+#include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/driver/sync_token_status.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "net/http/http_status_code.h"
@@ -341,14 +342,22 @@
   // Enter the "Sync paused" state.
   GetClient(0)->EnterSyncPausedStateForPrimaryAccount();
   ASSERT_TRUE(GetSyncService(0)->GetAuthError().IsPersistentError());
-  ASSERT_TRUE(AttemptToTriggerAuthError());
 
-  // Pausing sync may issue a reconfiguration, so wait until it finishes.
-  SyncTransportActiveChecker(GetSyncService(0)).Wait();
+  if (base::FeatureList::IsEnabled(switches::kStopSyncInPausedState)) {
+    // Sync should have shut itself down.
+    EXPECT_EQ(GetSyncService(0)->GetTransportState(),
+              syncer::SyncService::TransportState::DISABLED);
+    EXPECT_TRUE(GetSyncService(0)->HasDisableReason(
+        syncer::SyncService::DISABLE_REASON_PAUSED));
+  } else {
+    ASSERT_TRUE(AttemptToTriggerAuthError());
 
-  // While Sync itself is still considered active, the active data types should
-  // now be empty.
-  EXPECT_TRUE(GetSyncService(0)->IsSyncFeatureActive());
+    // Pausing sync may issue a reconfiguration, so wait until it finishes.
+    SyncTransportActiveChecker(GetSyncService(0)).Wait();
+  }
+
+  // The active data types should now be empty.
+  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Empty());
 
   // Clear the "Sync paused" state again.
   GetClient(0)->ExitSyncPausedStateForPrimaryAccount();
@@ -357,8 +366,13 @@
   NoAuthErrorChecker(GetSyncService(0)).Wait();
   ASSERT_FALSE(GetSyncService(0)->GetAuthError().IsPersistentError());
 
-  // Resuming sync could issue a reconfiguration, so wait until it finishes.
-  SyncTransportActiveChecker(GetSyncService(0)).Wait();
+  if (base::FeatureList::IsEnabled(switches::kStopSyncInPausedState)) {
+    // Once the auth error is gone, wait for Sync to start up again.
+    GetClient(0)->AwaitSyncSetupCompletion();
+  } else {
+    // Resuming sync could issue a reconfiguration, so wait until it finishes.
+    SyncTransportActiveChecker(GetSyncService(0)).Wait();
+  }
 
   // Now the active data types should be back.
   EXPECT_TRUE(GetSyncService(0)->IsSyncFeatureActive());
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 204949b..c40016d 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
+#include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -694,10 +695,14 @@
 }
 
 void SyncTest::SetupSyncNoWaitingForCompletion() {
-  SetupSyncInternal(/*wait_for_completion=*/false);
+  SetupSyncInternal(/*setup_mode=*/NO_WAITING);
 }
 
-void SyncTest::SetupSyncInternal(bool wait_for_completion) {
+void SyncTest::SetupSyncOneClientAfterAnother() {
+  SetupSyncInternal(/*setup_mode=*/WAIT_FOR_COMMITS_TO_COMPLETE);
+}
+
+void SyncTest::SetupSyncInternal(SetupSyncMode setup_mode) {
   // Create sync profiles and clients if they haven't already been created.
   if (profiles_.empty()) {
     if (!SetupClients()) {
@@ -747,18 +752,29 @@
           syncer::UserSelectableTypeSet::All()))
           << "SetupSync() failed.";
     }
-    if (wait_for_completion) {
-      // It's important to wait for each client before setting up the next one,
-      // otherwise multi-client tests get flaky.
-      // TODO(tschumann): It would be nice to figure out why.
-      client->AwaitSyncSetupCompletion();
+
+    // It's important to wait for each client before setting up the next one,
+    // otherwise multi-client tests get flaky.
+    // TODO(crbug.com/956043): It would be nice to figure out why.
+    switch (setup_mode) {
+      case NO_WAITING:
+        break;
+      case WAIT_FOR_SYNC_SETUP_TO_COMPLETE:
+        client->AwaitSyncSetupCompletion();
+        break;
+      case WAIT_FOR_COMMITS_TO_COMPLETE:
+        DCHECK(TestUsesSelfNotifications())
+            << "We need that for the UpdatedProgressMarkerChecker";
+        UpdatedProgressMarkerChecker checker(GetSyncService(client_index));
+        checker.Wait();
+        break;
     }
   }
 }
 
 bool SyncTest::SetupSync() {
   base::ScopedAllowBlockingForTesting allow_blocking;
-  SetupSyncInternal(/*wait_for_completion=*/true);
+  SetupSyncInternal(/*setup_mode=*/WAIT_FOR_SYNC_SETUP_TO_COMPLETE);
 
   // Because clients may modify sync data as part of startup (for example
   // local session-releated data is rewritten), we need to ensure all
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h
index 543f356..6aecfa77 100644
--- a/chrome/browser/sync/test/integration/sync_test.h
+++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -160,6 +160,13 @@
   // Like SetupSync() but does not wait for the clients to be ready to sync.
   void SetupSyncNoWaitingForCompletion();
 
+  // Like SetupSync() but does wait for commits to complete before proceeding to
+  // another client.
+  // TODO(crbug.com/956043): Investigate deeper why such sequential setup is
+  // needed by some tests and why using SetupSync() instead is causing
+  // flakiness. Ideally get rid of this function.
+  void SetupSyncOneClientAfterAnother();
+
   // Sets whether or not the sync clients in this test should respond to
   // notifications of their own commits.  Real sync clients do not do this, but
   // many test assertions require this behavior.
@@ -267,6 +274,11 @@
   network::TestURLLoaderFactory test_url_loader_factory_;
 
  private:
+  enum SetupSyncMode {
+    NO_WAITING,
+    WAIT_FOR_SYNC_SETUP_TO_COMPLETE,
+    WAIT_FOR_COMMITS_TO_COMPLETE
+  };
   // Handles Profile creation for given index. Profile's path and type is
   // determined at runtime based on server type.
   bool CreateProfile(int index);
@@ -327,7 +339,7 @@
   void InitializeInvalidations(int index);
 
   // Internal routine for setting up sync.
-  void SetupSyncInternal(bool wait_for_completion);
+  void SetupSyncInternal(SetupSyncMode setup_mode);
 
   // GAIA account used by the test case.
   std::string username_;
diff --git a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
index 7710d78f..f1a81a4 100644
--- a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
@@ -148,7 +148,10 @@
 
   base::HistogramTester histograms;
 
-  ASSERT_TRUE(SetupSync());
+  // Commit sequentially to make sure there is no race condition.
+  SetupSyncOneClientAfterAnother();
+  EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
+
   ASSERT_EQ(2U, GetAllAutoFillProfiles(0).size());
 
   // The order of events is roughly: First client (whichever that happens to be)
@@ -218,7 +221,8 @@
 
   AddProfile(0, profile0);
   AddProfile(1, profile1);
-  ASSERT_TRUE(SetupSync());
+  // Commit sequentially to make sure there is no race condition.
+  SetupSyncOneClientAfterAnother();
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
 
   EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
@@ -330,8 +334,8 @@
   ASSERT_NE(GetAllAutoFillProfiles(0)[0]->guid(),
             GetAllAutoFillProfiles(1)[0]->guid());
 
-  // Wait for the sync to happen.
-  ASSERT_TRUE(SetupSync());
+  // Commit sequentially to make sure there is no race condition.
+  SetupSyncOneClientAfterAnother();
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
 
   // Make sure that both clients have one profile.
diff --git a/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc b/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
index 0b1edb5..040c56ce 100644
--- a/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
@@ -43,7 +43,6 @@
 const char kValue1[] = "value1";
 const char kValue2[] = "value2";
 const char kValue3[] = "value3";
-const char kValue4[] = "value4";
 const char* kPassphrase = "12345";
 
 // A ChromeSyncClient that provides a ModelTypeControllerDelegate for
@@ -339,10 +338,8 @@
   ASSERT_TRUE(SetupSync());
   TestModelTypeSyncBridge* model0 = GetModelTypeSyncBridge(0);
   TestModelTypeSyncBridge* model1 = GetModelTypeSyncBridge(1);
-  model0->SetConflictResolution(ConflictResolution::UseNew(
-      FakeModelTypeSyncBridge::GenerateEntityData(kKey1, kValue4)));
-  model1->SetConflictResolution(ConflictResolution::UseNew(
-      FakeModelTypeSyncBridge::GenerateEntityData(kKey1, kValue4)));
+  model0->SetConflictResolution(ConflictResolution::kUseRemote);
+  model1->SetConflictResolution(ConflictResolution::kUseRemote);
 
   // Write initial value and wait for it to sync to the other client.
   model0->WriteItem(kKey1, kValue1);
@@ -363,14 +360,11 @@
   ASSERT_TRUE(ServerCountMatchStatusChecker(syncer::PREFERENCES, 2).Wait());
 
   // Trigger sync cycle on client 0 by delivering network change notification.
-  // Wait for it to resolve conflicting value to kResolutionValue by the custom
-  // conflict resolution logic in TestModelTypeSyncBridge.
+  // Wait for it to resolve conflicting value using the remote value coming from
+  // the server.
   net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
       net::NetworkChangeNotifier::CONNECTION_ETHERNET);
-  ASSERT_TRUE(DataChecker(model0, kKey1, kValue4).Wait());
-
-  // Wait for client 1 to settle on resolved value.
-  ASSERT_TRUE(DataChecker(model1, kKey1, kValue4).Wait());
+  ASSERT_TRUE(DataChecker(model0, kKey1, kValue3).Wait());
 }
 
 IN_PROC_BROWSER_TEST_F(TwoClientUssSyncTest, Error) {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index dac312c..8286d3e 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -108,8 +108,6 @@
     "confirm_bubble.h",
     "crypto_module_password_dialog.h",
     "cryptuiapi_shim.h",
-    "dark_mode_observer.cc",
-    "dark_mode_observer.h",
     "enterprise_startup_dialog.h",
     "find_bar/find_bar.h",
     "find_bar/find_bar_state.h",
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
index 0fa658c..2136ea0 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
@@ -202,8 +202,11 @@
   answer_image_view_->SetHorizontalAlignment(views::ImageView::CENTER);
   answer_image_view_->SetVerticalAlignment(views::ImageView::CENTER);
 
-  const base::string16& separator =
-      l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR);
+  const base::string16 separator = l10n_util::GetStringUTF16(
+      base::FeatureList::IsEnabled(
+          omnibox::kOmniboxAlternateMatchDescriptionSeparator)
+          ? IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR_ALTERNATE
+          : IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR);
   separator_view_->SetText(separator);
 }
 
diff --git a/chrome/browser/ui/webui/dark_mode_handler.h b/chrome/browser/ui/webui/dark_mode_handler.h
index a47965a..5215589 100644
--- a/chrome/browser/ui/webui/dark_mode_handler.h
+++ b/chrome/browser/ui/webui/dark_mode_handler.h
@@ -11,8 +11,8 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
-#include "chrome/browser/ui/dark_mode_observer.h"
 #include "content/public/browser/web_ui_message_handler.h"
+#include "ui/native_theme/dark_mode_observer.h"
 #include "ui/native_theme/native_theme.h"
 
 namespace base {
@@ -70,7 +70,7 @@
   // Profile to update data sources on. Injected for testing.
   Profile* const profile_;
 
-  DarkModeObserver dark_mode_observer_;
+  ui::DarkModeObserver dark_mode_observer_;
 
   // Populated if feature is enabled.
   std::string source_name_;
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.h b/chrome/browser/ui/webui/ntp/new_tab_ui.h
index f5e776d..53f6473e 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.h
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.h
@@ -7,10 +7,10 @@
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/ui/dark_mode_observer.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_ui_controller.h"
+#include "ui/native_theme/dark_mode_observer.h"
 
 class GURL;
 class Profile;
@@ -80,7 +80,7 @@
 
   Profile* GetProfile() const;
 
-  DarkModeObserver dark_mode_observer_;
+  ui::DarkModeObserver dark_mode_observer_;
 
   PrefChangeRegistrar pref_change_registrar_;
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler_unittest.cc
index 78b09934c..72007f3 100644
--- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler_unittest.cc
@@ -42,8 +42,11 @@
 }
 
 // Callback used for testing CupsRemovePrinter().
-void RemovedPrinter(bool* expected, bool result) {
-  EXPECT_EQ(*expected, result);
+void RemovedPrinter(base::OnceClosure quit_closure,
+                    bool* expected,
+                    bool result) {
+  *expected = result;
+  std::move(quit_closure).Run();
 }
 
 class FakePrinterConfigurer : public PrinterConfigurer {
@@ -135,11 +138,14 @@
 
   // We expect this printer removal to fail since the printer should have
   // already been removed by the previous call to 'removeCupsPrinter'.
-  bool expected = false;
-  client->CupsRemovePrinter("testprinter1",
-                            base::BindRepeating(&RemovedPrinter, &expected),
-                            base::DoNothing());
-  thread_bundle_.RunUntilIdle();
+  base::RunLoop run_loop;
+  bool expected = true;
+  client->CupsRemovePrinter(
+      "testprinter1",
+      base::BindRepeating(&RemovedPrinter, run_loop.QuitClosure(), &expected),
+      base::DoNothing());
+  run_loop.Run();
+  EXPECT_FALSE(expected);
 }
 
 }  // namespace settings.
diff --git a/chrome/browser/ui/webui/welcome/nux_helper.cc b/chrome/browser/ui/webui/welcome/nux_helper.cc
index 1601a02..33a9c633 100644
--- a/chrome/browser/ui/webui/welcome/nux_helper.cc
+++ b/chrome/browser/ui/webui/welcome/nux_helper.cc
@@ -53,9 +53,11 @@
   return true;
 }
 
-bool CanShowNTPBackgroundModule(const policy::PolicyMap& policies) {
-  // We shouldn't show this module if any policy is set that overrides the NTP.
-  return !policies.GetValue(policy::key::kNewTabPageLocation);
+bool CanShowNTPBackgroundModule(const policy::PolicyMap& policies,
+                                Profile* profile) {
+  // We can't set the background if the NTP is something other than Google.
+  return !policies.GetValue(policy::key::kNewTabPageLocation) &&
+         search::DefaultSearchProviderIsGoogle(profile);
 }
 
 bool CanShowSetDefaultModule(const policy::PolicyMap& policies) {
@@ -173,13 +175,13 @@
       policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()));
 }
 
-std::vector<std::string> GetAvailableModules(
-    const policy::PolicyMap& policies) {
+std::vector<std::string> GetAvailableModules(Profile* profile) {
+  const policy::PolicyMap& policies = GetPoliciesFromProfile(profile);
   std::vector<std::string> available_modules;
 
   if (CanShowGoogleAppModule(policies))
     available_modules.push_back("nux-google-apps");
-  if (CanShowNTPBackgroundModule(policies))
+  if (CanShowNTPBackgroundModule(policies, profile))
     available_modules.push_back("nux-ntp-background");
   if (CanShowSetDefaultModule(policies))
     available_modules.push_back("nux-set-as-default");
@@ -190,7 +192,7 @@
 }
 
 bool DoesOnboardingHaveModulesToShow(Profile* profile) {
-  return !GetAvailableModules(GetPoliciesFromProfile(profile)).empty();
+  return !GetAvailableModules(profile).empty();
 }
 
 std::string FilterModules(const std::string& requested_modules,
@@ -225,8 +227,7 @@
     returning_user_modules = kNuxOnboardingReturningUserModules.Get();
   }
 
-  const policy::PolicyMap& policies = GetPoliciesFromProfile(profile);
-  std::vector<std::string> available_modules = GetAvailableModules(policies);
+  std::vector<std::string> available_modules = GetAvailableModules(profile);
 
   base::DictionaryValue modules;
   modules.SetString("new-user",
diff --git a/chrome/test/data/webui/bluetooth_internals_browsertest.js b/chrome/test/data/webui/bluetooth_internals_browsertest.js
index d39dd8a..08690f4a 100644
--- a/chrome/test/data/webui/bluetooth_internals_browsertest.js
+++ b/chrome/test/data/webui/bluetooth_internals_browsertest.js
@@ -6,9 +6,6 @@
  * @fileoverview Tests for chrome://bluetooth-internals
  */
 
-/** @const {string} Path to source root. */
-var ROOT_PATH = '../../../../';
-
 /**
  * Test fixture for BluetoothInternals WebUI testing.
  * @constructor
@@ -33,12 +30,12 @@
 
   /** @override */
   extraLibraries: [
-    ROOT_PATH + 'third_party/mocha/mocha.js',
-    ROOT_PATH + 'chrome/test/data/webui/mocha_adapter.js',
-    ROOT_PATH + 'ui/webui/resources/js/promise_resolver.js',
-    ROOT_PATH + 'ui/webui/resources/js/cr.js',
-    ROOT_PATH + 'ui/webui/resources/js/util.js',
-    ROOT_PATH + 'chrome/test/data/webui/test_browser_proxy.js',
+    '//third_party/mocha/mocha.js',
+    '//chrome/test/data/webui/mocha_adapter.js',
+    '//ui/webui/resources/js/promise_resolver.js',
+    '//ui/webui/resources/js/cr.js',
+    '//ui/webui/resources/js/util.js',
+    '//chrome/test/data/webui/test_browser_proxy.js',
   ],
 
   preLoad: function() {
diff --git a/chrome/test/data/webui/chromeos/fake_networking_private.js b/chrome/test/data/webui/chromeos/fake_networking_private.js
index 67bccc7..539c08b 100644
--- a/chrome/test/data/webui/chromeos/fake_networking_private.js
+++ b/chrome/test/data/webui/chromeos/fake_networking_private.js
@@ -4,7 +4,7 @@
 
 /**
  * @fileoverview Fake implementation of chrome.networkingPrivate for testing.
- *    NOTE: Include "ROOT_PATH + 'ui/webui/resources/js/promise_resolver.js'"
+ *    NOTE: Include "'//ui/webui/resources/js/promise_resolver.js'"
  *    in any test that uses this.
  */
 cr.define('chrome', function() {
diff --git a/chrome/test/data/webui/engagement/site_engagement_browsertest.js b/chrome/test/data/webui/engagement/site_engagement_browsertest.js
index f445fff0..8b3bad1 100644
--- a/chrome/test/data/webui/engagement/site_engagement_browsertest.js
+++ b/chrome/test/data/webui/engagement/site_engagement_browsertest.js
@@ -5,7 +5,6 @@
 /**
  * @fileoverview Test suite for the Site Engagement WebUI.
  */
-var ROOT_PATH = '../../../../../';
 var EXAMPLE_URL_1 = 'http://example.com/';
 var EXAMPLE_URL_2 = 'http://shmlexample.com/';
 
@@ -33,8 +32,8 @@
   },
 
   extraLibraries: [
-    ROOT_PATH + 'third_party/mocha/mocha.js',
-    ROOT_PATH + 'chrome/test/data/webui/mocha_adapter.js',
+    '//third_party/mocha/mocha.js',
+    '//chrome/test/data/webui/mocha_adapter.js',
   ],
 
   /** @override */
diff --git a/chrome/test/data/webui/interventions_internals_browsertest.js b/chrome/test/data/webui/interventions_internals_browsertest.js
index db92c50..16b08a4b 100644
--- a/chrome/test/data/webui/interventions_internals_browsertest.js
+++ b/chrome/test/data/webui/interventions_internals_browsertest.js
@@ -6,9 +6,6 @@
  * @fileoverview Tests for interventions_internals.js
  */
 
-/** @const {string} Path to source root. */
-let ROOT_PATH = '../../../../';
-
 /**
  * Test fixture for InterventionsInternals WebUI testing.
  * @constructor
@@ -31,11 +28,11 @@
   isAsync: true,
 
   extraLibraries: [
-    ROOT_PATH + 'third_party/mocha/mocha.js',
-    ROOT_PATH + 'chrome/test/data/webui/mocha_adapter.js',
-    ROOT_PATH + 'ui/webui/resources/js/promise_resolver.js',
-    ROOT_PATH + 'ui/webui/resources/js/util.js',
-    ROOT_PATH + 'chrome/test/data/webui/test_browser_proxy.js',
+    '//third_party/mocha/mocha.js',
+    '//chrome/test/data/webui/mocha_adapter.js',
+    '//ui/webui/resources/js/promise_resolver.js',
+    '//ui/webui/resources/js/util.js',
+    '//chrome/test/data/webui/test_browser_proxy.js',
   ],
 
   preLoad: function() {
diff --git a/chrome/test/data/webui/media/media_engagement_browsertest.js b/chrome/test/data/webui/media/media_engagement_browsertest.js
index b1784d3..641ac51 100644
--- a/chrome/test/data/webui/media/media_engagement_browsertest.js
+++ b/chrome/test/data/webui/media/media_engagement_browsertest.js
@@ -5,7 +5,6 @@
 /**
  * @fileoverview Test suite for the Media Engagement WebUI.
  */
-var ROOT_PATH = '../../../../../';
 var EXAMPLE_URL_1 = 'http://example.com/';
 var EXAMPLE_URL_2 = 'http://shmlexample.com/';
 
@@ -44,8 +43,8 @@
   },
 
   extraLibraries: [
-    ROOT_PATH + 'third_party/mocha/mocha.js',
-    ROOT_PATH + 'chrome/test/data/webui/mocha_adapter.js',
+    '//third_party/mocha/mocha.js',
+    '//chrome/test/data/webui/mocha_adapter.js',
   ],
 };
 
diff --git a/chrome/test/data/webui/settings/all_sites_tests.js b/chrome/test/data/webui/settings/all_sites_tests.js
index 92152e9..5abc3a6 100644
--- a/chrome/test/data/webui/settings/all_sites_tests.js
+++ b/chrome/test/data/webui/settings/all_sites_tests.js
@@ -116,15 +116,10 @@
       // Use resolver to ensure that the list container is populated.
       const resolver = new PromiseResolver();
       // In Polymer2, we need to wait until after the next render for the list
-      // to be populated. TODO (rbpotter): Remove conditional when migration to
-      // Polymer 2 is completed.
-      if (Polymer.DomIf) {
-        Polymer.RenderStatus.beforeNextRender(testElement, () => {
-          resolver.resolve();
-        });
-      } else {
-        testElement.async(resolver.resolve);
-      }
+      // to be populated.
+      Polymer.RenderStatus.beforeNextRender(testElement, () => {
+        resolver.resolve();
+      });
       return resolver.promise.then(() => {
         assertEquals(3, testElement.siteGroupMap.size);
 
diff --git a/chrome/test/data/webui/settings/autofill_page_test.js b/chrome/test/data/webui/settings/autofill_page_test.js
index 548399f..8a8953f 100644
--- a/chrome/test/data/webui/settings/autofill_page_test.js
+++ b/chrome/test/data/webui/settings/autofill_page_test.js
@@ -27,11 +27,9 @@
       element.prefs = prefsElement.prefs;
       document.body.appendChild(element);
 
-      // TODO(dpapad): Update this once migration to Polymer 2 is done.
-      const domIfTag = Polymer.DomIf ? 'dom-if' : 'template';
-      element.$$(`${domIfTag}[route-path="/passwords"]`).if = true;
-      element.$$(`${domIfTag}[route-path="/payments"]`).if = true;
-      element.$$(`${domIfTag}[route-path="/addresses"]`).if = true;
+      element.$$('dom-if[route-path="/passwords"]').if = true;
+      element.$$('dom-if[route-path="/payments"]').if = true;
+      element.$$('dom-if[route-path="/addresses"]').if = true;
       Polymer.dom.flush();
       return element;
     }
diff --git a/chrome/test/data/webui/settings/settings_idle_load_browsertest.js b/chrome/test/data/webui/settings/settings_idle_load_browsertest.js
index 7dac8e3..61e46978 100644
--- a/chrome/test/data/webui/settings/settings_idle_load_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_idle_load_browsertest.js
@@ -4,8 +4,6 @@
 
 /** @fileoverview Tests for settings-idle-load. */
 
-/** @const {string} Path to root from chrome/test/data/webui/settings/. */
-const ROOT_PATH = '../../../../../';
 
 /**
  * @constructor
@@ -21,7 +19,7 @@
 
   /** @override */
   extraLibraries: [
-    ROOT_PATH + 'third_party/mocha/mocha.js',
+    '//third_party/mocha/mocha.js',
     '../mocha_adapter.js',
   ],
 
diff --git a/chrome/test/data/webui/sys_internals/sys_internals_browsertest.js b/chrome/test/data/webui/sys_internals/sys_internals_browsertest.js
index dc37a77a..38f2e39 100644
--- a/chrome/test/data/webui/sys_internals/sys_internals_browsertest.js
+++ b/chrome/test/data/webui/sys_internals/sys_internals_browsertest.js
@@ -5,7 +5,6 @@
 /**
  * @fileoverview Test suite for the SysInternals WebUI. (CrOS only)
  */
-const ROOT_PATH = '../../../../../';
 GEN('#include "chrome/common/chrome_features.h"');
 
 /* Set up this global variable to disable sending the update request. */
@@ -35,10 +34,10 @@
     'page_switch_test.js',
     'page_unit_test.js',
     'test_util.js',
-    ROOT_PATH + 'third_party/mocha/mocha.js',
-    ROOT_PATH + 'third_party/polymer/v1_0/components-chromium/' +
+    '//third_party/mocha/mocha.js',
+    '//third_party/polymer/v1_0/components-chromium/' +
         'iron-test-helpers/mock-interactions.js',
-    ROOT_PATH + 'chrome/test/data/webui/mocha_adapter.js',
+    '//chrome/test/data/webui/mocha_adapter.js',
   ],
 };
 
diff --git a/chrome/test/data/webui/usb_internals_browsertest.js b/chrome/test/data/webui/usb_internals_browsertest.js
index b4846b59..7b9ed42 100644
--- a/chrome/test/data/webui/usb_internals_browsertest.js
+++ b/chrome/test/data/webui/usb_internals_browsertest.js
@@ -6,9 +6,6 @@
  * @fileoverview Tests for chrome://usb-internals
  */
 
-/** @const {string} Path to source root. */
-const ROOT_PATH = '../../../../';
-
 /**
  * Test fixture for testing async methods of cr.js.
  * @constructor
@@ -32,12 +29,12 @@
 
   /** @override */
   extraLibraries: [
-    ROOT_PATH + 'third_party/mocha/mocha.js',
-    ROOT_PATH + 'chrome/test/data/webui/mocha_adapter.js',
-    ROOT_PATH + 'ui/webui/resources/js/promise_resolver.js',
-    ROOT_PATH + 'ui/webui/resources/js/cr.js',
-    ROOT_PATH + 'ui/webui/resources/js/util.js',
-    ROOT_PATH + 'chrome/test/data/webui/test_browser_proxy.js',
+    '//third_party/mocha/mocha.js',
+    '//chrome/test/data/webui/mocha_adapter.js',
+    '//ui/webui/resources/js/promise_resolver.js',
+    '//ui/webui/resources/js/cr.js',
+    '//ui/webui/resources/js/util.js',
+    '//chrome/test/data/webui/test_browser_proxy.js',
   ],
 
   preLoad: function() {
@@ -198,4 +195,4 @@
 
   // Run all registered tests.
   mocha.run();
-});
\ No newline at end of file
+});
diff --git a/chrome/test/data/webui/webui_resource_async_browsertest.js b/chrome/test/data/webui/webui_resource_async_browsertest.js
index 16fe6ae..ee445fa 100644
--- a/chrome/test/data/webui/webui_resource_async_browsertest.js
+++ b/chrome/test/data/webui/webui_resource_async_browsertest.js
@@ -6,9 +6,6 @@
  * @fileoverview Framework for running async JS tests for cr.js utility methods.
  */
 
-/** @const {string} Path to source root. */
-var ROOT_PATH = '../../../../';
-
 /** @const {string} Name of the chrome.send() message to be used in tests. */
 var CHROME_SEND_NAME = 'echoMessage';
 
@@ -33,10 +30,10 @@
 
   /** @override */
   extraLibraries: [
-    ROOT_PATH + 'third_party/mocha/mocha.js',
-    ROOT_PATH + 'chrome/test/data/webui/mocha_adapter.js',
-    ROOT_PATH + 'ui/webui/resources/js/promise_resolver.js',
-    ROOT_PATH + 'ui/webui/resources/js/cr.js',
+    '//third_party/mocha/mocha.js',
+    '//chrome/test/data/webui/mocha_adapter.js',
+    '//ui/webui/resources/js/promise_resolver.js',
+    '//ui/webui/resources/js/cr.js',
   ],
 };
 
diff --git a/chromeos/constants/chromeos_switches.cc b/chromeos/constants/chromeos_switches.cc
index 6a53165..e97fed28 100644
--- a/chromeos/constants/chromeos_switches.cc
+++ b/chromeos/constants/chromeos_switches.cc
@@ -213,9 +213,6 @@
 // Disable encryption migration for user's cryptohome to run latest Arc.
 const char kDisableEncryptionMigration[] = "disable-encryption-migration";
 
-// Disables notification when device is in end of life status.
-const char kDisableEolNotification[] = "disable-eol-notification";
-
 // Disables fine grained time zone detection.
 const char kDisableFineGrainedTimeZoneDetection[] =
     "disable-fine-grained-time-zone-detection";
diff --git a/chromeos/constants/chromeos_switches.h b/chromeos/constants/chromeos_switches.h
index 3be55f3f..ab8190b 100644
--- a/chromeos/constants/chromeos_switches.h
+++ b/chromeos/constants/chromeos_switches.h
@@ -73,8 +73,6 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const char kDisableEncryptionMigration[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
-extern const char kDisableEolNotification[];
-COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const char kDisableFineGrainedTimeZoneDetection[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const char kDisableGaiaServices[];
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
diff --git a/chromeos/dbus/power/fake_power_manager_client.cc b/chromeos/dbus/power/fake_power_manager_client.cc
index 8d8634d..9bf45d85 100644
--- a/chromeos/dbus/power/fake_power_manager_client.cc
+++ b/chromeos/dbus/power/fake_power_manager_client.cc
@@ -83,6 +83,7 @@
 
 void FakePowerManagerClient::AddObserver(Observer* observer) {
   observers_.AddObserver(observer);
+  observer->PowerManagerBecameAvailable(true);
 }
 
 void FakePowerManagerClient::RemoveObserver(Observer* observer) {
@@ -93,12 +94,6 @@
   return observers_.HasObserver(observer);
 }
 
-void FakePowerManagerClient::WaitForServiceToBeAvailable(
-    WaitForServiceToBeAvailableCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), true));
-}
-
 void FakePowerManagerClient::SetRenderProcessManagerDelegate(
     base::WeakPtr<RenderProcessManagerDelegate> delegate) {
   render_process_manager_delegate_ = delegate;
diff --git a/chromeos/dbus/power/fake_power_manager_client.h b/chromeos/dbus/power/fake_power_manager_client.h
index 9ba5e1f..1a376e55 100644
--- a/chromeos/dbus/power/fake_power_manager_client.h
+++ b/chromeos/dbus/power/fake_power_manager_client.h
@@ -80,8 +80,6 @@
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
   bool HasObserver(const Observer* observer) const override;
-  void WaitForServiceToBeAvailable(
-      WaitForServiceToBeAvailableCallback callback) override;
   void SetRenderProcessManagerDelegate(
       base::WeakPtr<RenderProcessManagerDelegate> delegate) override;
   void DecreaseScreenBrightness(bool allow_off) override;
diff --git a/chromeos/dbus/power/power_manager_client.cc b/chromeos/dbus/power/power_manager_client.cc
index 654ed8b..c7de7af 100644
--- a/chromeos/dbus/power/power_manager_client.cc
+++ b/chromeos/dbus/power/power_manager_client.cc
@@ -164,6 +164,10 @@
         base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived,
                    weak_ptr_factory_.GetWeakPtr()));
 
+    power_manager_proxy_->WaitForServiceToBeAvailable(
+        base::BindOnce(&PowerManagerClientImpl::NotifyServiceBecameAvailable,
+                       weak_ptr_factory_.GetWeakPtr()));
+
     // Listen to D-Bus signals emitted by powerd.
     typedef void (PowerManagerClientImpl::*SignalMethod)(dbus::Signal*);
     const std::map<const char*, SignalMethod> kSignalMethods = {
@@ -211,6 +215,9 @@
   void AddObserver(Observer* observer) override {
     DCHECK(observer);  // http://crbug.com/119976
     observers_.AddObserver(observer);
+
+    if (service_available_)
+      observer->PowerManagerBecameAvailable(*service_available_);
   }
 
   void RemoveObserver(Observer* observer) override {
@@ -221,11 +228,6 @@
     return observers_.HasObserver(observer);
   }
 
-  void WaitForServiceToBeAvailable(
-      WaitForServiceToBeAvailableCallback callback) override {
-    power_manager_proxy_->WaitForServiceToBeAvailable(std::move(callback));
-  }
-
   void SetRenderProcessManagerDelegate(
       base::WeakPtr<RenderProcessManagerDelegate> delegate) override {
     DCHECK(!render_process_manager_delegate_)
@@ -550,6 +552,12 @@
                                      base::DoNothing());
   }
 
+  void NotifyServiceBecameAvailable(bool available) {
+    service_available_ = available;
+    for (auto& observer : observers_)
+      observer.PowerManagerBecameAvailable(available);
+  }
+
   void NameOwnerChangedReceived(const std::string& old_owner,
                                 const std::string& new_owner) {
     POWER_LOG(EVENT) << "Power manager restarted. Old owner: "
@@ -1094,6 +1102,8 @@
   dbus::ObjectProxy* power_manager_proxy_ = nullptr;
   base::ObserverList<Observer>::Unchecked observers_;
 
+  base::Optional<bool> service_available_ = false;
+
   // The delay ID obtained from the RegisterSuspendDelay request.
   int32_t suspend_delay_id_ = -1;
   bool has_suspend_delay_id_ = false;
diff --git a/chromeos/dbus/power/power_manager_client.h b/chromeos/dbus/power/power_manager_client.h
index 26d25e5..5ea004b 100644
--- a/chromeos/dbus/power/power_manager_client.h
+++ b/chromeos/dbus/power/power_manager_client.h
@@ -63,6 +63,11 @@
    public:
     virtual ~Observer() {}
 
+    // Called when the power manager service becomes available. Will be called
+    // immediately and synchronously when a new observer is added to
+    // PowerManagerClient if the service's availability is already known.
+    virtual void PowerManagerBecameAvailable(bool available) {}
+
     // Called if the power manager process restarts.
     virtual void PowerManagerRestarted() {}
 
@@ -154,10 +159,6 @@
   virtual void RemoveObserver(Observer* observer) = 0;
   virtual bool HasObserver(const Observer* observer) const = 0;
 
-  // Runs the callback as soon as the service becomes available.
-  virtual void WaitForServiceToBeAvailable(
-      WaitForServiceToBeAvailableCallback callback) = 0;
-
   // Interface for managing the power consumption of renderer processes.
   class RenderProcessManagerDelegate {
    public:
diff --git a/chromeos/dbus/power/power_manager_client_unittest.cc b/chromeos/dbus/power/power_manager_client_unittest.cc
index a2c9d7c..181ad5c 100644
--- a/chromeos/dbus/power/power_manager_client_unittest.cc
+++ b/chromeos/dbus/power/power_manager_client_unittest.cc
@@ -202,35 +202,40 @@
 
     // |client_|'s Init() method should request a proxy for communicating with
     // powerd.
-    EXPECT_CALL(*bus_.get(),
+    EXPECT_CALL(*bus_,
                 GetObjectProxy(
                     power_manager::kPowerManagerServiceName,
                     dbus::ObjectPath(power_manager::kPowerManagerServicePath)))
         .WillRepeatedly(Return(proxy_.get()));
 
+    EXPECT_CALL(*bus_, GetDBusTaskRunner())
+        .WillRepeatedly(Return(message_loop_.task_runner().get()));
+    EXPECT_CALL(*bus_, GetOriginTaskRunner())
+        .WillRepeatedly(Return(message_loop_.task_runner().get()));
+
     // Save |client_|'s signal and name-owner-changed callbacks.
-    EXPECT_CALL(*proxy_.get(), DoConnectToSignal(kInterface, _, _, _))
+    EXPECT_CALL(*proxy_, DoConnectToSignal(kInterface, _, _, _))
         .WillRepeatedly(Invoke(this, &PowerManagerClientTest::ConnectToSignal));
-    EXPECT_CALL(*proxy_.get(), SetNameOwnerChangedCallback(_))
+    EXPECT_CALL(*proxy_, SetNameOwnerChangedCallback(_))
         .WillRepeatedly(SaveArg<0>(&name_owner_changed_callback_));
 
     // |client_|'s Init() method should register regular and dark suspend
     // delays.
     EXPECT_CALL(
-        *proxy_.get(),
+        *proxy_,
         DoCallMethod(HasMember(power_manager::kRegisterSuspendDelayMethod), _,
                      _))
         .WillRepeatedly(
             Invoke(this, &PowerManagerClientTest::RegisterSuspendDelay));
     EXPECT_CALL(
-        *proxy_.get(),
+        *proxy_,
         DoCallMethod(HasMember(power_manager::kRegisterDarkSuspendDelayMethod),
                      _, _))
         .WillRepeatedly(
             Invoke(this, &PowerManagerClientTest::RegisterSuspendDelay));
     // Init should also request a fresh power status.
     EXPECT_CALL(
-        *proxy_.get(),
+        *proxy_,
         DoCallMethod(HasMember(power_manager::kGetPowerSupplyPropertiesMethod),
                      _, _));
 
diff --git a/chromeos/services/power/public/cpp/power_manager_mojo_client.cc b/chromeos/services/power/public/cpp/power_manager_mojo_client.cc
index b413e9b..05a75fe 100644
--- a/chromeos/services/power/public/cpp/power_manager_mojo_client.cc
+++ b/chromeos/services/power/public/cpp/power_manager_mojo_client.cc
@@ -27,6 +27,7 @@
 
 void PowerManagerMojoClient::AddObserver(Observer* observer) {
   observers_.AddObserver(observer);
+  // TODO(estade): Call PowerManagerBecameAvailable as appropriate.
 }
 
 void PowerManagerMojoClient::RemoveObserver(Observer* observer) {
@@ -37,9 +38,6 @@
   return observers_.HasObserver(observer);
 }
 
-void PowerManagerMojoClient::WaitForServiceToBeAvailable(
-    WaitForServiceToBeAvailableCallback callback) {}
-
 void PowerManagerMojoClient::SetRenderProcessManagerDelegate(
     base::WeakPtr<RenderProcessManagerDelegate> delegate) {}
 
@@ -135,13 +133,18 @@
 
 void PowerManagerMojoClient::DeferScreenDim() {}
 
-void PowerManagerMojoClient::ScreenBrightnessChanged(double percent) {
-  power_manager::BacklightBrightnessChange change;
-  change.set_percent(percent);
+void PowerManagerMojoClient::ScreenBrightnessChanged(
+    const power_manager::BacklightBrightnessChange& change) {
   for (auto& observer : observers_)
     observer.ScreenBrightnessChanged(change);
 }
 
+void PowerManagerMojoClient::KeyboardBrightnessChanged(
+    const power_manager::BacklightBrightnessChange& change) {
+  for (auto& observer : observers_)
+    observer.KeyboardBrightnessChanged(change);
+}
+
 void PowerManagerMojoClient::InitAfterInterfaceBound() {
   DCHECK(controller_.is_bound());
   power::mojom::PowerManagerObserverAssociatedPtrInfo ptr_info;
diff --git a/chromeos/services/power/public/cpp/power_manager_mojo_client.h b/chromeos/services/power/public/cpp/power_manager_mojo_client.h
index ab798d8..637c7d4a 100644
--- a/chromeos/services/power/public/cpp/power_manager_mojo_client.h
+++ b/chromeos/services/power/public/cpp/power_manager_mojo_client.h
@@ -28,8 +28,6 @@
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
   bool HasObserver(const Observer* observer) const override;
-  void WaitForServiceToBeAvailable(
-      WaitForServiceToBeAvailableCallback callback) override;
   void SetRenderProcessManagerDelegate(
       base::WeakPtr<RenderProcessManagerDelegate> delegate) override;
   void DecreaseScreenBrightness(bool allow_off) override;
@@ -75,7 +73,10 @@
   void DeferScreenDim() override;
 
   // power::mojom::PowerManagerObserver:
-  void ScreenBrightnessChanged(double percent) override;
+  void ScreenBrightnessChanged(
+      const power_manager::BacklightBrightnessChange& change) override;
+  void KeyboardBrightnessChanged(
+      const power_manager::BacklightBrightnessChange& change) override;
 
   power::mojom::PowerManagerControllerPtr* interface_ptr() {
     return &controller_;
diff --git a/chromeos/services/power/public/cpp/power_manager_mojo_controller.cc b/chromeos/services/power/public/cpp/power_manager_mojo_controller.cc
index 148df0c6..8cec9a9 100644
--- a/chromeos/services/power/public/cpp/power_manager_mojo_controller.cc
+++ b/chromeos/services/power/public/cpp/power_manager_mojo_controller.cc
@@ -45,8 +45,12 @@
 
 void PowerManagerMojoController::ScreenBrightnessChanged(
     const power_manager::BacklightBrightnessChange& change) {
-  // TODO(estade): serialize and pass all of |change|.
-  client_->ScreenBrightnessChanged(change.percent());
+  client_->ScreenBrightnessChanged(change);
+}
+
+void PowerManagerMojoController::KeyboardBrightnessChanged(
+    const power_manager::BacklightBrightnessChange& change) {
+  client_->KeyboardBrightnessChanged(change);
 }
 
 }  // namespace chromeos
diff --git a/chromeos/services/power/public/cpp/power_manager_mojo_controller.h b/chromeos/services/power/public/cpp/power_manager_mojo_controller.h
index 1a27d49..a45d92f 100644
--- a/chromeos/services/power/public/cpp/power_manager_mojo_controller.h
+++ b/chromeos/services/power/public/cpp/power_manager_mojo_controller.h
@@ -34,6 +34,8 @@
   // PowerManagerClient::Observer:
   void ScreenBrightnessChanged(
       const power_manager::BacklightBrightnessChange& change) override;
+  void KeyboardBrightnessChanged(
+      const power_manager::BacklightBrightnessChange& change) override;
 
  private:
   mojo::BindingSet<power::mojom::PowerManagerController> binding_set_;
diff --git a/chromeos/services/power/public/mojom/OWNERS b/chromeos/services/power/public/mojom/OWNERS
index 08850f4..2c44a46 100644
--- a/chromeos/services/power/public/mojom/OWNERS
+++ b/chromeos/services/power/public/mojom/OWNERS
@@ -1,2 +1,6 @@
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromeos/services/power/public/mojom/mojom_traits.cc b/chromeos/services/power/public/mojom/mojom_traits.cc
new file mode 100644
index 0000000..7b1c1b8
--- /dev/null
+++ b/chromeos/services/power/public/mojom/mojom_traits.cc
@@ -0,0 +1,125 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/services/power/public/mojom/mojom_traits.h"
+
+namespace mojo {
+
+// static
+chromeos::power::mojom::BacklightBrightnessChangeCause
+EnumTraits<chromeos::power::mojom::BacklightBrightnessChangeCause,
+           power_manager::BacklightBrightnessChange_Cause>::
+    ToMojom(power_manager::BacklightBrightnessChange_Cause cause) {
+  switch (cause) {
+    case power_manager::BacklightBrightnessChange_Cause_USER_REQUEST:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::
+          kUserRequest;
+    case power_manager::BacklightBrightnessChange_Cause_USER_ACTIVITY:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::
+          kUserActivity;
+    case power_manager::BacklightBrightnessChange_Cause_USER_INACTIVITY:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::
+          kUserInactivity;
+    case power_manager::BacklightBrightnessChange_Cause_AMBIENT_LIGHT_CHANGED:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::
+          kAmbientLightChanged;
+    case power_manager::
+        BacklightBrightnessChange_Cause_EXTERNAL_POWER_CONNECTED:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::
+          kExternalPowerConnected;
+    case power_manager::
+        BacklightBrightnessChange_Cause_EXTERNAL_POWER_DISCONNECTED:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::
+          kExternalPowerDisconnected;
+    case power_manager::BacklightBrightnessChange_Cause_FORCED_OFF:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::kForcedOff;
+    case power_manager::BacklightBrightnessChange_Cause_NO_LONGER_FORCED_OFF:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::
+          kNoLongerForcedOff;
+    case power_manager::BacklightBrightnessChange_Cause_OTHER:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::kOther;
+    case power_manager::BacklightBrightnessChange_Cause_MODEL:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::kModel;
+    case power_manager::BacklightBrightnessChange_Cause_WAKE_NOTIFICATION:
+      return chromeos::power::mojom::BacklightBrightnessChangeCause::
+          kWakeNotification;
+  }
+  NOTREACHED();
+  return chromeos::power::mojom::BacklightBrightnessChangeCause::kUserRequest;
+}
+
+// static
+bool EnumTraits<chromeos::power::mojom::BacklightBrightnessChangeCause,
+                power_manager::BacklightBrightnessChange_Cause>::
+    FromMojom(chromeos::power::mojom::BacklightBrightnessChangeCause cause,
+              power_manager::BacklightBrightnessChange_Cause* out) {
+  switch (cause) {
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::kUserRequest:
+      *out = power_manager::BacklightBrightnessChange_Cause_USER_REQUEST;
+      return true;
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::kUserActivity:
+      *out = power_manager::BacklightBrightnessChange_Cause_USER_ACTIVITY;
+      return true;
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::
+        kUserInactivity:
+      *out = power_manager::BacklightBrightnessChange_Cause_USER_INACTIVITY;
+      return true;
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::
+        kAmbientLightChanged:
+      *out =
+          power_manager::BacklightBrightnessChange_Cause_AMBIENT_LIGHT_CHANGED;
+      return true;
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::
+        kExternalPowerConnected:
+      *out = power_manager::
+          BacklightBrightnessChange_Cause_EXTERNAL_POWER_CONNECTED;
+      return true;
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::
+        kExternalPowerDisconnected:
+      *out = power_manager::
+          BacklightBrightnessChange_Cause_EXTERNAL_POWER_DISCONNECTED;
+      return true;
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::kForcedOff:
+      *out = power_manager::BacklightBrightnessChange_Cause_FORCED_OFF;
+      return true;
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::
+        kNoLongerForcedOff:
+      *out =
+          power_manager::BacklightBrightnessChange_Cause_NO_LONGER_FORCED_OFF;
+      return true;
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::kOther:
+      *out = power_manager::BacklightBrightnessChange_Cause_OTHER;
+      return true;
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::kModel:
+      *out = power_manager::BacklightBrightnessChange_Cause_MODEL;
+      return true;
+    case chromeos::power::mojom::BacklightBrightnessChangeCause::
+        kWakeNotification:
+      *out = power_manager::BacklightBrightnessChange_Cause_WAKE_NOTIFICATION;
+      return true;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
+// static
+bool StructTraits<chromeos::power::mojom::BacklightBrightnessChangeDataView,
+                  power_manager::BacklightBrightnessChange>::
+    Read(chromeos::power::mojom::BacklightBrightnessChangeDataView data,
+         power_manager::BacklightBrightnessChange* out) {
+  if (data.percent() < 0. || data.percent() > 100.)
+    return false;
+
+  out->set_percent(data.percent());
+
+  power_manager::BacklightBrightnessChange_Cause cause;
+  if (!data.ReadCause(&cause))
+    return false;
+
+  out->set_cause(cause);
+  return true;
+}
+
+}  // namespace mojo
diff --git a/chromeos/services/power/public/mojom/mojom_traits.h b/chromeos/services/power/public/mojom/mojom_traits.h
new file mode 100644
index 0000000..f41a567
--- /dev/null
+++ b/chromeos/services/power/public/mojom/mojom_traits.h
@@ -0,0 +1,44 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_SERVICES_POWER_PUBLIC_MOJOM_MOJOM_TRAITS_H_
+#define CHROMEOS_SERVICES_POWER_PUBLIC_MOJOM_MOJOM_TRAITS_H_
+
+#include "chromeos/dbus/power_manager/backlight.pb.h"
+#include "chromeos/services/power/public/mojom/power_manager.mojom-shared.h"
+#include "chromeos/services/power/public/mojom/power_manager.mojom.h"
+#include "mojo/public/cpp/bindings/enum_traits.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<chromeos::power::mojom::BacklightBrightnessChangeCause,
+                  power_manager::BacklightBrightnessChange_Cause> {
+  static chromeos::power::mojom::BacklightBrightnessChangeCause ToMojom(
+      power_manager::BacklightBrightnessChange_Cause cause);
+
+  static bool FromMojom(
+      chromeos::power::mojom::BacklightBrightnessChangeCause cause,
+      power_manager::BacklightBrightnessChange_Cause* out);
+};
+
+template <>
+struct StructTraits<chromeos::power::mojom::BacklightBrightnessChangeDataView,
+                    power_manager::BacklightBrightnessChange> {
+  static double percent(
+      const power_manager::BacklightBrightnessChange& change) {
+    return change.percent();
+  }
+  static power_manager::BacklightBrightnessChange_Cause cause(
+      const power_manager::BacklightBrightnessChange& change) {
+    return change.cause();
+  }
+  static bool Read(
+      chromeos::power::mojom::BacklightBrightnessChangeDataView data,
+      power_manager::BacklightBrightnessChange* out);
+};
+
+}  // namespace mojo
+
+#endif  // CHROMEOS_SERVICES_POWER_PUBLIC_MOJOM_MOJOM_TRAITS_H_
diff --git a/chromeos/services/power/public/mojom/power_manager.mojom b/chromeos/services/power/public/mojom/power_manager.mojom
index 9fb289c6..f084e2e80 100644
--- a/chromeos/services/power/public/mojom/power_manager.mojom
+++ b/chromeos/services/power/public/mojom/power_manager.mojom
@@ -7,9 +7,32 @@
 // TODO(https://crbug.com/657632): This struct wrapper exists to allow the value
 // to be null.
 struct Brightness {
+  // Brightness percent, in the range [0.0, 100.0].
   double value;
 };
 
+// Correlates to power_manager::BacklightBrightnessChange_Cause
+enum BacklightBrightnessChangeCause {
+  kUserRequest,
+  kUserActivity,
+  kUserInactivity,
+  kAmbientLightChanged,
+  kExternalPowerConnected,
+  kExternalPowerDisconnected,
+  kForcedOff,
+  kNoLongerForcedOff,
+  kOther,
+  kModel,
+  kWakeNotification,
+};
+
+// Correlates to power_manager::BacklightBrightnessChange
+struct BacklightBrightnessChange {
+  // The brightness percent is in the range [0.0, 100.0].
+  double percent;
+  BacklightBrightnessChangeCause cause;
+};
+
 // The interface for handling out-of-process calls that query or adjust power
 // related state. The implementation relays calls to the D-Bus client, which
 // uses D-Bus to communicate with the Power Manager daemon. In Mash, this lives
@@ -25,6 +48,8 @@
 // An interface for observing changes to power state. The changes are dispatched
 // over mojo from PowerManagerController.
 interface PowerManagerObserver {
-  // TODO(estade): the parameter should be a BacklightBrightnessChange.
-  ScreenBrightnessChanged(double percent);
+  // All following methods and their semantics are copied from the
+  // PowerManagerClient::Observer interface. Refer to that for documentation.
+  ScreenBrightnessChanged(BacklightBrightnessChange change);
+  KeyboardBrightnessChanged(BacklightBrightnessChange change);
 };
diff --git a/chromeos/services/power/public/mojom/power_types.typemap b/chromeos/services/power/public/mojom/power_types.typemap
new file mode 100644
index 0000000..9f81e2d
--- /dev/null
+++ b/chromeos/services/power/public/mojom/power_types.typemap
@@ -0,0 +1,18 @@
+# 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.
+
+mojom = "//chromeos/services/power/public/mojom/power_manager.mojom"
+public_headers = [ "chromeos/dbus/power_manager/backlight.pb.h" ]
+traits_headers = [ "//chromeos/services/power/public/mojom/mojom_traits.h" ]
+sources = [
+  "//chromeos/services/power/public/mojom/mojom_traits.cc",
+]
+deps = [
+  "//chromeos/dbus/power:power_manager_proto",
+]
+
+type_mappings = [
+  "chromeos.power.mojom.BacklightBrightnessChange=power_manager::BacklightBrightnessChange",
+  "chromeos.power.mojom.BacklightBrightnessChangeCause=power_manager::BacklightBrightnessChange_Cause",
+]
diff --git a/chromeos/services/power/public/mojom/typemaps.gni b/chromeos/services/power/public/mojom/typemaps.gni
new file mode 100644
index 0000000..7296993
--- /dev/null
+++ b/chromeos/services/power/public/mojom/typemaps.gni
@@ -0,0 +1,5 @@
+# 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.
+
+typemaps = [ "//chromeos/services/power/public/mojom/power_types.typemap" ]
diff --git a/components/arc/DEPS b/components/arc/DEPS
index e9ddbc7d..781b1c8c 100644
--- a/components/arc/DEPS
+++ b/components/arc/DEPS
@@ -18,7 +18,7 @@
   "+storage/browser/fileapi",
   "+third_party/re2",
   "+third_party/skia",
-  "+ui/base/ime",
+  "+ui/base",
   "+ui/gfx/geometry",
   "+ui/gfx/range/range.h",
 ]
diff --git a/components/arc/session/arc_session_impl.cc b/components/arc/session/arc_session_impl.cc
index d0f3875..1fc905a 100644
--- a/components/arc/session/arc_session_impl.cc
+++ b/components/arc/session/arc_session_impl.cc
@@ -37,6 +37,7 @@
 #include "mojo/public/cpp/platform/platform_handle.h"
 #include "mojo/public/cpp/platform/socket_utils_posix.h"
 #include "mojo/public/cpp/system/invitation.h"
+#include "ui/base/ui_base_features.h"
 
 namespace arc {
 
@@ -371,8 +372,9 @@
       base::FeatureList::IsEnabled(arc::kNativeBridgeExperimentFeature));
   request.set_arc_file_picker_experiment(
       base::FeatureList::IsEnabled(arc::kFilePickerExperimentFeature));
-  // Enable Custom Tabs only on Dev and Cannary.
+  // Enable Custom Tabs only on Dev and Cannary, and only when Mash is enabled.
   const bool is_custom_tab_enabled =
+      base::FeatureList::IsEnabled(features::kSingleProcessMash) &&
       base::FeatureList::IsEnabled(arc::kCustomTabsExperimentFeature) &&
       delegate_->GetChannel() != version_info::Channel::STABLE &&
       delegate_->GetChannel() != version_info::Channel::BETA;
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc
index 46cacc5f..00c5e798 100644
--- a/components/exo/surface_unittest.cc
+++ b/components/exo/surface_unittest.cc
@@ -788,7 +788,7 @@
   ASSERT_EQ(1u, frame.render_pass_list.size());
   ASSERT_EQ(1u, frame.render_pass_list.back()->quad_list.size());
   viz::DrawQuad* draw_quad = frame.render_pass_list.back()->quad_list.back();
-  ASSERT_EQ(viz::DrawQuad::TEXTURE_CONTENT, draw_quad->material);
+  ASSERT_EQ(viz::DrawQuad::Material::kTextureContent, draw_quad->material);
 
   const viz::TextureDrawQuad* texture_quad =
       viz::TextureDrawQuad::MaterialCast(draw_quad);
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index e121d8f..c91a9ba 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -69,6 +69,8 @@
     "zcr_stylus.h",
     "zcr_vsync_feedback.cc",
     "zcr_vsync_feedback.h",
+    "zwp_linux_explicit_synchronization.cc",
+    "zwp_linux_explicit_synchronization.h",
   ]
 
   defines = [ "EXO_IMPLEMENTATION" ]
@@ -99,8 +101,6 @@
       "zcr_stylus_tools.h",
       "zwp_input_timestamps_manager.cc",
       "zwp_input_timestamps_manager.h",
-      "zwp_linux_explicit_synchronization.cc",
-      "zwp_linux_explicit_synchronization.h",
       "zwp_pointer_gestures.cc",
       "zwp_pointer_gestures.h",
       "zwp_relative_pointer_manager.cc",
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index 00be35b..2cd7455a 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -49,6 +49,7 @@
 #include "components/exo/wayland/zcr_secure_output.h"
 #include "components/exo/wayland/zcr_stylus.h"
 #include "components/exo/wayland/zcr_vsync_feedback.h"
+#include "components/exo/wayland/zwp_linux_explicit_synchronization.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 
@@ -63,7 +64,6 @@
 #include "components/exo/wayland/zcr_remote_shell.h"
 #include "components/exo/wayland/zcr_stylus_tools.h"
 #include "components/exo/wayland/zwp_input_timestamps_manager.h"
-#include "components/exo/wayland/zwp_linux_explicit_synchronization.h"
 #include "components/exo/wayland/zwp_pointer_gestures.h"
 #include "components/exo/wayland/zwp_relative_pointer_manager.h"
 #include "components/exo/wayland/zwp_text_input_manager.h"
@@ -134,6 +134,9 @@
                    bind_stylus_v2);
   wl_global_create(wl_display_.get(), &wl_seat_interface, kWlSeatVersion,
                    display_->seat(), bind_seat);
+  wl_global_create(wl_display_.get(),
+                   &zwp_linux_explicit_synchronization_v1_interface, 1,
+                   display_, bind_linux_explicit_synchronization);
 #if defined(OS_CHROMEOS)
   wl_global_create(wl_display_.get(), &wl_shell_interface, 1, display_,
                    bind_shell);
@@ -166,9 +169,6 @@
                    display_, bind_text_input_manager);
   wl_global_create(wl_display_.get(), &zxdg_shell_v6_interface, 1, display_,
                    bind_xdg_shell_v6);
-  wl_global_create(wl_display_.get(),
-                   &zwp_linux_explicit_synchronization_v1_interface, 1,
-                   display_, bind_linux_explicit_synchronization);
 #endif
 
 #if defined(USE_FULLSCREEN_SHELL)
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index 4faf829..fbf4a3d 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -123,6 +123,12 @@
 const base::Feature kOmniboxUICuesForSearchHistoryMatches{
     "OmniboxUICuesForSearchHistoryMatches", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Feature that shows an alternate separator before the description of
+// omnibox matches. In English, this changes the separator from '-' to '|'.
+const base::Feature kOmniboxAlternateMatchDescriptionSeparator{
+    "OmniboxAlternateMatchDescriptionSeparator",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Feature to enable clipboard provider to suggest copied text.
 const base::Feature kEnableClipboardProviderTextSuggestions{
     "OmniboxEnableClipboardProviderTextSuggestions",
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index 5607734..1457be7a 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -26,6 +26,7 @@
 extern const base::Feature kOmniboxPedalSuggestions;
 extern const base::Feature kOmniboxSuggestionTransparencyOptions;
 extern const base::Feature kOmniboxUICuesForSearchHistoryMatches;
+extern const base::Feature kOmniboxAlternateMatchDescriptionSeparator;
 extern const base::Feature kEnableClipboardProviderTextSuggestions;
 extern const base::Feature kEnableClipboardProviderImageSuggestions;
 extern const base::Feature kSearchProviderWarmUpOnFocus;
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.cc b/components/password_manager/core/browser/password_manager_metrics_util.cc
index f932aa55..14c7428 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.cc
+++ b/components/password_manager/core/browser/password_manager_metrics_util.cc
@@ -70,6 +70,10 @@
                             NUM_SYNC_STATES);
 }
 
+void LogApplySyncChangesState(ApplySyncChangesState state) {
+  UMA_HISTOGRAM_ENUMERATION("PasswordManager.ApplySyncChangesState", state);
+}
+
 void LogPasswordGenerationSubmissionEvent(PasswordSubmissionEvent event) {
   UMA_HISTOGRAM_ENUMERATION("PasswordGeneration.SubmissionEvent", event,
                             SUBMISSION_EVENT_ENUM_COUNT);
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h
index 7ea741ca..188c333 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -84,6 +84,17 @@
   NUM_SYNC_STATES
 };
 
+// Metrics: "PasswordManager.ApplySyncChangesState"
+enum class ApplySyncChangesState {
+  kApplyOK = 0,
+  kApplyAddFailed = 1,
+  kApplyUpdateFailed = 2,
+  kApplyDeleteFailed = 3,
+  kApplyMetadataChangesFailed = 4,
+
+  kMaxValue = kApplyMetadataChangesFailed,
+};
+
 // Metrics: "PasswordGeneration.SubmissionEvent"
 enum PasswordSubmissionEvent {
   PASSWORD_SUBMITTED,
@@ -356,6 +367,9 @@
 // Log what's preventing passwords from syncing.
 void LogPasswordSyncState(PasswordSyncState state);
 
+// Log what's preventing passwords from applying sync changes.
+void LogApplySyncChangesState(ApplySyncChangesState state);
+
 // Log submission events related to generation.
 void LogPasswordGenerationSubmissionEvent(PasswordSubmissionEvent event);
 
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge.cc b/components/password_manager/core/browser/sync/password_sync_bridge.cc
index 435f8da..ddeb0b09 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -518,6 +518,8 @@
           // and the last one should be the one representing the actual addition
           // in the DB.
           if (changes.empty()) {
+            metrics_util::LogApplySyncChangesState(
+                metrics_util::ApplySyncChangesState::kApplyAddFailed);
             return syncer::ModelError(
                 FROM_HERE, "Failed to add an entry to the password store.");
           }
@@ -546,6 +548,8 @@
           changes = password_store_sync_->UpdateLoginSync(
               PasswordFromEntityChange(*entity_change, /*sync_time=*/time_now));
           if (changes.empty()) {
+            metrics_util::LogApplySyncChangesState(
+                metrics_util::ApplySyncChangesState::kApplyUpdateFailed);
             return syncer::ModelError(
                 FROM_HERE, "Failed to update an entry in the password store.");
           }
@@ -558,6 +562,8 @@
           changes =
               password_store_sync_->RemoveLoginByPrimaryKeySync(primary_key);
           if (changes.empty()) {
+            metrics_util::LogApplySyncChangesState(
+                metrics_util::ApplySyncChangesState::kApplyDeleteFailed);
             return syncer::ModelError(
                 FROM_HERE,
                 "Failed to delete an entry from the password store.");
@@ -582,6 +588,8 @@
     base::Optional<syncer::ModelError> error =
         sync_metadata_store_change_list.TakeError();
     if (error) {
+      metrics_util::LogApplySyncChangesState(
+          metrics_util::ApplySyncChangesState::kApplyMetadataChangesFailed);
       return error;
     }
     transaction.Commit();
@@ -593,6 +601,8 @@
     // observers since they aren't interested in changes to sync metadata.
     password_store_sync_->NotifyLoginsChanged(password_store_changes);
   }
+  metrics_util::LogApplySyncChangesState(
+      metrics_util::ApplySyncChangesState::kApplyOK);
   return base::nullopt;
 }
 
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 4f38698..35b9831 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -227,7 +227,6 @@
     "model/blocking_model_type_store.h",
     "model/change_processor.cc",
     "model/change_processor.h",
-    "model/conflict_resolution.cc",
     "model/conflict_resolution.h",
     "model/data_batch.h",
     "model/data_type_activation_request.cc",
@@ -757,6 +756,7 @@
     "model_impl/processor_entity_unittest.cc",
     "model_impl/syncable_service_based_bridge_unittest.cc",
     "nigori/nigori_model_type_processor_unittest.cc",
+    "nigori/nigori_sync_bridge_impl_unittest.cc",
     "protocol/proto_enum_conversions_unittest.cc",
     "protocol/proto_value_conversions_unittest.cc",
     "syncable/change_record_unittest.cc",
diff --git a/components/sync/driver/sync_auth_manager.cc b/components/sync/driver/sync_auth_manager.cc
index 08278967..ee1d008 100644
--- a/components/sync/driver/sync_auth_manager.cc
+++ b/components/sync/driver/sync_auth_manager.cc
@@ -312,13 +312,25 @@
     SetLastAuthError(token_error);
 
     credentials_changed_callback_.Run();
-    return;
-  }
+  } else if (IsWebSignout(last_auth_error_)) {
+    // Conversely, if we just exited the web-signout state, we need to reset the
+    // last auth error and tell our client (i.e. the SyncService) so that it'll
+    // know to resume syncing (if appropriate).
+    // TODO(blundell): Long-term, it would be nicer if Sync didn't have to
+    // cache signin-level authentication errors.
+    SetLastAuthError(token_error);
+    credentials_changed_callback_.Run();
 
-  // If we already have an access token or previously failed to retrieve one
-  // (and hence the retry timer is running), then request a fresh access token
-  // now. This will also drop the current access token.
-  if (!access_token_.empty() || request_access_token_retry_timer_.IsRunning()) {
+    // If we have an open connection to the server, then also get a new access
+    // token now.
+    if (connection_open_) {
+      RequestAccessToken();
+    }
+  } else if (!access_token_.empty() ||
+             request_access_token_retry_timer_.IsRunning()) {
+    // If we already have an access token or previously failed to retrieve one
+    // (and hence the retry timer is running), then request a fresh access token
+    // now. This will also drop the current access token.
     DCHECK(!ongoing_access_token_fetch_);
     RequestAccessToken();
   } else if (last_auth_error_ != GoogleServiceAuthError::AuthErrorNone() &&
@@ -326,8 +338,8 @@
     // If we were in an auth error state, then now's also a good time to try
     // again. In this case it's possible that there is already a pending
     // request, in which case RequestAccessToken will simply do nothing.
-    // Note: This is necessary to get out of the "Sync paused" state (see
-    // above), or to recover if the refresh token was previously removed.
+    // Note: This is necessary to recover if the refresh token was previously
+    // removed.
     RequestAccessToken();
   }
 }
diff --git a/components/sync/driver/sync_auth_manager_unittest.cc b/components/sync/driver/sync_auth_manager_unittest.cc
index fbbc70c9..97f2a332 100644
--- a/components/sync/driver/sync_auth_manager_unittest.cc
+++ b/components/sync/driver/sync_auth_manager_unittest.cc
@@ -571,7 +571,13 @@
 TEST_F(SyncAuthManagerTest, DoesNotRequestAccessTokenIfSyncInactive) {
   std::string account_id =
       identity_env()->MakePrimaryAccountAvailable("test@email.com").account_id;
-  auto auth_manager = CreateAuthManager();
+
+  base::MockCallback<AccountStateChangedCallback> account_state_changed;
+  base::MockCallback<CredentialsChangedCallback> credentials_changed;
+  EXPECT_CALL(account_state_changed, Run()).Times(0);
+  EXPECT_CALL(credentials_changed, Run()).Times(0);
+  auto auth_manager =
+      CreateAuthManager(account_state_changed.Get(), credentials_changed.Get());
   auth_manager->RegisterForAuthNotifications();
   ASSERT_EQ(auth_manager->GetActiveAccountInfo().account_info.account_id,
             account_id);
@@ -581,6 +587,7 @@
   // An invalid refresh token gets set, i.e. we enter the "Sync paused" state
   // (only from SyncAuthManager's point of view - Sync as a whole is still
   // disabled).
+  EXPECT_CALL(credentials_changed, Run());
   identity_env()->SetInvalidRefreshTokenForPrimaryAccount();
   ASSERT_TRUE(auth_manager->GetCredentials().access_token.empty());
   ASSERT_TRUE(auth_manager->IsSyncPaused());
@@ -591,7 +598,11 @@
   EXPECT_CALL(access_token_requested, Run()).Times(0);
   identity_env()->SetCallbackForNextAccessTokenRequest(
       access_token_requested.Get());
+  // This *should* notify about changed credentials though, so that the
+  // SyncService can decide to start syncing.
+  EXPECT_CALL(credentials_changed, Run());
   identity_env()->SetRefreshTokenForPrimaryAccount();
+  ASSERT_FALSE(auth_manager->IsSyncPaused());
 
   // Since the access token request goes through posted tasks, we have to spin
   // the message loop to make sure it didn't happen.
diff --git a/components/sync/model/conflict_resolution.cc b/components/sync/model/conflict_resolution.cc
deleted file mode 100644
index eedeb0d..0000000
--- a/components/sync/model/conflict_resolution.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/sync/model/conflict_resolution.h"
-
-#include <utility>
-
-namespace syncer {
-
-// static
-ConflictResolution ConflictResolution::UseLocal() {
-  return ConflictResolution(USE_LOCAL, nullptr);
-}
-
-// static
-ConflictResolution ConflictResolution::UseRemote() {
-  return ConflictResolution(USE_REMOTE, nullptr);
-}
-
-// static
-ConflictResolution ConflictResolution::UseNew(
-    std::unique_ptr<EntityData> data) {
-  DCHECK(data);
-  return ConflictResolution(USE_NEW, std::move(data));
-}
-
-ConflictResolution::ConflictResolution(ConflictResolution&& other)
-    : ConflictResolution(other.type(), other.ExtractData()) {}
-
-ConflictResolution::~ConflictResolution() {}
-
-std::unique_ptr<EntityData> ConflictResolution::ExtractData() {
-  // Has data if and only if type is USE_NEW.
-  DCHECK((type_ == USE_NEW) == !!data_);
-  return std::move(data_);
-}
-
-ConflictResolution::ConflictResolution(Type type,
-                                       std::unique_ptr<EntityData> data)
-    : type_(type), data_(std::move(data)) {}
-
-}  // namespace syncer
diff --git a/components/sync/model/conflict_resolution.h b/components/sync/model/conflict_resolution.h
index 2399cc31..63d6d25 100644
--- a/components/sync/model/conflict_resolution.h
+++ b/components/sync/model/conflict_resolution.h
@@ -5,51 +5,20 @@
 #ifndef COMPONENTS_SYNC_MODEL_CONFLICT_RESOLUTION_H_
 #define COMPONENTS_SYNC_MODEL_CONFLICT_RESOLUTION_H_
 
-#include <memory>
-
-#include "components/sync/model/entity_data.h"
-
 namespace syncer {
 
-// A simple class to represent the resolution of a data conflict. We either:
+// An enum to represent the resolution of a data conflict. We either:
 // 1) Use the local client data and update the server.
 // 2) Use the remote server data and update the client.
-// 3) Use newly created data and update both.
-class ConflictResolution {
- public:
-  // This enum is used in histograms.xml and entries shouldn't be renumbered or
-  // removed. New entries must be added at the end, before TYPE_SIZE.
-  enum Type {
-    CHANGES_MATCH,  // Exists for logging purposes.
-    USE_LOCAL,
-    USE_REMOTE,
-    USE_NEW,
-    IGNORE_LOCAL_ENCRYPTION,   // Exists for logging purposes.
-    IGNORE_REMOTE_ENCRYPTION,  // Exists for logging purposes.
-    TYPE_SIZE,
-  };
-
-  // Convenience functions for brevity.
-  static ConflictResolution UseLocal();
-  static ConflictResolution UseRemote();
-  static ConflictResolution UseNew(std::unique_ptr<EntityData> data);
-
-  // Move constructor since we can't copy a unique_ptr.
-  ConflictResolution(ConflictResolution&& other);
-  ~ConflictResolution();
-
-  Type type() const { return type_; }
-
-  // Get the data for USE_NEW, or nullptr. Can only be called once.
-  std::unique_ptr<EntityData> ExtractData();
-
- private:
-  ConflictResolution(Type type, std::unique_ptr<EntityData> data);
-
-  const Type type_;
-  std::unique_ptr<EntityData> data_;
-
-  DISALLOW_COPY_AND_ASSIGN(ConflictResolution);
+// We use this enum for UMA and values shouldn't change.
+enum class ConflictResolution {
+  kChangesMatch,  // Exists for logging purposes.
+  kUseLocal,
+  kUseRemote,
+  kUseNewDEPRECATED,  // Deprecated because it's not used in production code.
+  kIgnoreLocalEncryption,   // Exists for logging purposes.
+  kIgnoreRemoteEncryption,  // Exists for logging purposes.
+  kTypeSize,
 };
 
 }  // namespace syncer
diff --git a/components/sync/model/fake_model_type_sync_bridge.cc b/components/sync/model/fake_model_type_sync_bridge.cc
index 5e05b68..f3f3ae3e 100644
--- a/components/sync/model/fake_model_type_sync_bridge.cc
+++ b/components/sync/model/fake_model_type_sync_bridge.cc
@@ -361,8 +361,7 @@
 ConflictResolution FakeModelTypeSyncBridge::ResolveConflict(
     const std::string& storage_key,
     const EntityData& remote_data) const {
-  DCHECK(conflict_resolution_);
-  return std::move(*conflict_resolution_);
+  return conflict_resolution_;
 }
 
 void FakeModelTypeSyncBridge::ApplyStopSyncChanges(
@@ -373,8 +372,7 @@
 
 void FakeModelTypeSyncBridge::SetConflictResolution(
     ConflictResolution resolution) {
-  conflict_resolution_ =
-      std::make_unique<ConflictResolution>(std::move(resolution));
+  conflict_resolution_ = resolution;
 }
 
 void FakeModelTypeSyncBridge::ErrorOnNextCall() {
diff --git a/components/sync/model/fake_model_type_sync_bridge.h b/components/sync/model/fake_model_type_sync_bridge.h
index 7fbf807f..f1c959a 100644
--- a/components/sync/model/fake_model_type_sync_bridge.h
+++ b/components/sync/model/fake_model_type_sync_bridge.h
@@ -169,7 +169,7 @@
   std::string GenerateStorageKey(const EntityData& entity_data);
 
   // The conflict resolution to use for calls to ResolveConflict.
-  std::unique_ptr<ConflictResolution> conflict_resolution_;
+  ConflictResolution conflict_resolution_;
 
   // The keys that the bridge will ignore.
   std::unordered_set<std::string> values_to_ignore_;
diff --git a/components/sync/model/model_type_sync_bridge.cc b/components/sync/model/model_type_sync_bridge.cc
index b6639f30..6edcdc8 100644
--- a/components/sync/model/model_type_sync_bridge.cc
+++ b/components/sync/model/model_type_sync_bridge.cc
@@ -40,9 +40,9 @@
     const std::string& storage_key,
     const EntityData& remote_data) const {
   if (remote_data.is_deleted()) {
-    return ConflictResolution::UseLocal();
+    return ConflictResolution::kUseLocal;
   }
-  return ConflictResolution::UseRemote();
+  return ConflictResolution::kUseRemote;
 }
 
 void ModelTypeSyncBridge::ApplyStopSyncChanges(
diff --git a/components/sync/model/model_type_sync_bridge.h b/components/sync/model/model_type_sync_bridge.h
index c753f61..fbe02684 100644
--- a/components/sync/model/model_type_sync_bridge.h
+++ b/components/sync/model/model_type_sync_bridge.h
@@ -16,7 +16,7 @@
 
 namespace syncer {
 
-class ConflictResolution;
+enum class ConflictResolution;
 class DataBatch;
 struct DataTypeActivationRequest;
 struct EntityData;
diff --git a/components/sync/model/model_type_sync_bridge_unittest.cc b/components/sync/model/model_type_sync_bridge_unittest.cc
index 761f57b..f221e8e4 100644
--- a/components/sync/model/model_type_sync_bridge_unittest.cc
+++ b/components/sync/model/model_type_sync_bridge_unittest.cc
@@ -36,7 +36,7 @@
   StubModelTypeSyncBridge bridge_;
 };
 
-// ResolveConflicts should return USE_REMOTE unless the remote data is deleted.
+// ResolveConflicts should return kUseRemote unless the remote data is deleted.
 TEST_F(ModelTypeSyncBridgeTest, DefaultConflictResolution) {
   EntityData local_data;
   EntityData remote_data;
@@ -46,26 +46,23 @@
   local_data.specifics.mutable_preference()->set_value("value");
   EXPECT_FALSE(local_data.is_deleted());
   EXPECT_TRUE(remote_data.is_deleted());
-  EXPECT_EQ(ConflictResolution::USE_LOCAL,
-            bridge()
-                ->ResolveConflict(/*storage_key=*/std::string(), remote_data)
-                .type());
+  EXPECT_EQ(
+      ConflictResolution::kUseLocal,
+      bridge()->ResolveConflict(/*storage_key=*/std::string(), remote_data));
 
   remote_data.specifics.mutable_preference()->set_value("value");
   EXPECT_FALSE(local_data.is_deleted());
   EXPECT_FALSE(remote_data.is_deleted());
-  EXPECT_EQ(ConflictResolution::USE_REMOTE,
-            bridge()
-                ->ResolveConflict(/*storage_key=*/std::string(), remote_data)
-                .type());
+  EXPECT_EQ(
+      ConflictResolution::kUseRemote,
+      bridge()->ResolveConflict(/*storage_key=*/std::string(), remote_data));
 
   local_data.specifics.clear_preference();
   EXPECT_TRUE(local_data.is_deleted());
   EXPECT_FALSE(remote_data.is_deleted());
-  EXPECT_EQ(ConflictResolution::USE_REMOTE,
-            bridge()
-                ->ResolveConflict(/*storage_key=*/std::string(), remote_data)
-                .type());
+  EXPECT_EQ(
+      ConflictResolution::kUseRemote,
+      bridge()->ResolveConflict(/*storage_key=*/std::string(), remote_data));
 }
 
 }  // namespace
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.cc b/components/sync/model_impl/client_tag_based_model_type_processor.cc
index da200ce..0cba013cf 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.cc
@@ -796,13 +796,13 @@
     return nullptr;
   }
 
-  ConflictResolution::Type resolution_type = ConflictResolution::TYPE_SIZE;
+  ConflictResolution resolution_type = ConflictResolution::kTypeSize;
   if (entity && entity->IsUnsynced()) {
     // Handle conflict resolution.
     resolution_type =
         ResolveConflict(*update, entity, entity_changes, storage_key_to_clear);
     UMA_HISTOGRAM_ENUMERATION("Sync.ResolveConflict", resolution_type,
-                              ConflictResolution::TYPE_SIZE);
+                              ConflictResolution::kTypeSize);
   } else {
     // Handle simple create/delete/update.
     base::Optional<EntityChange::ChangeType> change_type;
@@ -852,54 +852,51 @@
   return entity;
 }
 
-ConflictResolution::Type ClientTagBasedModelTypeProcessor::ResolveConflict(
+ConflictResolution ClientTagBasedModelTypeProcessor::ResolveConflict(
     const UpdateResponseData& update,
     ProcessorEntity* entity,
     EntityChangeList* changes,
     std::string* storage_key_to_clear) {
   const EntityData& remote_data = *update.entity;
 
-  ConflictResolution::Type resolution_type = ConflictResolution::TYPE_SIZE;
-  std::unique_ptr<EntityData> new_data;
+  ConflictResolution resolution_type = ConflictResolution::kTypeSize;
 
   // Determine the type of resolution.
   if (entity->MatchesData(remote_data)) {
     // The changes are identical so there isn't a real conflict.
-    resolution_type = ConflictResolution::CHANGES_MATCH;
+    resolution_type = ConflictResolution::kChangesMatch;
   } else if (entity->metadata().is_deleted()) {
     // Local tombstone vs remote update (non-deletion). Should be undeleted.
-    resolution_type = ConflictResolution::USE_REMOTE;
+    resolution_type = ConflictResolution::kUseRemote;
   } else if (entity->MatchesOwnBaseData()) {
     // If there is no real local change, then the entity must be unsynced due to
     // a pending local re-encryption request. In this case, the remote data
     // should win.
-    resolution_type = ConflictResolution::IGNORE_LOCAL_ENCRYPTION;
+    resolution_type = ConflictResolution::kIgnoreLocalEncryption;
   } else if (entity->MatchesBaseData(remote_data)) {
     // The remote data isn't actually changing from the last remote data that
     // was seen, so it must have been a re-encryption and can be ignored.
-    resolution_type = ConflictResolution::IGNORE_REMOTE_ENCRYPTION;
+    resolution_type = ConflictResolution::kIgnoreRemoteEncryption;
   } else {
     // There's a real data conflict here; let the bridge resolve it.
-    ConflictResolution resolution =
+    resolution_type =
         bridge_->ResolveConflict(entity->storage_key(), remote_data);
-    resolution_type = resolution.type();
-    new_data = resolution.ExtractData();
   }
 
   // Apply the resolution.
   switch (resolution_type) {
-    case ConflictResolution::CHANGES_MATCH:
+    case ConflictResolution::kChangesMatch:
       // Record the update and squash the pending commit.
       entity->RecordForcedUpdate(update);
       break;
-    case ConflictResolution::USE_LOCAL:
-    case ConflictResolution::IGNORE_REMOTE_ENCRYPTION:
+    case ConflictResolution::kUseLocal:
+    case ConflictResolution::kIgnoreRemoteEncryption:
       // Record that we received the update from the server but leave the
       // pending commit intact.
       entity->RecordIgnoredUpdate(update);
       break;
-    case ConflictResolution::USE_REMOTE:
-    case ConflictResolution::IGNORE_LOCAL_ENCRYPTION:
+    case ConflictResolution::kUseRemote:
+    case ConflictResolution::kIgnoreLocalEncryption:
       // Update client data to match server.
       if (update.entity->is_deleted()) {
         DCHECK(!entity->metadata().is_deleted());
@@ -920,21 +917,11 @@
       // Squash the pending commit.
       entity->RecordForcedUpdate(update);
       break;
-    case ConflictResolution::USE_NEW:
-      DCHECK(!entity->metadata().is_deleted());
-      // Record that we received the update.
-      entity->RecordIgnoredUpdate(update);
-      // Make a new pending commit to update the server.
-      entity->MakeLocalChange(std::move(new_data));
-      // Update the client with the new entity.
-      changes->push_back(EntityChange::CreateUpdate(
-          entity->storage_key(), entity->commit_data().Clone()));
-      break;
-    case ConflictResolution::TYPE_SIZE:
+    case ConflictResolution::kUseNewDEPRECATED:
+    case ConflictResolution::kTypeSize:
       NOTREACHED();
       break;
   }
-  DCHECK(!new_data);
 
   return resolution_type;
 }
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.h b/components/sync/model_impl/client_tag_based_model_type_processor.h
index 2e17196a..2efc4bf 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.h
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.h
@@ -140,10 +140,10 @@
                                  std::string* storage_key_to_clear);
 
   // Resolve a conflict between |update| and the pending commit in |entity|.
-  ConflictResolution::Type ResolveConflict(const UpdateResponseData& update,
-                                           ProcessorEntity* entity,
-                                           EntityChangeList* changes,
-                                           std::string* storage_key_to_clear);
+  ConflictResolution ResolveConflict(const UpdateResponseData& update,
+                                     ProcessorEntity* entity,
+                                     EntityChangeList* changes,
+                                     std::string* storage_key_to_clear);
 
   // Recommit all entities for encryption except those in |already_updated|.
   void RecommitAllForEncryption(
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
index e4d1fb2..4c3e8df 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
@@ -1346,7 +1346,7 @@
   InitializeToReadyState();
   // WriteAndAck entity to get id from the server.
   WriteItemAndAck(kKey1, kValue1);
-  bridge()->SetConflictResolution(ConflictResolution::UseLocal());
+  bridge()->SetConflictResolution(ConflictResolution::kUseLocal);
 
   // Change value locally and at the same time simulate conflicting update from
   // server.
@@ -1375,7 +1375,7 @@
 
   // The update from the server should be mostly ignored because local wins, but
   // the server ID should be updated.
-  bridge()->SetConflictResolution(ConflictResolution::UseLocal());
+  bridge()->SetConflictResolution(ConflictResolution::kUseLocal);
   worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue3));
   OnCommitDataLoaded();
   // In this test setup, the processor's nudge for commit immediately pulls
@@ -1480,7 +1480,7 @@
        ShouldResolveConflictToRemoteVersion) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
-  bridge()->SetConflictResolution(ConflictResolution::UseRemote());
+  bridge()->SetConflictResolution(ConflictResolution::kUseRemote);
   worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2));
 
   // Updated client data and metadata; no new commit request.
@@ -1495,7 +1495,7 @@
        ShouldResolveConflictToRemoteDeletion) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
-  bridge()->SetConflictResolution(ConflictResolution::UseRemote());
+  bridge()->SetConflictResolution(ConflictResolution::kUseRemote);
   worker()->TombstoneFromServer(kHash1);
 
   // Updated client data and metadata; no new commit request.
@@ -1505,23 +1505,6 @@
   EXPECT_EQ(2U, db()->metadata_change_count());
 }
 
-TEST_F(ClientTagBasedModelTypeProcessorTest,
-       ShouldResolveConflictToNewVersion) {
-  InitializeToReadyState();
-  bridge()->WriteItem(kKey1, kValue1);
-  bridge()->SetConflictResolution(
-      ConflictResolution::UseNew(GenerateEntityData(kKey1, kValue3)));
-
-  worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2));
-  EXPECT_EQ(2U, db()->data_change_count());
-  EXPECT_EQ(kValue3, db()->GetValue(kKey1));
-  EXPECT_EQ(2U, db()->metadata_change_count());
-  EXPECT_EQ(1, db()->GetMetadata(kKey1).server_version());
-  worker()->VerifyPendingCommits({{kHash1}, {kHash1}});
-  worker()->VerifyNthPendingCommit(1, {kHash1},
-                                   {GenerateSpecifics(kKey1, kValue3)});
-}
-
 // Test proper handling of disconnect and reconnect.
 //
 // Creates items in various states of commit and verifies they re-attempt to
@@ -1710,7 +1693,7 @@
   worker()->VerifyPendingCommits({{kHash1, kHash2}, {kHash4}});
 }
 
-// Test that re-encrypting enqueues the right data for USE_LOCAL conflicts.
+// Test that re-encrypting enqueues the right data for kUseLocal conflicts.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldResolveConflictToLocalDuringReencryption) {
   InitializeToReadyState();
@@ -1722,7 +1705,7 @@
   EntitySpecifics specifics = bridge()->WriteItem(kKey1, kValue2);
   worker()->VerifyPendingCommits({{kHash1}, {kHash1}});
 
-  bridge()->SetConflictResolution(ConflictResolution::UseLocal());
+  bridge()->SetConflictResolution(ConflictResolution::kUseLocal);
   // Unencrypted update needs to be re-commited with key k1.
   worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue3), 1, "");
   OnCommitDataLoaded();
@@ -1733,14 +1716,14 @@
   EXPECT_EQ(kValue2, db()->GetValue(kKey1));
 }
 
-// Test that re-encrypting enqueues the right data for USE_REMOTE conflicts.
+// Test that re-encrypting enqueues the right data for kUseRemote conflicts.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldResolveConflictToRemoteDuringReencryption) {
   InitializeToReadyState();
   worker()->UpdateWithEncryptionKey("k1");
   bridge()->WriteItem(kKey1, kValue1);
 
-  bridge()->SetConflictResolution(ConflictResolution::UseRemote());
+  bridge()->SetConflictResolution(ConflictResolution::kUseRemote);
   // Unencrypted update needs to be re-commited with key k1.
   EntitySpecifics specifics = GenerateSpecifics(kKey1, kValue2);
   worker()->UpdateFromServer(kHash1, specifics, 1, "");
@@ -1752,25 +1735,6 @@
   EXPECT_EQ(kValue2, db()->GetValue(kKey1));
 }
 
-// Test that re-encrypting enqueues the right data for USE_NEW conflicts.
-TEST_F(ClientTagBasedModelTypeProcessorTest,
-       ShouldResolveConflictToNewDuringReencryption) {
-  InitializeToReadyState();
-  worker()->UpdateWithEncryptionKey("k1");
-  bridge()->WriteItem(kKey1, kValue1);
-
-  bridge()->SetConflictResolution(
-      ConflictResolution::UseNew(GenerateEntityData(kKey1, kValue3)));
-  // Unencrypted update needs to be re-commited with key k1.
-  worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2), 1, "");
-
-  // Ensure the re-commit has the correct value.
-  EXPECT_EQ(2U, worker()->GetNumPendingCommits());
-  worker()->VerifyNthPendingCommit(1, {kHash1},
-                                   {GenerateSpecifics(kKey1, kValue3)});
-  EXPECT_EQ(kValue3, db()->GetValue(kKey1));
-}
-
 TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldHandleConflictWhileLoadingForReencryption) {
   InitializeToReadyState();
diff --git a/components/sync/model_impl/syncable_service_based_bridge.cc b/components/sync/model_impl/syncable_service_based_bridge.cc
index 4c342613..313451e 100644
--- a/components/sync/model_impl/syncable_service_based_bridge.cc
+++ b/components/sync/model_impl/syncable_service_based_bridge.cc
@@ -407,17 +407,17 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!remote_data.is_deleted()) {
-    return ConflictResolution::UseRemote();
+    return ConflictResolution::kUseRemote;
   }
 
   // Ignore local changes for extensions/apps when server had a delete, to
   // avoid unwanted reinstall of an uninstalled extension.
   if (type_ == EXTENSIONS || type_ == APPS) {
     DVLOG(1) << "Resolving conflict, ignoring local changes for extension/app";
-    return ConflictResolution::UseRemote();
+    return ConflictResolution::kUseRemote;
   }
 
-  return ConflictResolution::UseLocal();
+  return ConflictResolution::kUseLocal;
 }
 
 void SyncableServiceBasedBridge::ApplyStopSyncChanges(
diff --git a/components/sync/nigori/nigori_model_type_processor.cc b/components/sync/nigori/nigori_model_type_processor.cc
index 0de7874..2a99597 100644
--- a/components/sync/nigori/nigori_model_type_processor.cc
+++ b/components/sync/nigori/nigori_model_type_processor.cc
@@ -4,8 +4,10 @@
 
 #include "components/sync/nigori/nigori_model_type_processor.h"
 
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "components/sync/base/time.h"
 #include "components/sync/engine/commit_queue.h"
+#include "components/sync/engine/model_type_processor_proxy.h"
 #include "components/sync/model_impl/processor_entity.h"
 #include "components/sync/nigori/nigori_sync_bridge.h"
 
@@ -13,13 +15,15 @@
 
 namespace {
 
-// TODO(mamir): remove those and adjust the code accordingly.
+// TODO(mamir): remove those and adjust the code accordingly. Similarly in
+// tests.
 const char kNigoriStorageKey[] = "NigoriStorageKey";
 const char kNigoriClientTagHash[] = "NigoriClientTagHash";
 
 }  // namespace
 
-NigoriModelTypeProcessor::NigoriModelTypeProcessor() : bridge_(nullptr) {}
+NigoriModelTypeProcessor::NigoriModelTypeProcessor()
+    : bridge_(nullptr), weak_ptr_factory_for_worker_(this) {}
 
 NigoriModelTypeProcessor::~NigoriModelTypeProcessor() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -39,12 +43,11 @@
   DCHECK(IsConnected());
 
   DVLOG(1) << "Disconnecting sync for Encryption Keys";
-  // TODO(mamir): weak_ptr_factory_for_worker_.InvalidateWeakPtrs();
+  weak_ptr_factory_for_worker_.InvalidateWeakPtrs();
   worker_.reset();
   if (entity_) {
     entity_->ClearTransientSyncState();
   }
-  NOTIMPLEMENTED();
 }
 
 void NigoriModelTypeProcessor::GetLocalChanges(
@@ -87,27 +90,142 @@
     const sync_pb::ModelTypeState& type_state,
     const CommitResponseDataList& response_list) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  NOTIMPLEMENTED();
+  DCHECK(entity_);
+
+  model_type_state_ = type_state;
+  if (!response_list.empty()) {
+    entity_->ReceiveCommitResponse(response_list[0], /*commit_only=*/false,
+                                   ModelType::NIGORI);
+  } else {
+    // If the entity hasn't been mentioned in response_list, then it's not
+    // committed and we should reset its commit_requested_sequence_number so
+    // they are committed again on next sync cycle.
+    entity_->ClearTransientSyncState();
+  }
+  // Ask the bridge to persist the new metadata.
+  bridge_->ApplySyncChanges(/*data=*/base::nullopt);
 }
 
 void NigoriModelTypeProcessor::OnUpdateReceived(
     const sync_pb::ModelTypeState& type_state,
     UpdateResponseDataList updates) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  NOTIMPLEMENTED();
+  DCHECK(model_ready_to_sync_);
+  // If there is a model error, it must have been reported already but hasn't
+  // reached the sync engine yet. In this case return directly to avoid
+  // interactions with the bridge.
+  if (model_error_) {
+    return;
+  }
+
+  base::Optional<ModelError> error;
+
+  bool is_initial_sync = !model_type_state_.initial_sync_done();
+  model_type_state_ = type_state;
+
+  if (is_initial_sync) {
+    DCHECK(!entity_);
+    if (updates.empty()) {
+      error = bridge_->MergeSyncData(base::nullopt);
+    } else {
+      DCHECK(!updates[0]->entity->is_deleted());
+      entity_ = ProcessorEntity::CreateNew(
+          kNigoriStorageKey, kNigoriClientTagHash, updates[0]->entity->id,
+          updates[0]->entity->creation_time);
+      entity_->RecordAcceptedUpdate(*updates[0]);
+      error = bridge_->MergeSyncData(std::move(*updates[0]->entity));
+    }
+    if (error) {
+      // TODO(mamir): ReportError(*error);
+      NOTIMPLEMENTED();
+    }
+    return;
+  }
+
+  if (updates.empty()) {
+    bridge_->ApplySyncChanges(/*data=*/base::nullopt);
+    return;
+  }
+
+  DCHECK(entity_);
+  // We assume the bridge will issue errors in case of deletions. Therefore, we
+  // are adding the following DCHECK to simplify the code.
+  DCHECK(!updates[0]->entity->is_deleted());
+
+  if (entity_->UpdateIsReflection(updates[0]->response_version)) {
+    // Seen this update before; just ignore it.
+    bridge_->ApplySyncChanges(/*data=*/base::nullopt);
+    return;
+  }
+
+  if (entity_->IsUnsynced()) {
+    // TODO(mamir): conflict resolution
+    NOTIMPLEMENTED();
+  } else if (!entity_->MatchesData(*updates[0]->entity)) {
+    // Inform the bridge of the new or updated data.
+    entity_->RecordAcceptedUpdate(*updates[0]);
+    error = bridge_->ApplySyncChanges(std::move(*updates[0]->entity));
+  }
+
+  if (error) {
+    // TODO(mamir): ReportError(*error);
+    NOTIMPLEMENTED();
+    return;
+  }
+
+  // There may be new reasons to commit by the time this function is done.
+  NudgeForCommitIfNeeded();
 }
 
 void NigoriModelTypeProcessor::OnSyncStarting(
     const DataTypeActivationRequest& request,
     StartCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  NOTIMPLEMENTED();
+  DVLOG(1) << "Sync is starting for Encryption Keys";
+  DCHECK(request.error_handler) << "Encryption Keys";
+  DCHECK(callback) << "Encryption Keys";
+  DCHECK(!start_callback_) << "Encryption Keys";
+  DCHECK(!IsConnected()) << "Encryption Keys";
+
+  start_callback_ = std::move(callback);
+  activation_request_ = request;
+
+  ConnectIfReady();
 }
 
 void NigoriModelTypeProcessor::OnSyncStopping(
     SyncStopMetadataFate metadata_fate) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  NOTIMPLEMENTED();
+  // Disabling sync for a type shouldn't happen before the model is loaded
+  // because OnSyncStopping() is not allowed to be called before
+  // OnSyncStarting() has completed.
+  DCHECK(!start_callback_);
+
+  worker_.reset();
+
+  switch (metadata_fate) {
+    case syncer::KEEP_METADATA: {
+      break;
+    }
+
+    case syncer::CLEAR_METADATA: {
+      // The bridge is responsible for deleting all data and metadata upon
+      // disabling sync.
+      bridge_->ApplyDisableSyncChanges();
+      model_ready_to_sync_ = false;
+      entity_.reset();
+      model_type_state_ = sync_pb::ModelTypeState();
+      model_type_state_.mutable_progress_marker()->set_data_type_id(
+          sync_pb::EntitySpecifics::kNigoriFieldNumber);
+      // The model is still ready to sync (with the same |bridge_|) and same
+      // sync metadata.
+      ModelReadyToSync(bridge_, NigoriMetadataBatch());
+      break;
+    }
+  }
+
+  // Do not let any delayed callbacks to be called.
+  weak_ptr_factory_for_worker_.InvalidateWeakPtrs();
 }
 
 void NigoriModelTypeProcessor::GetAllNodesForDebugging(
@@ -154,8 +272,7 @@
     model_type_state_.mutable_progress_marker()->set_data_type_id(
         sync_pb::EntitySpecifics::kNigoriFieldNumber);
   }
-  // TODO(mamir): ConnectIfReady();
-  NOTIMPLEMENTED();
+  ConnectIfReady();
 }
 
 void NigoriModelTypeProcessor::Put(std::unique_ptr<EntityData> entity_data) {
@@ -194,6 +311,10 @@
   return nigori_metadata_batch;
 }
 
+bool NigoriModelTypeProcessor::IsConnectedForTest() const {
+  return IsConnected();
+}
+
 bool NigoriModelTypeProcessor::IsTrackingMetadata() {
   return model_type_state_.initial_sync_done();
 }
@@ -203,6 +324,40 @@
   return worker_ != nullptr;
 }
 
+void NigoriModelTypeProcessor::ConnectIfReady() {
+  if (!start_callback_) {
+    return;
+  }
+  if (!model_ready_to_sync_) {
+    return;
+  }
+  if (model_error_) {
+    activation_request_.error_handler.Run(model_error_.value());
+    start_callback_.Reset();
+    return;
+  }
+  DCHECK(model_ready_to_sync_);
+
+  if (!model_type_state_.has_cache_guid()) {
+    model_type_state_.set_cache_guid(activation_request_.cache_guid);
+  } else if (model_type_state_.cache_guid() != activation_request_.cache_guid) {
+    // TODO(mamir): implement error handling in case of cache GUID mismatch.
+    NOTIMPLEMENTED();
+  }
+
+  // Cache GUID verification earlier above guarantees the user is the same.
+  model_type_state_.set_authenticated_account_id(
+      activation_request_.authenticated_account_id);
+
+  auto activation_response = std::make_unique<DataTypeActivationResponse>();
+  activation_response->model_type_state = model_type_state_;
+  activation_response->type_processor =
+      std::make_unique<ModelTypeProcessorProxy>(
+          weak_ptr_factory_for_worker_.GetWeakPtr(),
+          base::SequencedTaskRunnerHandle::Get());
+  std::move(start_callback_).Run(std::move(activation_response));
+}
+
 void NigoriModelTypeProcessor::NudgeForCommitIfNeeded() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Don't bother sending anything if there's no one to send to.
diff --git a/components/sync/nigori/nigori_model_type_processor.h b/components/sync/nigori/nigori_model_type_processor.h
index b16b5b9..e15bbc66 100644
--- a/components/sync/nigori/nigori_model_type_processor.h
+++ b/components/sync/nigori/nigori_model_type_processor.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "components/sync/engine/model_type_processor.h"
+#include "components/sync/model/data_type_activation_request.h"
 #include "components/sync/model/model_type_controller_delegate.h"
 #include "components/sync/nigori/nigori_local_change_processor.h"
 #include "components/sync/protocol/entity_metadata.pb.h"
@@ -51,12 +52,17 @@
   void Put(std::unique_ptr<EntityData> entity_data) override;
   NigoriMetadataBatch GetMetadata() override;
 
+  bool IsConnectedForTest() const;
+
  private:
   bool IsTrackingMetadata();
 
   // Returns true if the handshake with sync thread is complete.
   bool IsConnected() const;
 
+  // If preconditions are met, informs sync that we are ready to connect.
+  void ConnectIfReady();
+
   // Nudges worker if there are any local changes to be committed.
   void NudgeForCommitIfNeeded() const;
 
@@ -71,6 +77,12 @@
   // metadata).
   bool model_ready_to_sync_ = false;
 
+  // Stores the start callback in between OnSyncStarting() and ReadyToConnect().
+  StartCallback start_callback_;
+
+  // The request context passed in as part of OnSyncStarting().
+  DataTypeActivationRequest activation_request_;
+
   // The first model error that occurred, if any. Stored to track model state
   // and so it can be passed to sync if it happened prior to sync being ready.
   base::Optional<ModelError> model_error_;
@@ -85,6 +97,9 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
+  // WeakPtrFactory for this processor which will be sent to sync thread.
+  base::WeakPtrFactory<NigoriModelTypeProcessor> weak_ptr_factory_for_worker_;
+
   DISALLOW_COPY_AND_ASSIGN(NigoriModelTypeProcessor);
 };
 
diff --git a/components/sync/nigori/nigori_model_type_processor_unittest.cc b/components/sync/nigori/nigori_model_type_processor_unittest.cc
index a878e84..eb04b07b 100644
--- a/components/sync/nigori/nigori_model_type_processor_unittest.cc
+++ b/components/sync/nigori/nigori_model_type_processor_unittest.cc
@@ -8,6 +8,9 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
 #include "components/sync/base/time.h"
 #include "components/sync/engine/commit_queue.h"
 #include "components/sync/nigori/nigori_sync_bridge.h"
@@ -18,16 +21,68 @@
 
 namespace {
 
+using testing::_;
 using testing::Eq;
 using testing::Ne;
+using testing::NotNull;
+
+// TODO(mamir): remove those and adjust the code accordingly.
+const char kNigoriClientTagHash[] = "NigoriClientTagHash";
 
 const char kNigoriNonUniqueName[] = "nigori";
+const char kNigoriServerId[] = "nigori_server_id";
+const char kCacheGuid[] = "generated_id";
+
+// |*arg| must be of type base::Optional<EntityData>.
+MATCHER_P(OptionalEntityDataHasDecryptorTokenKeyName, expected_key_name, "") {
+  return arg->specifics.nigori().keystore_decryptor_token().key_name() ==
+         expected_key_name;
+}
 
 void CaptureCommitRequest(CommitRequestDataList* dst,
                           CommitRequestDataList&& src) {
   *dst = std::move(src);
 }
 
+sync_pb::ModelTypeState CreateDummyModelTypeState() {
+  sync_pb::ModelTypeState model_type_state;
+  model_type_state.set_cache_guid(kCacheGuid);
+  model_type_state.set_initial_sync_done(true);
+  return model_type_state;
+}
+
+// Creates a dummy Nigori UpdateResponseData that has the keystore decryptor
+// token key name set.
+std::unique_ptr<syncer::UpdateResponseData> CreateDummyNigoriUpdateResponseData(
+    const std::string keystore_decryptor_token_key_name,
+    int response_version) {
+  auto entity_data = std::make_unique<syncer::EntityData>();
+  entity_data->id = kNigoriServerId;
+  sync_pb::NigoriSpecifics* nigori_specifics =
+      entity_data->specifics.mutable_nigori();
+  nigori_specifics->mutable_keystore_decryptor_token()->set_key_name(
+      keystore_decryptor_token_key_name);
+  entity_data->non_unique_name = kNigoriNonUniqueName;
+
+  auto response_data = std::make_unique<syncer::UpdateResponseData>();
+  response_data->entity = std::move(entity_data);
+  response_data->response_version = response_version;
+  return response_data;
+}
+
+CommitResponseData CreateNigoriCommitResponseData(
+    const CommitRequestData& commit_request_data,
+    int response_version) {
+  CommitResponseData commit_response_data;
+  commit_response_data.id = kNigoriServerId;
+  commit_response_data.client_tag_hash = kNigoriClientTagHash;
+  commit_response_data.sequence_number = commit_request_data.sequence_number;
+  commit_response_data.response_version = response_version;
+  commit_response_data.specifics_hash = commit_request_data.specifics_hash;
+  commit_response_data.unsynced_time = commit_request_data.unsynced_time;
+  return commit_response_data;
+}
+
 class MockNigoriSyncBridge : public NigoriSyncBridge {
  public:
   MockNigoriSyncBridge() = default;
@@ -36,8 +91,9 @@
   MOCK_METHOD1(
       MergeSyncData,
       base::Optional<ModelError>(const base::Optional<EntityData>& data));
-  MOCK_METHOD1(ApplySyncChanges,
-               base::Optional<ModelError>(const EntityData& data));
+  MOCK_METHOD1(
+      ApplySyncChanges,
+      base::Optional<ModelError>(const base::Optional<EntityData>& data));
   MOCK_METHOD0(GetData, std::unique_ptr<EntityData>());
   MOCK_METHOD2(ResolveConflict,
                ConflictResolution(const EntityData& local_data,
@@ -60,18 +116,24 @@
     mock_commit_queue_ptr_ = mock_commit_queue_.get();
   }
 
-  void SimulateModelReadyToSyncWithInitialSyncDone() {
+  void SimulateModelReadyToSync(bool initial_sync_done, int server_version) {
     NigoriMetadataBatch nigori_metadata_batch;
-    nigori_metadata_batch.model_type_state.set_initial_sync_done(true);
+    nigori_metadata_batch.model_type_state.set_initial_sync_done(
+        initial_sync_done);
     nigori_metadata_batch.entity_metadata = sync_pb::EntityMetadata();
     nigori_metadata_batch.entity_metadata->set_creation_time(
         TimeToProtoTime(base::Time::Now()));
     nigori_metadata_batch.entity_metadata->set_sequence_number(0);
     nigori_metadata_batch.entity_metadata->set_acked_sequence_number(0);
+    nigori_metadata_batch.entity_metadata->set_server_version(server_version);
     processor_.ModelReadyToSync(mock_nigori_sync_bridge(),
                                 std::move(nigori_metadata_batch));
   }
 
+  void SimulateModelReadyToSync(bool initial_sync_done) {
+    SimulateModelReadyToSync(initial_sync_done, /*server_version=*/1);
+  }
+
   void SimulateConnectSync() {
     processor_.ConnectSync(std::move(mock_commit_queue_));
   }
@@ -85,6 +147,10 @@
   NigoriModelTypeProcessor* processor() { return &processor_; }
 
  private:
+  // This sets SequencedTaskRunnerHandle on the current thread, which the type
+  // processor will pick up as the sync task runner.
+  base::test::ScopedTaskEnvironment task_environment_;
+
   testing::NiceMock<MockNigoriSyncBridge> mock_nigori_sync_bridge_;
   std::unique_ptr<testing::NiceMock<MockCommitQueue>> mock_commit_queue_;
   MockCommitQueue* mock_commit_queue_ptr_;
@@ -123,7 +189,7 @@
 }
 
 TEST_F(NigoriModelTypeProcessorTest, ShouldIncrementSequenceNumberWhenPut) {
-  SimulateModelReadyToSyncWithInitialSyncDone();
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
   base::Optional<sync_pb::EntityMetadata> entity_metadata1 =
       processor()->GetMetadata().entity_metadata;
   ASSERT_TRUE(entity_metadata1);
@@ -143,7 +209,7 @@
 }
 
 TEST_F(NigoriModelTypeProcessorTest, ShouldGetEmptyLocalChanges) {
-  SimulateModelReadyToSyncWithInitialSyncDone();
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
   CommitRequestDataList commit_request;
   processor()->GetLocalChanges(
       /*max_entries=*/10,
@@ -152,7 +218,7 @@
 }
 
 TEST_F(NigoriModelTypeProcessorTest, ShouldGetLocalChangesWhenPut) {
-  SimulateModelReadyToSyncWithInitialSyncDone();
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
 
   auto entity_data = std::make_unique<syncer::EntityData>();
   entity_data->specifics.mutable_nigori();
@@ -168,8 +234,125 @@
 }
 
 TEST_F(NigoriModelTypeProcessorTest,
+       ShouldSquashCommitRequestUponCommitCompleted) {
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
+
+  auto entity_data = std::make_unique<syncer::EntityData>();
+  entity_data->specifics.mutable_nigori();
+  entity_data->non_unique_name = kNigoriNonUniqueName;
+
+  processor()->Put(std::move(entity_data));
+  CommitRequestDataList commit_request_list;
+  processor()->GetLocalChanges(
+      /*max_entries=*/10,
+      base::BindOnce(&CaptureCommitRequest, &commit_request_list));
+  ASSERT_EQ(1U, commit_request_list.size());
+
+  CommitResponseDataList commit_response_list;
+  commit_response_list.push_back(CreateNigoriCommitResponseData(
+      *commit_request_list[0], /*response_version=*/processor()
+                                       ->GetMetadata()
+                                       .entity_metadata->server_version() +
+                                   1));
+
+  // ApplySyncChanges() should be called to trigger persistence of the metadata.
+  EXPECT_CALL(*mock_nigori_sync_bridge(), ApplySyncChanges(Eq(base::nullopt)));
+  processor()->OnCommitCompleted(CreateDummyModelTypeState(),
+                                 std::move(commit_response_list));
+
+  // There should be no more local changes.
+  commit_response_list.clear();
+  processor()->GetLocalChanges(
+      /*max_entries=*/10,
+      base::BindOnce(&CaptureCommitRequest, &commit_request_list));
+  EXPECT_TRUE(commit_request_list.empty());
+}
+
+TEST_F(NigoriModelTypeProcessorTest,
+       ShouldNotSquashCommitRequestUponEmptyCommitResponse) {
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
+
+  auto entity_data = std::make_unique<syncer::EntityData>();
+  entity_data->specifics.mutable_nigori();
+  entity_data->non_unique_name = kNigoriNonUniqueName;
+
+  processor()->Put(std::move(entity_data));
+  CommitRequestDataList commit_request_list;
+  processor()->GetLocalChanges(
+      /*max_entries=*/10,
+      base::BindOnce(&CaptureCommitRequest, &commit_request_list));
+  ASSERT_EQ(1U, commit_request_list.size());
+
+  // ApplySyncChanges() should be called to trigger persistence of the metadata.
+  EXPECT_CALL(*mock_nigori_sync_bridge(), ApplySyncChanges(Eq(base::nullopt)));
+  processor()->OnCommitCompleted(CreateDummyModelTypeState(),
+                                 CommitResponseDataList());
+
+  // Data has been moved into the previous request, so the processor will ask
+  // for the commit data once more.
+  ON_CALL(*mock_nigori_sync_bridge(), GetData()).WillByDefault([&]() {
+    auto entity_data = std::make_unique<syncer::EntityData>();
+    entity_data->specifics.mutable_nigori();
+    entity_data->non_unique_name = kNigoriNonUniqueName;
+    return entity_data;
+  });
+
+  // The commit should still be pending.
+  CommitResponseDataList commit_response_list;
+  processor()->GetLocalChanges(
+      /*max_entries=*/10,
+      base::BindOnce(&CaptureCommitRequest, &commit_request_list));
+  EXPECT_EQ(1U, commit_request_list.size());
+}
+
+TEST_F(NigoriModelTypeProcessorTest,
+       ShouldKeepAnotherCommitRequestUponCommitCompleted) {
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
+
+  auto entity_data = std::make_unique<syncer::EntityData>();
+  sync_pb::NigoriSpecifics* nigori_specifics =
+      entity_data->specifics.mutable_nigori();
+  nigori_specifics->set_encrypt_bookmarks(true);
+  entity_data->non_unique_name = kNigoriNonUniqueName;
+
+  processor()->Put(std::move(entity_data));
+  CommitRequestDataList commit_request_list;
+  processor()->GetLocalChanges(
+      /*max_entries=*/10,
+      base::BindOnce(&CaptureCommitRequest, &commit_request_list));
+  ASSERT_EQ(1U, commit_request_list.size());
+
+  CommitResponseDataList commit_response_list;
+  commit_response_list.push_back(CreateNigoriCommitResponseData(
+      *commit_request_list[0], /*response_version=*/processor()
+                                       ->GetMetadata()
+                                       .entity_metadata->server_version() +
+                                   1));
+
+  // Make another local change before the commit response is received.
+  entity_data = std::make_unique<syncer::EntityData>();
+  nigori_specifics = entity_data->specifics.mutable_nigori();
+  entity_data->non_unique_name = kNigoriNonUniqueName;
+  nigori_specifics->set_encrypt_preferences(true);
+  processor()->Put(std::move(entity_data));
+
+  // ApplySyncChanges() should be called to trigger persistence of the metadata.
+  EXPECT_CALL(*mock_nigori_sync_bridge(), ApplySyncChanges(Eq(base::nullopt)));
+  // Receive the commit response of the first request.
+  processor()->OnCommitCompleted(CreateDummyModelTypeState(),
+                                 std::move(commit_response_list));
+
+  // There should still be a local change.
+  commit_response_list.clear();
+  processor()->GetLocalChanges(
+      /*max_entries=*/10,
+      base::BindOnce(&CaptureCommitRequest, &commit_request_list));
+  EXPECT_EQ(1U, commit_request_list.size());
+}
+
+TEST_F(NigoriModelTypeProcessorTest,
        ShouldNudgeForCommitUponConnectSyncIfReadyToSyncAndLocalChanges) {
-  SimulateModelReadyToSyncWithInitialSyncDone();
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
 
   auto entity_data = std::make_unique<syncer::EntityData>();
   entity_data->specifics.mutable_nigori();
@@ -182,7 +365,7 @@
 }
 
 TEST_F(NigoriModelTypeProcessorTest, ShouldNudgeForCommitUponPutIfReadyToSync) {
-  SimulateModelReadyToSyncWithInitialSyncDone();
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
   SimulateConnectSync();
 
   auto entity_data = std::make_unique<syncer::EntityData>();
@@ -193,6 +376,123 @@
   processor()->Put(std::move(entity_data));
 }
 
+TEST_F(NigoriModelTypeProcessorTest, ShouldInvokeSyncStartCallback) {
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
+
+  syncer::DataTypeActivationRequest request;
+  request.error_handler = base::DoNothing();
+  request.cache_guid = kCacheGuid;
+
+  base::MockCallback<ModelTypeControllerDelegate::StartCallback> start_callback;
+  std::unique_ptr<DataTypeActivationResponse> captured_response;
+  EXPECT_CALL(start_callback, Run)
+      .WillOnce(testing::Invoke(
+          [&captured_response](
+              std::unique_ptr<DataTypeActivationResponse> response) {
+            captured_response = std::move(response);
+          }));
+  processor()->OnSyncStarting(request, start_callback.Get());
+  ASSERT_THAT(captured_response, NotNull());
+  EXPECT_EQ(kCacheGuid, captured_response->model_type_state.cache_guid());
+
+  // Test that the |processor()| has been set in the activation response.
+  ASSERT_FALSE(processor()->IsConnectedForTest());
+  captured_response->type_processor->ConnectSync(
+      std::make_unique<testing::NiceMock<MockCommitQueue>>());
+  // RunUntilIdle() is needed because ModelTypeProcessorProxy() is used and it
+  // internally does posting of tasks.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(processor()->IsConnectedForTest());
+}
+
+TEST_F(NigoriModelTypeProcessorTest, ShouldMergeSyncData) {
+  SimulateModelReadyToSync(/*initial_sync_done=*/false);
+
+  const std::string kDecryptorTokenKeyName = "key_name";
+  UpdateResponseDataList updates;
+  updates.push_back(CreateDummyNigoriUpdateResponseData(kDecryptorTokenKeyName,
+                                                        /*server_version=*/1));
+
+  EXPECT_CALL(*mock_nigori_sync_bridge(),
+              MergeSyncData(OptionalEntityDataHasDecryptorTokenKeyName(
+                  kDecryptorTokenKeyName)));
+
+  processor()->OnUpdateReceived(CreateDummyModelTypeState(),
+                                std::move(updates));
+}
+
+TEST_F(NigoriModelTypeProcessorTest, ShouldApplySyncChanges) {
+  SimulateModelReadyToSync(/*initial_sync_done=*/true, /*server_version=*/1);
+
+  const std::string kDecryptorTokenKeyName = "key_name";
+  UpdateResponseDataList updates;
+  updates.push_back(CreateDummyNigoriUpdateResponseData(kDecryptorTokenKeyName,
+                                                        /*server_version=*/2));
+
+  EXPECT_CALL(*mock_nigori_sync_bridge(),
+              ApplySyncChanges(OptionalEntityDataHasDecryptorTokenKeyName(
+                  kDecryptorTokenKeyName)));
+
+  processor()->OnUpdateReceived(CreateDummyModelTypeState(),
+                                std::move(updates));
+}
+
+TEST_F(NigoriModelTypeProcessorTest, ShouldApplySyncChangesWhenEmptyUpdates) {
+  const int kServerVersion = 1;
+  SimulateModelReadyToSync(/*initial_sync_done=*/true, kServerVersion);
+
+  // ApplySyncChanges() should still be called to trigger persistence of the
+  // metadata.
+  EXPECT_CALL(*mock_nigori_sync_bridge(), ApplySyncChanges(Eq(base::nullopt)));
+
+  processor()->OnUpdateReceived(CreateDummyModelTypeState(),
+                                UpdateResponseDataList());
+}
+
+TEST_F(NigoriModelTypeProcessorTest, ShouldApplySyncChangesWhenReflection) {
+  const int kServerVersion = 1;
+  SimulateModelReadyToSync(/*initial_sync_done=*/true, kServerVersion);
+
+  UpdateResponseDataList updates;
+  updates.push_back(CreateDummyNigoriUpdateResponseData(
+      /*keystore_decryptor_token_key_name=*/"key_name", kServerVersion));
+
+  // ApplySyncChanges() should still be called to trigger persistence of the
+  // metadata.
+  EXPECT_CALL(*mock_nigori_sync_bridge(), ApplySyncChanges(Eq(base::nullopt)));
+
+  processor()->OnUpdateReceived(CreateDummyModelTypeState(),
+                                std::move(updates));
+}
+
+TEST_F(NigoriModelTypeProcessorTest, ShouldStopSyncingAndKeepMetadata) {
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
+  syncer::DataTypeActivationRequest request;
+  request.error_handler = base::DoNothing();
+  request.cache_guid = kCacheGuid;
+  processor()->OnSyncStarting(request, base::DoNothing());
+  SimulateConnectSync();
+
+  ASSERT_TRUE(processor()->IsConnectedForTest());
+  EXPECT_CALL(*mock_nigori_sync_bridge(), ApplyDisableSyncChanges()).Times(0);
+  processor()->OnSyncStopping(syncer::KEEP_METADATA);
+  EXPECT_FALSE(processor()->IsConnectedForTest());
+}
+
+TEST_F(NigoriModelTypeProcessorTest, ShouldStopSyncingAndClearMetadata) {
+  SimulateModelReadyToSync(/*initial_sync_done=*/true);
+  syncer::DataTypeActivationRequest request;
+  request.error_handler = base::DoNothing();
+  request.cache_guid = kCacheGuid;
+  processor()->OnSyncStarting(request, base::DoNothing());
+  SimulateConnectSync();
+
+  ASSERT_TRUE(processor()->IsConnectedForTest());
+  EXPECT_CALL(*mock_nigori_sync_bridge(), ApplyDisableSyncChanges());
+  processor()->OnSyncStopping(syncer::CLEAR_METADATA);
+  EXPECT_FALSE(processor()->IsConnectedForTest());
+}
+
 }  // namespace
 
 }  // namespace syncer
diff --git a/components/sync/nigori/nigori_sync_bridge.h b/components/sync/nigori/nigori_sync_bridge.h
index 3c1944ff..a5cfbae 100644
--- a/components/sync/nigori/nigori_sync_bridge.h
+++ b/components/sync/nigori/nigori_sync_bridge.h
@@ -31,7 +31,7 @@
 
   // Apply changes from the sync server locally.
   virtual base::Optional<ModelError> ApplySyncChanges(
-      const EntityData& data) = 0;
+      const base::Optional<EntityData>& data) = 0;
 
   // Retrieve Nigori sync data.
   virtual std::unique_ptr<EntityData> GetData() = 0;
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc
index 2481db8..88ba75f 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -4,9 +4,54 @@
 
 #include "components/sync/nigori/nigori_sync_bridge_impl.h"
 
+#include "base/base64.h"
+#include "base/location.h"
+#include "components/sync/base/nigori.h"
+#include "components/sync/base/passphrase_enums.h"
+#include "components/sync/model/entity_data.h"
+#include "components/sync/protocol/encryption.pb.h"
+#include "components/sync/protocol/nigori_specifics.pb.h"
+
 namespace syncer {
 
-NigoriSyncBridgeImpl::NigoriSyncBridgeImpl() = default;
+namespace {
+
+// Attempts to decrypt |keystore_decryptor_token| with |keystore_keys|. Returns
+// serialized Nigori key if successful and base::nullopt otherwise.
+base::Optional<std::string> DecryptKeystoreDecryptor(
+    const std::vector<std::string> keystore_keys,
+    const sync_pb::EncryptedData& keystore_decryptor_token,
+    Encryptor* const encryptor) {
+  if (keystore_decryptor_token.blob().empty()) {
+    return base::nullopt;
+  }
+
+  Cryptographer cryptographer(encryptor);
+  for (const std::string& key : keystore_keys) {
+    KeyParams key_params = {KeyDerivationParams::CreateForPbkdf2(), key};
+    // TODO(crbug.com/922900): possible behavioral change. Old implementation
+    // fails only if we failed to add current keystore key. Failing to add any
+    // of these keys doesn't seem valid. This line seems to be a good candidate
+    // for UMA, as it's not a normal situation, if we fail to add any key.
+    if (!cryptographer.AddKey(key_params)) {
+      return base::nullopt;
+    }
+  }
+
+  std::string serialized_nigori_key;
+  // This check should never fail as long as we don't receive invalid data.
+  if (!cryptographer.CanDecrypt(keystore_decryptor_token) ||
+      !cryptographer.DecryptToString(keystore_decryptor_token,
+                                     &serialized_nigori_key)) {
+    return base::nullopt;
+  }
+  return serialized_nigori_key;
+}
+
+}  // namespace
+
+NigoriSyncBridgeImpl::NigoriSyncBridgeImpl(Encryptor* encryptor)
+    : cryptographer_(encryptor) {}
 
 NigoriSyncBridgeImpl::~NigoriSyncBridgeImpl() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -52,27 +97,99 @@
 
 bool NigoriSyncBridgeImpl::NeedKeystoreKey() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  NOTIMPLEMENTED();
+  // We never need to explicitly ask the server to provide the new keystore
+  // key, because server sends keystore keys every time it sends keystore-based
+  // Nigori node.
+  // TODO(crbug.com/922900): verify logic above. Old implementation is
+  // different, but it's probably only related to Nigori migration to keystore
+  // logic: there was no need to send new Nigori node from the server, because
+  // the migration was implemented on client side, but client needs
+  // keystore keys in order to perform the migration.
   return false;
 }
 
 bool NigoriSyncBridgeImpl::SetKeystoreKeys(
     const std::vector<std::string>& keys) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (keys.empty() || keys.back().empty()) {
+    return false;
+  }
+
+  keystore_keys_.resize(keys.size());
+  for (size_t i = 0; i < keys.size(); ++i) {
+    // We need to apply base64 encoding before using the keys to provide
+    // backward compatibility with non-USS implementation. It's actually needed
+    // only for the keys persisting, but was applied before passing keys to
+    // cryptographer, so we have to do the same.
+    base::Base64Encode(keys[i], &keystore_keys_[i]);
+  }
+
+  // TODO(crbug.com/922900): persist keystore keys.
+  // TODO(crbug.com/922900): support keystore rotation.
+  // TODO(crbug.com/922900): verify that this method is always called before
+  // update or init of Nigori node. If this is the case we don't need to touch
+  // cryptographer here. If this is not the case, old code is actually broken:
+  // 1. Receive and persist the Nigori node after keystore rotation on
+  // different client.
+  // 2. Browser crash.
+  // 3. After load we don't request new Nigori node from the server (we already
+  // have the newest one), so logic with simultaneous sending of Nigori node
+  // and keystore keys doesn't help. We don't request new keystore keys
+  // explicitly (we already have one). We can't decrypt and use Nigori node
+  // with old keystore keys.
   NOTIMPLEMENTED();
-  return false;
+  return true;
 }
 
 base::Optional<ModelError> NigoriSyncBridgeImpl::MergeSyncData(
     const base::Optional<EntityData>& data) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  NOTIMPLEMENTED();
-  return base::nullopt;
+  if (!data) {
+    return ModelError(FROM_HERE,
+                      "Received empty EntityData during initial "
+                      "sync of Nigori.");
+  }
+  return ApplySyncChanges(data);
 }
 
 base::Optional<ModelError> NigoriSyncBridgeImpl::ApplySyncChanges(
-    const EntityData& data) {
+    const base::Optional<EntityData>& data) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (data) {
+    DCHECK(data->specifics.has_nigori());
+    const sync_pb::NigoriSpecifics& nigori = data->specifics.nigori();
+
+    // TODO(crbug.com/922900): support other passphrase types.
+    if (ProtoPassphraseTypeToEnum(nigori.passphrase_type()) !=
+        PassphraseType::KEYSTORE_PASSPHRASE) {
+      NOTIMPLEMENTED();
+      return ModelError(FROM_HERE, "Only keystore Nigori node is supported.");
+    }
+
+    DCHECK(!keystore_keys_.empty());
+    // TODO(crbug.com/922900): verify that we don't need to check that
+    // nigori.encryption_keybag() and nigori.keystore_decryptor_token() are not
+    // empty.
+    sync_pb::EncryptedData keybag = nigori.encryption_keybag();
+    if (cryptographer_.CanDecrypt(keybag)) {
+      cryptographer_.InstallKeys(keybag);
+    } else {
+      cryptographer_.SetPendingKeys(keybag);
+      base::Optional<std::string> serialized_keystore_decryptor =
+          DecryptKeystoreDecryptor(keystore_keys_,
+                                   nigori.keystore_decryptor_token(),
+                                   cryptographer_.encryptor());
+      if (!serialized_keystore_decryptor ||
+          !cryptographer_.ImportNigoriKey(*serialized_keystore_decryptor) ||
+          !cryptographer_.is_ready()) {
+        return ModelError(FROM_HERE,
+                          "Failed to decrypt pending keys using the keystore "
+                          "decryptor token.");
+      }
+    }
+  }
+  // TODO(crbug.com/922900): implement updates of other data fields (e.g.
+  // passphrase type, encrypted types).
   NOTIMPLEMENTED();
   return base::nullopt;
 }
@@ -88,7 +205,7 @@
     const EntityData& remote_data) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   NOTIMPLEMENTED();
-  return ConflictResolution::UseLocal();
+  return ConflictResolution::kUseLocal;
 }
 
 void NigoriSyncBridgeImpl::ApplyDisableSyncChanges() {
@@ -96,4 +213,8 @@
   NOTIMPLEMENTED();
 }
 
+const Cryptographer& NigoriSyncBridgeImpl::GetCryptographerForTesting() const {
+  return cryptographer_;
+}
+
 }  // namespace syncer
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.h b/components/sync/nigori/nigori_sync_bridge_impl.h
index f52a676..cf3b3f6 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.h
+++ b/components/sync/nigori/nigori_sync_bridge_impl.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/sequence_checker.h"
+#include "components/sync/base/cryptographer.h"
 #include "components/sync/engine/sync_encryption_handler.h"
 #include "components/sync/model/conflict_resolution.h"
 #include "components/sync/model/model_error.h"
@@ -20,6 +21,8 @@
 
 namespace syncer {
 
+class Encryptor;
+
 // USS implementation of SyncEncryptionHandler.
 // This class holds the current Nigori state and processes incoming changes and
 // queries:
@@ -32,7 +35,9 @@
                              public NigoriSyncBridge,
                              public SyncEncryptionHandler {
  public:
-  NigoriSyncBridgeImpl();
+  // |encryptor| must not be null and must outlive this object and any copies
+  // of the Cryptographer exposed by this object.
+  explicit NigoriSyncBridgeImpl(Encryptor* encryptor);
   ~NigoriSyncBridgeImpl() override;
 
   // SyncEncryptionHandler implementation.
@@ -51,13 +56,26 @@
   // NigoriSyncBridge implementation.
   base::Optional<ModelError> MergeSyncData(
       const base::Optional<EntityData>& data) override;
-  base::Optional<ModelError> ApplySyncChanges(const EntityData& data) override;
+  base::Optional<ModelError> ApplySyncChanges(
+      const base::Optional<EntityData>& data) override;
   std::unique_ptr<EntityData> GetData() override;
   ConflictResolution ResolveConflict(const EntityData& local_data,
                                      const EntityData& remote_data) override;
   void ApplyDisableSyncChanges() override;
 
+  // TODO(crbug.com/922900): investigate whether we need this getter outside of
+  // tests and decide whether this method should be a part of
+  // SyncEncryptionHandler interface.
+  const Cryptographer& GetCryptographerForTesting() const;
+
  private:
+  // Base64 encoded keystore keys. The last element is the current keystore
+  // key. These keys are not a part of Nigori node and are persisted
+  // separately. Should be encrypted with OSCrypt before persisting.
+  std::vector<std::string> keystore_keys_;
+
+  Cryptographer cryptographer_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(NigoriSyncBridgeImpl);
diff --git a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
new file mode 100644
index 0000000..a9b4828
--- /dev/null
+++ b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
@@ -0,0 +1,222 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync/nigori/nigori_sync_bridge_impl.h"
+
+#include <utility>
+
+#include "base/base64.h"
+#include "components/sync/base/fake_encryptor.h"
+#include "components/sync/model/entity_data.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+
+namespace {
+
+using testing::Eq;
+
+const char kNigoriKeyName[] = "nigori-key";
+
+KeyParams Pbkdf2KeyParams(std::string key) {
+  return {KeyDerivationParams::CreateForPbkdf2(), std::move(key)};
+}
+
+KeyParams KeystoreKeyParams(const std::string& key) {
+  // Due to mis-encode of keystore keys to base64 we have to always encode such
+  // keys to provide backward compatibility.
+  std::string encoded_key;
+  base::Base64Encode(key, &encoded_key);
+  return Pbkdf2KeyParams(std::move(encoded_key));
+}
+
+class NigoriSyncBridgeImplTest : public testing::Test {
+ protected:
+  NigoriSyncBridgeImplTest() {
+    bridge_ = std::make_unique<NigoriSyncBridgeImpl>(&encryptor_);
+  }
+
+  NigoriSyncBridgeImpl* bridge() { return bridge_.get(); }
+
+  // Builds NigoriSpecifics with following fields:
+  // 1. encryption_keybag contains all keys derived from |keybag_keys_params|
+  // and encrypted with a key derived from |keybag_decryptor_params|.
+  // keystore_decryptor_token is always saved in encryption_keybag, even if it
+  // is not derived from any params in |keybag_keys_params|.
+  // 2. keystore_decryptor_token contains the key derived from
+  // |keybag_decryptor_params| and encrypted with a key derived from
+  // |keystore_key_params|.
+  // 3. passphrase_type is KEYSTORE_PASSHPRASE.
+  // 4. Other fields are default.
+  sync_pb::NigoriSpecifics BuildKeystoreNigoriSpecifics(
+      const std::vector<KeyParams>& keybag_keys_params,
+      const KeyParams& keystore_decryptor_params,
+      const KeyParams& keystore_key_params) {
+    sync_pb::NigoriSpecifics specifics =
+        sync_pb::NigoriSpecifics::default_instance();
+
+    Cryptographer cryptographer(&encryptor_);
+    cryptographer.AddKey(keystore_decryptor_params);
+    for (const KeyParams& key_params : keybag_keys_params) {
+      cryptographer.AddNonDefaultKey(key_params);
+    }
+    EXPECT_TRUE(cryptographer.GetKeys(specifics.mutable_encryption_keybag()));
+
+    std::string serialized_keystore_decryptor =
+        cryptographer.GetDefaultNigoriKeyData();
+    Cryptographer keystore_cryptographer(&encryptor_);
+    keystore_cryptographer.AddKey(keystore_key_params);
+    EXPECT_TRUE(keystore_cryptographer.EncryptString(
+        serialized_keystore_decryptor,
+        specifics.mutable_keystore_decryptor_token()));
+
+    specifics.set_passphrase_type(
+        sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
+    return specifics;
+  }
+
+ private:
+  // Don't change the order. |bridge_| should outlive |encryptor_|.
+  FakeEncryptor encryptor_;
+  std::unique_ptr<NigoriSyncBridgeImpl> bridge_;
+};
+
+MATCHER_P(CanDecryptWith, key_params, "") {
+  const Cryptographer& cryptographer = arg;
+  Nigori nigori;
+  nigori.InitByDerivation(key_params.derivation_params, key_params.password);
+  std::string nigori_name;
+  EXPECT_TRUE(
+      nigori.Permute(Nigori::Type::Password, kNigoriKeyName, &nigori_name));
+  const std::string unencrypted = "test";
+  sync_pb::EncryptedData encrypted;
+  encrypted.set_key_name(nigori_name);
+  EXPECT_TRUE(nigori.Encrypt(unencrypted, encrypted.mutable_blob()));
+
+  if (!cryptographer.CanDecrypt(encrypted)) {
+    return false;
+  }
+  std::string decrypted;
+  if (!cryptographer.DecryptToString(encrypted, &decrypted)) {
+    return false;
+  }
+  return decrypted == unencrypted;
+}
+
+MATCHER_P(HasDefaultKeyDerivedFrom, key_params, "") {
+  const Cryptographer& cryptographer = arg;
+  Nigori expected_default_nigori;
+  expected_default_nigori.InitByDerivation(key_params.derivation_params,
+                                           key_params.password);
+  std::string expected_default_key_name;
+  EXPECT_TRUE(expected_default_nigori.Permute(
+      Nigori::Type::Password, kNigoriKeyName, &expected_default_key_name));
+  return cryptographer.GetDefaultNigoriKeyName() == expected_default_key_name;
+}
+
+// Simplest case of keystore Nigori: we have only one keystore key and no old
+// keys. This keystore key is encrypted in both encryption_keybag and
+// keystore_decryptor_token. Client receives such Nigori if initialization of
+// Nigori node was done after keystore was introduced and no key rotations
+// happened.
+TEST_F(NigoriSyncBridgeImplTest, ShouldAcceptKeysFromKeystoreNigori) {
+  const std::string kRawKeystoreKey = "raw_keystore_key";
+  const KeyParams kKeystoreKeyParams = KeystoreKeyParams(kRawKeystoreKey);
+  EntityData entity_data;
+  *entity_data.specifics.mutable_nigori() = BuildKeystoreNigoriSpecifics(
+      /*keybag_keys_params=*/{kKeystoreKeyParams},
+      /*keystore_decryptor_params=*/kKeystoreKeyParams,
+      /*keystore_key_params=*/kKeystoreKeyParams);
+
+  EXPECT_TRUE(bridge()->SetKeystoreKeys({kRawKeystoreKey}));
+  EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
+              Eq(base::nullopt));
+
+  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
+  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
+}
+
+// Tests that client can properly process remote updates with rotated keystore
+// nigori. Cryptographer should be able to decrypt any data encrypted with any
+// keystore key and use current keystore key as default key.
+TEST_F(NigoriSyncBridgeImplTest, ShouldAcceptKeysFromRotatedKeystoreNigori) {
+  const std::string kRawOldKey = "raw_old_keystore_key";
+  const KeyParams kOldKeyParams = KeystoreKeyParams(kRawOldKey);
+  const std::string kRawCurrentKey = "raw_keystore_key";
+  const KeyParams kCurrentKeyParams = KeystoreKeyParams(kRawCurrentKey);
+  EntityData entity_data;
+  *entity_data.specifics.mutable_nigori() = BuildKeystoreNigoriSpecifics(
+      /*keybag_keys_params=*/{kOldKeyParams, kCurrentKeyParams},
+      /*keystore_decryptor_params=*/kCurrentKeyParams,
+      /*keystore_key_params=*/kCurrentKeyParams);
+
+  EXPECT_TRUE(bridge()->SetKeystoreKeys({kRawOldKey, kRawCurrentKey}));
+  EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
+              Eq(base::nullopt));
+
+  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
+  EXPECT_THAT(cryptographer, CanDecryptWith(kOldKeyParams));
+  EXPECT_THAT(cryptographer, CanDecryptWith(kCurrentKeyParams));
+  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kCurrentKeyParams));
+}
+
+// In the backward compatible mode keystore Nigori's keystore_decryptor_token
+// isn't a kestore key, however keystore_decryptor_token itself should be
+// encrypted with the keystore key.
+TEST_F(NigoriSyncBridgeImplTest,
+       ShouldAcceptKeysFromBackwardCompatibleKeystoreNigori) {
+  const KeyParams kGaiaKeyParams = Pbkdf2KeyParams("gaia_key");
+  const std::string kRawKeystoreKey = "raw_keystore_key";
+  const KeyParams kKeystoreKeyParams = KeystoreKeyParams(kRawKeystoreKey);
+  EntityData entity_data;
+  *entity_data.specifics.mutable_nigori() = BuildKeystoreNigoriSpecifics(
+      /*keybag_keys_params=*/{kGaiaKeyParams, kKeystoreKeyParams},
+      /*keystore_decryptor_params=*/kGaiaKeyParams,
+      /*keystore_key_params=*/kKeystoreKeyParams);
+
+  EXPECT_TRUE(bridge()->SetKeystoreKeys({kRawKeystoreKey}));
+  EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
+              Eq(base::nullopt));
+
+  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
+  EXPECT_THAT(cryptographer, CanDecryptWith(kGaiaKeyParams));
+  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kGaiaKeyParams));
+}
+
+// Tests that we can successfully use old keys from encryption_keybag in
+// backward compatible mode.
+TEST_F(NigoriSyncBridgeImplTest,
+       ShouldAcceptOldKeysFromBackwardCompatibleKeystoreNigori) {
+  // |kOldKeyParams| is needed to ensure we was able to decrypt
+  // encryption_keybag - there is no way to add key derived from
+  // |kOldKeyParams| to cryptographer without decrypting encryption_keybag.
+  const KeyParams kOldKeyParams = Pbkdf2KeyParams("old_key");
+  const KeyParams kCurrentKeyParams = Pbkdf2KeyParams("current_key");
+  const std::string kRawKeystoreKey = "raw_keystore_key";
+  const KeyParams kKeystoreKeyParams = KeystoreKeyParams(kRawKeystoreKey);
+  const std::vector<KeyParams> kAllKeyParams = {
+      kOldKeyParams, kCurrentKeyParams, kKeystoreKeyParams};
+  EntityData entity_data;
+  *entity_data.specifics.mutable_nigori() = BuildKeystoreNigoriSpecifics(
+      /*keybag_keys_params=*/kAllKeyParams,
+      /*keystore_decryptor_params=*/kCurrentKeyParams,
+      /*keystore_key_params=*/kKeystoreKeyParams);
+
+  EXPECT_TRUE(bridge()->SetKeystoreKeys({kRawKeystoreKey}));
+  EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
+              Eq(base::nullopt));
+
+  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
+  for (const KeyParams& key_params : kAllKeyParams) {
+    EXPECT_THAT(cryptographer, CanDecryptWith(key_params));
+  }
+  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kCurrentKeyParams));
+}
+
+}  // namespace
+
+}  // namespace syncer
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
index ff4500c6..17157de8 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -485,8 +485,8 @@
     bookmark_tracker_->Remove(update_entity.id);
     DLOG(WARNING) << "Conflict: CHANGES_MATCH";
     UMA_HISTOGRAM_ENUMERATION("Sync.ResolveConflict",
-                              syncer::ConflictResolution::CHANGES_MATCH,
-                              syncer::ConflictResolution::TYPE_SIZE);
+                              syncer::ConflictResolution::kChangesMatch,
+                              syncer::ConflictResolution::kTypeSize);
     return;
   }
 
@@ -497,8 +497,8 @@
                                            update.response_version);
     DLOG(WARNING) << "Conflict: USE_LOCAL";
     UMA_HISTOGRAM_ENUMERATION("Sync.ResolveConflict",
-                              syncer::ConflictResolution::USE_LOCAL,
-                              syncer::ConflictResolution::TYPE_SIZE);
+                              syncer::ConflictResolution::kUseLocal,
+                              syncer::ConflictResolution::kTypeSize);
     return;
   }
 
@@ -509,8 +509,8 @@
     ProcessCreate(update);
     DLOG(WARNING) << "Conflict: USE_REMOTE";
     UMA_HISTOGRAM_ENUMERATION("Sync.ResolveConflict",
-                              syncer::ConflictResolution::USE_REMOTE,
-                              syncer::ConflictResolution::TYPE_SIZE);
+                              syncer::ConflictResolution::kUseRemote,
+                              syncer::ConflictResolution::kTypeSize);
     return;
   }
 
@@ -559,8 +559,8 @@
     // The changes are identical so there isn't a real conflict.
     DLOG(WARNING) << "Conflict: CHANGES_MATCH";
     UMA_HISTOGRAM_ENUMERATION("Sync.ResolveConflict",
-                              syncer::ConflictResolution::CHANGES_MATCH,
-                              syncer::ConflictResolution::TYPE_SIZE);
+                              syncer::ConflictResolution::kChangesMatch,
+                              syncer::ConflictResolution::kTypeSize);
     return;
   }
 
@@ -568,8 +568,8 @@
   // wins. Update the model from server data.
   DLOG(WARNING) << "Conflict: USE_REMOTE";
   UMA_HISTOGRAM_ENUMERATION("Sync.ResolveConflict",
-                            syncer::ConflictResolution::USE_REMOTE,
-                            syncer::ConflictResolution::TYPE_SIZE);
+                            syncer::ConflictResolution::kUseRemote,
+                            syncer::ConflictResolution::kTypeSize);
   ApplyRemoteUpdate(update, tracked_entity, new_parent_entity, bookmark_model_,
                     bookmark_tracker_, favicon_service_);
 }
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
index 8352136..57fa918 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -843,7 +843,7 @@
   EXPECT_THAT(tracker.GetEntityForSyncId(kId), IsNull());
   histogram_tester.ExpectBucketCount(
       "Sync.ResolveConflict",
-      /*sample=*/syncer::ConflictResolution::CHANGES_MATCH, /*count=*/1);
+      /*sample=*/syncer::ConflictResolution::kChangesMatch, /*count=*/1);
 }
 
 TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
@@ -933,7 +933,7 @@
 
   histogram_tester.ExpectBucketCount(
       "Sync.ResolveConflict",
-      /*sample=*/syncer::ConflictResolution::CHANGES_MATCH, /*count=*/1);
+      /*sample=*/syncer::ConflictResolution::kChangesMatch, /*count=*/1);
 }
 
 TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
@@ -987,7 +987,7 @@
 
   histogram_tester.ExpectBucketCount(
       "Sync.ResolveConflict",
-      /*sample=*/syncer::ConflictResolution::USE_LOCAL, /*count=*/1);
+      /*sample=*/syncer::ConflictResolution::kUseLocal, /*count=*/1);
 }
 
 TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
@@ -1051,7 +1051,7 @@
 
   histogram_tester.ExpectBucketCount(
       "Sync.ResolveConflict",
-      /*sample=*/syncer::ConflictResolution::USE_REMOTE, /*count=*/1);
+      /*sample=*/syncer::ConflictResolution::kUseRemote, /*count=*/1);
 }
 
 TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
@@ -1101,7 +1101,7 @@
 
   histogram_tester.ExpectBucketCount(
       "Sync.ResolveConflict",
-      /*sample=*/syncer::ConflictResolution::CHANGES_MATCH, /*count=*/1);
+      /*sample=*/syncer::ConflictResolution::kChangesMatch, /*count=*/1);
 }
 
 TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
@@ -1158,7 +1158,7 @@
 
   histogram_tester.ExpectBucketCount(
       "Sync.ResolveConflict",
-      /*sample=*/syncer::ConflictResolution::USE_REMOTE, /*count=*/1);
+      /*sample=*/syncer::ConflictResolution::kUseRemote, /*count=*/1);
 }
 
 }  // namespace
diff --git a/components/test/data/payments/onpayerdetailchange.js b/components/test/data/payments/onpayerdetailchange.js
new file mode 100644
index 0000000..2b232be
--- /dev/null
+++ b/components/test/data/payments/onpayerdetailchange.js
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+var gPaymentResponse = null;
+var gRetryPromise = null;
+
+/**
+ * Launches the PaymentRequest UI
+ */
+function buy() {  // eslint-disable-line no-unused-vars
+  var options = {
+    requestPayerEmail: true,
+    requestPayerName: true,
+    requestPayerPhone: true,
+  };
+  getPaymentResponse(options)
+      .then(function(response) {
+        gPaymentResponse = response;
+        var eventPromise = new Promise(function(resolve) {
+          gPaymentResponse.addEventListener('payerdetailchange', function(e) {
+            e.updateWith({});
+            resolve();
+          });
+        });
+        eventPromise.then(function() {
+          gRetryPromise.then(function() {
+            print(JSON.stringify(gPaymentResponse, undefined, 2));
+            gPaymentResponse.complete('success');
+          });
+        });
+      });
+}
+
+/**
+ * Retry PaymentRequest UI with indicating validation error messages.
+ *
+ * @param {PaymentValidationErrors} validationErrors Represent validation errors
+ */
+function retry(validationErrors) {  // eslint-disable-line no-unused-vars
+  if (gPaymentResponse == null) {
+    return;
+  }
+
+  gRetryPromise = gPaymentResponse.retry(validationErrors);
+}
diff --git a/components/test/data/payments/payment_request_onpayerdetailchange.html b/components/test/data/payments/payment_request_onpayerdetailchange.html
new file mode 100644
index 0000000..669b6eb24
--- /dev/null
+++ b/components/test/data/payments/payment_request_onpayerdetailchange.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+<html>
+<head>
+<title>Retry test</title>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
+<link rel="stylesheet" type="text/css" href="style.css">
+</head>
+<body>
+<div><button onclick="buy()" id="buy">onpayerdetailchange test</button></div>
+<pre id="result"></pre>
+<script src="util.js"></script>
+<script src="retry_helper.js"></script>
+<script src="onpayerdetailchange.js"></script>
+</body>
+</html>
diff --git a/components/ui_devtools/viz/viz_devtools_unittest.cc b/components/ui_devtools/viz/viz_devtools_unittest.cc
index 37c4467..eca35980 100644
--- a/components/ui_devtools/viz/viz_devtools_unittest.cc
+++ b/components/ui_devtools/viz/viz_devtools_unittest.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/containers/flat_map.h"
+#include "base/strings/stringprintf.h"
+#include "base/unguessable_token.h"
 #include "components/ui_devtools/css_agent.h"
 #include "components/ui_devtools/ui_devtools_unittest_utils.h"
 #include "components/ui_devtools/ui_element.h"
diff --git a/components/viz/common/hit_test/hit_test_data_builder.cc b/components/viz/common/hit_test/hit_test_data_builder.cc
index 11210b7..b3f6af13 100644
--- a/components/viz/common/hit_test/hit_test_data_builder.cc
+++ b/components/viz/common/hit_test/hit_test_data_builder.cc
@@ -116,7 +116,7 @@
 
   const uint32_t render_pass_hit_test_region_list_start = regions->size();
   for (const DrawQuad* quad : render_pass->quad_list) {
-    if (quad->material == DrawQuad::SURFACE_CONTENT) {
+    if (quad->material == DrawQuad::Material::kSurfaceContent) {
       const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
 
       // Skip the quad if the transform is not invertible (i.e. it will not
@@ -151,7 +151,7 @@
                            surface_quad->ignores_input_event);
         }
       }
-    } else if (quad->material == DrawQuad::RENDER_PASS) {
+    } else if (quad->material == DrawQuad::Material::kRenderPass) {
       const RenderPassDrawQuad* render_quad =
           RenderPassDrawQuad::MaterialCast(quad);
       AddHitTestDataFromRenderPass(frame, render_quad->render_pass_id, regions,
diff --git a/components/viz/common/quads/debug_border_draw_quad.cc b/components/viz/common/quads/debug_border_draw_quad.cc
index fed85f8..54eb85b 100644
--- a/components/viz/common/quads/debug_border_draw_quad.cc
+++ b/components/viz/common/quads/debug_border_draw_quad.cc
@@ -18,7 +18,7 @@
                                  SkColor color,
                                  int width) {
   bool needs_blending = SkColorGetA(color) < 255;
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::DEBUG_BORDER, rect,
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kDebugBorder, rect,
                    visible_rect, needs_blending);
   this->color = color;
   this->width = width;
@@ -30,7 +30,7 @@
                                  bool needs_blending,
                                  SkColor color,
                                  int width) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::DEBUG_BORDER, rect,
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kDebugBorder, rect,
                    visible_rect, needs_blending);
   this->color = color;
   this->width = width;
@@ -38,7 +38,7 @@
 
 const DebugBorderDrawQuad* DebugBorderDrawQuad::MaterialCast(
     const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::DEBUG_BORDER);
+  DCHECK(quad->material == DrawQuad::Material::kDebugBorder);
   return static_cast<const DebugBorderDrawQuad*>(quad);
 }
 
diff --git a/components/viz/common/quads/draw_quad.cc b/components/viz/common/quads/draw_quad.cc
index d3158e67..b5177a20 100644
--- a/components/viz/common/quads/draw_quad.cc
+++ b/components/viz/common/quads/draw_quad.cc
@@ -16,7 +16,9 @@
 namespace viz {
 
 DrawQuad::DrawQuad()
-    : material(INVALID), needs_blending(false), shared_quad_state(nullptr) {}
+    : material(Material::kInvalid),
+      needs_blending(false),
+      shared_quad_state(nullptr) {}
 
 DrawQuad::DrawQuad(const DrawQuad& other) = default;
 
@@ -36,13 +38,13 @@
   this->shared_quad_state = shared_quad_state;
 
   DCHECK(shared_quad_state);
-  DCHECK(material != INVALID);
+  DCHECK(material != Material::kInvalid);
 }
 
 DrawQuad::~DrawQuad() {}
 
 void DrawQuad::AsValueInto(base::trace_event::TracedValue* value) const {
-  value->SetInteger("material", material);
+  value->SetInteger("material", static_cast<int>(material));
   TracedValue::SetIDRef(shared_quad_state, value, "shared_state");
 
   cc::MathUtil::AddToTracedValue("content_space_rect", rect, value);
diff --git a/components/viz/common/quads/draw_quad.h b/components/viz/common/quads/draw_quad.h
index ecc0ef4..5c39759e 100644
--- a/components/viz/common/quads/draw_quad.h
+++ b/components/viz/common/quads/draw_quad.h
@@ -33,19 +33,19 @@
 // quad's transform maps the content space to the target space.
 class VIZ_COMMON_EXPORT DrawQuad {
  public:
-  enum Material {
-    INVALID,
-    DEBUG_BORDER,
-    PICTURE_CONTENT,
-    RENDER_PASS,
-    SOLID_COLOR,
-    STREAM_VIDEO_CONTENT,
-    SURFACE_CONTENT,
-    TEXTURE_CONTENT,
-    TILED_CONTENT,
-    YUV_VIDEO_CONTENT,
-    VIDEO_HOLE,
-    MATERIAL_LAST = VIDEO_HOLE
+  enum class Material {
+    kInvalid,
+    kDebugBorder,
+    kPictureContent,
+    kRenderPass,
+    kSolidColor,
+    kStreamVideoContent,
+    kSurfaceContent,
+    kTextureContent,
+    kTiledContent,
+    kYuvVideoContent,
+    kVideoHole,
+    kMaxValue = kVideoHole
   };
 
   DrawQuad(const DrawQuad& other);
@@ -71,7 +71,7 @@
   // during serialization.
   const SharedQuadState* shared_quad_state;
 
-  bool IsDebugQuad() const { return material == DEBUG_BORDER; }
+  bool IsDebugQuad() const { return material == Material::kDebugBorder; }
 
   bool ShouldDrawWithBlending() const {
     return needs_blending || shared_quad_state->opacity < 1.0f ||
diff --git a/components/viz/common/quads/draw_quad_unittest.cc b/components/viz/common/quads/draw_quad_unittest.cc
index 2eba2ba..fc74ab7 100644
--- a/components/viz/common/quads/draw_quad_unittest.cc
+++ b/components/viz/common/quads/draw_quad_unittest.cc
@@ -176,13 +176,13 @@
   CREATE_SHARED_STATE();
 
   CREATE_QUAD_NEW(DebugBorderDrawQuad, visible_rect, color, width);
-  EXPECT_EQ(DrawQuad::DEBUG_BORDER, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kDebugBorder, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(color, copy_quad->color);
   EXPECT_EQ(width, copy_quad->width);
 
   CREATE_QUAD_ALL(DebugBorderDrawQuad, color, width);
-  EXPECT_EQ(DrawQuad::DEBUG_BORDER, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kDebugBorder, copy_quad->material);
   EXPECT_EQ(color, copy_quad->color);
   EXPECT_EQ(width, copy_quad->width);
 }
@@ -207,7 +207,7 @@
                      filters_scale, filters_origin, tex_coord_rect,
                      force_anti_aliasing_off, backdrop_filter_quality,
                      copied_render_pass_id);
-  EXPECT_EQ(DrawQuad::RENDER_PASS, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kRenderPass, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(copied_render_pass_id, copy_quad->render_pass_id);
   EXPECT_EQ(mask_resource_id, copy_quad->mask_resource_id());
@@ -222,7 +222,7 @@
                      mask_uv_rect, mask_texture_size, filters_scale,
                      filters_origin, tex_coord_rect, force_anti_aliasing_off,
                      backdrop_filter_quality, copied_render_pass_id);
-  EXPECT_EQ(DrawQuad::RENDER_PASS, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kRenderPass, copy_quad->material);
   EXPECT_EQ(copied_render_pass_id, copy_quad->render_pass_id);
   EXPECT_EQ(mask_resource_id, copy_quad->mask_resource_id());
   EXPECT_EQ(mask_uv_rect.ToString(), copy_quad->mask_uv_rect.ToString());
@@ -241,13 +241,13 @@
 
   CREATE_QUAD_NEW(SolidColorDrawQuad, visible_rect, color,
                   force_anti_aliasing_off);
-  EXPECT_EQ(DrawQuad::SOLID_COLOR, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kSolidColor, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(color, copy_quad->color);
   EXPECT_EQ(force_anti_aliasing_off, copy_quad->force_anti_aliasing_off);
 
   CREATE_QUAD_ALL(SolidColorDrawQuad, color, force_anti_aliasing_off);
-  EXPECT_EQ(DrawQuad::SOLID_COLOR, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kSolidColor, copy_quad->material);
   EXPECT_EQ(color, copy_quad->color);
   EXPECT_EQ(force_anti_aliasing_off, copy_quad->force_anti_aliasing_off);
 }
@@ -264,7 +264,7 @@
   CREATE_QUAD_NEW(StreamVideoDrawQuad, visible_rect, needs_blending,
                   resource_id, resource_size_in_pixels, uv_top_left,
                   uv_bottom_right);
-  EXPECT_EQ(DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kStreamVideoContent, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(needs_blending, copy_quad->needs_blending);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
@@ -274,7 +274,7 @@
 
   CREATE_QUAD_ALL(StreamVideoDrawQuad, resource_id, resource_size_in_pixels,
                   uv_top_left, uv_bottom_right);
-  EXPECT_EQ(DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kStreamVideoContent, copy_quad->material);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
   EXPECT_EQ(resource_size_in_pixels, copy_quad->resource_size_in_pixels());
   EXPECT_EQ(uv_top_left, copy_quad->uv_top_left);
@@ -295,7 +295,7 @@
                   SurfaceRange(fallback_surface_id, primary_surface_id),
                   SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/true,
                   /*ignores_input_event=*/true);
-  EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kSurfaceContent, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(primary_surface_id, copy_quad->surface_range.end());
   EXPECT_EQ(fallback_surface_id, *copy_quad->surface_range.start());
@@ -306,7 +306,7 @@
                   SurfaceRange(fallback_surface_id, primary_surface_id),
                   SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
                   /*ignores_input_event=*/false);
-  EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kSurfaceContent, copy_quad->material);
   EXPECT_EQ(primary_surface_id, copy_quad->surface_range.end());
   EXPECT_EQ(fallback_surface_id, *copy_quad->surface_range.start());
   EXPECT_FALSE(copy_quad->stretch_content_to_fill_bounds);
@@ -332,7 +332,7 @@
                   premultiplied_alpha, uv_top_left, uv_bottom_right,
                   SK_ColorTRANSPARENT, vertex_opacity, y_flipped,
                   nearest_neighbor, secure_output_only, protected_video_type);
-  EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kTextureContent, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(needs_blending, copy_quad->needs_blending);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
@@ -349,7 +349,7 @@
                   premultiplied_alpha, uv_top_left, uv_bottom_right,
                   SK_ColorTRANSPARENT, vertex_opacity, y_flipped,
                   nearest_neighbor, secure_output_only, protected_video_type);
-  EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kTextureContent, copy_quad->material);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
   EXPECT_EQ(resource_size_in_pixels, copy_quad->resource_size_in_pixels());
   EXPECT_EQ(premultiplied_alpha, copy_quad->premultiplied_alpha);
@@ -378,7 +378,7 @@
                   tex_coord_rect, texture_size, swizzle_contents,
                   contents_premultiplied, nearest_neighbor,
                   force_anti_aliasing_off);
-  EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kTiledContent, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(needs_blending, copy_quad->needs_blending);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
@@ -390,7 +390,7 @@
   CREATE_QUAD_ALL(TileDrawQuad, resource_id, tex_coord_rect, texture_size,
                   swizzle_contents, contents_premultiplied, nearest_neighbor,
                   force_anti_aliasing_off);
-  EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kTiledContent, copy_quad->material);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(texture_size, copy_quad->texture_size);
@@ -404,12 +404,12 @@
   CREATE_SHARED_STATE();
 
   CREATE_QUAD_NEW(VideoHoleDrawQuad, visible_rect, overlay_plane_id);
-  EXPECT_EQ(DrawQuad::VIDEO_HOLE, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kVideoHole, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(overlay_plane_id, copy_quad->overlay_plane_id);
 
   CREATE_QUAD_ALL(VideoHoleDrawQuad, overlay_plane_id);
-  EXPECT_EQ(DrawQuad::VIDEO_HOLE, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kVideoHole, copy_quad->material);
   EXPECT_EQ(overlay_plane_id, copy_quad->overlay_plane_id);
 }
 
@@ -437,7 +437,7 @@
                   uv_tex_size, y_plane_resource_id, u_plane_resource_id,
                   v_plane_resource_id, a_plane_resource_id, video_color_space,
                   resource_offset, resource_multiplier, bits_per_channel);
-  EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kYuvVideoContent, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(needs_blending, copy_quad->needs_blending);
   EXPECT_EQ(ya_tex_coord_rect, copy_quad->ya_tex_coord_rect);
@@ -458,7 +458,7 @@
                   u_plane_resource_id, v_plane_resource_id, a_plane_resource_id,
                   video_color_space, resource_offset, resource_multiplier,
                   bits_per_channel, protected_video_type);
-  EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kYuvVideoContent, copy_quad->material);
   EXPECT_EQ(ya_tex_coord_rect, copy_quad->ya_tex_coord_rect);
   EXPECT_EQ(uv_tex_coord_rect, copy_quad->uv_tex_coord_rect);
   EXPECT_EQ(ya_tex_size, copy_quad->ya_tex_size);
@@ -490,7 +490,7 @@
   CREATE_QUAD_NEW(PictureDrawQuad, visible_rect, needs_blending, tex_coord_rect,
                   texture_size, nearest_neighbor, texture_format, content_rect,
                   contents_scale, {}, display_item_list);
-  EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kPictureContent, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(needs_blending, copy_quad->needs_blending);
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
@@ -504,7 +504,7 @@
   CREATE_QUAD_ALL(PictureDrawQuad, tex_coord_rect, texture_size,
                   nearest_neighbor, texture_format, content_rect,
                   contents_scale, {}, display_item_list);
-  EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kPictureContent, copy_quad->material);
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(texture_size, copy_quad->texture_size);
   EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
@@ -683,7 +683,7 @@
                   uv_tex_size, y_plane_resource_id, u_plane_resource_id,
                   v_plane_resource_id, a_plane_resource_id, video_color_space,
                   0.0, 1.0, 5);
-  EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kYuvVideoContent, copy_quad->material);
   EXPECT_EQ(y_plane_resource_id, quad_new->y_plane_resource_id());
   EXPECT_EQ(u_plane_resource_id, quad_new->u_plane_resource_id());
   EXPECT_EQ(v_plane_resource_id, quad_new->v_plane_resource_id());
@@ -698,39 +698,39 @@
 TEST(DrawQuadTest, LargestQuadType) {
   size_t largest = 0;
 
-  for (int i = 0; i <= DrawQuad::MATERIAL_LAST; ++i) {
+  for (int i = 0; i <= static_cast<int>(DrawQuad::Material::kMaxValue); ++i) {
     switch (static_cast<DrawQuad::Material>(i)) {
-      case DrawQuad::DEBUG_BORDER:
+      case DrawQuad::Material::kDebugBorder:
         largest = std::max(largest, sizeof(DebugBorderDrawQuad));
         break;
-      case DrawQuad::PICTURE_CONTENT:
+      case DrawQuad::Material::kPictureContent:
         largest = std::max(largest, sizeof(PictureDrawQuad));
         break;
-      case DrawQuad::TEXTURE_CONTENT:
+      case DrawQuad::Material::kTextureContent:
         largest = std::max(largest, sizeof(TextureDrawQuad));
         break;
-      case DrawQuad::RENDER_PASS:
+      case DrawQuad::Material::kRenderPass:
         largest = std::max(largest, sizeof(RenderPassDrawQuad));
         break;
-      case DrawQuad::SOLID_COLOR:
+      case DrawQuad::Material::kSolidColor:
         largest = std::max(largest, sizeof(SolidColorDrawQuad));
         break;
-      case DrawQuad::SURFACE_CONTENT:
+      case DrawQuad::Material::kSurfaceContent:
         largest = std::max(largest, sizeof(SurfaceDrawQuad));
         break;
-      case DrawQuad::TILED_CONTENT:
+      case DrawQuad::Material::kTiledContent:
         largest = std::max(largest, sizeof(TileDrawQuad));
         break;
-      case DrawQuad::STREAM_VIDEO_CONTENT:
+      case DrawQuad::Material::kStreamVideoContent:
         largest = std::max(largest, sizeof(StreamVideoDrawQuad));
         break;
-      case DrawQuad::YUV_VIDEO_CONTENT:
+      case DrawQuad::Material::kYuvVideoContent:
         largest = std::max(largest, sizeof(YUVVideoDrawQuad));
         break;
-      case DrawQuad::VIDEO_HOLE:
+      case DrawQuad::Material::kVideoHole:
         largest = std::max(largest, sizeof(VideoHoleDrawQuad));
         break;
-      case DrawQuad::INVALID:
+      case DrawQuad::Material::kInvalid:
         break;
     }
   }
@@ -742,39 +742,39 @@
   // On failure, output the size of all quads for debugging.
   LOG(ERROR) << "largest " << largest;
   LOG(ERROR) << "kLargestDrawQuad " << LargestDrawQuadSize();
-  for (int i = 0; i <= DrawQuad::MATERIAL_LAST; ++i) {
+  for (int i = 0; i <= static_cast<int>(DrawQuad::Material::kMaxValue); ++i) {
     switch (static_cast<DrawQuad::Material>(i)) {
-      case DrawQuad::DEBUG_BORDER:
+      case DrawQuad::Material::kDebugBorder:
         LOG(ERROR) << "DebugBorderDrawQuad " << sizeof(DebugBorderDrawQuad);
         break;
-      case DrawQuad::PICTURE_CONTENT:
+      case DrawQuad::Material::kPictureContent:
         LOG(ERROR) << "PictureDrawQuad " << sizeof(PictureDrawQuad);
         break;
-      case DrawQuad::TEXTURE_CONTENT:
+      case DrawQuad::Material::kTextureContent:
         LOG(ERROR) << "TextureDrawQuad " << sizeof(TextureDrawQuad);
         break;
-      case DrawQuad::RENDER_PASS:
+      case DrawQuad::Material::kRenderPass:
         LOG(ERROR) << "RenderPassDrawQuad " << sizeof(RenderPassDrawQuad);
         break;
-      case DrawQuad::SOLID_COLOR:
+      case DrawQuad::Material::kSolidColor:
         LOG(ERROR) << "SolidColorDrawQuad " << sizeof(SolidColorDrawQuad);
         break;
-      case DrawQuad::SURFACE_CONTENT:
+      case DrawQuad::Material::kSurfaceContent:
         LOG(ERROR) << "SurfaceDrawQuad " << sizeof(SurfaceDrawQuad);
         break;
-      case DrawQuad::TILED_CONTENT:
+      case DrawQuad::Material::kTiledContent:
         LOG(ERROR) << "TileDrawQuad " << sizeof(TileDrawQuad);
         break;
-      case DrawQuad::STREAM_VIDEO_CONTENT:
+      case DrawQuad::Material::kStreamVideoContent:
         LOG(ERROR) << "StreamVideoDrawQuad " << sizeof(StreamVideoDrawQuad);
         break;
-      case DrawQuad::YUV_VIDEO_CONTENT:
+      case DrawQuad::Material::kYuvVideoContent:
         LOG(ERROR) << "YUVVideoDrawQuad " << sizeof(YUVVideoDrawQuad);
         break;
-      case DrawQuad::VIDEO_HOLE:
+      case DrawQuad::Material::kVideoHole:
         LOG(ERROR) << "VideoHoleDrawQuad " << sizeof(VideoHoleDrawQuad);
         break;
-      case DrawQuad::INVALID:
+      case DrawQuad::Material::kInvalid:
         break;
     }
   }
diff --git a/components/viz/common/quads/picture_draw_quad.cc b/components/viz/common/quads/picture_draw_quad.cc
index 588f354..0c1dc8f 100644
--- a/components/viz/common/quads/picture_draw_quad.cc
+++ b/components/viz/common/quads/picture_draw_quad.cc
@@ -31,8 +31,8 @@
     ImageAnimationMap image_animation_map,
     scoped_refptr<cc::DisplayItemList> display_item_list) {
   ContentDrawQuadBase::SetNew(
-      shared_quad_state, DrawQuad::PICTURE_CONTENT, rect, visible_rect,
-      needs_blending, tex_coord_rect, texture_size,
+      shared_quad_state, DrawQuad::Material::kPictureContent, rect,
+      visible_rect, needs_blending, tex_coord_rect, texture_size,
       !PlatformColor::SameComponentOrder(texture_format), false,
       nearest_neighbor, false);
   this->content_rect = content_rect;
@@ -56,8 +56,8 @@
     ImageAnimationMap image_animation_map,
     scoped_refptr<cc::DisplayItemList> display_item_list) {
   ContentDrawQuadBase::SetAll(
-      shared_quad_state, DrawQuad::PICTURE_CONTENT, rect, visible_rect,
-      needs_blending, tex_coord_rect, texture_size,
+      shared_quad_state, DrawQuad::Material::kPictureContent, rect,
+      visible_rect, needs_blending, tex_coord_rect, texture_size,
       !PlatformColor::SameComponentOrder(texture_format), false,
       nearest_neighbor, false);
   this->content_rect = content_rect;
@@ -68,7 +68,7 @@
 }
 
 const PictureDrawQuad* PictureDrawQuad::MaterialCast(const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::PICTURE_CONTENT);
+  DCHECK(quad->material == DrawQuad::Material::kPictureContent);
   return static_cast<const PictureDrawQuad*>(quad);
 }
 
diff --git a/components/viz/common/quads/render_pass.cc b/components/viz/common/quads/render_pass.cc
index 1da238d..00cbb78 100644
--- a/components/viz/common/quads/render_pass.cc
+++ b/components/viz/common/quads/render_pass.cc
@@ -147,7 +147,7 @@
     }
     DCHECK(quad->shared_quad_state == *sqs_iter);
 
-    if (quad->material == DrawQuad::RENDER_PASS) {
+    if (quad->material == DrawQuad::Material::kRenderPass) {
       const RenderPassDrawQuad* pass_quad =
           RenderPassDrawQuad::MaterialCast(quad);
       copy_pass->CopyFromAndAppendRenderPassDrawQuad(pass_quad,
@@ -278,36 +278,36 @@
 DrawQuad* RenderPass::CopyFromAndAppendDrawQuad(const DrawQuad* quad) {
   DCHECK(!shared_quad_state_list.empty());
   switch (quad->material) {
-    case DrawQuad::DEBUG_BORDER:
+    case DrawQuad::Material::kDebugBorder:
       CopyFromAndAppendTypedDrawQuad<DebugBorderDrawQuad>(quad);
       break;
-    case DrawQuad::PICTURE_CONTENT:
+    case DrawQuad::Material::kPictureContent:
       CopyFromAndAppendTypedDrawQuad<PictureDrawQuad>(quad);
       break;
-    case DrawQuad::TEXTURE_CONTENT:
+    case DrawQuad::Material::kTextureContent:
       CopyFromAndAppendTypedDrawQuad<TextureDrawQuad>(quad);
       break;
-    case DrawQuad::SOLID_COLOR:
+    case DrawQuad::Material::kSolidColor:
       CopyFromAndAppendTypedDrawQuad<SolidColorDrawQuad>(quad);
       break;
-    case DrawQuad::TILED_CONTENT:
+    case DrawQuad::Material::kTiledContent:
       CopyFromAndAppendTypedDrawQuad<TileDrawQuad>(quad);
       break;
-    case DrawQuad::STREAM_VIDEO_CONTENT:
+    case DrawQuad::Material::kStreamVideoContent:
       CopyFromAndAppendTypedDrawQuad<StreamVideoDrawQuad>(quad);
       break;
-    case DrawQuad::SURFACE_CONTENT:
+    case DrawQuad::Material::kSurfaceContent:
       CopyFromAndAppendTypedDrawQuad<SurfaceDrawQuad>(quad);
       break;
-    case DrawQuad::VIDEO_HOLE:
+    case DrawQuad::Material::kVideoHole:
       CopyFromAndAppendTypedDrawQuad<VideoHoleDrawQuad>(quad);
       break;
-    case DrawQuad::YUV_VIDEO_CONTENT:
+    case DrawQuad::Material::kYuvVideoContent:
       CopyFromAndAppendTypedDrawQuad<YUVVideoDrawQuad>(quad);
       break;
     // RenderPass quads need to use specific CopyFrom function.
-    case DrawQuad::RENDER_PASS:
-    case DrawQuad::INVALID:
+    case DrawQuad::Material::kRenderPass:
+    case DrawQuad::Material::kInvalid:
       // TODO(danakj): Why is this a check instead of dcheck, and validate from
       // IPC?
       CHECK(false);  // Invalid DrawQuad material.
diff --git a/components/viz/common/quads/render_pass_draw_quad.cc b/components/viz/common/quads/render_pass_draw_quad.cc
index 2eec14d..096a0013 100644
--- a/components/viz/common/quads/render_pass_draw_quad.cc
+++ b/components/viz/common/quads/render_pass_draw_quad.cc
@@ -55,8 +55,8 @@
                                 float backdrop_filter_quality) {
   DCHECK(render_pass_id);
 
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::RENDER_PASS, rect, visible_rect,
-                   needs_blending);
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kRenderPass, rect,
+                   visible_rect, needs_blending);
   this->render_pass_id = render_pass_id;
   resources.ids[kMaskResourceIdIndex] = mask_resource_id;
   resources.count = mask_resource_id ? 1 : 0;
@@ -71,7 +71,7 @@
 
 const RenderPassDrawQuad* RenderPassDrawQuad::MaterialCast(
     const DrawQuad* quad) {
-  DCHECK_EQ(quad->material, DrawQuad::RENDER_PASS);
+  DCHECK_EQ(quad->material, DrawQuad::Material::kRenderPass);
   return static_cast<const RenderPassDrawQuad*>(quad);
 }
 
diff --git a/components/viz/common/quads/solid_color_draw_quad.cc b/components/viz/common/quads/solid_color_draw_quad.cc
index 6708e20..b585f9b 100644
--- a/components/viz/common/quads/solid_color_draw_quad.cc
+++ b/components/viz/common/quads/solid_color_draw_quad.cc
@@ -19,8 +19,8 @@
                                 SkColor color,
                                 bool force_anti_aliasing_off) {
   bool needs_blending = SkColorGetA(color) != 255;
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::SOLID_COLOR, rect, visible_rect,
-                   needs_blending);
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kSolidColor, rect,
+                   visible_rect, needs_blending);
   this->color = color;
   this->force_anti_aliasing_off = force_anti_aliasing_off;
 }
@@ -31,15 +31,15 @@
                                 bool needs_blending,
                                 SkColor color,
                                 bool force_anti_aliasing_off) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::SOLID_COLOR, rect, visible_rect,
-                   needs_blending);
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kSolidColor, rect,
+                   visible_rect, needs_blending);
   this->color = color;
   this->force_anti_aliasing_off = force_anti_aliasing_off;
 }
 
 const SolidColorDrawQuad* SolidColorDrawQuad::MaterialCast(
     const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::SOLID_COLOR);
+  DCHECK(quad->material == DrawQuad::Material::kSolidColor);
   return static_cast<const SolidColorDrawQuad*>(quad);
 }
 
diff --git a/components/viz/common/quads/stream_video_draw_quad.cc b/components/viz/common/quads/stream_video_draw_quad.cc
index 47bada5..e939924c 100644
--- a/components/viz/common/quads/stream_video_draw_quad.cc
+++ b/components/viz/common/quads/stream_video_draw_quad.cc
@@ -21,8 +21,8 @@
                                  gfx::Size resource_size_in_pixels,
                                  const gfx::PointF& uv_top_left,
                                  const gfx::PointF& uv_bottom_right) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::STREAM_VIDEO_CONTENT, rect,
-                   visible_rect, needs_blending);
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kStreamVideoContent,
+                   rect, visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
   overlay_resources.size_in_pixels[kResourceIdIndex] = resource_size_in_pixels;
   resources.count = 1;
@@ -38,8 +38,8 @@
                                  gfx::Size resource_size_in_pixels,
                                  const gfx::PointF& uv_top_left,
                                  const gfx::PointF& uv_bottom_right) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::STREAM_VIDEO_CONTENT, rect,
-                   visible_rect, needs_blending);
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kStreamVideoContent,
+                   rect, visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
   overlay_resources.size_in_pixels[kResourceIdIndex] = resource_size_in_pixels;
   resources.count = 1;
@@ -49,7 +49,7 @@
 
 const StreamVideoDrawQuad* StreamVideoDrawQuad::MaterialCast(
     const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::STREAM_VIDEO_CONTENT);
+  DCHECK(quad->material == DrawQuad::Material::kStreamVideoContent);
   return static_cast<const StreamVideoDrawQuad*>(quad);
 }
 
diff --git a/components/viz/common/quads/surface_draw_quad.cc b/components/viz/common/quads/surface_draw_quad.cc
index e16353e..3ff364e 100644
--- a/components/viz/common/quads/surface_draw_quad.cc
+++ b/components/viz/common/quads/surface_draw_quad.cc
@@ -28,7 +28,7 @@
                              bool stretch_content_to_fill_bounds,
                              bool ignores_input_event) {
   bool needs_blending = true;
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::SURFACE_CONTENT, rect,
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kSurfaceContent, rect,
                    visible_rect, needs_blending);
   this->surface_range = surface_range;
   this->default_background_color = default_background_color;
@@ -44,7 +44,7 @@
                              SkColor default_background_color,
                              bool stretch_content_to_fill_bounds,
                              bool ignores_input_event) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::SURFACE_CONTENT, rect,
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kSurfaceContent, rect,
                    visible_rect, needs_blending);
   this->surface_range = surface_range;
   this->default_background_color = default_background_color;
@@ -53,7 +53,7 @@
 }
 
 const SurfaceDrawQuad* SurfaceDrawQuad::MaterialCast(const DrawQuad* quad) {
-  DCHECK_EQ(quad->material, DrawQuad::SURFACE_CONTENT);
+  DCHECK_EQ(quad->material, DrawQuad::Material::kSurfaceContent);
   return static_cast<const SurfaceDrawQuad*>(quad);
 }
 
diff --git a/components/viz/common/quads/texture_draw_quad.cc b/components/viz/common/quads/texture_draw_quad.cc
index 2f11c72..9b9fd69 100644
--- a/components/viz/common/quads/texture_draw_quad.cc
+++ b/components/viz/common/quads/texture_draw_quad.cc
@@ -35,7 +35,7 @@
   needs_blending = needs_blending || vertex_opacity[0] != 1.0f ||
                    vertex_opacity[1] != 1.0f || vertex_opacity[2] != 1.0f ||
                    vertex_opacity[3] != 1.0f;
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::TEXTURE_CONTENT, rect,
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kTextureContent, rect,
                    visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
   resources.count = 1;
@@ -68,7 +68,7 @@
                              bool nearest_neighbor,
                              bool secure_output_only,
                              ui::ProtectedVideoType protected_video_type) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::TEXTURE_CONTENT, rect,
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kTextureContent, rect,
                    visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
   overlay_resources.size_in_pixels[kResourceIdIndex] = resource_size_in_pixels;
@@ -88,7 +88,7 @@
 }
 
 const TextureDrawQuad* TextureDrawQuad::MaterialCast(const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::TEXTURE_CONTENT);
+  DCHECK(quad->material == DrawQuad::Material::kTextureContent);
   return static_cast<const TextureDrawQuad*>(quad);
 }
 
diff --git a/components/viz/common/quads/tile_draw_quad.cc b/components/viz/common/quads/tile_draw_quad.cc
index cc17510..8d0ecbd 100644
--- a/components/viz/common/quads/tile_draw_quad.cc
+++ b/components/viz/common/quads/tile_draw_quad.cc
@@ -25,10 +25,10 @@
                           bool is_premultiplied,
                           bool nearest_neighbor,
                           bool force_anti_aliasing_off) {
-  ContentDrawQuadBase::SetNew(shared_quad_state, DrawQuad::TILED_CONTENT, rect,
-                              visible_rect, needs_blending, tex_coord_rect,
-                              texture_size, swizzle_contents, is_premultiplied,
-                              nearest_neighbor, force_anti_aliasing_off);
+  ContentDrawQuadBase::SetNew(
+      shared_quad_state, DrawQuad::Material::kTiledContent, rect, visible_rect,
+      needs_blending, tex_coord_rect, texture_size, swizzle_contents,
+      is_premultiplied, nearest_neighbor, force_anti_aliasing_off);
   resources.ids[kResourceIdIndex] = resource_id;
   resources.count = 1;
 }
@@ -44,16 +44,16 @@
                           bool is_premultiplied,
                           bool nearest_neighbor,
                           bool force_anti_aliasing_off) {
-  ContentDrawQuadBase::SetAll(shared_quad_state, DrawQuad::TILED_CONTENT, rect,
-                              visible_rect, needs_blending, tex_coord_rect,
-                              texture_size, swizzle_contents, is_premultiplied,
-                              nearest_neighbor, force_anti_aliasing_off);
+  ContentDrawQuadBase::SetAll(
+      shared_quad_state, DrawQuad::Material::kTiledContent, rect, visible_rect,
+      needs_blending, tex_coord_rect, texture_size, swizzle_contents,
+      is_premultiplied, nearest_neighbor, force_anti_aliasing_off);
   resources.ids[kResourceIdIndex] = resource_id;
   resources.count = 1;
 }
 
 const TileDrawQuad* TileDrawQuad::MaterialCast(const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::TILED_CONTENT);
+  DCHECK(quad->material == DrawQuad::Material::kTiledContent);
   return static_cast<const TileDrawQuad*>(quad);
 }
 
diff --git a/components/viz/common/quads/video_hole_draw_quad.cc b/components/viz/common/quads/video_hole_draw_quad.cc
index a3c8425..cb9848c 100644
--- a/components/viz/common/quads/video_hole_draw_quad.cc
+++ b/components/viz/common/quads/video_hole_draw_quad.cc
@@ -20,7 +20,8 @@
                                const gfx::Rect& rect,
                                const gfx::Rect& visible_rect,
                                const base::UnguessableToken& overlay_plane_id) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::VIDEO_HOLE, rect, visible_rect,
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kVideoHole, rect,
+                   visible_rect,
                    /*needs_blending=*/false);
   this->overlay_plane_id = overlay_plane_id;
 }
@@ -30,13 +31,13 @@
                                const gfx::Rect& visible_rect,
                                bool needs_blending,
                                const base::UnguessableToken& overlay_plane_id) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::VIDEO_HOLE, rect, visible_rect,
-                   needs_blending);
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kVideoHole, rect,
+                   visible_rect, needs_blending);
   this->overlay_plane_id = overlay_plane_id;
 }
 
 const VideoHoleDrawQuad* VideoHoleDrawQuad::MaterialCast(const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::VIDEO_HOLE);
+  DCHECK(quad->material == DrawQuad::Material::kVideoHole);
   return static_cast<const VideoHoleDrawQuad*>(quad);
 }
 
diff --git a/components/viz/common/quads/yuv_video_draw_quad.cc b/components/viz/common/quads/yuv_video_draw_quad.cc
index cb1fa6e..1df7f39b 100644
--- a/components/viz/common/quads/yuv_video_draw_quad.cc
+++ b/components/viz/common/quads/yuv_video_draw_quad.cc
@@ -33,8 +33,8 @@
                               float offset,
                               float multiplier,
                               uint32_t bits_per_channel) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::YUV_VIDEO_CONTENT, rect,
-                   visible_rect, needs_blending);
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kYuvVideoContent,
+                   rect, visible_rect, needs_blending);
   this->ya_tex_coord_rect = ya_tex_coord_rect;
   this->uv_tex_coord_rect = uv_tex_coord_rect;
   this->ya_tex_size = ya_tex_size;
@@ -67,8 +67,8 @@
                               float multiplier,
                               uint32_t bits_per_channel,
                               ui::ProtectedVideoType protected_video_type) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::YUV_VIDEO_CONTENT, rect,
-                   visible_rect, needs_blending);
+  DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kYuvVideoContent,
+                   rect, visible_rect, needs_blending);
   this->ya_tex_coord_rect = ya_tex_coord_rect;
   this->uv_tex_coord_rect = uv_tex_coord_rect;
   this->ya_tex_size = ya_tex_size;
@@ -86,7 +86,7 @@
 }
 
 const YUVVideoDrawQuad* YUVVideoDrawQuad::MaterialCast(const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::YUV_VIDEO_CONTENT);
+  DCHECK(quad->material == DrawQuad::Material::kYuvVideoContent);
   return static_cast<const YUVVideoDrawQuad*>(quad);
 }
 
diff --git a/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.cc b/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.cc
index db2ef8e..b55ef3e41 100644
--- a/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.cc
+++ b/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.cc
@@ -9,6 +9,9 @@
 #include <vector>
 
 #include "base/files/file_util.h"
+#include "base/optional.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "components/viz/service/display/software_output_device.h"
 #include "components/viz/service/display_embedder/software_output_surface.h"
 #include "third_party/skia/include/encode/SkPngEncoder.h"
diff --git a/components/viz/service/display/ca_layer_overlay.cc b/components/viz/service/display/ca_layer_overlay.cc
index 2d0eed44..48268ba0 100644
--- a/components/viz/service/display/ca_layer_overlay.cc
+++ b/components/viz/service/display/ca_layer_overlay.cc
@@ -223,34 +223,34 @@
 
     ca_layer_overlay->bounds_rect = gfx::RectF(quad->rect);
 
-    *render_pass_draw_quad = quad->material == DrawQuad::RENDER_PASS;
+    *render_pass_draw_quad = quad->material == DrawQuad::Material::kRenderPass;
     switch (quad->material) {
-      case DrawQuad::TEXTURE_CONTENT:
+      case DrawQuad::Material::kTextureContent:
         return FromTextureQuad(resource_provider,
                                TextureDrawQuad::MaterialCast(quad),
                                ca_layer_overlay);
-      case DrawQuad::TILED_CONTENT:
+      case DrawQuad::Material::kTiledContent:
         return FromTileQuad(resource_provider, TileDrawQuad::MaterialCast(quad),
                             ca_layer_overlay);
-      case DrawQuad::SOLID_COLOR:
+      case DrawQuad::Material::kSolidColor:
         return FromSolidColorDrawQuad(SolidColorDrawQuad::MaterialCast(quad),
                                       ca_layer_overlay, skip);
-      case DrawQuad::STREAM_VIDEO_CONTENT:
+      case DrawQuad::Material::kStreamVideoContent:
         return FromStreamVideoQuad(resource_provider,
                                    StreamVideoDrawQuad::MaterialCast(quad),
                                    ca_layer_overlay);
-      case DrawQuad::DEBUG_BORDER:
+      case DrawQuad::Material::kDebugBorder:
         return CA_LAYER_FAILED_DEBUG_BORDER;
-      case DrawQuad::PICTURE_CONTENT:
+      case DrawQuad::Material::kPictureContent:
         return CA_LAYER_FAILED_PICTURE_CONTENT;
-      case DrawQuad::RENDER_PASS:
+      case DrawQuad::Material::kRenderPass:
         return FromRenderPassQuad(
             resource_provider, RenderPassDrawQuad::MaterialCast(quad),
             render_pass_filters, render_pass_backdrop_filters,
             ca_layer_overlay);
-      case DrawQuad::SURFACE_CONTENT:
+      case DrawQuad::Material::kSurfaceContent:
         return CA_LAYER_FAILED_SURFACE_CONTENT;
-      case DrawQuad::YUV_VIDEO_CONTENT:
+      case DrawQuad::Material::kYuvVideoContent:
         return CA_LAYER_FAILED_YUV_VIDEO_CONTENT;
       default:
         break;
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc
index bf9a25c5..d5bde069 100644
--- a/components/viz/service/display/dc_layer_overlay.cc
+++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -151,7 +151,7 @@
       continue;
     const DrawQuad* quad = *overlap_iter;
     gfx::RectF overlap_rect = ClippedQuadRectangle(quad);
-    if (quad->material == DrawQuad::SOLID_COLOR) {
+    if (quad->material == DrawQuad::Material::kSolidColor) {
       SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color;
       float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
       if (quad->ShouldDrawWithBlending() &&
@@ -242,7 +242,7 @@
     RenderPass* render_pass,
     gfx::Rect* damage_rect,
     QuadList::Iterator it) {
-  DCHECK_EQ(DrawQuad::RENDER_PASS, it->material);
+  DCHECK_EQ(DrawQuad::Material::kRenderPass, it->material);
   const RenderPassDrawQuad* rpdq = RenderPassDrawQuad::MaterialCast(*it);
 
   ++it;
@@ -348,7 +348,7 @@
     next_it = it;
     ++next_it;
 
-    if (it->material == DrawQuad::RENDER_PASS) {
+    if (it->material == DrawQuad::Material::kRenderPass) {
       next_it = ProcessRenderPassDrawQuad(render_pass, damage_rect, it);
       continue;
     }
@@ -357,7 +357,7 @@
     DCLayerResult result;
     auto uma_protected_video_type = ui::ProtectedVideoType::kClear;
     switch (it->material) {
-      case DrawQuad::YUV_VIDEO_CONTENT:
+      case DrawQuad::Material::kYuvVideoContent:
         result = FromYUVQuad(YUVVideoDrawQuad::MaterialCast(*it),
                              render_pass->transform_to_root_target,
                              has_hw_overlay_support_,
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index 846dac9..12b4b1d 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -215,7 +215,7 @@
   // The quad is expected to be the entire layer so that AA edges are correct.
   if (quad->shared_quad_state->quad_layer_rect != quad->rect)
     return nullptr;
-  if (quad->material != DrawQuad::TILED_CONTENT)
+  if (quad->material != DrawQuad::Material::kTiledContent)
     return nullptr;
 
   // TODO(chrishtr): support could be added for opacity, but care needs
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index e9de37a..d6cefc1 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -745,7 +745,7 @@
       // not entirely covered by draw quads in it; or the DrawQuad size is
       // smaller than the kMinimumDrawOcclusionSize; or the DrawQuad is inside
       // a 3d objects.
-      if (quad->material == ContentDrawQuadBase::Material::RENDER_PASS ||
+      if (quad->material == ContentDrawQuadBase::Material::kRenderPass ||
           (quad->visible_rect.width() <= minimum_draw_occlusion_width &&
            quad->visible_rect.height() <= minimum_draw_occlusion_height) ||
           quad->shared_quad_state->sorting_context_id != 0) {
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 19ce877..488edae2 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -498,45 +498,45 @@
 void GLRenderer::DoDrawQuad(const DrawQuad* quad,
                             const gfx::QuadF* clip_region) {
   DCHECK(quad->rect.Contains(quad->visible_rect));
-  if (quad->material != DrawQuad::TEXTURE_CONTENT) {
+  if (quad->material != DrawQuad::Material::kTextureContent) {
     FlushTextureQuadCache(SHARED_BINDING);
   }
 
   switch (quad->material) {
-    case DrawQuad::INVALID:
+    case DrawQuad::Material::kInvalid:
       NOTREACHED();
       break;
-    case DrawQuad::DEBUG_BORDER:
+    case DrawQuad::Material::kDebugBorder:
       DrawDebugBorderQuad(DebugBorderDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::PICTURE_CONTENT:
+    case DrawQuad::Material::kPictureContent:
       // PictureDrawQuad should only be used for resourceless software draws.
       NOTREACHED();
       break;
-    case DrawQuad::RENDER_PASS:
+    case DrawQuad::Material::kRenderPass:
       DrawRenderPassQuad(RenderPassDrawQuad::MaterialCast(quad), clip_region);
       break;
-    case DrawQuad::SOLID_COLOR:
+    case DrawQuad::Material::kSolidColor:
       DrawSolidColorQuad(SolidColorDrawQuad::MaterialCast(quad), clip_region);
       break;
-    case DrawQuad::STREAM_VIDEO_CONTENT:
+    case DrawQuad::Material::kStreamVideoContent:
       DrawStreamVideoQuad(StreamVideoDrawQuad::MaterialCast(quad), clip_region);
       break;
-    case DrawQuad::SURFACE_CONTENT:
+    case DrawQuad::Material::kSurfaceContent:
       // Surface content should be fully resolved to other quad types before
       // reaching a direct renderer.
       NOTREACHED();
       break;
-    case DrawQuad::TEXTURE_CONTENT:
+    case DrawQuad::Material::kTextureContent:
       EnqueueTextureQuad(TextureDrawQuad::MaterialCast(quad), clip_region);
       break;
-    case DrawQuad::TILED_CONTENT:
+    case DrawQuad::Material::kTiledContent:
       DrawTileQuad(TileDrawQuad::MaterialCast(quad), clip_region);
       break;
-    case DrawQuad::YUV_VIDEO_CONTENT:
+    case DrawQuad::Material::kYuvVideoContent:
       DrawYUVVideoQuad(YUVVideoDrawQuad::MaterialCast(quad), clip_region);
       break;
-    case DrawQuad::VIDEO_HOLE:
+    case DrawQuad::Material::kVideoHole:
       // VideoHoleDrawQuad should only be used by Cast, and should
       // have been replaced by cast-specific OverlayProcessor before
       // reach here. In non-cast build, an untrusted render could send such
diff --git a/components/viz/service/display/overlay_candidate.cc b/components/viz/service/display/overlay_candidate.cc
index 6e66603..038a3c94 100644
--- a/components/viz/service/display/overlay_candidate.cc
+++ b/components/viz/service/display/overlay_candidate.cc
@@ -125,16 +125,16 @@
   }
 
   switch (quad->material) {
-    case DrawQuad::TEXTURE_CONTENT:
+    case DrawQuad::Material::kTextureContent:
       return FromTextureQuad(resource_provider,
                              TextureDrawQuad::MaterialCast(quad), candidate);
-    case DrawQuad::TILED_CONTENT:
+    case DrawQuad::Material::kTiledContent:
       return FromTileQuad(resource_provider, TileDrawQuad::MaterialCast(quad),
                           candidate);
-    case DrawQuad::VIDEO_HOLE:
+    case DrawQuad::Material::kVideoHole:
       return FromVideoHoleQuad(
           resource_provider, VideoHoleDrawQuad::MaterialCast(quad), candidate);
-    case DrawQuad::STREAM_VIDEO_CONTENT:
+    case DrawQuad::Material::kStreamVideoContent:
       return FromStreamVideoQuad(resource_provider,
                                  StreamVideoDrawQuad::MaterialCast(quad),
                                  candidate);
@@ -150,7 +150,7 @@
   float opacity = quad->shared_quad_state->opacity;
   if (opacity < std::numeric_limits<float>::epsilon())
     return true;
-  if (quad->material != DrawQuad::SOLID_COLOR)
+  if (quad->material != DrawQuad::Material::kSolidColor)
     return false;
   const SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color;
   const float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
@@ -179,12 +179,12 @@
 // static
 bool OverlayCandidate::RequiresOverlay(const DrawQuad* quad) {
   switch (quad->material) {
-    case DrawQuad::TEXTURE_CONTENT:
+    case DrawQuad::Material::kTextureContent:
       return TextureDrawQuad::MaterialCast(quad)->protected_video_type ==
              ui::ProtectedVideoType::kHardwareProtected;
-    case DrawQuad::VIDEO_HOLE:
+    case DrawQuad::Material::kVideoHole:
       return true;
-    case DrawQuad::YUV_VIDEO_CONTENT:
+    case DrawQuad::Material::kYuvVideoContent:
       return YUVVideoDrawQuad::MaterialCast(quad)->protected_video_type ==
              ui::ProtectedVideoType::kHardwareProtected;
     default:
@@ -201,7 +201,7 @@
         render_pass_backdrop_filters) {
   for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
        ++overlap_iter) {
-    if (overlap_iter->material == DrawQuad::RENDER_PASS) {
+    if (overlap_iter->material == DrawQuad::Material::kRenderPass) {
       gfx::RectF overlap_rect = cc::MathUtil::MapClippedRect(
           overlap_iter->shared_quad_state->quad_to_target_transform,
           gfx::RectF(overlap_iter->rect));
@@ -353,7 +353,7 @@
 void OverlayCandidateList::AddToPromotionHintRequestorSetIfNeeded(
     const DisplayResourceProvider* resource_provider,
     const DrawQuad* quad) {
-  if (quad->material != DrawQuad::STREAM_VIDEO_CONTENT)
+  if (quad->material != DrawQuad::Material::kStreamVideoContent)
     return;
   ResourceId id = StreamVideoDrawQuad::MaterialCast(quad)->resource_id();
   if (!resource_provider->DoesResourceWantPromotionHint(id))
diff --git a/components/viz/service/display/overlay_strategy_underlay_cast.cc b/components/viz/service/display/overlay_strategy_underlay_cast.cc
index 6378ec1..1dfdea9a 100644
--- a/components/viz/service/display/overlay_strategy_underlay_cast.cc
+++ b/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -57,13 +57,13 @@
       // the underlay to be visible.
       // VIDEO_HOLE implies it requires overlay.
       is_underlay =
-          quad->material == DrawQuad::VIDEO_HOLE &&
+          quad->material == DrawQuad::Material::kVideoHole &&
           OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix,
                                          quad, &candidate);
       found_underlay = is_underlay;
     }
 
-    if (!found_underlay && quad->material == DrawQuad::SOLID_COLOR) {
+    if (!found_underlay && quad->material == DrawQuad::Material::kSolidColor) {
       const SolidColorDrawQuad* solid = SolidColorDrawQuad::MaterialCast(quad);
       if (solid->color == SK_ColorBLACK)
         continue;
@@ -92,7 +92,7 @@
 
     for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
       OverlayCandidate candidate;
-      if (it->material != DrawQuad::VIDEO_HOLE ||
+      if (it->material != DrawQuad::Material::kVideoHole ||
           !OverlayCandidate::FromDrawQuad(
               resource_provider, output_color_matrix, *it, &candidate)) {
         continue;
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index dbdd22a7..f0a7521 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -840,7 +840,7 @@
   const auto& quad_list = main_pass->quad_list;
   for (auto it = quad_list.BackToFrontBegin(); it != quad_list.BackToFrontEnd();
        ++it) {
-    EXPECT_NE(DrawQuad::TEXTURE_CONTENT, it->material);
+    EXPECT_NE(DrawQuad::Material::kTextureContent, it->material);
   }
 
   // Check that the right resource id got extracted.
@@ -1654,7 +1654,8 @@
   EXPECT_EQ(-1, candidate_list[0].plane_z_order);
   EXPECT_EQ(2U, main_pass->quad_list.size());
   // The overlay quad should have changed to a SOLID_COLOR quad.
-  EXPECT_EQ(main_pass->quad_list.back()->material, DrawQuad::SOLID_COLOR);
+  EXPECT_EQ(main_pass->quad_list.back()->material,
+            DrawQuad::Material::kSolidColor);
   auto* quad = static_cast<SolidColorDrawQuad*>(main_pass->quad_list.back());
   EXPECT_EQ(quad->rect, quad->visible_rect);
   EXPECT_EQ(false, quad->needs_blending);
@@ -1683,7 +1684,8 @@
   ASSERT_EQ(1U, candidate_list.size());
   EXPECT_EQ(-1, candidate_list[0].plane_z_order);
   // The overlay quad should have changed to a SOLID_COLOR quad.
-  EXPECT_EQ(main_pass->quad_list.front()->material, DrawQuad::SOLID_COLOR);
+  EXPECT_EQ(main_pass->quad_list.front()->material,
+            DrawQuad::Material::kSolidColor);
   auto* quad = static_cast<SolidColorDrawQuad*>(main_pass->quad_list.front());
   EXPECT_EQ(quad->rect, quad->visible_rect);
   EXPECT_EQ(false, quad->needs_blending);
@@ -2875,7 +2877,7 @@
   EXPECT_EQ(gfx::Rect(0, 0, 0, 0), overlay_damage);
 
   EXPECT_EQ(1u, pass_list[0]->quad_list.size());
-  EXPECT_EQ(DrawQuad::SOLID_COLOR,
+  EXPECT_EQ(DrawQuad::Material::kSolidColor,
             pass_list[0]->quad_list.ElementAt(0)->material);
 
   // The kHardwareProtectedVideo video quad is put into an underlay, and
@@ -2897,14 +2899,14 @@
   EXPECT_EQ(3u, pass_list[2]->quad_list.size());
 
   // The RPDQs are not modified.
-  EXPECT_EQ(DrawQuad::RENDER_PASS,
+  EXPECT_EQ(DrawQuad::Material::kRenderPass,
             pass_list[2]->quad_list.ElementAt(0)->material);
   EXPECT_EQ(child_pass1_id, static_cast<RenderPassDrawQuad*>(
                                 pass_list[2]->quad_list.ElementAt(0))
                                 ->render_pass_id);
 
   // A solid color quad is put behind the RPDQ containing the video.
-  EXPECT_EQ(DrawQuad::SOLID_COLOR,
+  EXPECT_EQ(DrawQuad::Material::kSolidColor,
             pass_list[2]->quad_list.ElementAt(1)->material);
   auto* rpdq_solid_color_quad =
       static_cast<SolidColorDrawQuad*>(pass_list[2]->quad_list.ElementAt(1));
@@ -2914,7 +2916,7 @@
   EXPECT_EQ(1.f, rpdq_solid_color_quad->shared_quad_state->opacity);
   EXPECT_FALSE(rpdq_solid_color_quad->ShouldDrawWithBlending());
 
-  EXPECT_EQ(DrawQuad::RENDER_PASS,
+  EXPECT_EQ(DrawQuad::Material::kRenderPass,
             pass_list[2]->quad_list.ElementAt(2)->material);
   EXPECT_EQ(child_pass2_id, static_cast<RenderPassDrawQuad*>(
                                 pass_list[2]->quad_list.ElementAt(2))
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index a3e5665..b6ab725 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -98,7 +98,7 @@
                           const gfx::Transform& contents_device_transform) {
   // PICTURE_CONTENT is not like the others, since it is executing a list of
   // draw calls into the canvas.
-  if (quad->material == DrawQuad::PICTURE_CONTENT)
+  if (quad->material == DrawQuad::Material::kPictureContent)
     return false;
   // Intersection with scissor and a quadrilateral is not necessarily a quad,
   // so don't complicate things
@@ -259,13 +259,13 @@
 
 bool IsAAForcedOff(const DrawQuad* quad) {
   switch (quad->material) {
-    case DrawQuad::PICTURE_CONTENT:
+    case DrawQuad::Material::kPictureContent:
       return PictureDrawQuad::MaterialCast(quad)->force_anti_aliasing_off;
-    case DrawQuad::RENDER_PASS:
+    case DrawQuad::Material::kRenderPass:
       return RenderPassDrawQuad::MaterialCast(quad)->force_anti_aliasing_off;
-    case DrawQuad::SOLID_COLOR:
+    case DrawQuad::Material::kSolidColor:
       return SolidColorDrawQuad::MaterialCast(quad)->force_anti_aliasing_off;
-    case DrawQuad::TILED_CONTENT:
+    case DrawQuad::Material::kTiledContent:
       return TileDrawQuad::MaterialCast(quad)->force_anti_aliasing_off;
     default:
       return false;
@@ -275,13 +275,13 @@
 SkFilterQuality GetFilterQuality(const DrawQuad* quad) {
   bool nearest_neighbor;
   switch (quad->material) {
-    case DrawQuad::PICTURE_CONTENT:
+    case DrawQuad::Material::kPictureContent:
       nearest_neighbor = PictureDrawQuad::MaterialCast(quad)->nearest_neighbor;
       break;
-    case DrawQuad::TEXTURE_CONTENT:
+    case DrawQuad::Material::kTextureContent:
       nearest_neighbor = TextureDrawQuad::MaterialCast(quad)->nearest_neighbor;
       break;
-    case DrawQuad::TILED_CONTENT:
+    case DrawQuad::Material::kTiledContent:
       nearest_neighbor = TileDrawQuad::MaterialCast(quad)->nearest_neighbor;
       break;
     default:
@@ -825,35 +825,35 @@
   }
 
   switch (quad->material) {
-    case DrawQuad::DEBUG_BORDER:
+    case DrawQuad::Material::kDebugBorder:
       DrawDebugBorderQuad(DebugBorderDrawQuad::MaterialCast(quad), &params);
       break;
-    case DrawQuad::PICTURE_CONTENT:
+    case DrawQuad::Material::kPictureContent:
       DrawPictureQuad(PictureDrawQuad::MaterialCast(quad), &params);
       break;
-    case DrawQuad::RENDER_PASS:
+    case DrawQuad::Material::kRenderPass:
       DrawRenderPassQuad(RenderPassDrawQuad::MaterialCast(quad), &params);
       break;
-    case DrawQuad::SOLID_COLOR:
+    case DrawQuad::Material::kSolidColor:
       DrawSolidColorQuad(SolidColorDrawQuad::MaterialCast(quad), &params);
       break;
-    case DrawQuad::STREAM_VIDEO_CONTENT:
+    case DrawQuad::Material::kStreamVideoContent:
       DrawStreamVideoQuad(StreamVideoDrawQuad::MaterialCast(quad), &params);
       break;
-    case DrawQuad::TEXTURE_CONTENT:
+    case DrawQuad::Material::kTextureContent:
       DrawTextureQuad(TextureDrawQuad::MaterialCast(quad), &params);
       break;
-    case DrawQuad::TILED_CONTENT:
+    case DrawQuad::Material::kTiledContent:
       DrawTileDrawQuad(TileDrawQuad::MaterialCast(quad), &params);
       break;
-    case DrawQuad::YUV_VIDEO_CONTENT:
+    case DrawQuad::Material::kYuvVideoContent:
       DrawYUVVideoQuad(YUVVideoDrawQuad::MaterialCast(quad), &params);
       break;
-    case DrawQuad::INVALID:
+    case DrawQuad::Material::kInvalid:
       DrawUnsupportedQuad(quad, &params);
       NOTREACHED();
       break;
-    case DrawQuad::VIDEO_HOLE:
+    case DrawQuad::Material::kVideoHole:
       // VideoHoleDrawQuad should only be used by Cast, and should
       // have been replaced by cast-specific OverlayProcessor before
       // reach here. In non-cast build, an untrusted render could send such
@@ -1029,10 +1029,10 @@
   if (batched_quads_.empty())
     return false;
 
-  if (new_quad->material != DrawQuad::RENDER_PASS &&
-      new_quad->material != DrawQuad::STREAM_VIDEO_CONTENT &&
-      new_quad->material != DrawQuad::TEXTURE_CONTENT &&
-      new_quad->material != DrawQuad::TILED_CONTENT)
+  if (new_quad->material != DrawQuad::Material::kRenderPass &&
+      new_quad->material != DrawQuad::Material::kStreamVideoContent &&
+      new_quad->material != DrawQuad::Material::kTextureContent &&
+      new_quad->material != DrawQuad::Material::kTiledContent)
     return true;
 
   if (batched_quad_state_.blend_mode != params.blend_mode ||
diff --git a/components/viz/service/display/software_renderer.cc b/components/viz/service/display/software_renderer.cc
index 477e98a..5c806a8 100644
--- a/components/viz/service/display/software_renderer.cc
+++ b/components/viz/service/display/software_renderer.cc
@@ -282,36 +282,36 @@
   }
 
   switch (quad->material) {
-    case DrawQuad::DEBUG_BORDER:
+    case DrawQuad::Material::kDebugBorder:
       DrawDebugBorderQuad(DebugBorderDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::PICTURE_CONTENT:
+    case DrawQuad::Material::kPictureContent:
       DrawPictureQuad(PictureDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::RENDER_PASS:
+    case DrawQuad::Material::kRenderPass:
       DrawRenderPassQuad(RenderPassDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::SOLID_COLOR:
+    case DrawQuad::Material::kSolidColor:
       DrawSolidColorQuad(SolidColorDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::TEXTURE_CONTENT:
+    case DrawQuad::Material::kTextureContent:
       DrawTextureQuad(TextureDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::TILED_CONTENT:
+    case DrawQuad::Material::kTiledContent:
       DrawTileQuad(TileDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::SURFACE_CONTENT:
+    case DrawQuad::Material::kSurfaceContent:
       // Surface content should be fully resolved to other quad types before
       // reaching a direct renderer.
       NOTREACHED();
       break;
-    case DrawQuad::INVALID:
-    case DrawQuad::YUV_VIDEO_CONTENT:
-    case DrawQuad::STREAM_VIDEO_CONTENT:
+    case DrawQuad::Material::kInvalid:
+    case DrawQuad::Material::kYuvVideoContent:
+    case DrawQuad::Material::kStreamVideoContent:
       DrawUnsupportedQuad(quad);
       NOTREACHED();
       break;
-    case DrawQuad::VIDEO_HOLE:
+    case DrawQuad::Material::kVideoHole:
       // VideoHoleDrawQuad should only be used by Cast, and should
       // have been replaced by cast-specific OverlayProcessor before
       // reach here. In non-cast build, an untrusted render could send such
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index b65c2e6..989191e 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -782,7 +782,7 @@
     DCHECK(quad->shared_quad_state->rounded_corner_bounds.IsEmpty() ||
            parent_rounded_corner_info.IsEmpty());
 
-    if (quad->material == DrawQuad::SURFACE_CONTENT) {
+    if (quad->material == DrawQuad::Material::kSurfaceContent) {
       const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
       // HandleSurfaceQuad may add other shared quad state, so reset the
       // current data.
@@ -829,7 +829,7 @@
       }
 
       DrawQuad* dest_quad;
-      if (quad->material == DrawQuad::RENDER_PASS) {
+      if (quad->material == DrawQuad::Material::kRenderPass) {
         const auto* pass_quad = RenderPassDrawQuad::MaterialCast(quad);
         RenderPassId original_pass_id = pass_quad->render_pass_id;
         RenderPassId remapped_pass_id =
@@ -843,7 +843,7 @@
 
         dest_quad = dest_pass->CopyFromAndAppendRenderPassDrawQuad(
             pass_quad, remapped_pass_id);
-      } else if (quad->material == DrawQuad::TEXTURE_CONTENT) {
+      } else if (quad->material == DrawQuad::Material::kTextureContent) {
         const auto* texture_quad = TextureDrawQuad::MaterialCast(quad);
         if (texture_quad->secure_output_only &&
             (!output_is_secure_ || copy_request_passes_.count(dest_pass->id))) {
@@ -1055,7 +1055,7 @@
         has_pixel_moving_filter ||
         base::ContainsKey(moved_pixel_passes_, remapped_pass_id);
     for (auto* quad : render_pass->quad_list) {
-      if (quad->material == DrawQuad::SURFACE_CONTENT) {
+      if (quad->material == DrawQuad::Material::kSurfaceContent) {
         const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
         gfx::Transform target_to_surface_transform(
             render_pass->transform_to_root_target,
@@ -1075,7 +1075,7 @@
             surface_quad->stretch_content_to_fill_bounds,
             surface_quad->shared_quad_state->is_clipped,
             clip_rect_in_root_target_space);
-      } else if (quad->material == DrawQuad::RENDER_PASS) {
+      } else if (quad->material == DrawQuad::Material::kRenderPass) {
         const auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
         if (in_moved_pixel_pass) {
           moved_pixel_passes_.insert(RemapPassId(
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index 6c6a17a..21d0f33 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -137,7 +137,7 @@
   struct Quad {
     static Quad SolidColorQuad(SkColor color, const gfx::Rect& rect) {
       Quad quad;
-      quad.material = DrawQuad::SOLID_COLOR;
+      quad.material = DrawQuad::Material::kSolidColor;
       quad.color = color;
       quad.rect = rect;
       return quad;
@@ -145,7 +145,7 @@
 
     static Quad YUVVideoQuad(const gfx::Rect& rect) {
       Quad quad;
-      quad.material = DrawQuad::YUV_VIDEO_CONTENT;
+      quad.material = DrawQuad::Material::kYuvVideoContent;
       quad.rect = rect;
       return quad;
     }
@@ -158,7 +158,7 @@
                             bool stretch_content_to_fill_bounds,
                             bool ignores_input_event) {
       Quad quad;
-      quad.material = DrawQuad::SURFACE_CONTENT;
+      quad.material = DrawQuad::Material::kSurfaceContent;
       quad.primary_surface_rect = primary_surface_rect;
       quad.surface_range = surface_range;
       quad.default_background_color = default_background_color;
@@ -175,7 +175,7 @@
                             bool stretch_content_to_fill_bounds,
                             bool ignores_input_event) {
       Quad quad;
-      quad.material = DrawQuad::SURFACE_CONTENT;
+      quad.material = DrawQuad::Material::kSurfaceContent;
       quad.primary_surface_rect = primary_surface_rect;
       quad.opacity = opacity;
       quad.to_target_transform = transform;
@@ -188,13 +188,13 @@
 
     static Quad RenderPassQuad(int id) {
       Quad quad;
-      quad.material = DrawQuad::RENDER_PASS;
+      quad.material = DrawQuad::Material::kRenderPass;
       quad.render_pass_id = id;
       return quad;
     }
 
     DrawQuad::Material material;
-    // Set when material==DrawQuad::SURFACE_CONTENT.
+    // Set when material==DrawQuad::Material::kSurfaceContent.
     SurfaceRange surface_range;
     SkColor default_background_color;
     bool stretch_content_to_fill_bounds;
@@ -202,14 +202,17 @@
     gfx::Rect primary_surface_rect;
     float opacity;
     gfx::Transform to_target_transform;
-    // Set when material==DrawQuad::SOLID_COLOR.
+    // Set when material==DrawQuad::Material::kSolidColor.
     SkColor color;
     gfx::Rect rect;
-    // Set when material==DrawQuad::RENDER_PASS.
+    // Set when material==DrawQuad::Material::kRenderPass.
     RenderPassId render_pass_id;
 
    private:
-    Quad() : material(DrawQuad::INVALID), opacity(1.f), color(SK_ColorWHITE) {}
+    Quad()
+        : material(DrawQuad::Material::kInvalid),
+          opacity(1.f),
+          color(SK_ColorWHITE) {}
   };
 
   struct Pass {
@@ -234,10 +237,10 @@
                             RenderPass* pass,
                             std::vector<SurfaceRange>* referenced_surfaces) {
     switch (desc.material) {
-      case DrawQuad::SOLID_COLOR:
+      case DrawQuad::Material::kSolidColor:
         cc::AddQuad(pass, desc.rect, desc.color);
         break;
-      case DrawQuad::SURFACE_CONTENT:
+      case DrawQuad::Material::kSurfaceContent:
         referenced_surfaces->emplace_back(desc.surface_range);
         AddSurfaceQuad(pass, desc.primary_surface_rect, desc.opacity,
                        desc.to_target_transform, desc.surface_range,
@@ -245,10 +248,10 @@
                        desc.stretch_content_to_fill_bounds,
                        desc.ignores_input_event);
         break;
-      case DrawQuad::RENDER_PASS:
+      case DrawQuad::Material::kRenderPass:
         AddRenderPassQuad(pass, desc.render_pass_id);
         break;
-      case DrawQuad::YUV_VIDEO_CONTENT:
+      case DrawQuad::Material::kYuvVideoContent:
         AddYUVVideoQuad(pass, desc.rect);
         break;
       default:
@@ -272,8 +275,8 @@
   static void TestQuadMatchesExpectations(Quad expected_quad,
                                           const DrawQuad* quad) {
     switch (expected_quad.material) {
-      case DrawQuad::SOLID_COLOR: {
-        ASSERT_EQ(DrawQuad::SOLID_COLOR, quad->material);
+      case DrawQuad::Material::kSolidColor: {
+        ASSERT_EQ(DrawQuad::Material::kSolidColor, quad->material);
 
         const auto* solid_color_quad = SolidColorDrawQuad::MaterialCast(quad);
 
@@ -281,8 +284,8 @@
         EXPECT_EQ(expected_quad.rect, solid_color_quad->rect);
         break;
       }
-      case DrawQuad::RENDER_PASS: {
-        ASSERT_EQ(DrawQuad::RENDER_PASS, quad->material);
+      case DrawQuad::Material::kRenderPass: {
+        ASSERT_EQ(DrawQuad::Material::kRenderPass, quad->material);
 
         const auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
 
@@ -1264,7 +1267,7 @@
 
   auto* output_quad = render_pass->quad_list.back();
 
-  EXPECT_EQ(DrawQuad::SOLID_COLOR, output_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kSolidColor, output_quad->material);
   gfx::RectF output_rect(100.f, 100.f);
 
   // SurfaceAggregator should stretch the SolidColorDrawQuad to fit the bounds
@@ -1337,7 +1340,7 @@
 
   auto* output_quad = render_pass->quad_list.back();
 
-  EXPECT_EQ(DrawQuad::SOLID_COLOR, output_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kSolidColor, output_quad->material);
   gfx::RectF output_rect(200.f, 200.f);
 
   // SurfaceAggregator should stretch the SolidColorDrawQuad to fit the bounds
@@ -1409,7 +1412,7 @@
 
   auto* output_quad = render_pass->quad_list.back();
 
-  EXPECT_EQ(DrawQuad::SOLID_COLOR, output_quad->material);
+  EXPECT_EQ(DrawQuad::Material::kSolidColor, output_quad->material);
   gfx::RectF output_rect(50.f, 50.f);
 
   // SurfaceAggregator should stretch the SolidColorDrawQuad to fit the bounds
@@ -1867,7 +1870,7 @@
 
     // This render pass pass quad will reference the first pass from the
     // embedded surface, which is the second pass in the aggregated frame.
-    ASSERT_EQ(DrawQuad::RENDER_PASS,
+    ASSERT_EQ(DrawQuad::Material::kRenderPass,
               third_pass_quad_list.ElementAt(1)->material);
     const auto* third_pass_render_pass_draw_quad =
         RenderPassDrawQuad::MaterialCast(third_pass_quad_list.ElementAt(1));
@@ -1889,7 +1892,7 @@
 
     // The next quad will be a render pass quad referencing the second pass from
     // the embedded surface, which is the third pass in the aggregated frame.
-    ASSERT_EQ(DrawQuad::RENDER_PASS,
+    ASSERT_EQ(DrawQuad::Material::kRenderPass,
               fourth_pass_quad_list.ElementAt(1)->material);
     const auto* fourth_pass_first_render_pass_draw_quad =
         RenderPassDrawQuad::MaterialCast(fourth_pass_quad_list.ElementAt(1));
@@ -1898,7 +1901,7 @@
 
     // The last quad will be a render pass quad referencing the first pass from
     // the root surface, which is the first pass overall.
-    ASSERT_EQ(DrawQuad::RENDER_PASS,
+    ASSERT_EQ(DrawQuad::Material::kRenderPass,
               fourth_pass_quad_list.ElementAt(2)->material);
     const auto* fourth_pass_second_render_pass_draw_quad =
         RenderPassDrawQuad::MaterialCast(fourth_pass_quad_list.ElementAt(2));
@@ -1917,7 +1920,7 @@
     // The last quad in the last pass will reference the second pass from the
     // root surface, which after aggregating is the fourth pass in the overall
     // list.
-    ASSERT_EQ(DrawQuad::RENDER_PASS,
+    ASSERT_EQ(DrawQuad::Material::kRenderPass,
               fifth_pass_quad_list.ElementAt(1)->material);
     const auto* fifth_pass_render_pass_draw_quad =
         RenderPassDrawQuad::MaterialCast(fifth_pass_quad_list.ElementAt(1));
@@ -2148,12 +2151,12 @@
   // Make sure the render pass quads reference the remapped pass IDs.
   DrawQuad* render_pass_quads[] = {aggregated_pass_list[1]->quad_list.front(),
                                    aggregated_pass_list[2]->quad_list.front()};
-  ASSERT_EQ(render_pass_quads[0]->material, DrawQuad::RENDER_PASS);
+  ASSERT_EQ(render_pass_quads[0]->material, DrawQuad::Material::kRenderPass);
   EXPECT_EQ(
       actual_pass_ids[0],
       RenderPassDrawQuad::MaterialCast(render_pass_quads[0])->render_pass_id);
 
-  ASSERT_EQ(render_pass_quads[1]->material, DrawQuad::RENDER_PASS);
+  ASSERT_EQ(render_pass_quads[1]->material, DrawQuad::Material::kRenderPass);
   EXPECT_EQ(
       actual_pass_ids[1],
       RenderPassDrawQuad::MaterialCast(render_pass_quads[1])->render_pass_id);
@@ -4178,7 +4181,8 @@
 
   auto* render_pass = frame.render_pass_list.back().get();
 
-  EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, render_pass->quad_list.back()->material);
+  EXPECT_EQ(DrawQuad::Material::kTextureContent,
+            render_pass->quad_list.back()->material);
 
   {
     auto pass = RenderPass::Create();
@@ -4205,14 +4209,15 @@
   render_pass = frame.render_pass_list.front().get();
 
   // Parent has copy request, so texture should not be drawn.
-  EXPECT_EQ(DrawQuad::SOLID_COLOR, render_pass->quad_list.back()->material);
+  EXPECT_EQ(DrawQuad::Material::kSolidColor,
+            render_pass->quad_list.back()->material);
 
   frame = aggregator_->Aggregate(surface2_id, GetNextDisplayTimeAndIncrement());
   EXPECT_EQ(1u, frame.render_pass_list.size());
   render_pass = frame.render_pass_list.front().get();
 
   // Copy request has been executed earlier, so texture should be drawn.
-  EXPECT_EQ(DrawQuad::TEXTURE_CONTENT,
+  EXPECT_EQ(DrawQuad::Material::kTextureContent,
             render_pass->quad_list.front()->material);
 
   aggregator_->set_output_is_secure(false);
@@ -4221,7 +4226,8 @@
   render_pass = frame.render_pass_list.back().get();
 
   // Output is insecure, so texture should be drawn.
-  EXPECT_EQ(DrawQuad::SOLID_COLOR, render_pass->quad_list.back()->material);
+  EXPECT_EQ(DrawQuad::Material::kSolidColor,
+            render_pass->quad_list.back()->material);
 }
 
 // Ensure that the render passes have correct color spaces.
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc b/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc
index 99befa4e..70bce5f 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc
@@ -439,9 +439,12 @@
   auto access = current_render_pass_id_ == 0
                     ? SkSurface::BackendSurfaceAccess::kPresent
                     : SkSurface::BackendSurfaceAccess::kNoAccess;
-  auto result = sk_current_surface_->flush(access, SkSurface::kNone_FlushFlags,
-                                           pending_semaphores_.size(),
-                                           pending_semaphores_.data());
+  GrFlushInfo flush_info = {
+      .fFlags = kNone_GrFlushFlags,
+      .fNumSemaphores = pending_semaphores_.size(),
+      .fSignalSemaphores = pending_semaphores_.data(),
+  };
+  auto result = sk_current_surface_->flush(access, flush_info);
   DCHECK_EQ(result, GrSemaphoresSubmitted::kYes);
   pending_semaphores_.clear();
   sk_current_surface_ = nullptr;
diff --git a/components/viz/service/surfaces/surface_hittest.cc b/components/viz/service/surfaces/surface_hittest.cc
index 6b630def..a884b3d 100644
--- a/components/viz/service/surfaces/surface_hittest.cc
+++ b/components/viz/service/surfaces/surface_hittest.cc
@@ -138,7 +138,7 @@
     }
 
     switch (quad->material) {
-      case DrawQuad::SURFACE_CONTENT: {
+      case DrawQuad::Material::kSurfaceContent: {
         // We've hit a SurfaceDrawQuad, we need to recurse into this
         // Surface.
         const SurfaceDrawQuad* surface_quad =
@@ -175,7 +175,7 @@
         break;
       }
 
-      case DrawQuad::RENDER_PASS: {
+      case DrawQuad::Material::kRenderPass: {
         // We've hit a RenderPassDrawQuad, we need to recurse into this
         // RenderPass.
         const RenderPassDrawQuad* render_quad =
@@ -257,7 +257,7 @@
   }
 
   for (const DrawQuad* quad : render_pass->quad_list) {
-    if (quad->material == DrawQuad::SURFACE_CONTENT) {
+    if (quad->material == DrawQuad::Material::kSurfaceContent) {
       gfx::Transform target_to_quad_transform;
       gfx::Transform quad_to_target_transform =
           quad->shared_quad_state->quad_to_target_transform;
@@ -285,7 +285,7 @@
       continue;
     }
 
-    if (quad->material == DrawQuad::RENDER_PASS) {
+    if (quad->material == DrawQuad::Material::kRenderPass) {
       // We've hit a RenderPassDrawQuad, we need to recurse into this
       // RenderPass.
       const RenderPassDrawQuad* render_quad =
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
new file mode 100644
index 0000000..c8cc9a5
--- /dev/null
+++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -0,0 +1,206 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h"
+
+#include "base/win/scoped_bstr.h"
+#include "base/win/scoped_safearray.h"
+#include "base/win/scoped_variant.h"
+#include "content/browser/accessibility/browser_accessibility.h"
+#include "content/browser/accessibility/browser_accessibility_com_win.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "content/test/accessibility_browser_test_utils.h"
+#include "net/base/escape.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+
+using Microsoft::WRL::ComPtr;
+
+namespace content {
+
+#define EXPECT_UIA_DOUBLE_SAFEARRAY_EQ(safearray, expected_property_values) \
+  {                                                                         \
+    EXPECT_EQ(sizeof(V_R8(LPVARIANT(NULL))),                                \
+              ::SafeArrayGetElemsize(safearray));                           \
+    ASSERT_EQ(1u, SafeArrayGetDim(safearray));                              \
+    LONG array_lower_bound;                                                 \
+    ASSERT_HRESULT_SUCCEEDED(                                               \
+        SafeArrayGetLBound(safearray, 1, &array_lower_bound));              \
+    LONG array_upper_bound;                                                 \
+    ASSERT_HRESULT_SUCCEEDED(                                               \
+        SafeArrayGetUBound(safearray, 1, &array_upper_bound));              \
+    double* array_data;                                                     \
+    ASSERT_HRESULT_SUCCEEDED(::SafeArrayAccessData(                         \
+        safearray, reinterpret_cast<void**>(&array_data)));                 \
+    size_t count = array_upper_bound - array_lower_bound + 1;               \
+    ASSERT_EQ(expected_property_values.size(), count);                      \
+    for (size_t i = 0; i < count; ++i) {                                    \
+      EXPECT_EQ(array_data[i], expected_property_values[i]);                \
+    }                                                                       \
+    ASSERT_HRESULT_SUCCEEDED(::SafeArrayUnaccessData(safearray));           \
+  }
+
+#define EXPECT_UIA_TEXTRANGE_EQ(provider, expected_content) \
+  {                                                         \
+    base::win::ScopedBstr provider_content;                 \
+    ASSERT_HRESULT_SUCCEEDED(                               \
+        provider->GetText(-1, provider_content.Receive())); \
+    EXPECT_STREQ(expected_content, provider_content);       \
+  }
+
+class AXPlatformNodeTextRangeProviderWinBrowserTest
+    : public ContentBrowserTest {
+ protected:
+  void LoadInitialAccessibilityTreeFromUrl(
+      const GURL& url,
+      ui::AXMode accessibility_mode = ui::kAXModeComplete) {
+    AccessibilityNotificationWaiter waiter(shell()->web_contents(),
+                                           accessibility_mode,
+                                           ax::mojom::Event::kLoadComplete);
+    NavigateToURL(shell(), url);
+    waiter.WaitForNotification();
+  }
+
+  void LoadInitialAccessibilityTreeFromHtmlFilePath(
+      const std::string& html_file_path,
+      ui::AXMode accessibility_mode = ui::kAXModeComplete) {
+    if (!embedded_test_server()->Started())
+      ASSERT_TRUE(embedded_test_server()->Start());
+    ASSERT_TRUE(embedded_test_server()->Started());
+    LoadInitialAccessibilityTreeFromUrl(
+        embedded_test_server()->GetURL(html_file_path), accessibility_mode);
+  }
+
+  void LoadInitialAccessibilityTreeFromHtml(
+      const std::string& html,
+      ui::AXMode accessibility_mode = ui::kAXModeComplete) {
+    LoadInitialAccessibilityTreeFromUrl(
+        GURL("data:text/html," + net::EscapeQueryParamValue(html, false)),
+        accessibility_mode);
+  }
+
+  BrowserAccessibilityManager* GetManagerAndAssertNonNull() {
+    auto GetManagerAndAssertNonNull =
+        [this](BrowserAccessibilityManager** result) {
+          WebContentsImpl* web_contents_impl =
+              static_cast<WebContentsImpl*>(shell()->web_contents());
+          ASSERT_NE(nullptr, web_contents_impl);
+          BrowserAccessibilityManager* browser_accessibility_manager =
+              web_contents_impl->GetRootBrowserAccessibilityManager();
+          ASSERT_NE(nullptr, browser_accessibility_manager);
+          *result = browser_accessibility_manager;
+        };
+
+    BrowserAccessibilityManager* browser_accessibility_manager;
+    GetManagerAndAssertNonNull(&browser_accessibility_manager);
+    return browser_accessibility_manager;
+  }
+
+  BrowserAccessibility* GetRootAndAssertNonNull() {
+    auto GetRootAndAssertNonNull = [this](BrowserAccessibility** result) {
+      BrowserAccessibility* root_browser_accessibility =
+          GetManagerAndAssertNonNull()->GetRoot();
+      ASSERT_NE(nullptr, result);
+      *result = root_browser_accessibility;
+    };
+
+    BrowserAccessibility* root_browser_accessibility;
+    GetRootAndAssertNonNull(&root_browser_accessibility);
+    return root_browser_accessibility;
+  }
+
+  BrowserAccessibility* FindNode(ax::mojom::Role role,
+                                 const std::string& name_or_value) {
+    return FindNodeInSubtree(*GetRootAndAssertNonNull(), role, name_or_value);
+  }
+
+  void GetTextRangeProviderFromTextNode(
+      ComPtr<ITextRangeProvider>& text_range_provider,
+      BrowserAccessibility* target_browser_accessibility) {
+    auto* provider_simple =
+        ToBrowserAccessibilityWin(target_browser_accessibility)->GetCOM();
+    ASSERT_NE(nullptr, provider_simple);
+
+    ComPtr<ITextProvider> text_provider;
+    EXPECT_HRESULT_SUCCEEDED(
+        provider_simple->GetPatternProvider(UIA_TextPatternId, &text_provider));
+    ASSERT_NE(nullptr, text_provider.Get());
+
+    EXPECT_HRESULT_SUCCEEDED(
+        text_provider->get_DocumentRange(&text_range_provider));
+    ASSERT_NE(nullptr, text_range_provider.Get());
+  }
+
+ private:
+  BrowserAccessibility* FindNodeInSubtree(BrowserAccessibility& node,
+                                          ax::mojom::Role role,
+                                          const std::string& name_or_value) {
+    const auto& name =
+        node.GetStringAttribute(ax::mojom::StringAttribute::kName);
+    const auto& value =
+        node.GetStringAttribute(ax::mojom::StringAttribute::kValue);
+    if (node.GetRole() == role &&
+        (name == name_or_value || value == name_or_value)) {
+      return &node;
+    }
+
+    for (unsigned int i = 0; i < node.PlatformChildCount(); ++i) {
+      BrowserAccessibility* result =
+          FindNodeInSubtree(*node.PlatformGetChild(i), role, name_or_value);
+      if (result)
+        return result;
+    }
+
+    return nullptr;
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
+                       GetBoundingRectangles) {
+  LoadInitialAccessibilityTreeFromHtml(std::string(R"HTML(
+      <!DOCTYPE html>
+      <html>
+        <head>
+          <style>
+            .break_word {
+              width: 50px;
+              word-wrap: break-word;
+            }
+          </style>
+        </head>
+        <body>
+          <p class="break_word">AsdfAsdfAsdf</p>
+        </body>
+      </html>
+  )HTML"));
+
+  auto* node = FindNode(ax::mojom::Role::kStaticText, "AsdfAsdfAsdf");
+  ASSERT_NE(nullptr, node);
+  EXPECT_TRUE(node->PlatformIsLeaf());
+  EXPECT_EQ(0u, node->PlatformChildCount());
+
+  ComPtr<ITextRangeProvider> text_range_provider;
+  GetTextRangeProviderFromTextNode(text_range_provider, node);
+  ASSERT_NE(nullptr, text_range_provider.Get());
+  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"AsdfAsdfAsdf");
+
+  base::win::ScopedSafearray rectangles;
+  EXPECT_HRESULT_SUCCEEDED(
+      text_range_provider->GetBoundingRectangles(rectangles.Receive()));
+
+  // |view_offset| is necessary to account for differences in the shell
+  // between platforms (e.g. title bar height) because the results of
+  // |GetBoundingRectangles| are in screen coordinates.
+  gfx::Vector2d view_offset =
+      node->manager()->GetViewBounds().OffsetFromOrigin();
+  std::vector<double> expected_values = {
+      8 + view_offset.x(), 16 + view_offset.y(), 49, 17,
+      8 + view_offset.x(), 34 + view_offset.y(), 44, 17};
+  EXPECT_UIA_DOUBLE_SAFEARRAY_EQ(rectangles.Get(), expected_values);
+}
+
+}  // namespace content
diff --git a/content/browser/service_worker/service_worker_script_loader_factory.cc b/content/browser/service_worker/service_worker_script_loader_factory.cc
index 3744c3e..c5aeeba2 100644
--- a/content/browser/service_worker/service_worker_script_loader_factory.cc
+++ b/content/browser/service_worker/service_worker_script_loader_factory.cc
@@ -72,8 +72,9 @@
   //       ServiceWorkerInstalledScriptLoader.
   //    2) If compared script info exists and specifies that the script is
   //       installed in an old service worker but content has changed, then
-  //       resume the paused state in the compared script info to load the
-  //       script.
+  //       ServiceWorkerNewScriptLoader::CreateForResume() is called to create
+  //       a ServiceWorkerNewScriptLoader to resume the paused state in the
+  //       compared script info.
   //    3) For other cases or if ServiceWorkerImportedScriptsUpdateCheck is not
   //       enabled, serve from network with installing the script
   //       (use ServiceWorkerNewScriptLoader::CreateForNetworkOnly() to
@@ -126,11 +127,11 @@
           return;
         case ServiceWorkerSingleScriptUpdateChecker::Result::kDifferent:
           // Case D.2:
-          // TODO(https://crbug.com/648295): Currently, this case is treated
-          // the same as case D.3. In future, the paused state in compared
-          // script info should be resumed instead of a fresh download.
-          NOTIMPLEMENTED();
-          break;
+          mojo::MakeStrongBinding(
+              ServiceWorkerNewScriptLoader::CreateForResume(
+                  options, resource_request, std::move(client), version),
+              std::move(request));
+          return;
         case ServiceWorkerSingleScriptUpdateChecker::Result::kNotCompared:
           // This is invalid, as scripts in compared script info must have been
           // compared.
diff --git a/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc b/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
index be215b4..0531290c 100644
--- a/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
+++ b/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
@@ -12,10 +12,12 @@
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "mojo/public/cpp/system/data_pipe_utils.h"
 #include "net/http/http_util.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/test/test_url_loader_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
 
 namespace content {
 
@@ -86,15 +88,15 @@
     base::RunLoop().RunUntilIdle();
 
     scope_ = GURL("https://host/scope");
+    script_url_ = GURL("https://host/script.js");
 
     blink::mojom::ServiceWorkerRegistrationOptions options;
     options.scope = scope_;
     registration_ = base::MakeRefCounted<ServiceWorkerRegistration>(
         options, 1L /* registration_id */, context->AsWeakPtr());
     version_ = base::MakeRefCounted<ServiceWorkerVersion>(
-        registration_.get(), GURL("https://host/script.js"),
-        blink::mojom::ScriptType::kClassic, context->storage()->NewVersionId(),
-        context->AsWeakPtr());
+        registration_.get(), script_url_, blink::mojom::ScriptType::kClassic,
+        context->storage()->NewVersionId(), context->AsWeakPtr());
 
     provider_host_ = CreateProviderHostForServiceWorkerContext(
         helper_->mock_render_process_id(), true /* is_parent_frame_secure */,
@@ -113,7 +115,7 @@
       network::TestURLLoaderClient* client) {
     network::mojom::URLLoaderPtr loader;
     network::ResourceRequest resource_request;
-    resource_request.url = scope_;
+    resource_request.url = script_url_;
     resource_request.resource_type = ResourceType::kServiceWorker;
     factory_->CreateLoaderAndStart(
         mojo::MakeRequest(&loader), 0 /* routing_id */, 0 /* request_id */,
@@ -126,6 +128,7 @@
   TestBrowserThreadBundle browser_thread_bundle_;
   std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
   GURL scope_;
+  GURL script_url_;
   scoped_refptr<ServiceWorkerRegistration> registration_;
   scoped_refptr<ServiceWorkerVersion> version_;
   base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
@@ -169,4 +172,97 @@
   EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
 }
 
+// This tests copying script and creating resume type
+// ServiceWorkerNewScriptLoaders when ServiceWorkerImportedScriptUpdateCheck
+// is enabled.
+class ServiceWorkerScriptLoaderFactoryCopyResumeTest
+    : public ServiceWorkerScriptLoaderFactoryTest {
+ public:
+  ServiceWorkerScriptLoaderFactoryCopyResumeTest() {
+    feature_list_.InitAndEnableFeature(
+        blink::features::kServiceWorkerImportedScriptUpdateCheck);
+  }
+  ~ServiceWorkerScriptLoaderFactoryCopyResumeTest() override = default;
+
+  void SetUp() override {
+    ServiceWorkerScriptLoaderFactoryTest::SetUp();
+    WriteToDiskCacheSync(helper_->context()->storage(), script_url_,
+                         kOldResourceId, kOldHeaders, kOldData, std::string());
+  }
+
+  void CheckResponse(const std::string& expected_body) {
+    // The response should also be stored in the storage.
+    EXPECT_TRUE(ServiceWorkerUpdateCheckTestUtils::VerifyStoredResponse(
+        version_->script_cache_map()->LookupResourceId(script_url_),
+        helper_->context()->storage(), expected_body));
+
+    EXPECT_TRUE(client_.has_received_response());
+    EXPECT_TRUE(client_.response_body().is_valid());
+
+    std::string response;
+    EXPECT_TRUE(
+        mojo::BlockingCopyToString(client_.response_body_release(), &response));
+    EXPECT_EQ(expected_body, response);
+  }
+
+ protected:
+  base::test::ScopedFeatureList feature_list_;
+  network::TestURLLoaderClient client_;
+  const std::vector<std::pair<std::string, std::string>> kOldHeaders = {
+      {"Content-Type", "text/javascript"},
+      {"Content-Length", "15"}};
+  const std::string kOldData = "old-script-data";
+  const int64_t kOldResourceId = 1;
+  const int64_t kNewResourceId = 2;
+};
+
+// Tests scripts are copied and loaded locally when compared to be
+// identical in update check.
+TEST_F(ServiceWorkerScriptLoaderFactoryCopyResumeTest, CopyScript) {
+  ServiceWorkerUpdateCheckTestUtils::SetComparedScriptInfoForVersion(
+      script_url_, kOldResourceId,
+      ServiceWorkerSingleScriptUpdateChecker::Result::kIdentical, nullptr,
+      version_.get());
+
+  network::mojom::URLLoaderPtr loader = CreateTestLoaderAndStart(&client_);
+  client_.RunUntilComplete();
+
+  EXPECT_EQ(net::OK, client_.completion_status().error_code);
+
+  // Checks the received response data.
+  CheckResponse(kOldData);
+}
+
+// Tests loader factory creates resume type ServiceWorkerNewScriptLoader to
+// continue paused download in update check.
+TEST_F(ServiceWorkerScriptLoaderFactoryCopyResumeTest,
+       CreateResumeTypeScriptLoader) {
+  const std::string kNewHeaders =
+      "HTTP/1.0 200 OK\0Content-Type: text/javascript\0Content-Length: 0\0\0";
+  const std::string kNewData = "";
+
+  mojo::ScopedDataPipeProducerHandle network_producer;
+  mojo::ScopedDataPipeConsumerHandle network_consumer;
+
+  ASSERT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(nullptr, &network_producer,
+                                                 &network_consumer));
+  ServiceWorkerUpdateCheckTestUtils::CreateAndSetComparedScriptInfoForVersion(
+      script_url_, 0, kNewHeaders, kNewData, kOldResourceId, kNewResourceId,
+      helper_.get(),
+      ServiceWorkerNewScriptLoader::NetworkLoaderState::kCompleted,
+      ServiceWorkerNewScriptLoader::WriterState::kCompleted,
+      std::move(network_consumer),
+      ServiceWorkerSingleScriptUpdateChecker::Result::kDifferent,
+      version_.get());
+
+  network::mojom::URLLoaderPtr loader = CreateTestLoaderAndStart(&client_);
+  network_producer.reset();
+  client_.RunUntilComplete();
+
+  EXPECT_EQ(net::OK, client_.completion_status().error_code);
+
+  // The received response has no body because kNewData is empty.
+  CheckResponse(kNewData);
+}
+
 }  // namespace content
diff --git a/content/browser/tracing/background_tracing_active_scenario.cc b/content/browser/tracing/background_tracing_active_scenario.cc
index 259b0a0..558bc51 100644
--- a/content/browser/tracing/background_tracing_active_scenario.cc
+++ b/content/browser/tracing/background_tracing_active_scenario.cc
@@ -142,12 +142,14 @@
     config.SetTraceBufferSizeInEvents(20000);
     config.SetTraceBufferSizeInKb(500);
   }
-#endif
-
+#else
+  // TODO(crbug.com/941318): Re-enable startup tracing for Android once all
+  // Perfetto-related deadlocks are resolved.
   if (!TracingControllerImpl::GetInstance()->IsTracing() &&
       tracing::TracingUsesPerfettoBackend()) {
     tracing::TraceEventDataSource::GetInstance()->SetupStartupTracing();
   }
+#endif
 
   if (!TracingControllerImpl::GetInstance()->StartTracing(
           config,
diff --git a/content/browser/tracing/background_tracing_manager_browsertest.cc b/content/browser/tracing/background_tracing_manager_browsertest.cc
index 20cf874..6e4b2c5 100644
--- a/content/browser/tracing/background_tracing_manager_browsertest.cc
+++ b/content/browser/tracing/background_tracing_manager_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/strings/pattern.h"
 #include "base/task/post_task.h"
 #include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
 #include "content/browser/tracing/background_startup_tracing_observer.h"
 #include "content/browser/tracing/background_tracing_active_scenario.h"
 #include "content/browser/tracing/background_tracing_manager_impl.h"
@@ -436,8 +437,15 @@
 // the full WaitForTracingEnabled() callback (background tracing will directly
 // enable the TraceLog so we get events prior to waiting for the whole IPC
 // sequence to enable tracing coming back from the tracing service).
+// Temporarily disabled startup tracing on Android to be able to unblock
+// Perfetto-based background tracing: https://crbug.com/941318
+#if defined(OS_ANDROID)
+#define MAYBE_EarlyTraceEventsInTrace DISABLED_EarlyTraceEventsInTrace
+#else
+#define MAYBE_EarlyTraceEventsInTrace EarlyTraceEventsInTrace
+#endif
 IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
-                       EarlyTraceEventsInTrace) {
+                       MAYBE_EarlyTraceEventsInTrace) {
   TestTraceReceiverHelper trace_receiver_helper;
   TestBackgroundTracingHelper background_tracing_helper;
 
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 02405c6..694278f9 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -3454,8 +3454,8 @@
 
 TEST_F(ResidentKeyAuthenticatorImplTest, GetAssertionSingle) {
   ASSERT_TRUE(virtual_device_.mutable_state()->InjectResidentKey(
-      /*credential_id=*/{4, 3, 2, 1}, kTestRelyingPartyId,
-      /*user_id=*/{1, 2, 3, 4}, "test@example.com", "Test User"));
+      /*credential_id=*/{{4, 3, 2, 1}}, kTestRelyingPartyId,
+      /*user_id=*/{{1, 2, 3, 4}}, "test@example.com", "Test User"));
 
   TestServiceManagerContext smc;
   AuthenticatorPtr authenticator = ConnectToAuthenticator();
@@ -3471,11 +3471,11 @@
 
 TEST_F(ResidentKeyAuthenticatorImplTest, GetAssertionMulti) {
   ASSERT_TRUE(virtual_device_.mutable_state()->InjectResidentKey(
-      /*credential_id=*/{4, 3, 2, 1}, kTestRelyingPartyId,
-      /*user_id=*/{1, 2, 3, 4}, "test@example.com", "Test User"));
+      /*credential_id=*/{{4, 3, 2, 1}}, kTestRelyingPartyId,
+      /*user_id=*/{{1, 2, 3, 4}}, "test@example.com", "Test User"));
   ASSERT_TRUE(virtual_device_.mutable_state()->InjectResidentKey(
-      /*credential_id=*/{4, 3, 2, 2}, kTestRelyingPartyId,
-      /*user_id=*/{5, 6, 7, 8}, "test2@example.com", "Test User 2"));
+      /*credential_id=*/{{4, 3, 2, 2}}, kTestRelyingPartyId,
+      /*user_id=*/{{5, 6, 7, 8}}, "test2@example.com", "Test User 2"));
 
   TestServiceManagerContext smc;
   AuthenticatorPtr authenticator = ConnectToAuthenticator();
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index f0ce32ba..f05c201f 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1146,6 +1146,7 @@
       "../browser/accessibility/accessibility_browsertest.cc",
       "../browser/accessibility/accessibility_browsertest.h",
       "../browser/accessibility/accessibility_win_browsertest.cc",
+      "../browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc",
       "../browser/accessibility/ax_platform_node_win_browsertest.cc",
       "../browser/renderer_host/accessibility_object_lifetime_win_browsertest.cc",
       "../browser/renderer_host/accessibility_tree_linkage_win_browsertest.cc",
diff --git a/device/bluetooth/bluetooth_local_gatt_service.h b/device/bluetooth/bluetooth_local_gatt_service.h
index 68791c09..c374583 100644
--- a/device/bluetooth/bluetooth_local_gatt_service.h
+++ b/device/bluetooth/bluetooth_local_gatt_service.h
@@ -45,8 +45,8 @@
   class Delegate {
    public:
     // Callbacks used for communicating GATT request responses.
-    typedef base::Callback<void(const std::vector<uint8_t>&)> ValueCallback;
-    typedef base::Closure ErrorCallback;
+    using ValueCallback = base::OnceCallback<void(const std::vector<uint8_t>&)>;
+    using ErrorCallback = base::OnceClosure;
 
     // Called when a remote device |device| requests to read the value of the
     // characteristic |characteristic| starting at offset |offset|.
@@ -65,8 +65,8 @@
         const BluetoothDevice* device,
         const BluetoothLocalGattCharacteristic* characteristic,
         int offset,
-        const ValueCallback& callback,
-        const ErrorCallback& error_callback) = 0;
+        ValueCallback callback,
+        ErrorCallback error_callback) = 0;
 
     // Called when a remote device |device| requests to write the value of the
     // characteristic |characteristic| starting at offset |offset|.
@@ -84,8 +84,8 @@
         const BluetoothLocalGattCharacteristic* characteristic,
         const std::vector<uint8_t>& value,
         int offset,
-        const base::Closure& callback,
-        const ErrorCallback& error_callback) = 0;
+        base::OnceClosure callback,
+        ErrorCallback error_callback) = 0;
 
     // Called when a remote device |device| requests to prepare write the value
     // of the characteristic |characteristic| starting at offset |offset|.
@@ -109,8 +109,8 @@
         const std::vector<uint8_t>& value,
         int offset,
         bool has_subsequent_request,
-        const base::Closure& callback,
-        const ErrorCallback& error_callback) = 0;
+        base::OnceClosure callback,
+        ErrorCallback error_callback) = 0;
 
     // Called when a remote device |device| requests to read the value of the
     // descriptor |descriptor| starting at offset |offset|.
@@ -129,8 +129,8 @@
         const BluetoothDevice* device,
         const BluetoothLocalGattDescriptor* descriptor,
         int offset,
-        const ValueCallback& callback,
-        const ErrorCallback& error_callback) = 0;
+        ValueCallback callback,
+        ErrorCallback error_callback) = 0;
 
     // Called when a remote device |devie| requests to write the value of the
     // descriptor |descriptor| starting at offset |offset|.
@@ -148,8 +148,8 @@
         const BluetoothLocalGattDescriptor* descriptor,
         const std::vector<uint8_t>& value,
         int offset,
-        const base::Closure& callback,
-        const ErrorCallback& error_callback) = 0;
+        base::OnceClosure callback,
+        ErrorCallback error_callback) = 0;
 
     // Called when a remote device |device| requests notifications to start for
     // |characteristic|. |notification_type| is either notify or indicate,
diff --git a/device/bluetooth/dbus/bluetooth_gatt_attribute_value_delegate.h b/device/bluetooth/dbus/bluetooth_gatt_attribute_value_delegate.h
index f1b54d27..0e3fd2c 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_attribute_value_delegate.h
+++ b/device/bluetooth/dbus/bluetooth_gatt_attribute_value_delegate.h
@@ -41,9 +41,8 @@
   // out if left pending for too long causing a disconnection.
   virtual void GetValue(
       const dbus::ObjectPath& device_path,
-      const device::BluetoothLocalGattService::Delegate::ValueCallback&
-          callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
+      device::BluetoothLocalGattService::Delegate::ValueCallback callback,
+      device::BluetoothLocalGattService::Delegate::ErrorCallback
           error_callback) = 0;
 
   // This method will be called, when a remote device requests to write the
@@ -56,8 +55,8 @@
   virtual void SetValue(
       const dbus::ObjectPath& device_path,
       const std::vector<uint8_t>& value,
-      const base::Closure& callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
+      base::OnceClosure callback,
+      device::BluetoothLocalGattService::Delegate::ErrorCallback
           error_callback) = 0;
 
   // This method will be called, when a remote device requests to start sending
@@ -82,8 +81,8 @@
       const std::vector<uint8_t>& value,
       int offset,
       bool has_subsequent_request,
-      const base::Closure& callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
+      base::OnceClosure callback,
+      device::BluetoothLocalGattService::Delegate::ErrorCallback
           error_callback) {}
 
  protected:
diff --git a/device/bluetooth/dbus/bluetooth_gatt_characteristic_delegate_wrapper.cc b/device/bluetooth/dbus/bluetooth_gatt_characteristic_delegate_wrapper.cc
index 241dc4e..63dbe95 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_characteristic_delegate_wrapper.cc
+++ b/device/bluetooth/dbus/bluetooth_gatt_characteristic_delegate_wrapper.cc
@@ -17,23 +17,21 @@
 
 void BluetoothGattCharacteristicDelegateWrapper::GetValue(
     const dbus::ObjectPath& device_path,
-    const device::BluetoothLocalGattService::Delegate::ValueCallback& callback,
-    const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-        error_callback) {
+    device::BluetoothLocalGattService::Delegate::ValueCallback callback,
+    device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback) {
   service()->GetDelegate()->OnCharacteristicReadRequest(
-      GetDeviceWithPath(device_path), characteristic_, 0, callback,
-      error_callback);
+      GetDeviceWithPath(device_path), characteristic_, 0, std::move(callback),
+      std::move(error_callback));
 }
 
 void BluetoothGattCharacteristicDelegateWrapper::SetValue(
     const dbus::ObjectPath& device_path,
     const std::vector<uint8_t>& value,
-    const base::Closure& callback,
-    const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-        error_callback) {
+    base::OnceClosure callback,
+    device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback) {
   service()->GetDelegate()->OnCharacteristicWriteRequest(
-      GetDeviceWithPath(device_path), characteristic_, value, 0, callback,
-      error_callback);
+      GetDeviceWithPath(device_path), characteristic_, value, 0,
+      std::move(callback), std::move(error_callback));
 }
 
 void BluetoothGattCharacteristicDelegateWrapper::StartNotifications(
@@ -54,12 +52,11 @@
     const std::vector<uint8_t>& value,
     int offset,
     bool has_subsequent_request,
-    const base::Closure& callback,
-    const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-        error_callback) {
+    base::OnceClosure callback,
+    device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback) {
   service()->GetDelegate()->OnCharacteristicPrepareWriteRequest(
       GetDeviceWithPath(device_path), characteristic_, value, offset,
-      has_subsequent_request, callback, error_callback);
+      has_subsequent_request, std::move(callback), std::move(error_callback));
 }
 
 }  // namespace bluez
diff --git a/device/bluetooth/dbus/bluetooth_gatt_characteristic_delegate_wrapper.h b/device/bluetooth/dbus/bluetooth_gatt_characteristic_delegate_wrapper.h
index 7ab62c1c..def89cc7 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_characteristic_delegate_wrapper.h
+++ b/device/bluetooth/dbus/bluetooth_gatt_characteristic_delegate_wrapper.h
@@ -31,24 +31,22 @@
   // BluetoothGattAttributeValueDelegate overrides:
   void GetValue(
       const dbus::ObjectPath& device_path,
-      const device::BluetoothLocalGattService::Delegate::ValueCallback&
-          callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-          error_callback) override;
-  void SetValue(
-      const dbus::ObjectPath& device_path,
-      const std::vector<uint8_t>& value,
-      const base::Closure& callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-          error_callback) override;
+      device::BluetoothLocalGattService::Delegate::ValueCallback callback,
+      device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback)
+      override;
+  void SetValue(const dbus::ObjectPath& device_path,
+                const std::vector<uint8_t>& value,
+                base::OnceClosure callback,
+                device::BluetoothLocalGattService::Delegate::ErrorCallback
+                    error_callback) override;
   void PrepareSetValue(
       const dbus::ObjectPath& device_path,
       const std::vector<uint8_t>& value,
       int offset,
       bool has_subsequent_request,
-      const base::Closure& callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-          error_callback) override;
+      base::OnceClosure callback,
+      device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback)
+      override;
   void StartNotifications(const dbus::ObjectPath& device_path,
                           device::BluetoothGattCharacteristic::NotificationType
                               notification_type) override;
diff --git a/device/bluetooth/dbus/bluetooth_gatt_characteristic_service_provider_impl.cc b/device/bluetooth/dbus/bluetooth_gatt_characteristic_service_provider_impl.cc
index 0df8b9c..7fe9b49a 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_characteristic_service_provider_impl.cc
+++ b/device/bluetooth/dbus/bluetooth_gatt_characteristic_service_provider_impl.cc
@@ -294,10 +294,12 @@
   DCHECK(delegate_);
   delegate_->GetValue(
       device_path,
-      base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnReadValue,
-                 weak_ptr_factory_.GetWeakPtr(), method_call, response_sender),
-      base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnFailure,
-                 weak_ptr_factory_.GetWeakPtr(), method_call, response_sender));
+      base::BindOnce(
+          &BluetoothGattCharacteristicServiceProviderImpl::OnReadValue,
+          weak_ptr_factory_.GetWeakPtr(), method_call, response_sender),
+      base::BindOnce(&BluetoothGattCharacteristicServiceProviderImpl::OnFailure,
+                     weak_ptr_factory_.GetWeakPtr(), method_call,
+                     response_sender));
 }
 
 void BluetoothGattCharacteristicServiceProviderImpl::WriteValue(
@@ -337,10 +339,12 @@
   DCHECK(delegate_);
   delegate_->SetValue(
       device_path, value,
-      base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnWriteValue,
-                 weak_ptr_factory_.GetWeakPtr(), method_call, response_sender),
-      base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnFailure,
-                 weak_ptr_factory_.GetWeakPtr(), method_call, response_sender));
+      base::BindOnce(
+          &BluetoothGattCharacteristicServiceProviderImpl::OnWriteValue,
+          weak_ptr_factory_.GetWeakPtr(), method_call, response_sender),
+      base::BindOnce(&BluetoothGattCharacteristicServiceProviderImpl::OnFailure,
+                     weak_ptr_factory_.GetWeakPtr(), method_call,
+                     response_sender));
 }
 
 void BluetoothGattCharacteristicServiceProviderImpl::PrepareWriteValue(
diff --git a/device/bluetooth/dbus/bluetooth_gatt_descriptor_delegate_wrapper.cc b/device/bluetooth/dbus/bluetooth_gatt_descriptor_delegate_wrapper.cc
index b561a1d..a60c511 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_descriptor_delegate_wrapper.cc
+++ b/device/bluetooth/dbus/bluetooth_gatt_descriptor_delegate_wrapper.cc
@@ -15,22 +15,21 @@
 
 void BluetoothGattDescriptorDelegateWrapper::GetValue(
     const dbus::ObjectPath& device_path,
-    const device::BluetoothLocalGattService::Delegate::ValueCallback& callback,
-    const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-        error_callback) {
+    device::BluetoothLocalGattService::Delegate::ValueCallback callback,
+    device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback) {
   service()->GetDelegate()->OnDescriptorReadRequest(
-      GetDeviceWithPath(device_path), descriptor_, 0, callback, error_callback);
+      GetDeviceWithPath(device_path), descriptor_, 0, std::move(callback),
+      std::move(error_callback));
 }
 
 void BluetoothGattDescriptorDelegateWrapper::SetValue(
     const dbus::ObjectPath& device_path,
     const std::vector<uint8_t>& value,
-    const base::Closure& callback,
-    const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-        error_callback) {
+    base::OnceClosure callback,
+    device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback) {
   service()->GetDelegate()->OnDescriptorWriteRequest(
-      GetDeviceWithPath(device_path), descriptor_, value, 0, callback,
-      error_callback);
+      GetDeviceWithPath(device_path), descriptor_, value, 0,
+      std::move(callback), std::move(error_callback));
 }
 
 }  // namespace bluez
diff --git a/device/bluetooth/dbus/bluetooth_gatt_descriptor_delegate_wrapper.h b/device/bluetooth/dbus/bluetooth_gatt_descriptor_delegate_wrapper.h
index d365f1c2..7b947bc 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_descriptor_delegate_wrapper.h
+++ b/device/bluetooth/dbus/bluetooth_gatt_descriptor_delegate_wrapper.h
@@ -31,16 +31,14 @@
   // BluetoothGattAttributeValueDelegate overrides:
   void GetValue(
       const dbus::ObjectPath& device_path,
-      const device::BluetoothLocalGattService::Delegate::ValueCallback&
-          callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-          error_callback) override;
-  void SetValue(
-      const dbus::ObjectPath& device_path,
-      const std::vector<uint8_t>& value,
-      const base::Closure& callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-          error_callback) override;
+      device::BluetoothLocalGattService::Delegate::ValueCallback callback,
+      device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback)
+      override;
+  void SetValue(const dbus::ObjectPath& device_path,
+                const std::vector<uint8_t>& value,
+                base::OnceClosure callback,
+                device::BluetoothLocalGattService::Delegate::ErrorCallback
+                    error_callback) override;
 
   void StartNotifications(const dbus::ObjectPath& device_path,
                           device::BluetoothGattCharacteristic::NotificationType
diff --git a/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_service_provider.cc b/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_service_provider.cc
index 5f96f55..330f041 100644
--- a/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_service_provider.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_service_provider.cc
@@ -115,9 +115,8 @@
 
 void FakeBluetoothGattCharacteristicServiceProvider::GetValue(
     const dbus::ObjectPath& device_path,
-    const device::BluetoothLocalGattService::Delegate::ValueCallback& callback,
-    const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-        error_callback) {
+    device::BluetoothLocalGattService::Delegate::ValueCallback callback,
+    device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback) {
   VLOG(1) << "GATT characteristic value Get request: " << object_path_.value()
           << " UUID: " << uuid_;
   // Check if this characteristic is registered.
@@ -126,27 +125,27 @@
           bluez::BluezDBusManager::Get()->GetBluetoothGattManagerClient());
   if (!fake_bluetooth_gatt_manager_client->IsServiceRegistered(service_path_)) {
     VLOG(1) << "GATT characteristic not registered.";
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   if (!CanRead(flags_)) {
     VLOG(1) << "GATT characteristic not readable.";
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   // Pass on to the delegate.
   DCHECK(delegate_);
-  delegate_->GetValue(device_path, callback, error_callback);
+  delegate_->GetValue(device_path, std::move(callback),
+                      std::move(error_callback));
 }
 
 void FakeBluetoothGattCharacteristicServiceProvider::SetValue(
     const dbus::ObjectPath& device_path,
     const std::vector<uint8_t>& value,
-    const base::Closure& callback,
-    const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-        error_callback) {
+    base::OnceClosure callback,
+    device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback) {
   VLOG(1) << "GATT characteristic value Set request: " << object_path_.value()
           << " UUID: " << uuid_;
   // Check if this characteristic is registered.
@@ -155,19 +154,20 @@
           bluez::BluezDBusManager::Get()->GetBluetoothGattManagerClient());
   if (!fake_bluetooth_gatt_manager_client->IsServiceRegistered(service_path_)) {
     VLOG(1) << "GATT characteristic not registered.";
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   if (!CanWrite(flags_)) {
     VLOG(1) << "GATT characteristic not writeable.";
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   // Pass on to the delegate.
   DCHECK(delegate_);
-  delegate_->SetValue(device_path, value, callback, error_callback);
+  delegate_->SetValue(device_path, value, std::move(callback),
+                      std::move(error_callback));
 }
 
 void FakeBluetoothGattCharacteristicServiceProvider::PrepareSetValue(
@@ -175,9 +175,8 @@
     const std::vector<uint8_t>& value,
     int offset,
     bool has_subsequent_write,
-    const base::Closure& callback,
-    const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-        error_callback) {
+    base::OnceClosure callback,
+    device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback) {
   VLOG(1) << "GATT characteristic value Prepare Set request: "
           << object_path_.value() << " UUID: " << uuid_;
   // Check if this characteristic is registered.
@@ -186,20 +185,20 @@
           bluez::BluezDBusManager::Get()->GetBluetoothGattManagerClient());
   if (!fake_bluetooth_gatt_manager_client->IsServiceRegistered(service_path_)) {
     VLOG(1) << "GATT characteristic not registered.";
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   if (!CanWrite(flags_)) {
     VLOG(1) << "GATT characteristic not writeable.";
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   // Pass on to the delegate.
   DCHECK(delegate_);
   delegate_->PrepareSetValue(device_path, value, offset, has_subsequent_write,
-                             callback, error_callback);
+                             std::move(callback), std::move(error_callback));
 }
 
 bool FakeBluetoothGattCharacteristicServiceProvider::NotificationsChange(
diff --git a/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_service_provider.h b/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_service_provider.h
index 06fdb3db..a1c3d0e1 100644
--- a/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_service_provider.h
+++ b/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_service_provider.h
@@ -41,23 +41,21 @@
   // GATT manager.
   void GetValue(
       const dbus::ObjectPath& device_path,
-      const device::BluetoothLocalGattService::Delegate::ValueCallback&
-          callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
+      device::BluetoothLocalGattService::Delegate::ValueCallback callback,
+      device::BluetoothLocalGattService::Delegate::ErrorCallback
           error_callback);
-  void SetValue(
-      const dbus::ObjectPath& device_path,
-      const std::vector<uint8_t>& value,
-      const base::Closure& callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-          error_callback);
+  void SetValue(const dbus::ObjectPath& device_path,
+                const std::vector<uint8_t>& value,
+                base::OnceClosure callback,
+                device::BluetoothLocalGattService::Delegate::ErrorCallback
+                    error_callback);
   void PrepareSetValue(
       const dbus::ObjectPath& device_path,
       const std::vector<uint8_t>& value,
       int offset,
       bool has_subsequent_write,
-      const base::Closure& callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
+      base::OnceClosure callback,
+      device::BluetoothLocalGattService::Delegate::ErrorCallback
           error_callback);
 
   // Method to simulate starting and stopping notifications.
diff --git a/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_service_provider.cc b/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_service_provider.cc
index 3c39ab3..3c1a927 100644
--- a/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_service_provider.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_service_provider.cc
@@ -97,9 +97,8 @@
 
 void FakeBluetoothGattDescriptorServiceProvider::GetValue(
     const dbus::ObjectPath& device_path,
-    const device::BluetoothLocalGattService::Delegate::ValueCallback& callback,
-    const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-        error_callback) {
+    device::BluetoothLocalGattService::Delegate::ValueCallback callback,
+    device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback) {
   VLOG(1) << "GATT descriptor value Get request: " << object_path_.value()
           << " UUID: " << uuid_;
   // Check if this descriptor is registered.
@@ -117,27 +116,27 @@
   if (!fake_bluetooth_gatt_manager_client->IsServiceRegistered(
           characteristic->service_path())) {
     VLOG(1) << "GATT descriptor not registered.";
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   if (!CanRead(flags_)) {
     VLOG(1) << "GATT descriptor not readable.";
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   // Pass on to the delegate.
   DCHECK(delegate_);
-  delegate_->GetValue(device_path, callback, error_callback);
+  delegate_->GetValue(device_path, std::move(callback),
+                      std::move(error_callback));
 }
 
 void FakeBluetoothGattDescriptorServiceProvider::SetValue(
     const dbus::ObjectPath& device_path,
     const std::vector<uint8_t>& value,
-    const base::Closure& callback,
-    const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-        error_callback) {
+    base::OnceClosure callback,
+    device::BluetoothLocalGattService::Delegate::ErrorCallback error_callback) {
   VLOG(1) << "GATT descriptor value Set request: " << object_path_.value()
           << " UUID: " << uuid_;
 
@@ -156,19 +155,20 @@
   if (!fake_bluetooth_gatt_manager_client->IsServiceRegistered(
           characteristic->service_path())) {
     VLOG(1) << "GATT descriptor not registered.";
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   if (!CanWrite(flags_)) {
     VLOG(1) << "GATT descriptor not writeable.";
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
 
   // Pass on to the delegate.
   DCHECK(delegate_);
-  delegate_->SetValue(device_path, value, callback, error_callback);
+  delegate_->SetValue(device_path, value, std::move(callback),
+                      std::move(error_callback));
 }
 
 const dbus::ObjectPath&
diff --git a/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_service_provider.h b/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_service_provider.h
index 981f7a6..785a999 100644
--- a/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_service_provider.h
+++ b/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_service_provider.h
@@ -41,16 +41,14 @@
   // GATT manager.
   void GetValue(
       const dbus::ObjectPath& device_path,
-      const device::BluetoothLocalGattService::Delegate::ValueCallback&
-          callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
+      device::BluetoothLocalGattService::Delegate::ValueCallback callback,
+      device::BluetoothLocalGattService::Delegate::ErrorCallback
           error_callback);
-  void SetValue(
-      const dbus::ObjectPath& device_path,
-      const std::vector<uint8_t>& value,
-      const base::Closure& callback,
-      const device::BluetoothLocalGattService::Delegate::ErrorCallback&
-          error_callback);
+  void SetValue(const dbus::ObjectPath& device_path,
+                const std::vector<uint8_t>& value,
+                base::OnceClosure callback,
+                device::BluetoothLocalGattService::Delegate::ErrorCallback
+                    error_callback);
 
   const dbus::ObjectPath& object_path() const override;
   const std::string& uuid() const { return uuid_; }
diff --git a/device/bluetooth/test/bluetooth_test.h b/device/bluetooth/test/bluetooth_test.h
index d9ad3e2..9d342dd 100644
--- a/device/bluetooth/test/bluetooth_test.h
+++ b/device/bluetooth/test/bluetooth_test.h
@@ -459,8 +459,8 @@
   virtual void SimulateLocalGattCharacteristicValueReadRequest(
       BluetoothDevice* from_device,
       BluetoothLocalGattCharacteristic* characteristic,
-      const BluetoothLocalGattService::Delegate::ValueCallback& value_callback,
-      const base::Closure& error_callback) {}
+      BluetoothLocalGattService::Delegate::ValueCallback value_callback,
+      base::OnceClosure error_callback) {}
 
   // Simulates write a value to a locally hosted GATT characteristic by a
   // remote central device.
@@ -468,8 +468,8 @@
       BluetoothDevice* from_device,
       BluetoothLocalGattCharacteristic* characteristic,
       const std::vector<uint8_t>& value_to_write,
-      const base::Closure& success_callback,
-      const base::Closure& error_callback) {}
+      base::OnceClosure success_callback,
+      base::OnceClosure error_callback) {}
 
   // Simulates prepare write a value to a locally hosted GATT characteristic by
   // a remote central device.
@@ -479,8 +479,8 @@
       const std::vector<uint8_t>& value_to_write,
       int offset,
       bool has_subsequent_write,
-      const base::Closure& success_callback,
-      const base::Closure& error_callback) {}
+      base::OnceClosure success_callback,
+      base::OnceClosure error_callback) {}
 
   // Simulates reading a value from a locally hosted GATT descriptor by a
   // remote central device. Returns the value that was read from the local
@@ -488,8 +488,8 @@
   virtual void SimulateLocalGattDescriptorValueReadRequest(
       BluetoothDevice* from_device,
       BluetoothLocalGattDescriptor* descriptor,
-      const BluetoothLocalGattService::Delegate::ValueCallback& value_callback,
-      const base::Closure& error_callback) {}
+      BluetoothLocalGattService::Delegate::ValueCallback value_callback,
+      base::OnceClosure error_callback) {}
 
   // Simulates write a value to a locally hosted GATT descriptor by a
   // remote central device.
@@ -497,8 +497,8 @@
       BluetoothDevice* from_device,
       BluetoothLocalGattDescriptor* descriptor,
       const std::vector<uint8_t>& value_to_write,
-      const base::Closure& success_callback,
-      const base::Closure& error_callback) {}
+      base::OnceClosure success_callback,
+      base::OnceClosure error_callback) {}
 
   // Simulates starting or stopping a notification session for a locally
   // hosted GATT characteristic by a remote device. Returns false if we were
diff --git a/device/bluetooth/test/bluetooth_test_bluez.cc b/device/bluetooth/test/bluetooth_test_bluez.cc
index 5cb7074..484ee1a6 100644
--- a/device/bluetooth/test/bluetooth_test_bluez.cc
+++ b/device/bluetooth/test/bluetooth_test_bluez.cc
@@ -37,17 +37,17 @@
 }
 
 void GetValueCallback(
-    const base::Closure& quit_closure,
-    const BluetoothLocalGattService::Delegate::ValueCallback& value_callback,
+    base::OnceClosure quit_closure,
+    BluetoothLocalGattService::Delegate::ValueCallback value_callback,
     const std::vector<uint8_t>& value) {
-  value_callback.Run(value);
-  quit_closure.Run();
+  std::move(value_callback).Run(value);
+  std::move(quit_closure).Run();
 }
 
-void ClosureCallback(const base::Closure& quit_closure,
-                     const base::Closure& callback) {
-  callback.Run();
-  quit_closure.Run();
+void ClosureCallback(base::OnceClosure quit_closure,
+                     base::OnceClosure callback) {
+  std::move(callback).Run();
+  std::move(quit_closure).Run();
 }
 
 dbus::ObjectPath GetDevicePath(BluetoothDevice* device) {
@@ -164,8 +164,8 @@
 void BluetoothTestBlueZ::SimulateLocalGattCharacteristicValueReadRequest(
     BluetoothDevice* from_device,
     BluetoothLocalGattCharacteristic* characteristic,
-    const BluetoothLocalGattService::Delegate::ValueCallback& value_callback,
-    const base::Closure& error_callback) {
+    BluetoothLocalGattService::Delegate::ValueCallback value_callback,
+    base::OnceClosure error_callback) {
   bluez::BluetoothLocalGattCharacteristicBlueZ* characteristic_bluez =
       static_cast<bluez::BluetoothLocalGattCharacteristicBlueZ*>(
           characteristic);
@@ -187,8 +187,10 @@
   base::RunLoop run_loop;
   characteristic_provider->GetValue(
       GetDevicePath(from_device),
-      base::Bind(&GetValueCallback, run_loop.QuitClosure(), value_callback),
-      base::Bind(&ClosureCallback, run_loop.QuitClosure(), error_callback));
+      base::BindOnce(&GetValueCallback, run_loop.QuitClosure(),
+                     std::move(value_callback)),
+      base::BindOnce(&ClosureCallback, run_loop.QuitClosure(),
+                     std::move(error_callback)));
   run_loop.Run();
 }
 
@@ -196,8 +198,8 @@
     BluetoothDevice* from_device,
     BluetoothLocalGattCharacteristic* characteristic,
     const std::vector<uint8_t>& value_to_write,
-    const base::Closure& success_callback,
-    const base::Closure& error_callback) {
+    base::OnceClosure success_callback,
+    base::OnceClosure error_callback) {
   bluez::BluetoothLocalGattCharacteristicBlueZ* characteristic_bluez =
       static_cast<bluez::BluetoothLocalGattCharacteristicBlueZ*>(
           characteristic);
@@ -219,8 +221,10 @@
   base::RunLoop run_loop;
   characteristic_provider->SetValue(
       GetDevicePath(from_device), value_to_write,
-      base::Bind(&ClosureCallback, run_loop.QuitClosure(), success_callback),
-      base::Bind(&ClosureCallback, run_loop.QuitClosure(), error_callback));
+      base::BindOnce(&ClosureCallback, run_loop.QuitClosure(),
+                     std::move(success_callback)),
+      base::BindOnce(&ClosureCallback, run_loop.QuitClosure(),
+                     std::move(error_callback)));
   run_loop.Run();
 }
 
@@ -231,8 +235,8 @@
         const std::vector<uint8_t>& value_to_write,
         int offset,
         bool has_subsequent_write,
-        const base::Closure& success_callback,
-        const base::Closure& error_callback) {
+        base::OnceClosure success_callback,
+        base::OnceClosure error_callback) {
   bluez::BluetoothLocalGattCharacteristicBlueZ* characteristic_bluez =
       static_cast<bluez::BluetoothLocalGattCharacteristicBlueZ*>(
           characteristic);
@@ -254,16 +258,18 @@
   base::RunLoop run_loop;
   characteristic_provider->PrepareSetValue(
       GetDevicePath(from_device), value_to_write, offset, has_subsequent_write,
-      base::Bind(&ClosureCallback, run_loop.QuitClosure(), success_callback),
-      base::Bind(&ClosureCallback, run_loop.QuitClosure(), error_callback));
+      base::BindOnce(&ClosureCallback, run_loop.QuitClosure(),
+                     std::move(success_callback)),
+      base::BindOnce(&ClosureCallback, run_loop.QuitClosure(),
+                     std::move(error_callback)));
   run_loop.Run();
 }
 
 void BluetoothTestBlueZ::SimulateLocalGattDescriptorValueReadRequest(
     BluetoothDevice* from_device,
     BluetoothLocalGattDescriptor* descriptor,
-    const BluetoothLocalGattService::Delegate::ValueCallback& value_callback,
-    const base::Closure& error_callback) {
+    BluetoothLocalGattService::Delegate::ValueCallback value_callback,
+    base::OnceClosure error_callback) {
   bluez::BluetoothLocalGattDescriptorBlueZ* descriptor_bluez =
       static_cast<bluez::BluetoothLocalGattDescriptorBlueZ*>(descriptor);
   bluez::FakeBluetoothGattManagerClient* fake_bluetooth_gatt_manager_client =
@@ -283,8 +289,10 @@
   base::RunLoop run_loop;
   descriptor_provider->GetValue(
       GetDevicePath(from_device),
-      base::Bind(&GetValueCallback, run_loop.QuitClosure(), value_callback),
-      base::Bind(&ClosureCallback, run_loop.QuitClosure(), error_callback));
+      base::BindOnce(&GetValueCallback, run_loop.QuitClosure(),
+                     std::move(value_callback)),
+      base::BindOnce(&ClosureCallback, run_loop.QuitClosure(),
+                     std::move(error_callback)));
   run_loop.Run();
 }
 
@@ -292,8 +300,8 @@
     BluetoothDevice* from_device,
     BluetoothLocalGattDescriptor* descriptor,
     const std::vector<uint8_t>& value_to_write,
-    const base::Closure& success_callback,
-    const base::Closure& error_callback) {
+    base::OnceClosure success_callback,
+    base::OnceClosure error_callback) {
   bluez::BluetoothLocalGattDescriptorBlueZ* descriptor_bluez =
       static_cast<bluez::BluetoothLocalGattDescriptorBlueZ*>(descriptor);
   bluez::FakeBluetoothGattManagerClient* fake_bluetooth_gatt_manager_client =
@@ -313,8 +321,10 @@
   base::RunLoop run_loop;
   descriptor_provider->SetValue(
       GetDevicePath(from_device), value_to_write,
-      base::Bind(&ClosureCallback, run_loop.QuitClosure(), success_callback),
-      base::Bind(&ClosureCallback, run_loop.QuitClosure(), error_callback));
+      base::BindOnce(&ClosureCallback, run_loop.QuitClosure(),
+                     std::move(success_callback)),
+      base::BindOnce(&ClosureCallback, run_loop.QuitClosure(),
+                     std::move(error_callback)));
   run_loop.Run();
 }
 
diff --git a/device/bluetooth/test/bluetooth_test_bluez.h b/device/bluetooth/test/bluetooth_test_bluez.h
index 1871b75..e2dfbaa 100644
--- a/device/bluetooth/test/bluetooth_test_bluez.h
+++ b/device/bluetooth/test/bluetooth_test_bluez.h
@@ -39,33 +39,33 @@
   void SimulateLocalGattCharacteristicValueReadRequest(
       BluetoothDevice* from_device,
       BluetoothLocalGattCharacteristic* characteristic,
-      const BluetoothLocalGattService::Delegate::ValueCallback& value_callback,
-      const base::Closure& error_callback) override;
+      BluetoothLocalGattService::Delegate::ValueCallback value_callback,
+      base::OnceClosure error_callback) override;
   void SimulateLocalGattCharacteristicValueWriteRequest(
       BluetoothDevice* from_device,
       BluetoothLocalGattCharacteristic* characteristic,
       const std::vector<uint8_t>& value_to_write,
-      const base::Closure& success_callback,
-      const base::Closure& error_callback) override;
+      base::OnceClosure success_callback,
+      base::OnceClosure error_callback) override;
   void SimulateLocalGattCharacteristicValuePrepareWriteRequest(
       BluetoothDevice* from_device,
       BluetoothLocalGattCharacteristic* characteristic,
       const std::vector<uint8_t>& value_to_write,
       int offset,
       bool has_subsequent_write,
-      const base::Closure& success_callback,
-      const base::Closure& error_callback) override;
+      base::OnceClosure success_callback,
+      base::OnceClosure error_callback) override;
   void SimulateLocalGattDescriptorValueReadRequest(
       BluetoothDevice* from_device,
       BluetoothLocalGattDescriptor* descriptor,
-      const BluetoothLocalGattService::Delegate::ValueCallback& value_callback,
-      const base::Closure& error_callback) override;
+      BluetoothLocalGattService::Delegate::ValueCallback value_callback,
+      base::OnceClosure error_callback) override;
   void SimulateLocalGattDescriptorValueWriteRequest(
       BluetoothDevice* from_device,
       BluetoothLocalGattDescriptor* descriptor,
       const std::vector<uint8_t>& value_to_write,
-      const base::Closure& success_callback,
-      const base::Closure& error_callback) override;
+      base::OnceClosure success_callback,
+      base::OnceClosure error_callback) override;
   bool SimulateLocalGattCharacteristicNotificationsRequest(
       BluetoothLocalGattCharacteristic* characteristic,
       bool start) override;
diff --git a/device/bluetooth/test/test_bluetooth_local_gatt_service_delegate.cc b/device/bluetooth/test/test_bluetooth_local_gatt_service_delegate.cc
index eac618dba..8cad873d 100644
--- a/device/bluetooth/test/test_bluetooth_local_gatt_service_delegate.cc
+++ b/device/bluetooth/test/test_bluetooth_local_gatt_service_delegate.cc
@@ -23,16 +23,16 @@
     const BluetoothDevice* device,
     const BluetoothLocalGattCharacteristic* characteristic,
     int offset,
-    const ValueCallback& callback,
-    const ErrorCallback& error_callback) {
+    ValueCallback callback,
+    ErrorCallback error_callback) {
   EXPECT_EQ(expected_characteristic_->GetIdentifier(),
             characteristic->GetIdentifier());
   if (should_fail_) {
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
   last_seen_device_ = device->GetIdentifier();
-  callback.Run(BluetoothGattServerTest::GetValue(value_to_write_));
+  std::move(callback).Run(BluetoothGattServerTest::GetValue(value_to_write_));
 }
 
 void TestBluetoothLocalGattServiceDelegate::OnCharacteristicWriteRequest(
@@ -40,17 +40,17 @@
     const BluetoothLocalGattCharacteristic* characteristic,
     const std::vector<uint8_t>& value,
     int offset,
-    const base::Closure& callback,
-    const ErrorCallback& error_callback) {
+    base::OnceClosure callback,
+    ErrorCallback error_callback) {
   EXPECT_EQ(expected_characteristic_->GetIdentifier(),
             characteristic->GetIdentifier());
   if (should_fail_) {
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
   last_seen_device_ = device->GetIdentifier();
   last_written_value_ = BluetoothGattServerTest::GetInteger(value);
-  callback.Run();
+  std::move(callback).Run();
 }
 
 void TestBluetoothLocalGattServiceDelegate::OnCharacteristicPrepareWriteRequest(
@@ -59,12 +59,12 @@
     const std::vector<uint8_t>& value,
     int offset,
     bool has_subsequent_request,
-    const base::Closure& callback,
-    const ErrorCallback& error_callback) {
+    base::OnceClosure callback,
+    ErrorCallback error_callback) {
   EXPECT_EQ(expected_characteristic_->GetIdentifier(),
             characteristic->GetIdentifier());
   if (should_fail_) {
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
   // For testing purpose, we don't maintain a queue for all the pending prepare
@@ -73,22 +73,22 @@
   if (!has_subsequent_request)
     last_written_value_ = BluetoothGattServerTest::GetInteger(value);
   last_seen_device_ = device->GetIdentifier();
-  callback.Run();
+  std::move(callback).Run();
 }
 
 void TestBluetoothLocalGattServiceDelegate::OnDescriptorReadRequest(
     const BluetoothDevice* device,
     const BluetoothLocalGattDescriptor* descriptor,
     int offset,
-    const ValueCallback& callback,
-    const ErrorCallback& error_callback) {
+    ValueCallback callback,
+    ErrorCallback error_callback) {
   EXPECT_EQ(expected_descriptor_->GetIdentifier(), descriptor->GetIdentifier());
   if (should_fail_) {
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
   last_seen_device_ = device->GetIdentifier();
-  callback.Run(BluetoothGattServerTest::GetValue(value_to_write_));
+  std::move(callback).Run(BluetoothGattServerTest::GetValue(value_to_write_));
 }
 
 void TestBluetoothLocalGattServiceDelegate::OnDescriptorWriteRequest(
@@ -96,16 +96,16 @@
     const BluetoothLocalGattDescriptor* descriptor,
     const std::vector<uint8_t>& value,
     int offset,
-    const base::Closure& callback,
-    const ErrorCallback& error_callback) {
+    base::OnceClosure callback,
+    ErrorCallback error_callback) {
   EXPECT_EQ(expected_descriptor_->GetIdentifier(), descriptor->GetIdentifier());
   if (should_fail_) {
-    error_callback.Run();
+    std::move(error_callback).Run();
     return;
   }
   last_seen_device_ = device->GetIdentifier();
   last_written_value_ = BluetoothGattServerTest::GetInteger(value);
-  callback.Run();
+  std::move(callback).Run();
 }
 
 void TestBluetoothLocalGattServiceDelegate::OnNotificationsStart(
diff --git a/device/bluetooth/test/test_bluetooth_local_gatt_service_delegate.h b/device/bluetooth/test/test_bluetooth_local_gatt_service_delegate.h
index 7c638563..3a0189cf 100644
--- a/device/bluetooth/test/test_bluetooth_local_gatt_service_delegate.h
+++ b/device/bluetooth/test/test_bluetooth_local_gatt_service_delegate.h
@@ -27,35 +27,35 @@
       const BluetoothDevice* device,
       const BluetoothLocalGattCharacteristic* characteristic,
       int offset,
-      const ValueCallback& callback,
-      const ErrorCallback& error_callback) override;
+      ValueCallback callback,
+      ErrorCallback error_callback) override;
   void OnCharacteristicWriteRequest(
       const BluetoothDevice* device,
       const BluetoothLocalGattCharacteristic* characteristic,
       const std::vector<uint8_t>& value,
       int offset,
-      const base::Closure& callback,
-      const ErrorCallback& error_callback) override;
+      base::OnceClosure callback,
+      ErrorCallback error_callback) override;
   void OnCharacteristicPrepareWriteRequest(
       const BluetoothDevice* device,
       const BluetoothLocalGattCharacteristic* characteristic,
       const std::vector<uint8_t>& value,
       int offset,
       bool has_subsequent_request,
-      const base::Closure& callback,
-      const ErrorCallback& error_callback) override;
+      base::OnceClosure callback,
+      ErrorCallback error_callback) override;
   void OnDescriptorReadRequest(const BluetoothDevice* device,
                                const BluetoothLocalGattDescriptor* descriptor,
                                int offset,
-                               const ValueCallback& callback,
-                               const ErrorCallback& error_callback) override;
+                               ValueCallback callback,
+                               ErrorCallback error_callback) override;
 
   void OnDescriptorWriteRequest(const BluetoothDevice* device,
                                 const BluetoothLocalGattDescriptor* descriptor,
                                 const std::vector<uint8_t>& value,
                                 int offset,
-                                const base::Closure& callback,
-                                const ErrorCallback& error_callback) override;
+                                base::OnceClosure callback,
+                                ErrorCallback error_callback) override;
   void OnNotificationsStart(
       const BluetoothDevice* device,
       device::BluetoothGattCharacteristic::NotificationType notification_type,
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn
index 69c41d0..d1aecfc5 100644
--- a/device/fido/BUILD.gn
+++ b/device/fido/BUILD.gn
@@ -52,6 +52,7 @@
     "cable/fido_cable_discovery.h",
     "cable/fido_cable_handshake_handler.cc",
     "cable/fido_cable_handshake_handler.h",
+    "credential_management.h",
     "ctap2_device_operation.h",
     "ctap_empty_authenticator_request.cc",
     "ctap_empty_authenticator_request.h",
diff --git a/device/fido/authenticator_data.cc b/device/fido/authenticator_data.cc
index 104967a4..b6681e69 100644
--- a/device/fido/authenticator_data.cc
+++ b/device/fido/authenticator_data.cc
@@ -6,8 +6,11 @@
 
 #include <utility>
 
+#include "base/strings/string_number_conversions.h"
+#include "components/cbor/diagnostic_writer.h"
 #include "components/cbor/reader.h"
 #include "components/cbor/writer.h"
+#include "components/device_event_log/device_event_log.h"
 #include "device/fido/attested_credential_data.h"
 #include "device/fido/fido_parsing_utils.h"
 
@@ -43,8 +46,19 @@
 
   base::Optional<cbor::Value> extensions;
   if (flag_byte & static_cast<uint8_t>(Flag::kExtensionDataIncluded)) {
-    extensions = cbor::Reader::Read(auth_data);
-    if (!extensions || !extensions->is_map()) {
+    cbor::Reader::DecoderError error;
+    extensions = cbor::Reader::Read(auth_data, &error);
+    if (!extensions) {
+      FIDO_LOG(ERROR)
+          << "CBOR decoding of authenticator data extensions failed ("
+          << cbor::Reader::ErrorCodeToString(error) << ") from "
+          << base::HexEncode(auth_data.data(), auth_data.size());
+      return base::nullopt;
+    }
+    if (!extensions->is_map()) {
+      FIDO_LOG(ERROR)
+          << "Incorrect CBOR structure of authenticator data extensions: "
+          << cbor::DiagnosticWriter::Write(*extensions);
       return base::nullopt;
     }
   } else if (!auth_data.empty()) {
diff --git a/device/fido/authenticator_supported_options.cc b/device/fido/authenticator_supported_options.cc
index bf98a6b9..12253ed4 100644
--- a/device/fido/authenticator_supported_options.cc
+++ b/device/fido/authenticator_supported_options.cc
@@ -51,6 +51,13 @@
       break;
   }
 
+  if (options.supports_credential_management) {
+    option_map.emplace(kCredentialManagementMapKey, true);
+  }
+  if (options.supports_credential_management_preview) {
+    option_map.emplace(kCredentialManagementPreviewMapKey, true);
+  }
+
   return cbor::Value(std::move(option_map));
 }
 
diff --git a/device/fido/authenticator_supported_options.h b/device/fido/authenticator_supported_options.h
index eb4e08c30..65e6fea 100644
--- a/device/fido/authenticator_supported_options.h
+++ b/device/fido/authenticator_supported_options.h
@@ -38,22 +38,31 @@
       const AuthenticatorSupportedOptions& other);
   ~AuthenticatorSupportedOptions();
 
-  // Indicates that the device is attached to the client and therefore can't be
-  // removed and used on another client.
+  // Indicates that the authenticator is attached to the client and therefore
+  // can't be removed and used on another client.
   bool is_platform_device = false;
-  // Indicates that the device is capable of storing keys on the device itself
+  // Indicates that the authenticator is capable of storing keys on the
+  // authenticator itself
   // and therefore can satisfy the authenticatorGetAssertion request with
   // allowList parameter not specified or empty.
   bool supports_resident_key = false;
-  // Indicates whether the device is capable of verifying the user on its own.
+  // Indicates whether the authenticator is capable of verifying the user on its
+  // own.
   UserVerificationAvailability user_verification_availability =
       UserVerificationAvailability::kNotSupported;
-  // supports_user_presence indicates whether the device can assert user
+  // supports_user_presence indicates whether the authenticator can assert user
   // presence. E.g. a touch for a USB device, or being placed in the reader
   // field for an NFC device.
   bool supports_user_presence = true;
-  // Represents whether client pin in set and stored in device. Set as null
-  // optional if client pin capability is not supported by the authenticator.
+  // Indicates whether the authenticator supports the CTAP2
+  // authenticatorCredentialManagement command.
+  bool supports_credential_management = false;
+  // Indicates whether the authenticator supports the vendor-specific preview of
+  // the CTAP2 authenticatorCredentialManagement command.
+  bool supports_credential_management_preview = false;
+  // Represents whether client pin is set and stored in authenticator. Set as
+  // null optional if client pin capability is not supported by the
+  // authenticator.
   ClientPinAvailability client_pin_availability =
       ClientPinAvailability::kNotSupported;
 };
diff --git a/device/fido/credential_management.h b/device/fido/credential_management.h
new file mode 100644
index 0000000..0f80bfc
--- /dev/null
+++ b/device/fido/credential_management.h
@@ -0,0 +1,50 @@
+// 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 DEVICE_FIDO_CREDENTIAL_MANAGEMENT_H_
+#define DEVICE_FIDO_CREDENTIAL_MANAGEMENT_H_
+
+#include "base/component_export.h"
+
+namespace device {
+
+// https://drafts.fidoalliance.org/fido-2/latest/fido-client-to-authenticator-protocol-v2.0-wd-20190409.html#authenticatorCredentialManagement
+
+enum class CredentialManagementRequestKey : uint8_t {
+  kSubCommand = 0x01,
+  kSubCommandParams = 0x02,
+  kPinProtocol = 0x03,
+  kPinAuth = 0x04,
+};
+
+enum class CredentialManagementRequestParamKey : uint8_t {
+  kRPIDHash = 0x01,
+  kCredentialID = 0x02,
+};
+
+enum class CredentialManagementResponseKey : uint8_t {
+  kExistingResidentCredentialsCount = 0x01,
+  kMaxPossibleRemainingResidentCredentialsCount = 0x02,
+  kRP = 0x03,
+  kRPIDHash = 0x04,
+  kTotalRPs = 0x05,
+  kUser = 0x06,
+  kCredentialID = 0x07,
+  kPublicKey = 0x08,
+  kTotalCredentials = 0x09,
+  kCredProtect = 0x0a,
+};
+
+enum class CredentialManagementSubCommand : uint8_t {
+  kGetCredsMetadata = 0x01,
+  kEnumerateRPsBegin = 0x02,
+  kEnumerateRPsGetNextRP = 0x03,
+  kEnumerateCredentialsBegin = 0x04,
+  kEnumerateCredentialsGetNextCredential = 0x05,
+  kDeleteCredential = 0x06,
+};
+
+}  // namespace device
+
+#endif  // DEVICE_FIDO_CREDENTIAL_MANAGEMENT_H_
diff --git a/device/fido/device_response_converter.cc b/device/fido/device_response_converter.cc
index e92f63c..771a62a 100644
--- a/device/fido/device_response_converter.cc
+++ b/device/fido/device_response_converter.cc
@@ -279,6 +279,24 @@
             ClientPinAvailability::kSupportedButPinNotSet;
       }
     }
+
+    option_map_it = option_map.find(CBOR(kCredentialManagementMapKey));
+    if (option_map_it != option_map.end()) {
+      if (!option_map_it->second.is_bool()) {
+        return base::nullopt;
+      }
+      options.supports_credential_management = option_map_it->second.GetBool();
+    }
+
+    option_map_it = option_map.find(CBOR(kCredentialManagementPreviewMapKey));
+    if (option_map_it != option_map.end()) {
+      if (!option_map_it->second.is_bool()) {
+        return base::nullopt;
+      }
+      options.supports_credential_management_preview =
+          option_map_it->second.GetBool();
+    }
+
     response.options = std::move(options);
   }
 
diff --git a/device/fido/fido_constants.cc b/device/fido/fido_constants.cc
index 360622c..fa78ae3 100644
--- a/device/fido/fido_constants.cc
+++ b/device/fido/fido_constants.cc
@@ -27,6 +27,8 @@
 const char kIconUrlMapKey[] = "icon";
 const char kCredentialTypeMapKey[] = "type";
 const char kCredentialAlgorithmMapKey[] = "alg";
+const char kCredentialManagementMapKey[] = "credMgmt";
+const char kCredentialManagementPreviewMapKey[] = "credentialMgmtPreview";
 
 const base::TimeDelta kDeviceTimeout = base::TimeDelta::FromSeconds(3);
 const base::TimeDelta kU2fRetryDelay = base::TimeDelta::FromMilliseconds(200);
diff --git a/device/fido/fido_constants.h b/device/fido/fido_constants.h
index 868ca59..ee442e7 100644
--- a/device/fido/fido_constants.h
+++ b/device/fido/fido_constants.h
@@ -247,6 +247,7 @@
   kAuthenticatorGetInfo = 0x04,
   kAuthenticatorClientPin = 0x06,
   kAuthenticatorReset = 0x07,
+  kAuthenticatorCredentialManagement = 0x0a,
 };
 
 enum class CoseAlgorithmIdentifier : int { kCoseEs256 = -7 };
@@ -314,6 +315,9 @@
 COMPONENT_EXPORT(DEVICE_FIDO) extern const char kIconUrlMapKey[];
 COMPONENT_EXPORT(DEVICE_FIDO) extern const char kCredentialTypeMapKey[];
 COMPONENT_EXPORT(DEVICE_FIDO) extern const char kCredentialAlgorithmMapKey[];
+COMPONENT_EXPORT(DEVICE_FIDO) extern const char kCredentialManagementMapKey[];
+COMPONENT_EXPORT(DEVICE_FIDO)
+extern const char kCredentialManagementPreviewMapKey[];
 
 // HID transport specific constants.
 constexpr uint32_t kHidBroadcastChannel = 0xffffffff;
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc
index 9797562d..a7dd629 100644
--- a/device/fido/virtual_ctap2_device.cc
+++ b/device/fido/virtual_ctap2_device.cc
@@ -4,11 +4,13 @@
 
 #include "device/fido/virtual_ctap2_device.h"
 
+#include <algorithm>
 #include <array>
 #include <string>
 #include <utility>
 
 #include "base/bind.h"
+#include "base/containers/span.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -17,6 +19,7 @@
 #include "crypto/ec_private_key.h"
 #include "device/fido/authenticator_get_assertion_response.h"
 #include "device/fido/authenticator_make_credential_response.h"
+#include "device/fido/credential_management.h"
 #include "device/fido/ctap_get_assertion_request.h"
 #include "device/fido/ctap_make_credential_request.h"
 #include "device/fido/ec_public_key.h"
@@ -404,9 +407,37 @@
   return CtapDeviceResponseCode::kSuccess;
 }
 
+CtapDeviceResponseCode CheckCredentialManagementPINAuth(
+    const cbor::Value::MapValue& request_map,
+    base::span<const uint8_t> pin_token,
+    base::span<const uint8_t> pinauth_bytes) {
+  const auto pin_protocol_it = request_map.find(cbor::Value(
+      static_cast<int>(CredentialManagementRequestKey::kPinProtocol)));
+  if (pin_protocol_it == request_map.end() ||
+      !pin_protocol_it->second.is_unsigned()) {
+    return CtapDeviceResponseCode::kCtap2ErrCBORUnexpectedType;
+  }
+  if (pin_protocol_it->second.GetUnsigned() != pin::kProtocolVersion) {
+    return CtapDeviceResponseCode::kCtap2ErrInvalidOption;
+  }
+  const auto pinauth_it = request_map.find(
+      cbor::Value(static_cast<int>(CredentialManagementRequestKey::kPinAuth)));
+  if (pinauth_it == request_map.end() || !pinauth_it->second.is_bytestring()) {
+    return CtapDeviceResponseCode::kCtap2ErrCBORUnexpectedType;
+  }
+  if (!CheckPINToken(pin_token, pinauth_it->second.GetBytestring(),
+                     pinauth_bytes)) {
+    return CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid;
+  }
+  return CtapDeviceResponseCode::kSuccess;
+}
 }  // namespace
 
 VirtualCtap2Device::Config::Config() = default;
+VirtualCtap2Device::Config::Config(const Config&) = default;
+VirtualCtap2Device::Config& VirtualCtap2Device::Config::operator=(
+    const Config&) = default;
+VirtualCtap2Device::Config::~Config() = default;
 
 VirtualCtap2Device::VirtualCtap2Device()
     : VirtualFidoDevice(), weak_factory_(this) {
@@ -457,6 +488,11 @@
     options.supports_resident_key = true;
   }
 
+  if (config.credential_management_support) {
+    options_updated = true;
+    options.supports_credential_management = true;
+  }
+
   if (options_updated) {
     device_info_->options = std::move(options);
   }
@@ -510,6 +546,9 @@
     case CtapRequestCommand::kAuthenticatorClientPin:
       response_code = OnPINCommand(request_bytes, &response_data);
       break;
+    case CtapRequestCommand::kAuthenticatorCredentialManagement:
+      response_code = OnCredentialManagement(request_bytes, &response_data);
+      break;
     default:
       break;
   }
@@ -1010,6 +1049,247 @@
   return CtapDeviceResponseCode::kSuccess;
 }
 
+CtapDeviceResponseCode VirtualCtap2Device::OnCredentialManagement(
+    base::span<const uint8_t> request_bytes,
+    std::vector<uint8_t>* response) {
+  if (!device_info_->options.supports_credential_management) {
+    return CtapDeviceResponseCode::kCtap2ErrUnsupportedOption;
+  }
+
+  const auto& cbor_request = cbor::Reader::Read(request_bytes);
+  if (!cbor_request || !cbor_request->is_map()) {
+    return CtapDeviceResponseCode::kCtap2ErrCBORUnexpectedType;
+  }
+  const auto& request_map = cbor_request->GetMap();
+  const auto subcommand_it = request_map.find(cbor::Value(
+      static_cast<int>(CredentialManagementRequestKey::kSubCommand)));
+  if (subcommand_it == request_map.end() ||
+      !subcommand_it->second.is_unsigned()) {
+    return CtapDeviceResponseCode::kCtap2ErrCBORUnexpectedType;
+  }
+  const int64_t subcommand = subcommand_it->second.GetUnsigned();
+
+  cbor::Value::MapValue response_map;
+  switch (static_cast<CredentialManagementSubCommand>(subcommand)) {
+    case CredentialManagementSubCommand::kGetCredsMetadata: {
+      CtapDeviceResponseCode pin_status = CheckCredentialManagementPINAuth(
+          request_map, mutable_state()->pin_token,
+          {{static_cast<uint8_t>(subcommand)}});
+      if (pin_status != CtapDeviceResponseCode::kSuccess) {
+        return pin_status;
+      }
+
+      const size_t num_resident =
+          std::count_if(mutable_state()->registrations.begin(),
+                        mutable_state()->registrations.end(),
+                        [](const auto& it) { return it.second.is_resident; });
+      response_map.emplace(
+          static_cast<int>(CredentialManagementResponseKey::
+                               kExistingResidentCredentialsCount),
+          static_cast<int64_t>(num_resident));
+
+      const size_t num_remaining =
+          config_.resident_credential_storage - num_resident;
+      DCHECK(0 <= num_remaining);
+      response_map.emplace(
+          static_cast<int>(CredentialManagementResponseKey::
+                               kMaxPossibleRemainingResidentCredentialsCount),
+          static_cast<int64_t>(num_remaining));
+
+      *response =
+          cbor::Writer::Write(cbor::Value(std::move(response_map))).value();
+      return CtapDeviceResponseCode::kSuccess;
+    }
+
+    case CredentialManagementSubCommand::kEnumerateRPsBegin: {
+      CtapDeviceResponseCode pin_status = CheckCredentialManagementPINAuth(
+          request_map, mutable_state()->pin_token,
+          {{static_cast<uint8_t>(subcommand)}});
+      if (pin_status != CtapDeviceResponseCode::kSuccess) {
+        return pin_status;
+      }
+
+      InitPendingRPs();
+      response_map.emplace(
+          static_cast<int>(CredentialManagementResponseKey::kTotalRPs),
+          static_cast<int>(mutable_state()->pending_rps.size()));
+      if (!mutable_state()->pending_rps.empty()) {
+        GetNextRP(&response_map);
+      }
+
+      *response =
+          cbor::Writer::Write(cbor::Value(std::move(response_map))).value();
+      return CtapDeviceResponseCode::kSuccess;
+    }
+
+    case CredentialManagementSubCommand::kEnumerateRPsGetNextRP: {
+      if (mutable_state()->pending_rps.empty()) {
+        return CtapDeviceResponseCode::kCtap2ErrNotAllowed;
+      }
+      GetNextRP(&response_map);
+
+      *response =
+          cbor::Writer::Write(cbor::Value(std::move(response_map))).value();
+      return CtapDeviceResponseCode::kSuccess;
+    }
+
+    case CredentialManagementSubCommand::kEnumerateCredentialsBegin: {
+      const auto params_it = request_map.find(cbor::Value(
+          static_cast<int>(CredentialManagementRequestKey::kSubCommandParams)));
+      if (params_it == request_map.end() && !params_it->second.is_map()) {
+        return CtapDeviceResponseCode::kCtap2ErrCBORUnexpectedType;
+      }
+      const cbor::Value::MapValue& params = params_it->second.GetMap();
+
+      // pinAuth = LEFT(HMAC-SHA-256(pinToken, enumerateCredentialsBegin (0x04)
+      //                                       || subCommandParams), 16)
+      std::vector<uint8_t> pinauth_bytes =
+          cbor::Writer::Write(cbor::Value(params)).value();
+      pinauth_bytes.insert(pinauth_bytes.begin(),
+                           static_cast<uint8_t>(subcommand));
+      CtapDeviceResponseCode pin_status = CheckCredentialManagementPINAuth(
+          request_map, mutable_state()->pin_token, pinauth_bytes);
+      if (pin_status != CtapDeviceResponseCode::kSuccess) {
+        return pin_status;
+      }
+
+      const auto rp_id_hash_it = params.find(cbor::Value(
+          static_cast<int>(CredentialManagementRequestParamKey::kRPIDHash)));
+      if (rp_id_hash_it == params.end() ||
+          !rp_id_hash_it->second.is_bytestring() ||
+          rp_id_hash_it->second.GetBytestring().size() != kRpIdHashLength) {
+        return CtapDeviceResponseCode::kCtap2ErrCBORUnexpectedType;
+      }
+
+      InitPendingRegistrations(rp_id_hash_it->second.GetBytestring());
+      if (mutable_state()->pending_registrations.empty()) {
+        return CtapDeviceResponseCode::kCtap2ErrNoCredentials;
+      }
+      response_map.swap(mutable_state()->pending_registrations.front());
+      response_map.emplace(
+          static_cast<int>(CredentialManagementResponseKey::kTotalCredentials),
+          static_cast<int>(mutable_state()->pending_registrations.size()));
+      mutable_state()->pending_registrations.pop_front();
+
+      *response =
+          cbor::Writer::Write(cbor::Value(std::move(response_map))).value();
+      return CtapDeviceResponseCode::kSuccess;
+    }
+
+    case CredentialManagementSubCommand::
+        kEnumerateCredentialsGetNextCredential: {
+      if (mutable_state()->pending_registrations.empty()) {
+        return CtapDeviceResponseCode::kCtap2ErrNotAllowed;
+      }
+      response_map.swap(mutable_state()->pending_registrations.front());
+      mutable_state()->pending_registrations.pop_front();
+
+      *response =
+          cbor::Writer::Write(cbor::Value(std::move(response_map))).value();
+      return CtapDeviceResponseCode::kSuccess;
+    }
+
+    case CredentialManagementSubCommand::kDeleteCredential: {
+      const auto params_it = request_map.find(cbor::Value(
+          static_cast<int>(CredentialManagementRequestKey::kSubCommandParams)));
+      if (params_it == request_map.end() && !params_it->second.is_map()) {
+        return CtapDeviceResponseCode::kCtap2ErrCBORUnexpectedType;
+      }
+      const cbor::Value::MapValue& params = params_it->second.GetMap();
+      // pinAuth = LEFT(HMAC-SHA-256(pinToken, enumerateCredentialsBegin (0x04)
+      //                                       || subCommandParams), 16)
+      std::vector<uint8_t> pinauth_bytes =
+          cbor::Writer::Write(cbor::Value(params)).value();
+      pinauth_bytes.insert(pinauth_bytes.begin(),
+                           static_cast<uint8_t>(subcommand));
+      CtapDeviceResponseCode pin_status = CheckCredentialManagementPINAuth(
+          request_map, mutable_state()->pin_token, pinauth_bytes);
+      if (pin_status != CtapDeviceResponseCode::kSuccess) {
+        return pin_status;
+      }
+
+      // The spec doesn't say, but we clear the enumerateRPs and
+      // enumerateCredentials states after deleteCredential to avoid having to
+      // update them.
+      mutable_state()->pending_rps.clear();
+      mutable_state()->pending_registrations.clear();
+
+      const auto credential_id_it = params.find(cbor::Value(static_cast<int>(
+          CredentialManagementRequestParamKey::kCredentialID)));
+      if (credential_id_it == params.end() ||
+          !credential_id_it->second.is_bytestring()) {
+        return CtapDeviceResponseCode::kCtap2ErrCBORUnexpectedType;
+      }
+      const std::vector<uint8_t>& credential_id =
+          credential_id_it->second.GetBytestring();
+      if (!base::ContainsKey(mutable_state()->registrations, credential_id)) {
+        return CtapDeviceResponseCode::kCtap2ErrNoCredentials;
+      }
+      mutable_state()->registrations.erase(credential_id);
+      *response = {};
+      return CtapDeviceResponseCode::kSuccess;
+    }
+  }
+  NOTREACHED();
+  return CtapDeviceResponseCode::kCtap2ErrInvalidOption;
+}
+
+void VirtualCtap2Device::InitPendingRPs() {
+  mutable_state()->pending_rps.clear();
+  std::set<std::string> rp_ids;
+  for (const auto& registration : mutable_state()->registrations) {
+    if (!registration.second.is_resident) {
+      continue;
+    }
+    DCHECK(!registration.second.is_u2f && registration.second.user &&
+           registration.second.rp);
+    if (!base::ContainsKey(rp_ids, registration.second.rp->rp_id())) {
+      mutable_state()->pending_rps.push_back(*registration.second.rp);
+    }
+  }
+}
+
+void VirtualCtap2Device::InitPendingRegistrations(
+    base::span<const uint8_t> rp_id_hash) {
+  DCHECK_EQ(rp_id_hash.size(), kRpIdHashLength);
+  mutable_state()->pending_registrations.clear();
+  for (const auto& registration : mutable_state()->registrations) {
+    if (!registration.second.is_resident ||
+        !std::equal(rp_id_hash.begin(), rp_id_hash.end(),
+                    registration.second.application_parameter.begin())) {
+      continue;
+    }
+    DCHECK(!registration.second.is_u2f && registration.second.user &&
+           registration.second.rp);
+    cbor::Value::MapValue response_map;
+    response_map.emplace(
+        static_cast<int>(CredentialManagementResponseKey::kUser),
+        PublicKeyCredentialUserEntity::ConvertToCBOR(
+            *registration.second.user));
+    response_map.emplace(
+        static_cast<int>(CredentialManagementResponseKey::kCredentialID),
+        registration.first);
+    std::string public_key;
+    CHECK(registration.second.private_key->ExportRawPublicKey(&public_key));
+    response_map.emplace(
+        static_cast<int>(CredentialManagementResponseKey::kPublicKey),
+        ConstructECPublicKey(public_key)->EncodeAsCOSEKey());
+    mutable_state()->pending_registrations.emplace_back(
+        std::move(response_map));
+  }
+}
+
+void VirtualCtap2Device::GetNextRP(cbor::Value::MapValue* response_map) {
+  DCHECK(!mutable_state()->pending_rps.empty());
+  response_map->emplace(static_cast<int>(CredentialManagementResponseKey::kRP),
+                        mutable_state()->pending_rps.front().ConvertToCBOR());
+  response_map->emplace(
+      static_cast<int>(CredentialManagementResponseKey::kRPIDHash),
+      fido_parsing_utils::CreateSHA256Hash(
+          mutable_state()->pending_rps.front().rp_id()));
+  mutable_state()->pending_rps.pop_front();
+}
+
 CtapDeviceResponseCode VirtualCtap2Device::OnAuthenticatorGetInfo(
     std::vector<uint8_t>* response) const {
   *response = AuthenticatorGetInfoResponse::EncodeToCBOR(*device_info_);
diff --git a/device/fido/virtual_ctap2_device.h b/device/fido/virtual_ctap2_device.h
index 29135c2..08b141c 100644
--- a/device/fido/virtual_ctap2_device.h
+++ b/device/fido/virtual_ctap2_device.h
@@ -33,6 +33,9 @@
  public:
   struct COMPONENT_EXPORT(DEVICE_FIDO) Config {
     Config();
+    Config(const Config&);
+    Config& operator=(const Config&);
+    ~Config();
 
     // u2f_support, if true, makes this device a dual-protocol (i.e. CTAP2 and
     // U2F) device.
@@ -40,6 +43,7 @@
     bool pin_support = false;
     bool internal_uv_support = false;
     bool resident_key_support = false;
+    bool credential_management_support = false;
     // resident_credential_storage is the number of resident credentials that
     // the device will store before returning KEY_STORE_FULL.
     size_t resident_credential_storage = 3;
@@ -83,10 +87,16 @@
                                             std::vector<uint8_t>* response);
   CtapDeviceResponseCode OnPINCommand(base::span<const uint8_t> request,
                                       std::vector<uint8_t>* response);
-
+  CtapDeviceResponseCode OnCredentialManagement(
+      base::span<const uint8_t> request,
+      std::vector<uint8_t>* response);
   CtapDeviceResponseCode OnAuthenticatorGetInfo(
       std::vector<uint8_t>* response) const;
 
+  void InitPendingRPs();
+  void GetNextRP(cbor::Value::MapValue* response_map);
+  void InitPendingRegistrations(base::span<const uint8_t> rp_id_hash);
+
   AttestedCredentialData ConstructAttestedCredentialData(
       std::vector<uint8_t> u2f_data,
       std::unique_ptr<PublicKey> public_key);
diff --git a/device/fido/virtual_fido_device.cc b/device/fido/virtual_fido_device.cc
index d40f9c2..62a50cb0 100644
--- a/device/fido/virtual_fido_device.cc
+++ b/device/fido/virtual_fido_device.cc
@@ -62,7 +62,7 @@
 VirtualFidoDevice::State::~State() = default;
 
 bool VirtualFidoDevice::State::InjectRegistration(
-    const std::vector<uint8_t>& credential_id,
+    base::span<const uint8_t> credential_id,
     const std::string& relying_party_id) {
   auto application_parameter =
       fido_parsing_utils::CreateSHA256Hash(relying_party_id);
@@ -75,25 +75,27 @@
                                 0 /* signature counter */);
 
   bool was_inserted;
-  std::tie(std::ignore, was_inserted) =
-      registrations.emplace(credential_id, std::move(registration));
+  std::tie(std::ignore, was_inserted) = registrations.emplace(
+      fido_parsing_utils::Materialize(credential_id), std::move(registration));
   return was_inserted;
 }
 
 bool VirtualFidoDevice::State::InjectResidentKey(
-    const std::vector<uint8_t>& credential_id,
+    base::span<const uint8_t> credential_id,
     const std::string& relying_party_id,
-    const std::vector<uint8_t>& user_id,
+    base::span<const uint8_t> user_id,
     const std::string& name,
     const std::string& display_name) {
   auto application_parameter =
       fido_parsing_utils::CreateSHA256Hash(relying_party_id);
+  const std::vector<uint8_t> user_id_bytes =
+      fido_parsing_utils::Materialize(user_id);
 
   // Cannot create a duplicate credential for the same (RP ID, user ID) pair.
   for (const auto& registration : registrations) {
     if (registration.second.is_resident &&
         application_parameter == registration.second.application_parameter &&
-        user_id == registration.second.user->id) {
+        user_id_bytes == registration.second.user->id) {
       return false;
     }
   }
@@ -105,14 +107,14 @@
                                 std::move(application_parameter),
                                 0 /* signature counter */);
   registration.is_resident = true;
-  PublicKeyCredentialUserEntity user(user_id);
+  PublicKeyCredentialUserEntity user(std::move(user_id_bytes));
   user.name = name;
   user.display_name = display_name;
   registration.user = std::move(user);
 
   bool was_inserted;
-  std::tie(std::ignore, was_inserted) =
-      registrations.emplace(credential_id, std::move(registration));
+  std::tie(std::ignore, was_inserted) = registrations.emplace(
+      fido_parsing_utils::Materialize(credential_id), std::move(registration));
   return was_inserted;
 }
 
diff --git a/device/fido/virtual_fido_device.h b/device/fido/virtual_fido_device.h
index f43bd0be..bfcd28f 100644
--- a/device/fido/virtual_fido_device.h
+++ b/device/fido/virtual_fido_device.h
@@ -22,6 +22,7 @@
 #include "device/fido/fido_constants.h"
 #include "device/fido/fido_device.h"
 #include "device/fido/fido_parsing_utils.h"
+#include "device/fido/public_key_credential_rp_entity.h"
 #include "device/fido/public_key_credential_user_entity.h"
 #include "net/cert/x509_util.h"
 #include "third_party/boringssl/src/include/openssl/base.h"
@@ -57,6 +58,8 @@
 
     // user is only valid if |is_resident| is true.
     base::Optional<device::PublicKeyCredentialUserEntity> user;
+    // rp is only valid if |is_resident| is true.
+    base::Optional<device::PublicKeyCredentialRpEntity> rp;
 
     DISALLOW_COPY_AND_ASSIGN(RegistrationData);
   };
@@ -120,6 +123,14 @@
     // GetNextAssertion request.
     std::vector<std::vector<uint8_t>> pending_assertions;
 
+    // pending_rps contains the remaining RPs to return a previous
+    // authenticatorCredentialManagement command.
+    std::list<device::PublicKeyCredentialRpEntity> pending_rps;
+
+    // pending_registrations contains the remaining |is_resident| registration
+    // to return from a previous authenticatorCredentialManagement command.
+    std::list<cbor::Value::MapValue> pending_registrations;
+
     FidoTransportProtocol transport =
         FidoTransportProtocol::kUsbHumanInterfaceDevice;
 
@@ -129,16 +140,16 @@
     //
     // Returns true on success. Will fail if there already exists a credential
     // with the given ID or if private-key generation fails.
-    bool InjectRegistration(const std::vector<uint8_t>& credential_id,
+    bool InjectRegistration(base::span<const uint8_t> credential_id,
                             const std::string& relying_party_id);
 
     // InjectResidentKey adds a resident credential with the specified values.
     // Returns false if there already exists a resident credential for the same
     // (RP ID, user ID) pair, or for the same credential ID. Otherwise returns
     // true.
-    bool InjectResidentKey(const std::vector<uint8_t>& credential_id,
+    bool InjectResidentKey(base::span<const uint8_t> credential_id,
                            const std::string& relying_party_id,
-                           const std::vector<uint8_t>& user_id,
+                           base::span<const uint8_t> user_id,
                            const std::string& name,
                            const std::string& display_name);
 
diff --git a/docs/mac_build_instructions.md b/docs/mac_build_instructions.md
index 9ee43ac0..9003d19 100644
--- a/docs/mac_build_instructions.md
+++ b/docs/mac_build_instructions.md
@@ -31,9 +31,10 @@
 $ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
 ```
 
-Add `depot_tools` to the end of your PATH (you will probably want to put this
-in your `~/.bashrc` or `~/.zshrc`). Assuming you cloned `depot_tools` to
-`/path/to/depot_tools`:
+Add `depot_tools` to the end of your PATH (you will probably want to put this in
+your `~/.bash_profile` or `~/.zshrc`). Assuming you cloned `depot_tools` to
+`/path/to/depot_tools` (note: you **must** use the absolute path or Python will
+not be able to find infra tools):
 
 ```shell
 $ export PATH="$PATH:/path/to/depot_tools"
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
index bb5cf07..1b644db 100644
--- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
@@ -217,23 +217,23 @@
 namespace extensions {
 
 BluetoothLowEnergyEventRouter::AttributeValueRequest::AttributeValueRequest(
-    const Delegate::ValueCallback& value_callback,
-    const Delegate::ErrorCallback& error_callback) {
+    Delegate::ValueCallback value_callback,
+    Delegate::ErrorCallback error_callback) {
   this->type = ATTRIBUTE_READ_REQUEST;
-  this->value_callback = value_callback;
-  this->error_callback = error_callback;
+  this->value_callback = std::move(value_callback);
+  this->error_callback = std::move(error_callback);
 }
 
 BluetoothLowEnergyEventRouter::AttributeValueRequest::AttributeValueRequest(
-    const base::Closure& success_callback,
-    const Delegate::ErrorCallback& error_callback) {
+    base::OnceClosure success_callback,
+    Delegate::ErrorCallback error_callback) {
   this->type = ATTRIBUTE_WRITE_REQUEST;
-  this->success_callback = success_callback;
-  this->error_callback = error_callback;
+  this->success_callback = std::move(success_callback);
+  this->error_callback = std::move(error_callback);
 }
 
-BluetoothLowEnergyEventRouter::AttributeValueRequest::~AttributeValueRequest() {
-}
+BluetoothLowEnergyEventRouter::AttributeValueRequest::~AttributeValueRequest() =
+    default;
 
 BluetoothLowEnergyEventRouter::BluetoothLowEnergyEventRouter(
     content::BrowserContext* context)
@@ -1086,8 +1086,8 @@
     const device::BluetoothDevice* device,
     const device::BluetoothLocalGattCharacteristic* characteristic,
     int offset,
-    const Delegate::ValueCallback& value_callback,
-    const Delegate::ErrorCallback& error_callback) {
+    Delegate::ValueCallback value_callback,
+    Delegate::ErrorCallback error_callback) {
   const std::string& service_id = characteristic->GetService()->GetIdentifier();
   if (service_id_to_extension_id_.find(service_id) ==
       service_id_to_extension_id_.end()) {
@@ -1099,8 +1099,8 @@
   const std::string& extension_id = service_id_to_extension_id_.at(service_id);
   apibtle::Request request;
   request.request_id = StoreSentRequest(
-      extension_id,
-      std::make_unique<AttributeValueRequest>(value_callback, error_callback));
+      extension_id, std::make_unique<AttributeValueRequest>(
+                        std::move(value_callback), std::move(error_callback)));
   PopulateDevice(device, &request);
   DispatchEventToExtension(
       extension_id, events::BLUETOOTH_LOW_ENERGY_ON_CHARACTERISTIC_READ_REQUEST,
@@ -1114,8 +1114,8 @@
     const device::BluetoothLocalGattCharacteristic* characteristic,
     const std::vector<uint8_t>& value,
     int offset,
-    const base::Closure& callback,
-    const Delegate::ErrorCallback& error_callback) {
+    base::OnceClosure callback,
+    Delegate::ErrorCallback error_callback) {
   const std::string& service_id = characteristic->GetService()->GetIdentifier();
   if (service_id_to_extension_id_.find(service_id) ==
       service_id_to_extension_id_.end()) {
@@ -1128,8 +1128,8 @@
 
   apibtle::Request request;
   request.request_id = StoreSentRequest(
-      extension_id,
-      std::make_unique<AttributeValueRequest>(callback, error_callback));
+      extension_id, std::make_unique<AttributeValueRequest>(
+                        std::move(callback), std::move(error_callback)));
   request.value = std::make_unique<std::vector<uint8_t>>(value);
   PopulateDevice(device, &request);
   DispatchEventToExtension(
@@ -1146,19 +1146,19 @@
     const std::vector<uint8_t>& value,
     int offset,
     bool has_subsequent_request,
-    const base::Closure& callback,
-    const Delegate::ErrorCallback& error_callback) {
+    base::OnceClosure callback,
+    Delegate::ErrorCallback error_callback) {
   // TODO(crbug/856869): Support reliable write.
-  OnCharacteristicWriteRequest(device, characteristic, value, offset, callback,
-                               error_callback);
+  OnCharacteristicWriteRequest(device, characteristic, value, offset,
+                               std::move(callback), std::move(error_callback));
 }
 
 void BluetoothLowEnergyEventRouter::OnDescriptorReadRequest(
     const device::BluetoothDevice* device,
     const device::BluetoothLocalGattDescriptor* descriptor,
     int offset,
-    const Delegate::ValueCallback& value_callback,
-    const Delegate::ErrorCallback& error_callback) {
+    Delegate::ValueCallback value_callback,
+    Delegate::ErrorCallback error_callback) {
   const std::string& service_id =
       descriptor->GetCharacteristic()->GetService()->GetIdentifier();
   if (service_id_to_extension_id_.find(service_id) ==
@@ -1172,8 +1172,8 @@
 
   apibtle::Request request;
   request.request_id = StoreSentRequest(
-      extension_id,
-      std::make_unique<AttributeValueRequest>(value_callback, error_callback));
+      extension_id, std::make_unique<AttributeValueRequest>(
+                        std::move(value_callback), std::move(error_callback)));
   PopulateDevice(device, &request);
   DispatchEventToExtension(
       extension_id,
@@ -1188,8 +1188,8 @@
     const device::BluetoothLocalGattDescriptor* descriptor,
     const std::vector<uint8_t>& value,
     int offset,
-    const base::Closure& callback,
-    const Delegate::ErrorCallback& error_callback) {
+    base::OnceClosure callback,
+    Delegate::ErrorCallback error_callback) {
   const std::string& service_id =
       descriptor->GetCharacteristic()->GetService()->GetIdentifier();
   if (service_id_to_extension_id_.find(service_id) ==
@@ -1203,8 +1203,8 @@
 
   apibtle::Request request;
   request.request_id = StoreSentRequest(
-      extension_id,
-      std::make_unique<AttributeValueRequest>(callback, error_callback));
+      extension_id, std::make_unique<AttributeValueRequest>(
+                        std::move(callback), std::move(error_callback)));
   request.value = std::make_unique<std::vector<uint8_t>>(value);
   PopulateDevice(device, &request);
   DispatchEventToExtension(
@@ -1379,14 +1379,14 @@
   request_id_map->erase(request_iter);
 
   if (is_error) {
-    request->error_callback.Run();
+    std::move(request->error_callback).Run();
     return;
   }
 
   if (request->type == AttributeValueRequest::ATTRIBUTE_READ_REQUEST) {
-    request->value_callback.Run(value);
+    std::move(request->value_callback).Run(value);
   } else {
-    request->success_callback.Run();
+    std::move(request->success_callback).Run();
   }
 }
 
diff --git a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
index 41bcaf6..26b7c4bb 100644
--- a/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
+++ b/extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h
@@ -68,15 +68,15 @@
    public:
     enum RequestType { ATTRIBUTE_READ_REQUEST, ATTRIBUTE_WRITE_REQUEST };
 
-    AttributeValueRequest(const Delegate::ValueCallback& value_callback,
-                          const Delegate::ErrorCallback& error_callback);
-    AttributeValueRequest(const base::Closure& success_callback,
-                          const Delegate::ErrorCallback& error_callback);
+    AttributeValueRequest(Delegate::ValueCallback value_callback,
+                          Delegate::ErrorCallback error_callback);
+    AttributeValueRequest(base::OnceClosure success_callback,
+                          Delegate::ErrorCallback error_callback);
     ~AttributeValueRequest();
 
     RequestType type;
     Delegate::ValueCallback value_callback;
-    base::Closure success_callback;
+    base::OnceClosure success_callback;
     Delegate::ErrorCallback error_callback;
 
    private:
@@ -310,36 +310,36 @@
       const device::BluetoothDevice* device,
       const device::BluetoothLocalGattCharacteristic* characteristic,
       int offset,
-      const Delegate::ValueCallback& value_callback,
-      const Delegate::ErrorCallback& error_callback) override;
+      Delegate::ValueCallback value_callback,
+      Delegate::ErrorCallback error_callback) override;
   void OnCharacteristicWriteRequest(
       const device::BluetoothDevice* device,
       const device::BluetoothLocalGattCharacteristic* characteristic,
       const std::vector<uint8_t>& value,
       int offset,
-      const base::Closure& callback,
-      const Delegate::ErrorCallback& error_callback) override;
+      base::OnceClosure callback,
+      Delegate::ErrorCallback error_callback) override;
   void OnCharacteristicPrepareWriteRequest(
       const device::BluetoothDevice* device,
       const device::BluetoothLocalGattCharacteristic* characteristic,
       const std::vector<uint8_t>& value,
       int offset,
       bool has_subsequent_request,
-      const base::Closure& callback,
-      const Delegate::ErrorCallback& error_callback) override;
+      base::OnceClosure callback,
+      Delegate::ErrorCallback error_callback) override;
   void OnDescriptorReadRequest(
       const device::BluetoothDevice* device,
       const device::BluetoothLocalGattDescriptor* descriptor,
       int offset,
-      const Delegate::ValueCallback& value_callback,
-      const Delegate::ErrorCallback& error_callback) override;
+      Delegate::ValueCallback value_callback,
+      Delegate::ErrorCallback error_callback) override;
   void OnDescriptorWriteRequest(
       const device::BluetoothDevice* device,
       const device::BluetoothLocalGattDescriptor* descriptor,
       const std::vector<uint8_t>& value,
       int offset,
-      const base::Closure& callback,
-      const Delegate::ErrorCallback& error_callback) override;
+      base::OnceClosure callback,
+      Delegate::ErrorCallback error_callback) override;
   void OnNotificationsStart(
       const device::BluetoothDevice* device,
       device::BluetoothGattCharacteristic::NotificationType notification_type,
diff --git a/extensions/browser/extension_service_worker_message_filter.cc b/extensions/browser/extension_service_worker_message_filter.cc
index 59c4915..65ffa9b 100644
--- a/extensions/browser/extension_service_worker_message_filter.cc
+++ b/extensions/browser/extension_service_worker_message_filter.cc
@@ -73,6 +73,7 @@
     int64_t service_worker_version_id,
     const std::string& request_uuid) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  active_request_uuids_.insert(request_uuid);
   // The worker might have already stopped before we got here, so the increment
   // below might fail legitimately. Therefore, we do not send bad_message to the
   // worker even if it fails.
@@ -86,7 +87,12 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   bool status = service_worker_context_->FinishedExternalRequest(
       service_worker_version_id, request_uuid);
-  if (!status) {
+  if (!status)
+    LOG(ERROR) << "ServiceWorkerContext::FinishedExternalRequest failed.";
+  bool erased = active_request_uuids_.erase(request_uuid) == 1;
+  // The worker may have already stopped before we got here, so only report
+  // a bad message if we didn't have an increment for the UUID.
+  if (!erased) {
     bad_message::ReceivedBadMessage(
         this, bad_message::ESWMF_INVALID_DECREMENT_ACTIVITY);
   }
diff --git a/extensions/browser/extension_service_worker_message_filter.h b/extensions/browser/extension_service_worker_message_filter.h
index 6976e492..9d4a73b 100644
--- a/extensions/browser/extension_service_worker_message_filter.h
+++ b/extensions/browser/extension_service_worker_message_filter.h
@@ -5,6 +5,8 @@
 #ifndef EXTENSIONS_BROWSER_EXTENSION_SERVICE_WORKER_MESSAGE_FILTER_H_
 #define EXTENSIONS_BROWSER_EXTENSION_SERVICE_WORKER_MESSAGE_FILTER_H_
 
+#include <unordered_set>
+
 #include "base/macros.h"
 #include "content/public/browser/browser_message_filter.h"
 #include "content/public/browser/browser_thread.h"
@@ -71,6 +73,8 @@
                   content::BrowserThread::DeleteOnUIThread>
       dispatcher_;
 
+  std::unordered_set<std::string> active_request_uuids_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionServiceWorkerMessageFilter);
 };
 
diff --git a/fuchsia/fidl/cast/cast_channel.fidl b/fuchsia/fidl/cast/cast_channel.fidl
index 8fb702e..1d72753 100644
--- a/fuchsia/fidl/cast/cast_channel.fidl
+++ b/fuchsia/fidl/cast/cast_channel.fidl
@@ -11,10 +11,10 @@
 protocol CastChannel {
   /// Receives an opened Cast |channel| from the Cast application.
   /// Open() must not be called again until the preceding call has returned.
-  [Transitional="Transitional method to migrate the fuchsia.web API."]
   Open(fuchsia.web.MessagePort channel) -> ();
 
   // TODO(crbug.com/946732): Remove this once callers have migrated to Open().
+  [Transitional="Deprecated method to migrate the fuchsia.web API."]
   OnOpened(chromium.web.MessagePort channel) -> ();
 };
 
diff --git a/fuchsia/runners/BUILD.gn b/fuchsia/runners/BUILD.gn
index 82bbe3b..7595902 100644
--- a/fuchsia/runners/BUILD.gn
+++ b/fuchsia/runners/BUILD.gn
@@ -54,7 +54,6 @@
     "//base",
     "//fuchsia/base",
     "//fuchsia/base:modular",
-    "//fuchsia/engine:legacy_message_port_bridge",
     "//third_party/fuchsia-sdk/sdk:modular",
     "//url",
   ]
diff --git a/fuchsia/runners/cast/cast_channel_bindings.cc b/fuchsia/runners/cast/cast_channel_bindings.cc
index 26a2caf..e05d362 100644
--- a/fuchsia/runners/cast/cast_channel_bindings.cc
+++ b/fuchsia/runners/cast/cast_channel_bindings.cc
@@ -16,7 +16,6 @@
 #include "base/path_service.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "fuchsia/base/mem_buffer_util.h"
-#include "fuchsia/engine/legacy_message_port_bridge.h"
 #include "fuchsia/runners/cast/cast_platform_bindings_ids.h"
 #include "fuchsia/runners/cast/named_message_port_connector.h"
 
@@ -103,11 +102,8 @@
     fuchsia::web::MessagePortPtr channel) {
   if (consumer_ready_for_port_) {
     consumer_ready_for_port_ = false;
-    chromium::web::MessagePortPtr chromium_message_port;
-    new cr_fuchsia::LegacyMessagePortBridge(chromium_message_port.NewRequest(),
-                                            std::move(channel));
-    channel_consumer_->OnOpened(
-        std::move(chromium_message_port),
+    channel_consumer_->Open(
+        std::move(channel),
         fit::bind_member(this, &CastChannelBindings::OnConsumerReadyForPort));
   } else {
     connected_channel_queue_.push_front(std::move(channel));
diff --git a/fuchsia/runners/cast/cast_channel_bindings_browsertest.cc b/fuchsia/runners/cast/cast_channel_bindings_browsertest.cc
index fe00f3e..fc9f5d5 100644
--- a/fuchsia/runners/cast/cast_channel_bindings_browsertest.cc
+++ b/fuchsia/runners/cast/cast_channel_bindings_browsertest.cc
@@ -55,8 +55,8 @@
     callback();
   }
 
-  void OnOpened(fidl::InterfaceHandle<chromium::web::MessagePort> channel,
-                OnOpenedCallback receive_next_channel_cb) override {
+  void Open(fidl::InterfaceHandle<fuchsia::web::MessagePort> channel,
+            OpenCallback receive_next_channel_cb) override {
     connected_channel_ = channel.Bind();
     receive_next_channel_cb_ = std::move(receive_next_channel_cb);
 
@@ -89,14 +89,15 @@
 
   std::string ReadStringFromChannel() {
     base::RunLoop run_loop;
-    cr_fuchsia::ResultReceiver<chromium::web::WebMessage> message(
+    cr_fuchsia::ResultReceiver<fuchsia::web::WebMessage> message(
         run_loop.QuitClosure());
     connected_channel_->ReceiveMessage(
         cr_fuchsia::CallbackToFitFunction(message.GetReceiveCallback()));
     run_loop.Run();
 
     std::string data;
-    CHECK(cr_fuchsia::StringFromMemBuffer(message->data, &data));
+    CHECK(message->has_data());
+    CHECK(cr_fuchsia::StringFromMemBuffer(message->data(), &data));
     return data;
   }
 
@@ -121,7 +122,7 @@
   cr_fuchsia::TestNavigationListener navigation_listener_;
 
   // The connected Cast Channel.
-  chromium::web::MessagePortPtr connected_channel_;
+  fuchsia::web::MessagePortPtr connected_channel_;
 
   // A pending on-connect callback, to be invoked once a Cast Channel is
   // received.
@@ -129,7 +130,7 @@
 
  private:
   const base::RunLoop::ScopedRunTimeoutForTest run_timeout_;
-  OnOpenedCallback receive_next_channel_cb_;
+  OpenCallback receive_next_channel_cb_;
 
   DISALLOW_COPY_AND_ASSIGN(CastChannelBindingsTest);
 };
@@ -191,16 +192,17 @@
 
     // Send a message to the channel.
     {
-      chromium::web::WebMessage message;
-      message.data = cr_fuchsia::MemBufferFromString("hello");
+      fuchsia::web::WebMessage message;
+      message.set_data(cr_fuchsia::MemBufferFromString("hello"));
 
       base::RunLoop run_loop;
-      cr_fuchsia::ResultReceiver<bool> post_result(run_loop.QuitClosure());
+      cr_fuchsia::ResultReceiver<fuchsia::web::MessagePort_PostMessage_Result>
+          post_result(run_loop.QuitClosure());
       connected_channel_->PostMessage(
           std::move(message),
           cr_fuchsia::CallbackToFitFunction(post_result.GetReceiveCallback()));
       run_loop.Run();
-      EXPECT_EQ(true, *post_result);
+      EXPECT_TRUE(post_result->is_response());
     }
 
     EXPECT_EQ("ack hello", ReadStringFromChannel());
diff --git a/fuchsia/runners/cast/cast_runner_integration_test.cc b/fuchsia/runners/cast/cast_runner_integration_test.cc
index 59ac7da..888e50c 100644
--- a/fuchsia/runners/cast/cast_runner_integration_test.cc
+++ b/fuchsia/runners/cast/cast_runner_integration_test.cc
@@ -44,7 +44,7 @@
       : binding_(directory, this) {}
 
   // Returns null if the Cast channel is not open.
-  const chromium::web::MessagePortPtr& port() const { return port_; }
+  const fuchsia::web::MessagePortPtr& port() const { return port_; }
 
   void set_on_opened(base::OnceClosure on_opened) {
     on_opened_ = std::move(on_opened);
@@ -52,8 +52,8 @@
 
  protected:
   // chromium::cast::CastChannel implementation.
-  void OnOpened(fidl::InterfaceHandle<chromium::web::MessagePort> channel,
-                OnOpenedCallback callback_ignored) override {
+  void Open(fidl::InterfaceHandle<fuchsia::web::MessagePort> channel,
+            OpenCallback callback_ignored) override {
     port_ = channel.Bind();
 
     if (on_opened_)
@@ -66,7 +66,7 @@
       binding_;
 
   // Null until the Cast app connects to the Cast channel.
-  chromium::web::MessagePortPtr port_;
+  fuchsia::web::MessagePortPtr port_;
 
   // Invoked when the contect opens a new Cast channel, if set.
   base::OnceClosure on_opened_;
@@ -334,14 +334,15 @@
   auto expected_list = {"this", "is", "a", "test"};
   for (const std::string& expected : expected_list) {
     base::RunLoop run_loop;
-    cr_fuchsia::ResultReceiver<chromium::web::WebMessage> message(
+    cr_fuchsia::ResultReceiver<fuchsia::web::WebMessage> message(
         run_loop.QuitClosure());
     component_state_->cast_channel()->port()->ReceiveMessage(
         cr_fuchsia::CallbackToFitFunction(message.GetReceiveCallback()));
     run_loop.Run();
 
     std::string data;
-    ASSERT_TRUE(cr_fuchsia::StringFromMemBuffer(message->data, &data));
+    ASSERT_TRUE(message->has_data());
+    ASSERT_TRUE(cr_fuchsia::StringFromMemBuffer(message->data(), &data));
     EXPECT_EQ(data, expected);
   }
 
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index 1ea963d6..bb2ff41 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -396,6 +396,11 @@
 }
 
 builder_mixins {
+  name: "linux-xenial"
+  dimensions: "os:Ubuntu-16.04"
+}
+
+builder_mixins {
   name: "linux-angle-try"
   mixins: "linux"
   mixins: "angle-try"
@@ -3380,6 +3385,15 @@
     builders {
       mixins: "android-try"
       mixins: "builderless"
+      name: "android_cronet_tester"
+      dimensions: "os:Ubuntu-14.04"
+      recipe {
+        properties: "buildername:android-cronet-arm-dbg"
+      }
+    }
+    builders {
+      mixins: "android-try"
+      mixins: "builderless"
       name: "android-cronet-arm-dbg"
       dimensions: "os:Ubuntu-14.04"
     }
@@ -3402,20 +3416,6 @@
       name: "android-oreo-arm64-cts-networkservice-dbg"
       dimensions: "os:Ubuntu-14.04"
     }
-    # TODO(jbudorick): Remove this after fully migrating ANSR.
-    builders {
-      mixins: "android-try"
-      mixins: "goma-j150"
-      name: "android_n5x_swarming_rel"
-      auto_builder_dimension: NO
-      dimensions: "builder:android-marshmallow-arm64-rel"
-      dimensions: "os:Ubuntu-14.04"
-      # TODO(hinoka): Make this 16 core after crbug.com/875708
-      dimensions: "cores:"
-      recipe {
-        properties: "buildername:android-marshmallow-arm64-rel"
-      }
-    }
     builders {
       mixins: "android-try"
       mixins: "goma-j300"
@@ -3626,8 +3626,6 @@
     }
     builders { mixins: "linux-try" name: "leak_detection_linux" }
     builders { mixins: "linux-angle-try" name: "linux-angle-rel" }
-    builders { mixins: "linux-angle-try" name: "linux_angle_compile_dbg_ng" }
-    builders { mixins: "linux-angle-try" name: "linux_angle_dbg_ng" }
     builders { mixins: "linux-angle-try" name: "linux_angle_deqp_rel_ng" }
     builders { mixins: "linux-angle-try" name: "linux_angle_ozone_rel_ng" }
     builders {
@@ -3754,8 +3752,6 @@
     builders { mixins: "ios-try" name: "ios-slimnav" }
     builders { mixins: "mac-dawn-try" name: "dawn-mac-x64-deps-rel" }
     builders { mixins: "mac-angle-try" name: "mac-angle-rel" }
-    builders { mixins: "mac-angle-try" name: "mac_angle_compile_dbg_ng" }
-    builders { mixins: "mac-angle-try" name: "mac_angle_dbg_ng" }
     builders {
       mixins: "mac-try"
       name: "mac-jumbo-rel"
@@ -3879,12 +3875,7 @@
       }
     }
     builders { mixins: "win-angle-try" name: "win-angle-rel" }
-    builders { mixins: "win-angle-try" name: "win_angle_compile_x64_rel_ng" }
-    builders { mixins: "win-angle-try" name: "win_angle_compile_x64_dbg_ng" }
-    builders { mixins: "win-angle-try" name: "win_angle_compile_dbg_ng" }
     builders { mixins: "win-angle-try" name: "win_angle_deqp_rel_ng" }
-    builders { mixins: "win-angle-try" name: "win_angle_x64_rel_ng" }
-    builders { mixins: "win-angle-try" name: "win_angle_x64_deqp_rel_ng" }
     builders { mixins: "win-try" name: "win_archive" }
     builders {
       mixins: "win-try"
@@ -4036,12 +4027,12 @@
 
     # Android
 
-    builders { mixins: "linux"  name: "WebRTC Chromium Android Builder" }
-    builders { mixins: "linux"  name: "WebRTC Chromium Android Tester" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium Android Builder" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium Android Tester" }
 
     # Linux
 
-    builders { mixins: "linux"  name: "WebRTC Chromium Linux Builder" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium Linux Builder" }
     builders { mixins: "linux"  name: "WebRTC Chromium Linux Tester" }
 
     # Mac
@@ -4089,11 +4080,11 @@
 
     # Android
 
-    builders { mixins: "linux"  name: "WebRTC Chromium FYI Android Builder" }
-    builders { mixins: "linux"  name: "WebRTC Chromium FYI Android Builder (dbg)" }
-    builders { mixins: "linux"  name: "WebRTC Chromium FYI Android Builder ARM64 (dbg)" }
-    builders { mixins: "linux"  name: "WebRTC Chromium FYI Android Tests (dbg) (K Nexus5)" }
-    builders { mixins: "linux"  name: "WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium FYI Android Builder" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium FYI Android Builder (dbg)" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium FYI Android Builder ARM64 (dbg)" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium FYI Android Tests (dbg) (K Nexus5)" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)" }
 
     # iOS
 
@@ -4102,9 +4093,9 @@
 
     # Linux
 
-    builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Builder" }
-    builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Builder (dbg)" }
-    builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Tester" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium FYI Linux Builder" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium FYI Linux Builder (dbg)" }
+    builders { mixins: "linux-xenial"  name: "WebRTC Chromium FYI Linux Tester" }
 
     # Mac
 
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index ae745627..8d92d29 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -1965,227 +1965,6 @@
 
 consoles {
   header_id: "chromium"
-  id: "luci.chromium.clang"
-  name: "luci.chromium.clang"
-  repo_url: "https://chromium.googlesource.com/chromium/src"
-  refs: "refs/heads/master"
-  manifest_name: "REVISION"
-  include_experimental_builds: true
-
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTLinux"
-    category: "ToT Linux"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chrome.ci/ToTLinuxOfficial"
-    category: "ToT Linux"
-    short_name: "ofi"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTLinux (dbg)"
-    category: "ToT Linux"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTLinuxASan"
-    category: "ToT Linux"
-    short_name: "asn"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTLinuxASanLibfuzzer"
-    category: "ToT Linux"
-    short_name: "fuz"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTLinuxMSan"
-    category: "ToT Linux"
-    short_name: "msn"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTLinuxTSan"
-    category: "ToT Linux"
-    short_name: "tsn"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTLinuxThinLTO"
-    category: "ToT Linux"
-    short_name: "lto"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTLinuxUBSanVptr"
-    category: "ToT Linux"
-    short_name: "usn"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTAndroid"
-    category: "ToT Android"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTAndroid (dbg)"
-    category: "ToT Android"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTAndroid x64"
-    category: "ToT Android"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTAndroid64"
-    category: "ToT Android"
-    short_name: "a64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTAndroidASan"
-    category: "ToT Android"
-    short_name: "asn"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTAndroidCFI"
-    category: "ToT Android"
-    short_name: "cfi"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTAndroidOfficial"
-    category: "ToT Android"
-    short_name: "off"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTMac"
-    category: "ToT Mac"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chrome.ci/ToTMacOfficial"
-    category: "ToT Mac"
-    short_name: "ofi"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTMac (dbg)"
-    category: "ToT Mac"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTMacASan"
-    category: "ToT Mac"
-    short_name: "asn"
-  }
-  builders {
-    name: "buildbucket/luci.chrome.ci/ToTWin"
-    category: "ToT Windows"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chrome.ci/ToTWinOfficial"
-    category: "ToT Windows"
-    short_name: "ofi"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTWin(dbg)"
-    category: "ToT Windows"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTWin(dll)"
-    category: "ToT Windows"
-    short_name: "dll"
-  }
-  builders {
-    name: "buildbucket/luci.chrome.ci/ToTWin64"
-    category: "ToT Windows|x64"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTWin64(dbg)"
-    category: "ToT Windows|x64"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTWin64(dll)"
-    category: "ToT Windows|x64"
-    short_name: "dll"
-  }
-  builders {
-    name: "buildbucket/luci.chrome.ci/ToTWinThinLTO64"
-    category: "ToT Windows|x64"
-    short_name: "lto"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTWinLibcxx64"
-    category: "ToT Windows|x64"
-    short_name: "cxx"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/CrWinAsan"
-    category: "ToT Windows|Asan"
-    short_name: "asn"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/CrWinAsan(dll)"
-    category: "ToT Windows|Asan"
-    short_name: "dll"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTWinASanLibfuzzer"
-    category: "ToT Windows|Asan"
-    short_name: "fuz"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/linux-win_cross-rel"
-    category: "ToT Windows"
-    short_name: "lxw"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTLinuxCoverage"
-    category: "ToT Code Coverage"
-    short_name: "linux"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTMacCoverage"
-    category: "ToT Code Coverage"
-    short_name: "mac"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/CFI Linux CF"
-    category: "CFI|Linux"
-    short_name: "CF"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/CFI Linux ToT"
-    category: "CFI|Linux"
-    short_name: "ToT"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTWinCFI"
-    category: "CFI|Win"
-    short_name: "x86"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTWinCFI64"
-    category: "CFI|Win"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTiOS"
-    category: "iOS"
-    short_name: "sim"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/ToTiOSDevice"
-    category: "iOS"
-    short_name: "dev"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/UBSanVptr Linux"
-    short_name: "usn"
-  }
-}
-
-
-consoles {
-  header_id: "chromium"
   id: "chromium.fyi.goma"
   name: "chromium.fyi.goma"
   repo_url: "https://chromium.googlesource.com/chromium/src"
@@ -4553,9 +4332,6 @@
     name: "buildbucket/luci.chromium.try/linux-angle-rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux_angle_dbg_ng"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux_angle_deqp_rel_ng"
   }
   builders {
@@ -4565,26 +4341,11 @@
     name: "buildbucket/luci.chromium.try/mac-angle-rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/mac_angle_dbg_ng"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/win-angle-rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/win_angle_dbg_ng"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/win_angle_deqp_rel_ng"
   }
-  builders {
-    name: "buildbucket/luci.chromium.try/win_angle_x64_dbg_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try/win_angle_x64_deqp_rel_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try/win_angle_x64_rel_ng"
-  }
   builder_view_only: true
 }
 
@@ -4818,9 +4579,6 @@
     name: "buildbucket/luci.chromium.try/linux_android_dbg_ng"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux_angle_dbg_ng"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux_angle_deqp_rel_ng"
   }
   builders {
@@ -4942,9 +4700,6 @@
     name: "buildbucket/luci.chromium.try/mac-rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/mac_angle_dbg_ng"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/mac_chromium_10.10_macviews"
   }
   builders {
@@ -5010,21 +4765,9 @@
     name: "buildbucket/luci.chromium.try/win-jumbo-rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/win_angle_dbg_ng"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/win_angle_deqp_rel_ng"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/win_angle_x64_dbg_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try/win_angle_x64_deqp_rel_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try/win_angle_x64_rel_ng"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/win_archive"
   }
   builders {
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
index d538318..712a6e2 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
@@ -151,13 +151,13 @@
       kSelectedTabHistogramName, TabUsageRecorder::IN_MEMORY, 1, failureBlock);
 
   // Evict the tab.
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
 
   GREYAssertTrue(chrome_test_util::IsIncognitoMode(),
                  @"Failed to switch to incognito mode");
 
   // Switch back to the normal tabs. Should be on tab one.
-  CHROME_EG_ASSERT_ON_ERROR(SwitchToNormalMode());
+  CHROME_EG_ASSERT_NO_ERROR(SwitchToNormalMode());
 
   [ChromeEarlGrey waitForWebViewContainingText:kURL1FirstWord];
 
@@ -219,11 +219,11 @@
   // Evict the tab. Create a dummy tab so that switching back to normal mode
   // does not trigger a reload immediately.
   [ChromeEarlGrey openNewTab];
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
   [ChromeEarlGrey waitForIncognitoTabCount:1];
 
   // Switch back to the normal tabs. Should be on tab one.
-  CHROME_EG_ASSERT_ON_ERROR(SwitchToNormalMode());
+  CHROME_EG_ASSERT_NO_ERROR(SwitchToNormalMode());
 
   chrome_test_util::SelectTabAtIndexInCurrentMode(0);
   [ChromeEarlGrey waitForWebViewContainingText:kURL1FirstWord];
@@ -258,13 +258,13 @@
                  @"Fail to state tabs as cold start tabs");
 
   // Open two incognito tabs with urls, clearing normal tabs from memory.
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
 
   [ChromeEarlGrey waitForIncognitoTabCount:2];
 
   // Switch back to the normal tabs.
-  CHROME_EG_ASSERT_ON_ERROR(SwitchToNormalMode());
+  CHROME_EG_ASSERT_NO_ERROR(SwitchToNormalMode());
 
   [ChromeEarlGrey waitForWebViewContainingText:kURL2FirstWord];
 
@@ -314,13 +314,13 @@
                  @"Fail to simulate tab backgrounding.");
 
   // Open incognito and clear normal tabs from memory.
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
   GREYAssertTrue(chrome_test_util::IsIncognitoMode(),
                  @"Failed to switch to incognito mode");
   histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 0, failureBlock);
 
   // Switch back to the normal tabs.
-  CHROME_EG_ASSERT_ON_ERROR(SwitchToNormalMode());
+  CHROME_EG_ASSERT_NO_ERROR(SwitchToNormalMode());
 
   [ChromeEarlGrey waitForWebViewContainingText:kURL2FirstWord];
 
@@ -352,8 +352,8 @@
   [ChromeEarlGrey closeAllTabsInCurrentMode];
   GURL URL = web::test::HttpServer::MakeUrl(kTestUrl1);
   NewMainTabWithURL(URL, kURL1FirstWord);
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
-  CHROME_EG_ASSERT_ON_ERROR(SwitchToNormalMode());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(SwitchToNormalMode());
 
   [ChromeEarlGrey waitForWebViewContainingText:kURL1FirstWord];
   [ChromeEarlGrey waitForMainTabCount:1];
@@ -386,7 +386,7 @@
   [ChromeEarlGrey openNewTab];
   [ChromeEarlGrey openNewTab];
   chrome_test_util::LoadUrl(slowURL);
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
 
   web::test::SetUpHttpServer(std::make_unique<web::DelayedResponseProvider>(
       std::make_unique<HtmlResponseProvider>(responses), kSlowURLDelay));
@@ -438,7 +438,7 @@
 
   NewMainTabWithURL(slowURL, "Slow");
 
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
   web::test::SetUpHttpServer(std::make_unique<web::DelayedResponseProvider>(
       std::make_unique<HtmlResponseProvider>(responses), kSlowURLDelay));
 
@@ -488,8 +488,8 @@
   };
 
   NewMainTabWithURL(slowURL, responses[slowURL]);
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
-  CHROME_EG_ASSERT_ON_ERROR(SwitchToNormalMode());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(SwitchToNormalMode());
 
   [ChromeEarlGreyUI openSettingsMenu];
   [ChromeEarlGreyUI tapSettingsMenuButton:SettingsMenuPrivacyButton()];
@@ -518,7 +518,7 @@
   [ChromeEarlGrey openNewTab];
   chrome_test_util::LoadUrl(slowURL);
 
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
 
   web::test::SetUpHttpServer(std::make_unique<web::DelayedResponseProvider>(
       std::make_unique<HtmlResponseProvider>(responses), kSlowURLDelay));
@@ -608,8 +608,8 @@
 
   NSUInteger tabIndex = chrome_test_util::GetMainTabCount() - 1;
   [ChromeEarlGrey openNewTab];
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
-  CHROME_EG_ASSERT_ON_ERROR(SwitchToNormalMode());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(SwitchToNormalMode());
 
   chrome_test_util::SelectTabAtIndexInCurrentMode(tabIndex);
   [ChromeEarlGrey waitForWebViewContainingText:"arrived"];
@@ -656,8 +656,8 @@
   [ChromeEarlGrey waitForWebViewContainingText:"Whee"];
   NSUInteger tabIndex = chrome_test_util::GetMainTabCount() - 1;
   [ChromeEarlGrey openNewTab];
-  CHROME_EG_ASSERT_ON_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
-  CHROME_EG_ASSERT_ON_ERROR(SwitchToNormalMode());
+  CHROME_EG_ASSERT_NO_ERROR(OpenNewIncognitoTabUsingUIAndEvictMainTabs());
+  CHROME_EG_ASSERT_NO_ERROR(SwitchToNormalMode());
 
   chrome_test_util::SelectTabAtIndexInCurrentMode(tabIndex);
   [ChromeEarlGrey waitForWebViewContainingText:"Whee"];
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_test_util.mm b/ios/chrome/browser/metrics/tab_usage_recorder_test_util.mm
index 9a1e59cc..038bc1e0 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder_test_util.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder_test_util.mm
@@ -21,8 +21,8 @@
 #import "ios/chrome/test/app/tab_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
-#import "ios/chrome/test/earl_grey/chrome_error_util.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
+#import "ios/testing/nserror_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -73,7 +73,7 @@
   bool success = base::test::ios::WaitUntilConditionOrTimeout(
       kWaitElementTimeout, condition);
   if (!success) {
-    return chrome_test_util::NSErrorWithLocalizedDescription(
+    return testing::NSErrorWithLocalizedDescription(
         @"Waiting switch to incognito mode.");
   }
 
@@ -83,13 +83,13 @@
 
 NSError* SwitchToNormalMode() {
   if (!chrome_test_util::IsIncognitoMode()) {
-    return chrome_test_util::NSErrorWithLocalizedDescription(
+    return testing::NSErrorWithLocalizedDescription(
         @"Switching to normal mode is only allowed from Incognito.");
   }
 
   // Enter the tab grid to switch modes.
   if (!ShowTabSwitcher()) {
-    return chrome_test_util::NSErrorWithLocalizedDescription(
+    return testing::NSErrorWithLocalizedDescription(
         @"Tab switcher could not be tapped.");
   }
 
@@ -113,7 +113,7 @@
 
   if (!base::test::ios::WaitUntilConditionOrTimeout(kWaitElementTimeout,
                                                     condition)) {
-    return chrome_test_util::NSErrorWithLocalizedDescription(
+    return testing::NSErrorWithLocalizedDescription(
         @"Waiting switch to normal mode.");
   }
 
diff --git a/ios/chrome/browser/metrics/ukm_egtest.mm b/ios/chrome/browser/metrics/ukm_egtest.mm
index 24b5896..d2288d6 100644
--- a/ios/chrome/browser/metrics/ukm_egtest.mm
+++ b/ios/chrome/browser/metrics/ukm_egtest.mm
@@ -200,7 +200,7 @@
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
       performAction:grey_tap()];
 
-  CHROME_EG_ASSERT_ON_ERROR([SigninEarlGreyUtils checkSignedOut]);
+  CHROME_EG_ASSERT_NO_ERROR([SigninEarlGreyUtils checkSignedOut]);
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/overlays/BUILD.gn b/ios/chrome/browser/overlays/BUILD.gn
index b1e55f3..168ebc6e 100644
--- a/ios/chrome/browser/overlays/BUILD.gn
+++ b/ios/chrome/browser/overlays/BUILD.gn
@@ -40,6 +40,7 @@
   testonly = true
   sources = [
     "overlay_manager_impl_unittest.mm",
+    "overlay_request_impl_unittest.cc",
     "overlay_request_queue_impl_unittest.mm",
     "overlay_request_unittest.cc",
     "overlay_response_unittest.cc",
diff --git a/ios/chrome/browser/overlays/README.md b/ios/chrome/browser/overlays/README.md
index 20ba31d..6ccea4e9 100644
--- a/ios/chrome/browser/overlays/README.md
+++ b/ios/chrome/browser/overlays/README.md
@@ -87,6 +87,17 @@
     OverlayRequest::CreateWithConfig<AlertConfig>(
         "alert title", "message text");
 
+A callback can be added to the request to use the response info:
+
+    OverlayCallback callback =
+        base::BindOnce(base::RetainBlock(^(OverlayResponse* response) {
+      if (!response)
+        return;
+      AlertInfo* info = response->GetInfo<AlertInfo>();
+      /* Handle button tap at info->tapped\_button\_index() */
+    }));
+    request->set_callback(std::move(callback));
+
 Manager clients can then supply this request to the OverlayManager for
 scheduling over the web content area:
 
diff --git a/ios/chrome/browser/overlays/overlay_request_impl.cc b/ios/chrome/browser/overlays/overlay_request_impl.cc
index bf767fdb..b76d06b 100644
--- a/ios/chrome/browser/overlays/overlay_request_impl.cc
+++ b/ios/chrome/browser/overlays/overlay_request_impl.cc
@@ -12,10 +12,10 @@
 }
 
 OverlayRequestImpl::OverlayRequestImpl() {}
-OverlayRequestImpl::~OverlayRequestImpl() {}
 
-base::SupportsUserData* OverlayRequestImpl::data() {
-  return this;
+OverlayRequestImpl::~OverlayRequestImpl() {
+  if (!callback_.is_null())
+    std::move(callback_).Run(response());
 }
 
 void OverlayRequestImpl::set_response(
@@ -26,3 +26,12 @@
 OverlayResponse* OverlayRequestImpl::response() const {
   return response_.get();
 }
+
+void OverlayRequestImpl::set_callback(OverlayCallback callback) {
+  DCHECK(callback_.is_null());
+  callback_ = std::move(callback);
+}
+
+base::SupportsUserData* OverlayRequestImpl::data() {
+  return this;
+}
diff --git a/ios/chrome/browser/overlays/overlay_request_impl.h b/ios/chrome/browser/overlays/overlay_request_impl.h
index 652218c..bc452d4 100644
--- a/ios/chrome/browser/overlays/overlay_request_impl.h
+++ b/ios/chrome/browser/overlays/overlay_request_impl.h
@@ -16,15 +16,18 @@
   OverlayRequestImpl();
   ~OverlayRequestImpl() override;
 
- private:
   // OverlayRequest:
   void set_response(std::unique_ptr<OverlayResponse> response) override;
   OverlayResponse* response() const override;
+  void set_callback(OverlayCallback callback) override;
   base::SupportsUserData* data() override;
 
+ private:
   // The response containing the user interaction information for the overlay
   // resulting from this response.
   std::unique_ptr<OverlayResponse> response_;
+  // The callback to be executed upon dismissal of the overlay.
+  OverlayCallback callback_;
 };
 
 #endif  // IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_REQUEST_IMPL_H_
diff --git a/ios/chrome/browser/overlays/overlay_request_impl_unittest.cc b/ios/chrome/browser/overlays/overlay_request_impl_unittest.cc
new file mode 100644
index 0000000..823dc3c8
--- /dev/null
+++ b/ios/chrome/browser/overlays/overlay_request_impl_unittest.cc
@@ -0,0 +1,33 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/overlays/overlay_request_impl.h"
+
+#include "base/bind.h"
+#include "ios/chrome/browser/overlays/public/overlay_response.h"
+#include "ios/chrome/browser/overlays/test/fake_overlay_user_data.h"
+#include "testing/platform_test.h"
+
+using OverlayRequestImplTest = PlatformTest;
+
+// Tests that OverlayRequestImpls execute their callbacks upon destruction.
+TEST_F(OverlayRequestImplTest, ExecuteCallback) {
+  void* kResponseData = &kResponseData;
+  std::unique_ptr<OverlayRequest> request =
+      OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr);
+  OverlayRequestImpl* request_impl =
+      static_cast<OverlayRequestImpl*>(request.get());
+  __block bool callback_executed = false;
+  OverlayCallback callback =
+      base::BindOnce(base::RetainBlock(^(OverlayResponse* response) {
+        callback_executed =
+            response &&
+            response->GetInfo<FakeOverlayUserData>()->value() == kResponseData;
+      }));
+  request_impl->set_callback(std::move(callback));
+  request->set_response(
+      OverlayResponse::CreateWithInfo<FakeOverlayUserData>(kResponseData));
+  request = nullptr;
+  EXPECT_TRUE(callback_executed);
+}
diff --git a/ios/chrome/browser/overlays/public/overlay_request.h b/ios/chrome/browser/overlays/public/overlay_request.h
index b6efcfc..6c34fda 100644
--- a/ios/chrome/browser/overlays/public/overlay_request.h
+++ b/ios/chrome/browser/overlays/public/overlay_request.h
@@ -7,14 +7,20 @@
 
 #include <memory>
 
+#include "base/callback.h"
 #include "base/supports_user_data.h"
 
 class OverlayResponse;
 
+// Callback for OverlayRequests.  If an overlay requires a completion block to
+// be executed after its UI is dismissed, OverlayManager clients can provide a
+// callback that uses the OverlayResponse provided to the request.  |response|
+// may be null if no response has been provided.
+typedef base::OnceCallback<void(OverlayResponse* response)> OverlayCallback;
+
 // Model object used to track overlays requested for OverlayManager.
 class OverlayRequest {
  public:
-  OverlayRequest() = default;
   virtual ~OverlayRequest() = default;
 
   // Creates an OverlayRequest configured with an OverlayUserData of type
@@ -48,7 +54,14 @@
   // UI resulting from this request.
   virtual OverlayResponse* response() const = 0;
 
- private:
+  // Setter for the callback.  Provided callbacks are guaranteed to be executed,
+  // either upon dismissal of the request's corresponding overlay UI or upon
+  // cancellation of the request.
+  virtual void set_callback(OverlayCallback callback) = 0;
+
+ protected:
+  OverlayRequest() = default;
+
   // Creates an unconfigured OverlayRequest.
   static std::unique_ptr<OverlayRequest> Create();
 
diff --git a/ios/chrome/browser/overlays/public/overlay_response.h b/ios/chrome/browser/overlays/public/overlay_response.h
index 9b63f433..8b48bc1 100644
--- a/ios/chrome/browser/overlays/public/overlay_response.h
+++ b/ios/chrome/browser/overlays/public/overlay_response.h
@@ -13,7 +13,6 @@
 // UI.
 class OverlayResponse {
  public:
-  OverlayResponse() = default;
   virtual ~OverlayResponse() = default;
 
   // Creates an OverlayResponse with an OverlayUserData of type InfoType.
@@ -39,7 +38,9 @@
     return InfoType::FromUserData(data());
   }
 
- private:
+ protected:
+  OverlayResponse() = default;
+
   // Creates an OverlayResponse with no info attached to it.
   static std::unique_ptr<OverlayResponse> Create();
 
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index 58a89b9b..65bc0955 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -167,6 +167,7 @@
     "//google_apis",
     "//ios/chrome/browser/autofill",
     "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/passwords/test",
     "//ios/chrome/browser/ssl",
     "//ios/chrome/browser/ui/autofill:autofill",
     "//ios/chrome/browser/ui/commands",
diff --git a/ios/chrome/browser/passwords/credential_manager_unittest.mm b/ios/chrome/browser/passwords/credential_manager_unittest.mm
index 65d4ae9..b29ac5c 100644
--- a/ios/chrome/browser/passwords/credential_manager_unittest.mm
+++ b/ios/chrome/browser/passwords/credential_manager_unittest.mm
@@ -9,13 +9,9 @@
 #include "base/bind.h"
 #include "base/mac/foundation_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/password_manager/core/browser/password_manager.h"
-#include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/test_password_store.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
 #include "ios/chrome/browser/passwords/credential_manager_util.h"
+#import "ios/chrome/browser/passwords/test/test_password_manager_client.h"
 #include "ios/chrome/browser/ssl/ios_security_state_tab_helper.h"
 #include "ios/web/public/navigation_item.h"
 #include "ios/web/public/navigation_manager.h"
@@ -25,7 +21,6 @@
 #include "net/ssl/ssl_connection_status_flags.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/origin.h"
 
@@ -33,10 +28,6 @@
 #error "This file requires ARC support."
 #endif
 
-using password_manager::PasswordStore;
-using password_manager::PasswordManager;
-using password_manager::PasswordFormManagerForUI;
-using password_manager::TestPasswordStore;
 using testing::_;
 using url::Origin;
 
@@ -58,102 +49,6 @@
 // SSL certificate to load for testing.
 constexpr char kCertFileName[] = "ok_cert.pem";
 
-// Mocks PasswordManagerClient, used indirectly by CredentialManager.
-class MockPasswordManagerClient
-    : public password_manager::StubPasswordManagerClient {
- public:
-  MockPasswordManagerClient()
-      : last_committed_url_(kHttpsWebOrigin), password_manager_(this) {
-    store_ = base::MakeRefCounted<TestPasswordStore>();
-    store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
-    prefs_ = std::make_unique<TestingPrefServiceSimple>();
-    prefs_->registry()->RegisterBooleanPref(
-        password_manager::prefs::kCredentialsEnableAutosignin, true);
-    prefs_->registry()->RegisterBooleanPref(
-        password_manager::prefs::kWasAutoSignInFirstRunExperienceShown, true);
-  }
-
-  // PasswordManagerClient:
-  MOCK_METHOD0(OnCredentialManagerUsed, bool());
-
-  // PromptUserTo*Ptr functions allow to both override PromptUserTo* methods
-  // and expect calls.
-  MOCK_METHOD1(PromptUserToSavePasswordPtr, void(PasswordFormManagerForUI*));
-  MOCK_METHOD3(PromptUserToChooseCredentialsPtr,
-               bool(const std::vector<autofill::PasswordForm*>& local_forms,
-                    const GURL& origin,
-                    const CredentialsCallback& callback));
-
-  scoped_refptr<TestPasswordStore> password_store() const { return store_; }
-  void set_password_store(scoped_refptr<TestPasswordStore> store) {
-    store_ = store;
-  }
-
-  PasswordFormManagerForUI* pending_manager() const { return manager_.get(); }
-
-  void set_current_url(const GURL& current_url) {
-    last_committed_url_ = current_url;
-  }
-
- private:
-  // PasswordManagerClient:
-  PrefService* GetPrefs() const override { return prefs_.get(); }
-  PasswordStore* GetPasswordStore() const override { return store_.get(); }
-  const PasswordManager* GetPasswordManager() const override {
-    return &password_manager_;
-  }
-  const GURL& GetLastCommittedEntryURL() const override {
-    return last_committed_url_;
-  }
-  // Stores |manager| into |manager_|. Save() should be
-  // called manually in test. To put expectation on this function being called,
-  // use PromptUserToSavePasswordPtr.
-  bool PromptUserToSaveOrUpdatePassword(
-      std::unique_ptr<PasswordFormManagerForUI> manager,
-      bool update_password) override;
-  // Mocks choosing a credential by the user. To put expectation on this
-  // function being called, use PromptUserToChooseCredentialsPtr.
-  bool PromptUserToChooseCredentials(
-      std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
-      const GURL& origin,
-      const CredentialsCallback& callback) override;
-
-  std::unique_ptr<TestingPrefServiceSimple> prefs_;
-  GURL last_committed_url_;
-  PasswordManager password_manager_;
-  std::unique_ptr<PasswordFormManagerForUI> manager_;
-  scoped_refptr<TestPasswordStore> store_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient);
-};
-
-bool MockPasswordManagerClient::PromptUserToSaveOrUpdatePassword(
-    std::unique_ptr<PasswordFormManagerForUI> manager,
-    bool update_password) {
-  EXPECT_FALSE(update_password);
-  manager_.swap(manager);
-  PromptUserToSavePasswordPtr(manager_.get());
-  return true;
-}
-
-bool MockPasswordManagerClient::PromptUserToChooseCredentials(
-    std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
-    const GURL& origin,
-    const CredentialsCallback& callback) {
-  EXPECT_FALSE(local_forms.empty());
-  const autofill::PasswordForm* form = local_forms[0].get();
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(callback, base::Owned(new autofill::PasswordForm(*form))));
-  std::vector<autofill::PasswordForm*> raw_forms(local_forms.size());
-  std::transform(local_forms.begin(), local_forms.end(), raw_forms.begin(),
-                 [](const std::unique_ptr<autofill::PasswordForm>& form) {
-                   return form.get();
-                 });
-  PromptUserToChooseCredentialsPtr(raw_forms, origin, callback);
-  return true;
-}
-
 }  // namespace
 
 class CredentialManagerBaseTest
@@ -204,7 +99,7 @@
   void SetUp() override {
     CredentialManagerBaseTest::SetUp();
 
-    client_ = std::make_unique<MockPasswordManagerClient>();
+    client_ = std::make_unique<TestPasswordManagerClient>();
     manager_ = std::make_unique<CredentialManager>(client_.get(), web_state());
 
     // Inject JavaScript and set up secure context.
@@ -256,7 +151,7 @@
   }
 
  protected:
-  std::unique_ptr<MockPasswordManagerClient> client_;
+  std::unique_ptr<TestPasswordManagerClient> client_;
   std::unique_ptr<CredentialManager> manager_;
 
   autofill::PasswordForm password_credential_form_1_;
diff --git a/ios/chrome/browser/passwords/test/BUILD.gn b/ios/chrome/browser/passwords/test/BUILD.gn
new file mode 100644
index 0000000..96843d1
--- /dev/null
+++ b/ios/chrome/browser/passwords/test/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("test") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+
+  sources = [
+    "test_password_manager_client.h",
+    "test_password_manager_client.mm",
+  ]
+
+  deps = [
+    "//components/password_manager/core/browser:test_support",
+    "//components/password_manager/core/common",
+    "//components/prefs",
+    "//components/prefs:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/passwords/test/test_password_manager_client.h b/ios/chrome/browser/passwords/test/test_password_manager_client.h
new file mode 100644
index 0000000..eefa1a1f
--- /dev/null
+++ b/ios/chrome/browser/passwords/test/test_password_manager_client.h
@@ -0,0 +1,78 @@
+// 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 IOS_CHROME_BROWSER_PASSWORDS_TEST_TEST_PASSWORD_MANAGER_CLIENT_H_
+#define IOS_CHROME_BROWSER_PASSWORDS_TEST_TEST_PASSWORD_MANAGER_CLIENT_H_
+
+#include "components/password_manager/core/browser/stub_password_manager_client.h"
+
+#include "components/password_manager/core/browser/password_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace password_manager {
+class PasswordFormManagerForUI;
+class TestPasswordStore;
+class PasswordStore;
+}  // namespace password_manager
+class TestingPrefServiceSimple;
+
+using password_manager::PasswordFormManagerForUI;
+using password_manager::PasswordManager;
+using password_manager::PasswordStore;
+using password_manager::TestPasswordStore;
+
+// Test PasswordManagerClient.
+class TestPasswordManagerClient
+    : public password_manager::StubPasswordManagerClient {
+ public:
+  TestPasswordManagerClient();
+  ~TestPasswordManagerClient() override;
+
+  // PasswordManagerClient:
+  MOCK_METHOD0(OnCredentialManagerUsed, bool());
+
+  // PromptUserTo*Ptr functions allow to both override PromptUserTo* methods
+  // and expect calls.
+  MOCK_METHOD1(PromptUserToSavePasswordPtr, void(PasswordFormManagerForUI*));
+  MOCK_METHOD3(PromptUserToChooseCredentialsPtr,
+               bool(const std::vector<autofill::PasswordForm*>& local_forms,
+                    const GURL& origin,
+                    const CredentialsCallback& callback));
+
+  scoped_refptr<TestPasswordStore> password_store() const;
+  void set_password_store(scoped_refptr<TestPasswordStore> store);
+
+  PasswordFormManagerForUI* pending_manager() const;
+
+  void set_current_url(const GURL& current_url);
+
+ private:
+  // PasswordManagerClient:
+  PrefService* GetPrefs() const override;
+  PasswordStore* GetPasswordStore() const override;
+  const PasswordManager* GetPasswordManager() const override;
+  const GURL& GetLastCommittedEntryURL() const override;
+  // Stores |manager| into |manager_|. Save() should be
+  // called manually in test. To put expectation on this function being called,
+  // use PromptUserToSavePasswordPtr.
+  bool PromptUserToSaveOrUpdatePassword(
+      std::unique_ptr<PasswordFormManagerForUI> manager,
+      bool update_password) override;
+  // Mocks choosing a credential by the user. To put expectation on this
+  // function being called, use PromptUserToChooseCredentialsPtr.
+  bool PromptUserToChooseCredentials(
+      std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
+      const GURL& origin,
+      const CredentialsCallback& callback) override;
+
+  std::unique_ptr<TestingPrefServiceSimple> prefs_;
+  GURL last_committed_url_;
+  PasswordManager password_manager_;
+  std::unique_ptr<PasswordFormManagerForUI> manager_;
+  scoped_refptr<TestPasswordStore> store_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestPasswordManagerClient);
+};
+
+#endif  // IOS_CHROME_BROWSER_PASSWORDS_TEST_TEST_PASSWORD_MANAGER_CLIENT_H_
diff --git a/ios/chrome/browser/passwords/test/test_password_manager_client.mm b/ios/chrome/browser/passwords/test/test_password_manager_client.mm
new file mode 100644
index 0000000..39fe3330
--- /dev/null
+++ b/ios/chrome/browser/passwords/test/test_password_manager_client.mm
@@ -0,0 +1,95 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/passwords/test/test_password_manager_client.h"
+
+#include "components/password_manager/core/browser/test_password_store.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// HTTPS origin corresponding to kHostName.
+constexpr char kHttpsWebOrigin[] = "https://www.example.com/";
+}  // namespace
+
+TestPasswordManagerClient::TestPasswordManagerClient()
+    : last_committed_url_(kHttpsWebOrigin), password_manager_(this) {
+  store_ = base::MakeRefCounted<TestPasswordStore>();
+  store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
+  prefs_ = std::make_unique<TestingPrefServiceSimple>();
+  prefs_->registry()->RegisterBooleanPref(
+      password_manager::prefs::kCredentialsEnableAutosignin, true);
+  prefs_->registry()->RegisterBooleanPref(
+      password_manager::prefs::kWasAutoSignInFirstRunExperienceShown, true);
+}
+
+TestPasswordManagerClient::~TestPasswordManagerClient() = default;
+
+scoped_refptr<TestPasswordStore> TestPasswordManagerClient::password_store()
+    const {
+  return store_;
+}
+
+void TestPasswordManagerClient::set_password_store(
+    scoped_refptr<TestPasswordStore> store) {
+  store_ = store;
+}
+
+PasswordFormManagerForUI* TestPasswordManagerClient::pending_manager() const {
+  return manager_.get();
+}
+
+void TestPasswordManagerClient::set_current_url(const GURL& current_url) {
+  last_committed_url_ = current_url;
+}
+
+// Private Methods
+
+PrefService* TestPasswordManagerClient::GetPrefs() const {
+  return prefs_.get();
+}
+
+PasswordStore* TestPasswordManagerClient::GetPasswordStore() const {
+  return store_.get();
+}
+
+const PasswordManager* TestPasswordManagerClient::GetPasswordManager() const {
+  return &password_manager_;
+}
+
+const GURL& TestPasswordManagerClient::GetLastCommittedEntryURL() const {
+  return last_committed_url_;
+}
+
+bool TestPasswordManagerClient::PromptUserToSaveOrUpdatePassword(
+    std::unique_ptr<PasswordFormManagerForUI> manager,
+    bool update_password) {
+  EXPECT_FALSE(update_password);
+  manager_.swap(manager);
+  PromptUserToSavePasswordPtr(manager_.get());
+  return true;
+}
+
+bool TestPasswordManagerClient::PromptUserToChooseCredentials(
+    std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
+    const GURL& origin,
+    const CredentialsCallback& callback) {
+  EXPECT_FALSE(local_forms.empty());
+  const autofill::PasswordForm* form = local_forms[0].get();
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(callback, base::Owned(new autofill::PasswordForm(*form))));
+  std::vector<autofill::PasswordForm*> raw_forms(local_forms.size());
+  std::transform(local_forms.begin(), local_forms.end(), raw_forms.begin(),
+                 [](const std::unique_ptr<autofill::PasswordForm>& form) {
+                   return form.get();
+                 });
+  PromptUserToChooseCredentialsPtr(raw_forms, origin, callback);
+  return true;
+}
diff --git a/ios/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_ios.h b/ios/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_ios.h
index bcc9e0f..ba386076 100644
--- a/ios/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_ios.h
+++ b/ios/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_ios.h
@@ -12,11 +12,17 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/send_tab_to_self/send_tab_to_self_model.h"
 #include "components/send_tab_to_self/send_tab_to_self_model_observer.h"
+#import "ios/chrome/browser/web_state_list/web_state_list_observer.h"
+#import "ios/web/public/web_state/web_state_observer.h"
 
 namespace ios {
 class ChromeBrowserState;
 }
 
+namespace web {
+class WebState;
+}
+
 namespace send_tab_to_self {
 class SendTabToSelfEntry;
 class SendTabToSelfModel;
@@ -24,12 +30,15 @@
 // Service that listens for SendTabToSelf model changes and calls UI
 // handlers to update the UI accordingly.
 class SendTabToSelfClientServiceIOS : public KeyedService,
-                                      public SendTabToSelfModelObserver {
+                                      public SendTabToSelfModelObserver,
+                                      public WebStateListObserver,
+                                      public web::WebStateObserver {
  public:
   SendTabToSelfClientServiceIOS(ios::ChromeBrowserState* browser_state,
                                 SendTabToSelfModel* model);
   ~SendTabToSelfClientServiceIOS() override;
 
+  // SendTabToSelfModelObserver::
   // Keeps track of when the model is loaded so that updates to the
   // model can be pushed afterwards.
   void SendTabToSelfModelLoaded() override;
@@ -41,13 +50,41 @@
   // registered through ReceivingUIRegistry.
   void EntriesRemovedRemotely(const std::vector<std::string>& guids) override;
 
+  // WebStateListObserver::
+  void WebStateActivatedAt(WebStateList* web_state_list,
+                           web::WebState* old_web_state,
+                           web::WebState* new_web_state,
+                           int active_index,
+                           int reason) override;
+
+  // WebStateObserver::
+  void WasShown(web::WebState* web_state) override;
+  void WebStateDestroyed(web::WebState* web_state) override;
+
  private:
+  // Display an infobar for |entry| on the specified |web_state|.
+  void DisplayInfoBar(web::WebState* web_state,
+                      const SendTabToSelfEntry* entry);
+
+  // Stop observing the WebState and WebStateList and reset associated
+  // variables.
+  void CleanUpObserversAndVariables();
+
   // Owned by the SendTabToSelfSyncService which should outlive this class
   SendTabToSelfModel* model_;
 
   // The current browser state. Must outlive this object.
   ios::ChromeBrowserState* browser_state_;
 
+  // The pending SendTabToSelf entry to display an InfoBar for.
+  const SendTabToSelfEntry* entry_ = nullptr;
+
+  // The WebStateList that is being observed.
+  WebStateList* web_state_list_ = nullptr;
+
+  // The WebState that is being observed.
+  web::WebState* web_state_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(SendTabToSelfClientServiceIOS);
 };
 
diff --git a/ios/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_ios.mm b/ios/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_ios.mm
index 52dc7e0..c30858f 100644
--- a/ios/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_ios.mm
+++ b/ios/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_ios.mm
@@ -40,6 +40,16 @@
 SendTabToSelfClientServiceIOS::~SendTabToSelfClientServiceIOS() {
   model_->RemoveObserver(this);
   model_ = nullptr;
+
+  if (web_state_list_) {
+    web_state_list_->RemoveObserver(this);
+    web_state_list_ = nullptr;
+  }
+
+  if (web_state_) {
+    web_state_->RemoveObserver(this);
+    web_state_ = nullptr;
+  }
 }
 
 void SendTabToSelfClientServiceIOS::SendTabToSelfModelLoaded() {
@@ -69,24 +79,37 @@
     return;
   }
 
-  // If there is no web state or it is not visible, we cannot add an infobar to
-  // it.
-  // TODO(crbug.com/944602): Wait until a web state is active and add the info
-  // bar then.
   web::WebState* web_state = web_state_list->GetActiveWebState();
   if (!web_state || !web_state->IsVisible()) {
-    NOTIMPLEMENTED();
+    // If the active WebState is not visible it means the user is in the
+    // Tab Grid screen or a Settings page. Register as an observer of the
+    // active WebState and WebStateList in order to be notified if the WebState
+    // becomes visible again, or if the user changes tab or creates a new tab.
+    if (web_state) {
+      web_state_ = web_state;
+      web_state_->AddObserver(this);
+    }
+
+    if (!web_state_list_ || web_state_list_ != web_state_list) {
+      if (web_state_list_) {
+        web_state_list_->RemoveObserver(this);
+      }
+      web_state_list_ = web_state_list;
+      web_state_list_->AddObserver(this);
+    }
+
+    // Pick the most recent entry since only one Infobar can be shown at a time.
+    // TODO(crbug.com/944602): Create a function that returns the most recently
+    // shared entry.
+    entry_ = new_entries.back();
+
     return;
   }
 
-  infobars::InfoBarManager* infobar_manager =
-      InfoBarManagerImpl::FromWebState(web_state);
-
   // Since we can only show one infobar at the time, pick the most recent entry.
   // TODO(crbug.com/944602): Create a function that returns the most recently
   // shared entry.
-  infobar_manager->AddInfoBar(CreateConfirmInfoBar(
-      IOSSendTabToSelfInfoBarDelegate::Create(new_entries.back())));
+  DisplayInfoBar(web_state, new_entries.back());
 }
 
 void SendTabToSelfClientServiceIOS::EntriesRemovedRemotely(
@@ -97,4 +120,68 @@
   NOTIMPLEMENTED();
 }
 
+void SendTabToSelfClientServiceIOS::WebStateActivatedAt(
+    WebStateList* web_state_list,
+    web::WebState* old_web_state,
+    web::WebState* new_web_state,
+    int active_index,
+    int reason) {
+  DCHECK(entry_);
+
+  // This can happen if the user close the last tab in the tab picker.
+  if (!new_web_state) {
+    return;
+  }
+
+  DisplayInfoBar(new_web_state, entry_);
+
+  CleanUpObserversAndVariables();
+}
+
+void SendTabToSelfClientServiceIOS::WasShown(web::WebState* web_state) {
+  DCHECK(entry_);
+  DCHECK(web_state_);
+
+  DisplayInfoBar(web_state_, entry_);
+
+  CleanUpObserversAndVariables();
+}
+
+void SendTabToSelfClientServiceIOS::WebStateDestroyed(
+    web::WebState* web_state) {
+  DCHECK(web_state_);
+  DCHECK(web_state_ == web_state);
+
+  web_state_->RemoveObserver(this);
+  web_state_ = nullptr;
+}
+
+void SendTabToSelfClientServiceIOS::DisplayInfoBar(
+    web::WebState* web_state,
+    const SendTabToSelfEntry* entry) {
+  infobars::InfoBarManager* infobar_manager =
+      InfoBarManagerImpl::FromWebState(web_state);
+
+  if (!infobar_manager) {
+    return;
+  }
+
+  infobar_manager->AddInfoBar(
+      CreateConfirmInfoBar(IOSSendTabToSelfInfoBarDelegate::Create(entry)));
+}
+
+void SendTabToSelfClientServiceIOS::CleanUpObserversAndVariables() {
+  DCHECK(web_state_list_);
+
+  entry_ = nullptr;
+
+  web_state_list_->RemoveObserver(this);
+  web_state_list_ = nullptr;
+
+  if (web_state_) {
+    web_state_->RemoveObserver(this);
+    web_state_ = nullptr;
+  }
+}
+
 }  // namespace send_tab_to_self
diff --git a/ios/chrome/browser/ui/authentication/signin_earlgrey_utils.mm b/ios/chrome/browser/ui/authentication/signin_earlgrey_utils.mm
index 5072da3c..bf5eb4272 100644
--- a/ios/chrome/browser/ui/authentication/signin_earlgrey_utils.mm
+++ b/ios/chrome/browser/ui/authentication/signin_earlgrey_utils.mm
@@ -11,8 +11,8 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
-#import "ios/chrome/test/earl_grey/chrome_error_util.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h"
+#import "ios/testing/nserror_util.h"
 #include "services/identity/public/cpp/identity_manager.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -41,7 +41,7 @@
 
 + (NSError*)checkSignedInWithIdentity:(ChromeIdentity*)identity {
   if (identity == nil) {
-    return chrome_test_util::NSErrorWithLocalizedDescription(
+    return testing::NSErrorWithLocalizedDescription(
         @"Need to give an identity");
   }
 
@@ -62,7 +62,7 @@
                       @"Unexpected Gaia ID of the signed in user [expected = "
                       @"\"%@\", actual = \"%s\"]",
                       identity.gaiaID, info.gaia.c_str()];
-    return chrome_test_util::NSErrorWithLocalizedDescription(errorStr);
+    return testing::NSErrorWithLocalizedDescription(errorStr);
   }
 
   return nil;
@@ -79,7 +79,7 @@
 
   if (IdentityManagerFactory::GetForBrowserState(browser_state)
           ->HasPrimaryAccount()) {
-    return chrome_test_util::NSErrorWithLocalizedDescription(
+    return testing::NSErrorWithLocalizedDescription(
         @"Unexpected signed in user");
   }
 
diff --git a/ios/chrome/browser/ui/first_run/first_run_egtest.mm b/ios/chrome/browser/ui/first_run/first_run_egtest.mm
index e14f3da..6a7222b 100644
--- a/ios/chrome/browser/ui/first_run/first_run_egtest.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_egtest.mm
@@ -222,7 +222,7 @@
   [[EarlGrey selectElementWithMatcher:AccountConsistencySetupSigninButton()]
       performAction:grey_tap()];
 
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity]);
 
   // Undo the sign-in and dismiss the Sign In screen.
@@ -232,7 +232,7 @@
       performAction:grey_tap()];
 
   // |identity| shouldn't be signed in.
-  CHROME_EG_ASSERT_ON_ERROR([SigninEarlGreyUtils checkSignedOut]);
+  CHROME_EG_ASSERT_NO_ERROR([SigninEarlGreyUtils checkSignedOut]);
 }
 
 // Signs in to an account and then taps the Advanced link to go to settings.
@@ -275,7 +275,7 @@
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
       performAction:grey_tap()];
 
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity]);
 
   GREYAssertTrue(sync_service->HasFinishedInitialSetup(),
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm
index 8cbe1656..88a3216 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm
@@ -97,7 +97,7 @@
       "http://ios/testing/data/http_server_files/two_pages.pdf");
   [ChromeEarlGrey loadURL:URL];
 
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 
   // Initial y scroll positions are set to make room for the toolbar.
   // TODO(crbug.com/618887) Replace use of specific values when API which
@@ -138,12 +138,12 @@
       selectElementWithMatcher:WebViewScrollView(
                                    chrome_test_util::GetCurrentWebState())]
       performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 
   // Test that the toolbar is still visible even after attempting to hide it
   // on swipe up.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 
   // Reenable synchronization.
   if (@available(iOS 12, *)) {
@@ -172,18 +172,18 @@
 
   // Test that the toolbar is hidden after a user swipes up.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
 
   // Test that the toolbar is visible after a user swipes down.
   [[EarlGrey
       selectElementWithMatcher:WebViewScrollView(
                                    chrome_test_util::GetCurrentWebState())]
       performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 
   // Test that the toolbar is hidden after a user swipes up.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
 }
 
 // Tests that link clicks from a chrome:// to chrome:// link result in the
@@ -227,12 +227,12 @@
 
   // Scroll to hide the UI.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
 
   // Test that the toolbar is visible when moving from one chrome:// link to
   // another chrome:// link.
   GREYAssert(TapWebViewElementWithId("version"), @"Failed to tap \"version\"");
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 }
 
 // Tests hiding and showing of the header with a user scroll on a long page.
@@ -245,16 +245,16 @@
   web::test::SetUpSimpleHttpServer(responses);
 
   [ChromeEarlGrey loadURL:URL];
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
   // Simulate a user scroll down.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
   // Simulate a user scroll up.
   [[EarlGrey
       selectElementWithMatcher:WebViewScrollView(
                                    chrome_test_util::GetCurrentWebState())]
       performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 }
 
 // Tests that reloading of a page shows the header even if it was not shown
@@ -275,12 +275,12 @@
 
   // Hide the toolbar.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
 
   GREYAssert(TapWebViewElementWithId("link"), @"Failed to tap \"link\"");
 
   // Main test is here: Make sure the header is still visible!
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 }
 
 // Test to make sure the header is shown when a Tab opened by the current Tab is
@@ -316,7 +316,7 @@
 
   // Hide the toolbar.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
 
   // Open new window.
   GREYAssert(TapWebViewElementWithId("link1"), @"Failed to tap \"link1\"");
@@ -329,7 +329,7 @@
 
   // Hide the toolbar.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
 
   // Close the tab by tapping link2.
   NSError* error = nil;
@@ -349,7 +349,7 @@
 
   // Make sure the toolbar is on the screen.
   [ChromeEarlGrey waitForMainTabCount:1];
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 }
 
 // Tests that the header is shown when a regular page (non-native page) is
@@ -379,24 +379,24 @@
   [ChromeEarlGrey waitForWebViewContainingText:"link1"];
   // Dismiss the toolbar.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
 
   // Navigate to the other page.
   GREYAssert(TapWebViewElementWithId("link1"), @"Failed to tap \"link1\"");
   [ChromeEarlGrey waitForWebViewContainingText:"link2"];
 
   // Make sure toolbar is shown since a new load has started.
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 
   // Dismiss the toolbar.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
 
   // Go back.
   GREYAssert(TapWebViewElementWithId("link2"), @"Failed to tap \"link2\"");
 
   // Make sure the toolbar has loaded now that a new page has loaded.
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 }
 
 // Tests that the header is shown when a native page is loaded from a page where
@@ -418,13 +418,13 @@
 
   // Dismiss the toolbar.
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
 
   // Go back to NTP, which is a native view.
   GREYAssert(TapWebViewElementWithId("link"), @"Failed to tap \"link\"");
 
   // Make sure the toolbar is visible now that a new page has loaded.
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 }
 
 // Tests that the header is shown when loading an error page in a native view
@@ -445,11 +445,11 @@
 
   [ChromeEarlGrey loadURL:URL];
   HideToolbarUsingUI();
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:NO]);
 
   GREYAssert(TapWebViewElementWithId("link"), @"Failed to tap \"link\"");
   AssertURLIs(ErrorPageResponseProvider::GetDnsFailureUrl());
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
 }
 
 @end
diff --git a/ios/chrome/browser/ui/payments/payment_request_accessibility_egtest.mm b/ios/chrome/browser/ui/payments/payment_request_accessibility_egtest.mm
index 74d06cd7..7b806459 100644
--- a/ios/chrome/browser/ui/payments/payment_request_accessibility_egtest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_accessibility_egtest.mm
@@ -103,14 +103,14 @@
   [super setUp];
 
   _profile = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:_profile]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:_profile]);
 
   _creditCard1 = autofill::test::GetCreditCard();
   _creditCard1.set_billing_address_id(_profile.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:_creditCard1]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:_creditCard1]);
 
   _creditCard2 = autofill::test::GetCreditCard2();
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:_creditCard2]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:_creditCard2]);
 
   [ChromeEarlGrey
       loadURL:web::test::HttpServer::MakeUrl(kPaymentRequestDemoPage)];
diff --git a/ios/chrome/browser/ui/payments/payment_request_can_make_payment_egtest.mm b/ios/chrome/browser/ui/payments/payment_request_can_make_payment_egtest.mm
index 53ab6ca..ca0e51e 100644
--- a/ios/chrome/browser/ui/payments/payment_request_can_make_payment_egtest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_can_make_payment_egtest.mm
@@ -56,7 +56,7 @@
 
 // Tests canMakePayment() when visa is required and user has a visa instrument.
 - (void)testCanMakePaymentIsSupported {
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [self addCreditCard:autofill::test::GetCreditCard()]);  // visa.
   [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kCanMakePaymentPage)];
 
@@ -68,7 +68,7 @@
 // Tests canMakePayment() when visa is required, user has a visa instrument, and
 // user is in incognito mode.
 - (void)testCanMakePaymentIsSupportedInIncognitoMode {
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [self addCreditCard:autofill::test::GetCreditCard()]);  // visa.
   // Open an Incognito tab.
   [ChromeEarlGreyUI openToolsMenu];
@@ -119,7 +119,7 @@
   PrefService* prefs = chrome_test_util::GetOriginalBrowserState()->GetPrefs();
   prefs->SetBoolean(payments::kCanMakePaymentEnabled, false);
 
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [self addCreditCard:autofill::test::GetCreditCard()]);  // visa.
 
   [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kCanMakePaymentPage)];
@@ -137,7 +137,7 @@
   PrefService* prefs = chrome_test_util::GetOriginalBrowserState()->GetPrefs();
   prefs->SetBoolean(payments::kCanMakePaymentEnabled, false);
 
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [self addCreditCard:autofill::test::GetCreditCard()]);  // visa.
 
   // Open an Incognito tab.
@@ -203,7 +203,7 @@
       waitForWebViewContainingTexts:
           {"NotAllowedError", "Not allowed to check whether can make payment"}];
 
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [self addCreditCard:autofill::test::GetCreditCard()]);  // visa.
 
   // Query visa payment method.
@@ -269,7 +269,7 @@
       waitForWebViewContainingTexts:
           {"NotAllowedError", "Not allowed to check whether can make payment"}];
 
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [self addCreditCard:autofill::test::GetCreditCard()]);  // visa.
 
   // Query basic-card payment method with "supportedNetworks": ["visa"] in the
diff --git a/ios/chrome/browser/ui/payments/payment_request_cancel_pay_abort_egtest.mm b/ios/chrome/browser/ui/payments/payment_request_cancel_pay_abort_egtest.mm
index 6837b9b..4dd64e0 100644
--- a/ios/chrome/browser/ui/payments/payment_request_cancel_pay_abort_egtest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_cancel_pay_abort_egtest.mm
@@ -169,11 +169,11 @@
 // Promise returned by response.complete() with an appropriate response message.
 - (void)testOpenAndPay {
   autofill::AutofillProfile profile = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:profile]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:profile]);
 
   autofill::CreditCard card = autofill::test::GetCreditCard();
   card.set_billing_address_id(profile.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:card]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:card]);
 
   [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kNoShippingPage)];
 
diff --git a/ios/chrome/browser/ui/payments/payment_request_debit_egtest.mm b/ios/chrome/browser/ui/payments/payment_request_debit_egtest.mm
index 1d0faee9..e0c6c65e 100644
--- a/ios/chrome/browser/ui/payments/payment_request_debit_egtest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_debit_egtest.mm
@@ -77,7 +77,7 @@
   [super setUp];
   _profile = std::make_unique<autofill::AutofillProfile>(
       autofill::test::GetFullProfile());
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:*_profile]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:*_profile]);
 
   // Allow canMakePayment to return a truthful value by default.
   PrefService* prefs = chrome_test_util::GetOriginalBrowserState()->GetPrefs();
@@ -181,7 +181,7 @@
   // All local cards have "unknown" card type by design.
   autofill::CreditCard card = autofill::test::GetCreditCard();
   card.set_billing_address_id(_profile->guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:card]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:card]);
 
   [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kDebitPage)];
 
diff --git a/ios/chrome/browser/ui/payments/payment_request_egtest_base.mm b/ios/chrome/browser/ui/payments/payment_request_egtest_base.mm
index b5fe95b..0bb82f6 100644
--- a/ios/chrome/browser/ui/payments/payment_request_egtest_base.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_egtest_base.mm
@@ -21,8 +21,8 @@
 #include "ios/chrome/browser/payments/ios_payment_request_cache_factory.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
-#import "ios/chrome/test/earl_grey/chrome_error_util.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
+#import "ios/testing/nserror_util.h"
 #import "ios/web/public/test/http_server/http_server.h"
 #import "ios/web/public/test/web_view_interaction_test_util.h"
 
@@ -93,8 +93,7 @@
                    [self personalDataManager] -> GetProfiles().size();
       });
   if (!isProfileAdded) {
-    return chrome_test_util::NSErrorWithLocalizedDescription(
-        @"Failed to add profile.");
+    return testing::NSErrorWithLocalizedDescription(@"Failed to add profile.");
   }
   return nil;
 }
@@ -109,7 +108,7 @@
                    [self personalDataManager] -> GetCreditCards().size();
       });
   if (!isCreditCardAdded) {
-    return chrome_test_util::NSErrorWithLocalizedDescription(
+    return testing::NSErrorWithLocalizedDescription(
         @"Failed to add credit card.");
   }
   return nil;
diff --git a/ios/chrome/browser/ui/payments/payment_request_journey_logger_egtest.mm b/ios/chrome/browser/ui/payments/payment_request_journey_logger_egtest.mm
index df81be2..7c85bca 100644
--- a/ios/chrome/browser/ui/payments/payment_request_journey_logger_egtest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_journey_logger_egtest.mm
@@ -38,22 +38,22 @@
 
 - (void)addProfiles {
   _profile1 = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:_profile1]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:_profile1]);
 
   _profile2 = autofill::test::GetFullProfile2();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:_profile2]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:_profile2]);
 }
 
 - (void)addCard1 {
   _creditCard1 = autofill::test::GetCreditCard();
   _creditCard1.set_billing_address_id(_profile1.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:_creditCard1]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:_creditCard1]);
 }
 
 - (void)addCard2 {
   _creditCard2 = autofill::test::GetCreditCard2();
   _creditCard2.set_billing_address_id(_profile2.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:_creditCard2]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:_creditCard2]);
 }
 
 #pragma mark - Tests
diff --git a/ios/chrome/browser/ui/payments/payment_request_modifiers_egtest.mm b/ios/chrome/browser/ui/payments/payment_request_modifiers_egtest.mm
index b19a1b7..455e23c 100644
--- a/ios/chrome/browser/ui/payments/payment_request_modifiers_egtest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_modifiers_egtest.mm
@@ -81,13 +81,13 @@
 
 - (void)addProfile {
   _profile = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:_profile]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:_profile]);
 }
 
 - (void)addLocalCard {
   _localCard = autofill::test::GetCreditCard();  // Visa.
   _localCard.set_billing_address_id(_profile.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:_localCard]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:_localCard]);
 }
 
 - (void)addServerCardWithType:(autofill::CreditCard::CardType)cardType {
diff --git a/ios/chrome/browser/ui/payments/payment_request_payment_response_egtest.mm b/ios/chrome/browser/ui/payments/payment_request_payment_response_egtest.mm
index b29f691..132e867 100644
--- a/ios/chrome/browser/ui/payments/payment_request_payment_response_egtest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_payment_response_egtest.mm
@@ -63,10 +63,10 @@
 - (void)testPaymentResponseNoShipping {
   // Create a billing address and a card that uses it.
   autofill::AutofillProfile billingAddress = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:billingAddress]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:billingAddress]);
   autofill::CreditCard card = autofill::test::GetCreditCard();  // visa
   card.set_billing_address_id(billingAddress.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:card]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:card]);
 
   [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kNoShippingPage)];
 
@@ -124,16 +124,16 @@
 - (void)testPaymentResponseFreeShipping {
   // Create a billing address and a card that uses it.
   autofill::AutofillProfile billingAddress = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:billingAddress]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:billingAddress]);
   autofill::CreditCard card = autofill::test::GetCreditCard();  // visa
   card.set_billing_address_id(billingAddress.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:card]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:card]);
 
   // Create a shipping address with a higher frecency score, so that it is
   // selected as the default shipping address.
   autofill::AutofillProfile shippingAddress = autofill::test::GetFullProfile2();
   shippingAddress.set_use_count(2000);
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:shippingAddress]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:shippingAddress]);
 
   [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kFreeShippingPage)];
 
@@ -183,11 +183,11 @@
 - (void)testPaymentResponseAllContactDetails {
   // Create a billing address and a card that uses it.
   autofill::AutofillProfile billingAddress = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:billingAddress]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:billingAddress]);
 
   autofill::CreditCard card = autofill::test::GetCreditCard();  // visa
   card.set_billing_address_id(billingAddress.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:card]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:card]);
 
   [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kContactDetailsPage)];
 
@@ -219,11 +219,11 @@
 - (void)testPaymentResponseOneContactDetail {
   // Create a billing address and a card that uses it.
   autofill::AutofillProfile billingAddress = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:billingAddress]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:billingAddress]);
 
   autofill::CreditCard card = autofill::test::GetCreditCard();  // visa
   card.set_billing_address_id(billingAddress.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:card]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:card]);
 
   [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kRequestEmailPage)];
 
diff --git a/ios/chrome/browser/ui/payments/payment_request_show_egtest.mm b/ios/chrome/browser/ui/payments/payment_request_show_egtest.mm
index 607c793..b33ef4074 100644
--- a/ios/chrome/browser/ui/payments/payment_request_show_egtest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_show_egtest.mm
@@ -50,11 +50,11 @@
   [super setUp];
 
   autofill::AutofillProfile profile = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:profile]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:profile]);
 
   autofill::CreditCard localCard = autofill::test::GetCreditCard();  // Visa.
   localCard.set_billing_address_id(profile.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:localCard]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:localCard]);
 }
 
 #pragma mark - Tests
diff --git a/ios/chrome/browser/ui/payments/payment_request_use_stats_egtest.mm b/ios/chrome/browser/ui/payments/payment_request_use_stats_egtest.mm
index 7514b06..361e571 100644
--- a/ios/chrome/browser/ui/payments/payment_request_use_stats_egtest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_use_stats_egtest.mm
@@ -59,10 +59,10 @@
 // Sets up a credit card with an associated billing address.
 - (void)setUpCreditCard {
   autofill::AutofillProfile billingAddress = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:billingAddress]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:billingAddress]);
   autofill::CreditCard card = autofill::test::GetCreditCard();  // visa
   card.set_billing_address_id(billingAddress.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:card]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:card]);
 }
 
 // Completes the Payment Request.
@@ -96,11 +96,11 @@
 
   // Setup a credit card with an associated billing address.
   autofill::AutofillProfile billingAddress = autofill::test::GetFullProfile();
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:billingAddress]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:billingAddress]);
 
   autofill::CreditCard card = autofill::test::GetCreditCard();  // visa
   card.set_billing_address_id(billingAddress.guid());
-  CHROME_EG_ASSERT_ON_ERROR([self addCreditCard:card]);
+  CHROME_EG_ASSERT_NO_ERROR([self addCreditCard:card]);
 
   // Check that the initial use stats were set correctly.
   autofill::CreditCard* initialCard =
@@ -143,7 +143,7 @@
   // selected as the default shipping address.
   autofill::AutofillProfile shippingAddress = autofill::test::GetFullProfile2();
   shippingAddress.set_use_count(3);
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:shippingAddress]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:shippingAddress]);
 
   // Check that the initial use stats were set correctly.
   autofill::AutofillProfile* initialShipping =
@@ -175,7 +175,7 @@
   // selected as the default shipping address.
   autofill::AutofillProfile contactAddress = autofill::test::GetFullProfile2();
   contactAddress.set_use_count(3);
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:contactAddress]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:contactAddress]);
 
   // Check that the initial use stats were set correctly.
   autofill::AutofillProfile* initialContact =
@@ -207,7 +207,7 @@
   // the default shipping and contact address.
   autofill::AutofillProfile multiAddress = autofill::test::GetFullProfile2();
   multiAddress.set_use_count(3);
-  CHROME_EG_ASSERT_ON_ERROR([self addAutofillProfile:multiAddress]);
+  CHROME_EG_ASSERT_NO_ERROR([self addAutofillProfile:multiAddress]);
 
   // Check that the initial use stats were set correctly.
   autofill::AutofillProfile* initialAddress =
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
index 1e336318c..292b8e35 100644
--- a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
@@ -79,7 +79,7 @@
 
   [[EarlGrey selectElementWithMatcher:PrimarySignInButton()]
       assertWithMatcher:grey_sufficientlyVisible()];
-  CHROME_EG_ASSERT_ON_ERROR([SigninEarlGreyUtils checkSignedOut]);
+  CHROME_EG_ASSERT_NO_ERROR([SigninEarlGreyUtils checkSignedOut]);
 
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
       performAction:grey_tap()];
@@ -105,7 +105,7 @@
 
   [[EarlGrey selectElementWithMatcher:PrimarySignInButton()]
       assertWithMatcher:grey_sufficientlyVisible()];
-  CHROME_EG_ASSERT_ON_ERROR([SigninEarlGreyUtils checkSignedOut]);
+  CHROME_EG_ASSERT_NO_ERROR([SigninEarlGreyUtils checkSignedOut]);
 
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
       performAction:grey_tap()];
@@ -138,7 +138,7 @@
                                    grey_accessibilityLabel(identity2.userEmail),
                                    grey_sufficientlyVisible(), nil)]
       assertWithMatcher:grey_nil()];
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity1]);
 
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
@@ -178,7 +178,7 @@
                                    grey_accessibilityLabel(identity2.userEmail),
                                    grey_sufficientlyVisible(), nil)]
       assertWithMatcher:grey_nil()];
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity1]);
 
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
@@ -205,7 +205,7 @@
   // Check that the user is signed out and the Main Settings screen is shown.
   [[EarlGrey selectElementWithMatcher:PrimarySignInButton()]
       assertWithMatcher:grey_sufficientlyVisible()];
-  CHROME_EG_ASSERT_ON_ERROR([SigninEarlGreyUtils checkSignedOut]);
+  CHROME_EG_ASSERT_NO_ERROR([SigninEarlGreyUtils checkSignedOut]);
 
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
       performAction:grey_tap()];
@@ -234,7 +234,7 @@
   [[EarlGrey selectElementWithMatcher:chrome_test_util::
                                           SettingsAccountsCollectionView()]
       assertWithMatcher:grey_sufficientlyVisible()];
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity]);
 
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
diff --git a/ios/chrome/browser/ui/settings/signin_settings_egtest.mm b/ios/chrome/browser/ui/settings/signin_settings_egtest.mm
index 05f208f2..abe03b30 100644
--- a/ios/chrome/browser/ui/settings/signin_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/signin_settings_egtest.mm
@@ -63,7 +63,7 @@
   [SigninEarlGreyUI confirmSigninConfirmationDialog];
 
   // User signed in.
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity]);
   [SigninEarlGreyUI checkSigninPromoNotVisible];
   [[EarlGrey selectElementWithMatcher:SettingsAccountButton()]
@@ -84,7 +84,7 @@
   [SigninEarlGreyUI confirmSigninConfirmationDialog];
 
   // User signed in.
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity]);
   [SigninEarlGreyUI checkSigninPromoNotVisible];
   [[EarlGrey selectElementWithMatcher:SettingsAccountButton()]
diff --git a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
index 14c8e61a..e1b124c 100644
--- a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
+++ b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
@@ -87,7 +87,7 @@
   [SigninEarlGreyUI signinWithIdentity:identity];
 
   // Check |identity| is signed-in.
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity]);
 }
 
@@ -123,7 +123,7 @@
   [[EarlGrey selectElementWithMatcher:matcher] performAction:grey_tap()];
 
   // Check the signed-in user did change.
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity2]);
 
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
@@ -163,7 +163,7 @@
       performAction:grey_tap()];
 
   // Check the signed-in user did change.
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity2]);
 
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
@@ -194,7 +194,7 @@
   SetEarlGreySynchronizationEnabled(YES);
 
   [SigninEarlGreyUI confirmSigninConfirmationDialog];
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:managed_identity]);
 
   // Switch Sync account to |identity|.
@@ -211,7 +211,7 @@
   TapButtonWithLabelId(IDS_IOS_MANAGED_SWITCH_ACCEPT_BUTTON);
   SetEarlGreySynchronizationEnabled(YES);
 
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity]);
 
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
@@ -246,7 +246,7 @@
       performAction:grey_tap()];
 
   // Check that there is no signed in user.
-  CHROME_EG_ASSERT_ON_ERROR([SigninEarlGreyUtils checkSignedOut]);
+  CHROME_EG_ASSERT_NO_ERROR([SigninEarlGreyUtils checkSignedOut]);
 }
 
 // Tests that signing out of a managed account from the Settings works
@@ -269,7 +269,7 @@
   SetEarlGreySynchronizationEnabled(YES);
 
   [SigninEarlGreyUI confirmSigninConfirmationDialog];
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity]);
 
   // Go to Accounts Settings and tap the sign out button.
@@ -290,7 +290,7 @@
       performAction:grey_tap()];
 
   // Check that there is no signed in user.
-  CHROME_EG_ASSERT_ON_ERROR([SigninEarlGreyUtils checkSignedOut]);
+  CHROME_EG_ASSERT_NO_ERROR([SigninEarlGreyUtils checkSignedOut]);
 }
 
 // Tests that signing in, tapping the Settings link on the confirmation screen
@@ -323,7 +323,7 @@
           IDS_IOS_SETTINGS_TITLE);
   [[EarlGrey selectElementWithMatcher:settings_matcher]
       assertWithMatcher:grey_notVisible()];
-  CHROME_EG_ASSERT_ON_ERROR(
+  CHROME_EG_ASSERT_NO_ERROR(
       [SigninEarlGreyUtils checkSignedInWithIdentity:identity]);
 }
 
@@ -436,7 +436,7 @@
       onElementWithMatcher:chrome_test_util::SettingsAccountsCollectionView()]
       performAction:grey_tap()];
   TapButtonWithLabelId(IDS_IOS_DISCONNECT_DIALOG_CONTINUE_BUTTON_MOBILE);
-  CHROME_EG_ASSERT_ON_ERROR([SigninEarlGreyUtils checkSignedOut]);
+  CHROME_EG_ASSERT_NO_ERROR([SigninEarlGreyUtils checkSignedOut]);
   [[EarlGrey selectElementWithMatcher:SecondarySignInButton()]
       performAction:grey_tap()];
   [SigninEarlGreyUI selectIdentityWithEmail:identity1.userEmail];
@@ -461,7 +461,7 @@
   TapButtonWithLabelId(IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SKIP_BUTTON);
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
       performAction:grey_tap()];
-  CHROME_EG_ASSERT_ON_ERROR([SigninEarlGreyUtils checkSignedOut]);
+  CHROME_EG_ASSERT_NO_ERROR([SigninEarlGreyUtils checkSignedOut]);
 }
 
 // Opens the sign in screen from the bookmarks and then cancel it by tapping on
diff --git a/ios/chrome/browser/web/progress_indicator_egtest.mm b/ios/chrome/browser/web/progress_indicator_egtest.mm
index 50743f1..73c94cd 100644
--- a/ios/chrome/browser/web/progress_indicator_egtest.mm
+++ b/ios/chrome/browser/web/progress_indicator_egtest.mm
@@ -197,7 +197,7 @@
   [[EarlGrey selectElementWithMatcher:ProgressViewWithProgress(0.5)]
       assertWithMatcher:grey_sufficientlyVisible()];
 
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
   infinitePendingProvider->Abort();
 }
 
@@ -237,7 +237,7 @@
   [[EarlGrey selectElementWithMatcher:ProgressViewWithProgress(0.5)]
       assertWithMatcher:grey_sufficientlyVisible()];
 
-  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
+  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGreyUI waitForToolbarVisible:YES]);
   infinitePendingProvider->Abort();
 }
 
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index 9a82b3f4..b599c19 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -231,7 +231,6 @@
     "chrome_earl_grey_ui.h",
     "chrome_earl_grey_ui.mm",
     "chrome_error_util.h",
-    "chrome_error_util.mm",
     "chrome_matchers.h",
     "chrome_matchers.mm",
     "chrome_matchers_app_interface.h",
@@ -282,6 +281,7 @@
 
   public_deps = [
     "//build/config/ios:xctest",
+    "//ios/testing:nserror_support",
     "//ios/third_party/earl_grey:earl_grey+link",
     "//ios/third_party/gtx:gtx+link",
     "//ios/web/public/test",
@@ -317,8 +317,6 @@
   sources = [
     "chrome_actions_app_interface.h",
     "chrome_actions_app_interface.mm",
-    "chrome_error_util.h",
-    "chrome_error_util.mm",
     "chrome_matchers_app_interface.h",
     "chrome_matchers_app_interface.mm",
   ]
@@ -345,6 +343,7 @@
     "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/test/app:test_support",
+    "//ios/testing:nserror_support",
     "//ios/testing/earl_grey:eg_app_support+eg2",
     "//ios/testing/earl_grey:eg_app_support+eg2",
     "//ios/third_party/earl_grey2:app_framework+link",
@@ -368,7 +367,6 @@
     "chrome_actions.mm",
     "chrome_actions_app_interface.h",
     "chrome_error_util.h",
-    "chrome_error_util.mm",
     "chrome_matchers.h",
     "chrome_matchers.mm",
     "chrome_matchers_app_interface.h",
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm b/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
index 3c16bea8..48e5c87b 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
@@ -19,8 +19,8 @@
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #include "ios/chrome/test/app/navigation_test_util.h"
-#import "ios/chrome/test/earl_grey/chrome_error_util.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
+#import "ios/testing/nserror_util.h"
 #import "ios/web/public/test/earl_grey/js_test_util.h"
 #import "ios/web/public/test/earl_grey/web_view_matchers.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -219,7 +219,7 @@
 
   if (!base::test::ios::WaitUntilConditionOrTimeout(
           kWaitForToolbarAnimationTimeout, condition)) {
-    return chrome_test_util::NSErrorWithLocalizedDescription(errorMessage);
+    return testing::NSErrorWithLocalizedDescription(errorMessage);
   }
 
   return nil;
diff --git a/ios/chrome/test/earl_grey/chrome_error_util.h b/ios/chrome/test/earl_grey/chrome_error_util.h
index 4f9422e8..53b65e80 100644
--- a/ios/chrome/test/earl_grey/chrome_error_util.h
+++ b/ios/chrome/test/earl_grey/chrome_error_util.h
@@ -5,14 +5,11 @@
 #ifndef IOS_CHROME_TEST_EARL_GREY_CHROME_ERROR_UTIL_H_
 #define IOS_CHROME_TEST_EARL_GREY_CHROME_ERROR_UTIL_H_
 
-@class NSError;
-@class NSString;
-
 // Wraps an expression that returns an NSError*, asserting if an error is
 // returned. Used in EG test code to assert if app helpers fail. For example:
-//  CHROME_EG_ASSERT_ON_ERROR(helperReturningNSError());
-//  CHROME_EG_ASSERT_ON_ERROR([ChromeEarlGrey helperReturningNSError]);
-#define CHROME_EG_ASSERT_ON_ERROR(expression)                           \
+//  CHROME_EG_ASSERT_NO_ERROR(helperReturningNSError());
+//  CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGrey helperReturningNSError]);
+#define CHROME_EG_ASSERT_NO_ERROR(expression)                           \
   {                                                                     \
     NSError* error = expression;                                        \
     GREYAssert(error == nil || [error isKindOfClass:[NSError class]],   \
@@ -20,12 +17,4 @@
     GREYAssertNil(error, error.localizedDescription);                   \
   }
 
-namespace chrome_test_util {
-
-// Returns a NSError with generic domain and error code, and the provided string
-// as localizedDescription.
-NSError* NSErrorWithLocalizedDescription(NSString* error_description);
-
-}  // namespace chrome_test_util
-
 #endif  // IOS_CHROME_TEST_EARL_GREY_CHROME_ERROR_UTIL_H_
diff --git a/ios/testing/BUILD.gn b/ios/testing/BUILD.gn
index 8962a84..4495a6f 100644
--- a/ios/testing/BUILD.gn
+++ b/ios/testing/BUILD.gn
@@ -12,6 +12,15 @@
   ]
 }
 
+source_set("nserror_support") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "nserror_util.h",
+    "nserror_util.mm",
+  ]
+}
+
 source_set("embedded_test_server_support") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
diff --git a/ios/testing/nserror_util.h b/ios/testing/nserror_util.h
new file mode 100644
index 0000000..c66401a19
--- /dev/null
+++ b/ios/testing/nserror_util.h
@@ -0,0 +1,19 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_TESTING_NSERROR_UTIL_H_
+#define IOS_TESTING_NSERROR_UTIL_H_
+
+@class NSError;
+@class NSString;
+
+namespace testing {
+
+// Returns a NSError with generic domain and error code, and the provided string
+// as localizedDescription.
+NSError* NSErrorWithLocalizedDescription(NSString* error_description);
+
+}  // namespace testing
+
+#endif  // IOS_TESTING_NSERROR_UTIL_H_
diff --git a/ios/chrome/test/earl_grey/chrome_error_util.mm b/ios/testing/nserror_util.mm
similarity index 83%
rename from ios/chrome/test/earl_grey/chrome_error_util.mm
rename to ios/testing/nserror_util.mm
index 1d9207bd..1df0bc6 100644
--- a/ios/chrome/test/earl_grey/chrome_error_util.mm
+++ b/ios/testing/nserror_util.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/test/earl_grey/chrome_error_util.h"
+#import "ios/testing/nserror_util.h"
 
 #import <Foundation/Foundation.h>
 
@@ -10,7 +10,7 @@
 #error "This file requires ARC support."
 #endif
 
-namespace chrome_test_util {
+namespace testing {
 
 NSError* NSErrorWithLocalizedDescription(NSString* error_description) {
   NSDictionary* userInfo = @{
@@ -22,4 +22,4 @@
                                 userInfo:userInfo];
 }
 
-}  // namespace chrome_test_util
+}  // namespace testing
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index df79706..5fd32e6c 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -333,6 +333,7 @@
   sources = [
     "net/cert_host_pair_unittest.cc",
     "net/cert_policy_unittest.cc",
+    "net/cookies/crw_wk_http_cookie_store_unittest.mm",
     "net/cookies/system_cookie_store_util_unittest.mm",
     "net/cookies/wk_cookie_util_unittest.mm",
     "net/cookies/wk_http_system_cookie_store_unittest.mm",
diff --git a/ios/web/net/cookies/BUILD.gn b/ios/web/net/cookies/BUILD.gn
index a6247d3..33c391a 100644
--- a/ios/web/net/cookies/BUILD.gn
+++ b/ios/web/net/cookies/BUILD.gn
@@ -14,6 +14,8 @@
   ]
 
   sources = [
+    "crw_wk_http_cookie_store.h",
+    "crw_wk_http_cookie_store.mm",
     "system_cookie_store_util.mm",
     "wk_cookie_util.h",
     "wk_cookie_util.mm",
diff --git a/ios/web/net/cookies/crw_wk_http_cookie_store.h b/ios/web/net/cookies/crw_wk_http_cookie_store.h
new file mode 100644
index 0000000..5e40617f
--- /dev/null
+++ b/ios/web/net/cookies/crw_wk_http_cookie_store.h
@@ -0,0 +1,42 @@
+// Copyright (c) 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 IOS_WEB_NET_COOKIES_CRW_WK_HTTP_COOKIE_STORE_H_
+#define IOS_WEB_NET_COOKIES_CRW_WK_HTTP_COOKIE_STORE_H_
+
+#import <Foundation/Foundation.h>
+#import <WebKit/WebKit.h>
+
+// A WKHTTPCookieStore wrapper which caches the output of getAllCookies call to
+// use on subsequent calls, while observing the core WKHTTPCookieStore to
+// invalidate the cached copy once the store is updated.
+// This class implements a fix for when WKHTTPCookieStore's getAllCookies method
+// callback is not called bug, see crbug.com/885218 for details.
+// All the methods of CRWWKHTTPCookieStore follow the same rules of the
+// wrapped WKHTTPCookieStore.
+@interface CRWWKHTTPCookieStore : NSObject
+
+// CRWWKHTTPCookieStore will not retain the WKHTTPCookieStore instance, and it
+// will be deleted with the owning WKWebSiteDataStore.
+@property(nonatomic, weak) WKHTTPCookieStore* HTTPCookieStore;
+
+// Fetches all stored cookies. If the store didn't change between calls, this
+// method will return the cached result of the last call.
+// TODO(crbug.com/946171): Remove caching when WKHTTPCookieStore performance bug
+// is fixed.
+- (void)getAllCookies:(void (^)(NSArray<NSHTTPCookie*>*))completionHandler;
+
+// Sets |cookie| to the store, and invokes |completionHandler| after cookie is
+// set.
+- (void)setCookie:(NSHTTPCookie*)cookie
+    completionHandler:(void (^)(void))completionHandler;
+
+// Deletes |cookie| from the store, and invokes |completionHandler| after cookie
+// is deleted.
+- (void)deleteCookie:(NSHTTPCookie*)cookie
+    completionHandler:(void (^)(void))completionHandler;
+
+@end
+
+#endif  // IOS_WEB_NET_COOKIES_CRW_WK_HTTP_COOKIE_STORE_H_
diff --git a/ios/web/net/cookies/crw_wk_http_cookie_store.mm b/ios/web/net/cookies/crw_wk_http_cookie_store.mm
new file mode 100644
index 0000000..1f0f5ab
--- /dev/null
+++ b/ios/web/net/cookies/crw_wk_http_cookie_store.mm
@@ -0,0 +1,93 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/net/cookies/crw_wk_http_cookie_store.h"
+
+#include "base/logging.h"
+#include "ios/web/public/web_thread.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// Prioritizes queued WKHTTPCookieStore completion handlers to run as soon as
+// possible. This function is needed because some of WKHTTPCookieStore methods
+// completion handlers are not called until there is a WKWebView on the view
+// hierarchy.
+void PrioritizeWKHTTPCookieStoreCallbacks() {
+  // TODO(crbug.com/885218): Currently this hack is needed to fix
+  // crbug.com/885218. Remove when the behavior of
+  // [WKHTTPCookieStore getAllCookies:] changes.
+  NSSet* data_types = [NSSet setWithObject:WKWebsiteDataTypeCookies];
+  [[WKWebsiteDataStore defaultDataStore]
+      fetchDataRecordsOfTypes:data_types
+            completionHandler:^(NSArray<WKWebsiteDataRecord*>* records){
+            }];
+}
+}  // namespace
+
+@interface CRWWKHTTPCookieStore () <WKHTTPCookieStoreObserver>
+
+// The last getAllCookies output. Will always be set from the UI
+// thread.
+@property(nonatomic) NSArray<NSHTTPCookie*>* cachedCookies;
+
+@end
+
+@implementation CRWWKHTTPCookieStore
+
+- (void)dealloc {
+  [_HTTPCookieStore removeObserver:self];
+}
+
+- (void)getAllCookies:(void (^)(NSArray<NSHTTPCookie*>*))completionHandler {
+  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  NSArray<NSHTTPCookie*>* result = _HTTPCookieStore ? _cachedCookies : @[];
+  if (result) {
+    dispatch_async(dispatch_get_main_queue(), ^{
+      completionHandler(result);
+    });
+  } else {
+    __weak __typeof(self) weakSelf = self;
+    [_HTTPCookieStore getAllCookies:^(NSArray<NSHTTPCookie*>* cookies) {
+      weakSelf.cachedCookies = cookies;
+      completionHandler(cookies);
+    }];
+    PrioritizeWKHTTPCookieStoreCallbacks();
+  }
+}
+
+- (void)setCookie:(NSHTTPCookie*)cookie
+    completionHandler:(nullable void (^)(void))completionHandler {
+  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  _cachedCookies = nil;
+  [_HTTPCookieStore setCookie:cookie completionHandler:completionHandler];
+}
+
+- (void)deleteCookie:(NSHTTPCookie*)cookie
+    completionHandler:(nullable void (^)(void))completionHandler {
+  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  _cachedCookies = nil;
+  [_HTTPCookieStore deleteCookie:cookie completionHandler:completionHandler];
+}
+
+- (void)setHTTPCookieStore:(WKHTTPCookieStore*)newCookieStore {
+  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  _cachedCookies = nil;
+  if (newCookieStore == _HTTPCookieStore)
+    return;
+  [_HTTPCookieStore removeObserver:self];
+  _HTTPCookieStore = newCookieStore;
+  [_HTTPCookieStore addObserver:self];
+}
+
+#pragma mark WKHTTPCookieStoreObserver method
+
+- (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore*)cookieStore {
+  DCHECK(_HTTPCookieStore == cookieStore);
+  _cachedCookies = nil;
+}
+
+@end
diff --git a/ios/web/net/cookies/crw_wk_http_cookie_store_unittest.mm b/ios/web/net/cookies/crw_wk_http_cookie_store_unittest.mm
new file mode 100644
index 0000000..4d7e9568
--- /dev/null
+++ b/ios/web/net/cookies/crw_wk_http_cookie_store_unittest.mm
@@ -0,0 +1,225 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/net/cookies/crw_wk_http_cookie_store.h"
+
+#import <WebKit/WebKit.h>
+
+#include "base/run_loop.h"
+#import "base/test/ios/wait_util.h"
+#include "ios/net/cookies/cookie_store_ios_test_util.h"
+#include "ios/web/public/test/test_web_thread_bundle.h"
+#include "ios/web/public/test/web_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+#import "third_party/ocmock/gtest_support.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using base::test::ios::WaitUntilConditionOrTimeout;
+using base::test::ios::kWaitForCookiesTimeout;
+
+class CRWWKHTTPCookieStoreTest : public PlatformTest {
+ public:
+  CRWWKHTTPCookieStoreTest()
+      : crw_cookie_store_([[CRWWKHTTPCookieStore alloc] init]) {
+    mock_http_cookie_store_ = OCMPartialMock(CreateDataStore().httpCookieStore);
+    crw_cookie_store_.HTTPCookieStore = mock_http_cookie_store_;
+    NSURL* test_cookie_url = [NSURL URLWithString:@"http://foo.google.com/bar"];
+    test_cookie_1_ = [NSHTTPCookie cookieWithProperties:@{
+      NSHTTPCookiePath : test_cookie_url.path,
+      NSHTTPCookieName : @"test1",
+      NSHTTPCookieValue : @"value1",
+      NSHTTPCookieDomain : test_cookie_url.host,
+    }];
+    test_cookie_2_ = [NSHTTPCookie cookieWithProperties:@{
+      NSHTTPCookiePath : test_cookie_url.path,
+      NSHTTPCookieName : @"test2",
+      NSHTTPCookieValue : @"value2",
+      NSHTTPCookieDomain : test_cookie_url.host,
+    }];
+  }
+
+  // Returns a new WKWebSiteDataStore.
+  WKWebsiteDataStore* CreateDataStore() {
+    WKWebsiteDataStore* data_store =
+        [WKWebsiteDataStore nonPersistentDataStore];
+    // This is needed to force WKWebSiteDataStore to be created, otherwise the
+    // cookie isn't set in some cases.
+    NSSet* data_types = [NSSet setWithObject:WKWebsiteDataTypeCookies];
+    [data_store
+        fetchDataRecordsOfTypes:data_types
+              completionHandler:^(NSArray<WKWebsiteDataRecord*>* records){
+              }];
+    return data_store;
+  }
+
+  // Adds |cookie| to the CRWWKHTTPCookieStore.
+  bool SetCookie(NSHTTPCookie* cookie) WARN_UNUSED_RESULT {
+    __block bool cookie_set = false;
+    [crw_cookie_store_ setCookie:cookie
+               completionHandler:^{
+                 cookie_set = true;
+               }];
+    return WaitUntilConditionOrTimeout(kWaitForCookiesTimeout, ^bool {
+      return cookie_set;
+    });
+  }
+
+  // Deletes |cookie| from the CRWWKHTTPCookieStore.
+  bool DeleteCookie(NSHTTPCookie* cookie) WARN_UNUSED_RESULT {
+    __block bool cookie_deleted = false;
+    [crw_cookie_store_ deleteCookie:cookie
+                  completionHandler:^{
+                    cookie_deleted = true;
+                  }];
+    return WaitUntilConditionOrTimeout(kWaitForCookiesTimeout, ^bool {
+      return cookie_deleted;
+    });
+  }
+
+  // Gets all cookies from CRWWKHTTPCookieStore and ensures that getAllCookies
+  // callback was called.
+  NSArray<NSHTTPCookie*>* GetCookies() WARN_UNUSED_RESULT {
+    __block NSArray<NSHTTPCookie*>* result_cookies = nil;
+    __block bool callback_called = false;
+    [crw_cookie_store_ getAllCookies:^(NSArray<NSHTTPCookie*>* cookies) {
+      callback_called = true;
+      result_cookies = cookies;
+    }];
+    bool success = WaitUntilConditionOrTimeout(kWaitForCookiesTimeout, ^bool {
+      return callback_called;
+    });
+    EXPECT_TRUE(success);
+    return result_cookies;
+  }
+
+ protected:
+  web::TestWebThreadBundle thread_bundle_;
+  CRWWKHTTPCookieStore* crw_cookie_store_;
+  id mock_http_cookie_store_ = nil;
+  NSHTTPCookie* test_cookie_1_ = nil;
+  NSHTTPCookie* test_cookie_2_ = nil;
+};
+
+// Tests that getting cookies are cached correctly for consecutive calls.
+TEST_F(CRWWKHTTPCookieStoreTest, GetCookiesCachedCorrectly) {
+  EXPECT_TRUE(SetCookie(test_cookie_1_));
+
+  OCMExpect([mock_http_cookie_store_ getAllCookies:[OCMArg any]])
+      .andForwardToRealObject();
+  NSArray<NSHTTPCookie*>* result_1 = GetCookies();
+  EXPECT_EQ(1U, result_1.count);
+
+  // Internal getAllCookies shouldn't be called again.
+  [[mock_http_cookie_store_ reject] getAllCookies:[OCMArg any]];
+  NSArray<NSHTTPCookie*>* result_2 = GetCookies();
+
+  // Check that the same exact object is returned.
+  EXPECT_EQ(result_1, result_2);
+  EXPECT_NSEQ(result_1, result_2);
+  EXPECT_OCMOCK_VERIFY(mock_http_cookie_store_);
+}
+
+// Tests that |setCookie:| works correctly and invalidates the cache.
+TEST_F(CRWWKHTTPCookieStoreTest, SetCookie) {
+  // Verify that internal cookie store setCookie method was called.
+  OCMExpect([mock_http_cookie_store_ setCookie:test_cookie_1_
+                             completionHandler:[OCMArg any]])
+      .andForwardToRealObject();
+  EXPECT_TRUE(SetCookie(test_cookie_1_));
+
+  // internal getAllCookies should be called.
+  OCMExpect([mock_http_cookie_store_ getAllCookies:[OCMArg any]])
+      .andForwardToRealObject();
+
+  NSArray<NSHTTPCookie*>* result_1 = GetCookies();
+  // Verify that there is a cookie in the cookie store.
+  EXPECT_EQ(1U, result_1.count);
+
+  // Verify that internal cookie store setCookie method was called.
+  OCMExpect([mock_http_cookie_store_ setCookie:test_cookie_2_
+                             completionHandler:[OCMArg any]])
+      .andForwardToRealObject();
+  EXPECT_TRUE(SetCookie(test_cookie_2_));
+
+  // Verify that cache was invalidated and internal getAllCookies is called.
+  OCMExpect([mock_http_cookie_store_ getAllCookies:[OCMArg any]])
+      .andForwardToRealObject();
+  NSArray<NSHTTPCookie*>* result_2 = GetCookies();
+
+  // Check that the cookies returned was changed and cache was invalidated.
+  EXPECT_NSNE(result_1, result_2);
+  EXPECT_OCMOCK_VERIFY(mock_http_cookie_store_);
+}
+
+// Tests that |deleteCookie:| works correctly and invalidates the cache.
+TEST_F(CRWWKHTTPCookieStoreTest, DeleteCookie) {
+  EXPECT_TRUE(SetCookie(test_cookie_1_));
+  EXPECT_TRUE(SetCookie(test_cookie_2_));
+  NSArray<NSHTTPCookie*>* result_1 = GetCookies();
+  EXPECT_EQ(2U, result_1.count);
+
+  // Verify that internal cookie store deleteCookie method is called.
+  OCMExpect([mock_http_cookie_store_ deleteCookie:test_cookie_2_
+                                completionHandler:[OCMArg any]])
+      .andForwardToRealObject();
+
+  EXPECT_TRUE(DeleteCookie(test_cookie_2_));
+
+  // Verify that cache was invalidated and internal getAllCookies is called.
+  OCMExpect([mock_http_cookie_store_ getAllCookies:[OCMArg any]])
+      .andForwardToRealObject();
+
+  NSArray<NSHTTPCookie*>* result_2 = GetCookies();
+  EXPECT_EQ(1U, result_2.count);
+
+  EXPECT_OCMOCK_VERIFY(mock_http_cookie_store_);
+}
+
+// Tests that chacing work correctly after changing the internal cookieStore.
+TEST_F(CRWWKHTTPCookieStoreTest, ChangeCookieStore) {
+  EXPECT_TRUE(SetCookie(test_cookie_1_));
+  // Verify that cache was invalidated and internal getAllCookies is called.
+  OCMExpect([mock_http_cookie_store_ getAllCookies:[OCMArg any]])
+      .andForwardToRealObject();
+  NSArray<NSHTTPCookie*>* result_1 = GetCookies();
+  EXPECT_EQ(1U, result_1.count);
+  EXPECT_OCMOCK_VERIFY(mock_http_cookie_store_);
+
+  // Change the internal cookie store.
+  [mock_http_cookie_store_ stopMocking];
+  mock_http_cookie_store_ = OCMPartialMock(CreateDataStore().httpCookieStore);
+  crw_cookie_store_.HTTPCookieStore = mock_http_cookie_store_;
+
+  // Verify that internal getAllCookies is called.
+  OCMExpect([mock_http_cookie_store_ getAllCookies:[OCMArg any]])
+      .andForwardToRealObject();
+  NSArray<NSHTTPCookie*>* result_3 = GetCookies();
+  // There should be no cookies in the new cookie store.
+  EXPECT_EQ(0U, result_3.count);
+
+  EXPECT_TRUE(SetCookie(test_cookie_2_));
+
+  // Verify that cache was invalidated and internal getAllCookies is called.
+  OCMExpect([mock_http_cookie_store_ getAllCookies:[OCMArg any]])
+      .andForwardToRealObject();
+  NSArray<NSHTTPCookie*>* result_4 = GetCookies();
+  EXPECT_EQ(1U, result_4.count);
+  EXPECT_OCMOCK_VERIFY(mock_http_cookie_store_);
+}
+
+// Tests that if the internal cookie store is nil, getAllCookie will still run
+// its callback.
+TEST_F(CRWWKHTTPCookieStoreTest, NilCookieStore) {
+  [mock_http_cookie_store_ stopMocking];
+  crw_cookie_store_.HTTPCookieStore = nil;
+  // GetCookies should return empty array when there is no cookie store.
+  NSArray<NSHTTPCookie*>* result = GetCookies();
+  EXPECT_EQ(0U, result.count);
+}
diff --git a/ios/web/net/cookies/system_cookie_store_util.mm b/ios/web/net/cookies/system_cookie_store_util.mm
index fe616dafd..4f63ec1 100644
--- a/ios/web/net/cookies/system_cookie_store_util.mm
+++ b/ios/web/net/cookies/system_cookie_store_util.mm
@@ -12,6 +12,7 @@
 #import "ios/web/net/cookies/wk_cookie_util.h"
 #import "ios/web/net/cookies/wk_http_system_cookie_store.h"
 #include "ios/web/public/browser_state.h"
+#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -24,12 +25,10 @@
   if (base::FeatureList::IsEnabled(web::features::kWKHTTPSystemCookieStore)) {
     // Using WKHTTPCookieStore guarantee that cookies are always in sync and
     // allows SystemCookieStore to handle cookies for OffTheRecord browser.
-    WKHTTPCookieStore* wk_cookie_store =
-        web::WKCookieStoreForBrowserState(browser_state);
-    return std::make_unique<web::WKHTTPSystemCookieStore>(wk_cookie_store);
+    WKWebViewConfigurationProvider& config_provider =
+        WKWebViewConfigurationProvider::FromBrowserState(browser_state);
+    return std::make_unique<web::WKHTTPSystemCookieStore>(&config_provider);
   }
-  // TODO(crbug.com/759229): Return a different CookieStore for OffTheRecord
-  // browser state.
   return std::make_unique<net::NSHTTPSystemCookieStore>();
 }
 
diff --git a/ios/web/net/cookies/wk_http_system_cookie_store.h b/ios/web/net/cookies/wk_http_system_cookie_store.h
index bd98c54..e6e8d6e 100644
--- a/ios/web/net/cookies/wk_http_system_cookie_store.h
+++ b/ios/web/net/cookies/wk_http_system_cookie_store.h
@@ -9,15 +9,19 @@
 #import <WebKit/WebKit.h>
 
 #import "ios/net/cookies/system_cookie_store.h"
+#import "ios/web/net/cookies/crw_wk_http_cookie_store.h"
+#import "ios/web/web_state/ui/wk_web_view_configuration_provider_observer.h"
 
 namespace web {
 
 // This class is an implementation of SystemCookieStore, WKHTTPSystemCookieStore
 // uses WKHTTPCookieStore as the underlying system cookie store.
 class API_AVAILABLE(ios(11.0)) WKHTTPSystemCookieStore
-    : public net::SystemCookieStore {
+    : public net::SystemCookieStore,
+      public WKWebViewConfigurationProviderObserver {
  public:
-  explicit WKHTTPSystemCookieStore(WKHTTPCookieStore* cookie_store);
+  explicit WKHTTPSystemCookieStore(
+      WKWebViewConfigurationProvider* config_provider);
 
   ~WKHTTPSystemCookieStore() override;
 
@@ -43,16 +47,40 @@
   NSHTTPCookieAcceptPolicy GetCookieAcceptPolicy() override;
 
  private:
-  // Run |callback| on |cookies| after sorting them  as per RFC6265.
-  static void RunSystemCookieCallbackForCookies(
+  // Gets cookies on UI Thread then processes the result and runs callback on IO
+  // thread. If |include_url| is not empty, only include cookies that match it.
+  void GetCookiesAsyncInternal(
+      const GURL& include_url,
+      net::SystemCookieStore::SystemCookieCallbackForCookies callback);
+
+  // WKWebViewConfigurationProviderObserver:
+  // Updates the internal WKHTTPCookieStore and its observer.
+  void DidCreateNewConfiguration(
+      WKWebViewConfigurationProvider* config_provider,
+      WKWebViewConfiguration* new_config) override;
+
+  // WKWebViewConfigurationProviderObserver:
+  // Stops observing |config_provider|.
+  void ConfigurationProviderDestroyed(
+      WKWebViewConfigurationProvider* config_provider) override;
+
+  // Filters |cookies| to match |include_url|, sorts based on RFC6265 using
+  // |weak_time_manager| and then runs |callback|.
+  // If |include_url| is empty then cookies are processed without filtering.
+  static void ProcessGetCookiesResultInIOThread(
       net::SystemCookieStore::SystemCookieCallbackForCookies callback,
       base::WeakPtr<net::CookieCreationTimeManager> weak_time_manager,
+      const GURL& include_url,
       NSArray<NSHTTPCookie*>* cookies);
 
-  // cookie_store_ must be deleted in the UI thread, So by making it weak
-  // WKHTTPSystemCookieStore will not retain the WKHTTPCookieStore instance, and
-  // it will be deleted with the owning WKWebSiteDataStore.
-  __weak WKHTTPCookieStore* cookie_store_;
+  // Using CRWWKHTTPCookieStore instead of using WKHTTPCookieStore directly to
+  // work around several bugs on WKHTTPCookieStore.
+  CRWWKHTTPCookieStore* crw_cookie_store_ = nil;
+
+  // The WKWebViewConfigurationProvider object that is observed by this cookie
+  // store. If this cookie store doesn't observe any
+  // WKWebViewConfigurationProvider |config_provider_| will be nullptr.
+  WKWebViewConfigurationProvider* config_provider_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(WKHTTPSystemCookieStore);
 };
diff --git a/ios/web/net/cookies/wk_http_system_cookie_store.mm b/ios/web/net/cookies/wk_http_system_cookie_store.mm
index 466fd434..9f6b966 100644
--- a/ios/web/net/cookies/wk_http_system_cookie_store.mm
+++ b/ios/web/net/cookies/wk_http_system_cookie_store.mm
@@ -11,6 +11,7 @@
 #include "ios/net/cookies/system_cookie_util.h"
 #include "ios/web/public/web_task_traits.h"
 #include "ios/web/public/web_thread.h"
+#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/cookies/canonical_cookie.h"
 #include "url/gurl.h"
@@ -49,29 +50,21 @@
          net::CanonicalCookie::CookieInclusionStatus::INCLUDE;
 }
 
-// Prioritizes queued WKHTTPCookieStore completion handlers to run as soon as
-// possible. This function is needed because some of WKHTTPCookieStore methods
-// completion handlers are not called until there is a WKWebView on the view
-// hierarchy.
-void PrioritizeWKHTTPCookieStoreCallbacks() {
-  // TODO(crbug.com/885218): Currently this hack is needed to fix
-  // crbug.com/885218. Remove when the behavior of
-  // [WKHTTPCookieStore getAllCookies:] changes.
-  NSSet* data_types = [NSSet setWithObject:WKWebsiteDataTypeCookies];
-  [[WKWebsiteDataStore defaultDataStore]
-      removeDataOfTypes:data_types
-          modifiedSince:[NSDate distantFuture]
-      completionHandler:^{
-      }];
-}
-
 }  // namespace
 
 WKHTTPSystemCookieStore::WKHTTPSystemCookieStore(
-    WKHTTPCookieStore* cookie_store)
-    : cookie_store_(cookie_store) {}
+    WKWebViewConfigurationProvider* config_provider)
+    : crw_cookie_store_([[CRWWKHTTPCookieStore alloc] init]),
+      config_provider_(config_provider) {
+  crw_cookie_store_.HTTPCookieStore = config_provider->GetWebViewConfiguration()
+                                          .websiteDataStore.httpCookieStore;
+  config_provider->AddObserver(this);
+}
 
-WKHTTPSystemCookieStore::~WKHTTPSystemCookieStore() = default;
+WKHTTPSystemCookieStore::~WKHTTPSystemCookieStore() {
+  if (config_provider_)
+    config_provider_->RemoveObserver(this);
+}
 
 #pragma mark -
 #pragma mark SystemCookieStore methods
@@ -79,77 +72,23 @@
 void WKHTTPSystemCookieStore::GetCookiesForURLAsync(
     const GURL& url,
     SystemCookieCallbackForCookies callback) {
-  // This function shouldn't be called if cookie_store_ is deleted.
-  DCHECK(cookie_store_);
   net::ReportGetCookiesForURLCall(
       net::SystemCookieStoreType::kWKHTTPSystemCookieStore);
-  __block SystemCookieCallbackForCookies shared_callback = std::move(callback);
-  base::WeakPtr<net::CookieCreationTimeManager> weak_time_manager =
-      creation_time_manager_->GetWeakPtr();
-  __weak WKHTTPCookieStore* block_cookie_store = cookie_store_;
-  GURL block_url = url;
-  base::PostTaskWithTraits(
-      FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{
-        WKHTTPCookieStore* strong_cookie_store = block_cookie_store;
-        if (strong_cookie_store) {
-          [strong_cookie_store
-              getAllCookies:^(NSArray<NSHTTPCookie*>* cookies) {
-                NSMutableArray* result = [NSMutableArray array];
-                for (NSHTTPCookie* cookie in cookies) {
-                  if (ShouldIncludeForRequestUrl(cookie, block_url)) {
-                    [result addObject:cookie];
-                  }
-                }
-                net::ReportGetCookiesForURLResult(
-                    net::SystemCookieStoreType::kWKHTTPSystemCookieStore,
-                    result.count != 0);
-                RunSystemCookieCallbackForCookies(std::move(shared_callback),
-                                                  weak_time_manager, result);
-              }];
-          PrioritizeWKHTTPCookieStoreCallbacks();
-        } else {
-          net::ReportGetCookiesForURLResult(
-              net::SystemCookieStoreType::kWKHTTPSystemCookieStore, false);
-          RunSystemCookieCallbackForCookies(std::move(shared_callback),
-                                            weak_time_manager, @[]);
-        }
-      }));
+  GetCookiesAsyncInternal(url, std::move(callback));
 }
 
 void WKHTTPSystemCookieStore::GetAllCookiesAsync(
     SystemCookieCallbackForCookies callback) {
-  // This function shouldn't be called if cookie_store_ is deleted.
-  DCHECK(cookie_store_);
-  __block SystemCookieCallbackForCookies shared_callback = std::move(callback);
-  __weak WKHTTPCookieStore* block_cookie_store = cookie_store_;
-  base::WeakPtr<net::CookieCreationTimeManager> weak_time_manager =
-      creation_time_manager_->GetWeakPtr();
-  base::PostTaskWithTraits(
-      FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{
-        WKHTTPCookieStore* strong_cookie_store = block_cookie_store;
-        if (strong_cookie_store) {
-          [strong_cookie_store
-              getAllCookies:^(NSArray<NSHTTPCookie*>* cookies) {
-                RunSystemCookieCallbackForCookies(std::move(shared_callback),
-                                                  weak_time_manager, cookies);
-              }];
-          PrioritizeWKHTTPCookieStoreCallbacks();
-        } else {
-          RunSystemCookieCallbackForCookies(std::move(shared_callback),
-                                            weak_time_manager, @[]);
-        }
-      }));
+  GetCookiesAsyncInternal(GURL::EmptyGURL(), std::move(callback));
 }
 
 void WKHTTPSystemCookieStore::DeleteCookieAsync(NSHTTPCookie* cookie,
                                                 SystemCookieCallback callback) {
-  // This function shouldn't be called if cookie_store_ is deleted.
-  DCHECK(cookie_store_);
   __block SystemCookieCallback shared_callback = std::move(callback);
   base::WeakPtr<net::CookieCreationTimeManager> weak_time_manager =
       creation_time_manager_->GetWeakPtr();
   NSHTTPCookie* block_cookie = cookie;
-  __weak WKHTTPCookieStore* block_cookie_store = cookie_store_;
+  __weak __typeof(crw_cookie_store_) block_cookie_store = crw_cookie_store_;
   base::PostTaskWithTraits(
       FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{
         [block_cookie_store
@@ -169,8 +108,8 @@
     NSHTTPCookie* cookie,
     const base::Time* optional_creation_time,
     SystemCookieCallback callback) {
-  // cookies can't be set if cookie_store_ is deleted.
-  DCHECK(cookie_store_);
+  // cookies can't be set if crw_cookie_store_ is deleted.
+  DCHECK(crw_cookie_store_);
   __block SystemCookieCallback shared_callback = std::move(callback);
   base::WeakPtr<net::CookieCreationTimeManager> weak_time_manager =
       creation_time_manager_->GetWeakPtr();
@@ -178,7 +117,7 @@
   base::Time cookie_time = base::Time::Now();
   if (optional_creation_time && !optional_creation_time->is_null())
     cookie_time = *optional_creation_time;
-  __weak WKHTTPCookieStore* block_cookie_store = cookie_store_;
+  __weak __typeof(crw_cookie_store_) block_cookie_store = crw_cookie_store_;
   base::PostTaskWithTraits(
       FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{
         [block_cookie_store
@@ -201,7 +140,7 @@
   __block SystemCookieCallback shared_callback = std::move(callback);
   base::WeakPtr<net::CookieCreationTimeManager> weak_time_manager =
       creation_time_manager_->GetWeakPtr();
-  __weak WKHTTPCookieStore* block_cookie_store = cookie_store_;
+  __weak __typeof(crw_cookie_store_) block_cookie_store = crw_cookie_store_;
   base::PostTaskWithTraits(
       FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{
         [block_cookie_store getAllCookies:^(NSArray<NSHTTPCookie*>* cookies) {
@@ -242,28 +181,83 @@
   return [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookieAcceptPolicy];
 }
 
+#pragma mark WKWebViewConfigurationProviderObserver implementation
+
+void WKHTTPSystemCookieStore::DidCreateNewConfiguration(
+    WKWebViewConfigurationProvider* provider,
+    WKWebViewConfiguration* new_config) {
+  crw_cookie_store_.HTTPCookieStore =
+      new_config.websiteDataStore.httpCookieStore;
+}
+
+void WKHTTPSystemCookieStore::ConfigurationProviderDestroyed(
+    WKWebViewConfigurationProvider* config_provider) {
+  DCHECK_EQ(config_provider_, config_provider);
+  config_provider->RemoveObserver(this);
+  config_provider_ = nullptr;
+}
+
 #pragma mark private methods
 
+void WKHTTPSystemCookieStore::GetCookiesAsyncInternal(
+    const GURL& include_url,
+    SystemCookieCallbackForCookies callback) {
+  __block SystemCookieCallbackForCookies shared_callback = std::move(callback);
+  base::WeakPtr<net::CookieCreationTimeManager> weak_time_manager =
+      creation_time_manager_->GetWeakPtr();
+  __weak __typeof(crw_cookie_store_) weak_cookie_store = crw_cookie_store_;
+  GURL block_url = include_url;
+  base::PostTaskWithTraits(
+      FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{
+        __typeof(weak_cookie_store) strong_cookie_store = weak_cookie_store;
+        if (strong_cookie_store) {
+          [strong_cookie_store
+              getAllCookies:^(NSArray<NSHTTPCookie*>* cookies) {
+                ProcessGetCookiesResultInIOThread(std::move(shared_callback),
+                                                  weak_time_manager, block_url,
+                                                  cookies);
+              }];
+        } else {
+          ProcessGetCookiesResultInIOThread(std::move(shared_callback),
+                                            weak_time_manager, block_url, @[]);
+        }
+      }));
+}
+
 // static
-// Runs |callback| on |cookies| after sorting them as per RFC6265 using
-// |weak_time_manager|.
-void WKHTTPSystemCookieStore::RunSystemCookieCallbackForCookies(
+void WKHTTPSystemCookieStore::ProcessGetCookiesResultInIOThread(
     net::SystemCookieStore::SystemCookieCallbackForCookies callback,
     base::WeakPtr<net::CookieCreationTimeManager> weak_time_manager,
+    const GURL& include_url,
     NSArray<NSHTTPCookie*>* _Nonnull cookies) {
   if (callback.is_null())
     return;
-  NSArray* block_cookies = cookies;
+  __block NSArray* block_cookies = cookies;
+  GURL block_url = include_url;
+
   __block net::SystemCookieStore::SystemCookieCallbackForCookies
       shared_callback = std::move(callback);
   RunBlockOnIOThread(^{
+    if (!block_url.is_empty()) {
+      NSMutableArray* filtered_cookies = [NSMutableArray array];
+      for (NSHTTPCookie* cookie in block_cookies) {
+        if (ShouldIncludeForRequestUrl(cookie, block_url)) {
+          [filtered_cookies addObject:cookie];
+        }
+      }
+      net::ReportGetCookiesForURLResult(
+          net::SystemCookieStoreType::kWKHTTPSystemCookieStore,
+          filtered_cookies.count != 0);
+      block_cookies = filtered_cookies;
+    }
+
     if (weak_time_manager) {
-      NSArray* result = [block_cookies
+      NSArray* sorted_results = [block_cookies
           sortedArrayUsingFunction:net::SystemCookieStore::CompareCookies
                            context:weak_time_manager.get()];
-      std::move(shared_callback).Run(result);
+      std::move(shared_callback).Run(sorted_results);
     } else {
-      std::move(shared_callback).Run(block_cookies);
+      std::move(shared_callback).Run([block_cookies copy]);
     }
   });
 }
diff --git a/ios/web/net/cookies/wk_http_system_cookie_store_unittest.mm b/ios/web/net/cookies/wk_http_system_cookie_store_unittest.mm
index c59951b..18437c8 100644
--- a/ios/web/net/cookies/wk_http_system_cookie_store_unittest.mm
+++ b/ios/web/net/cookies/wk_http_system_cookie_store_unittest.mm
@@ -11,7 +11,10 @@
 
 #import "base/test/ios/wait_util.h"
 #include "ios/net/cookies/system_cookie_store_unittest_template.h"
+#include "ios/web/public/test/fakes/test_browser_state.h"
+#include "ios/web/public/test/scoped_testing_web_client.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
+#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -24,10 +27,13 @@
 // WKHTTPSystemCookieStore.
 class WKHTTPSystemCookieStoreTestDelegate {
  public:
-  WKHTTPSystemCookieStoreTestDelegate()
-      : shared_store_(
-            [WKWebsiteDataStore nonPersistentDataStore].httpCookieStore),
-        store_(std::make_unique<web::WKHTTPSystemCookieStore>(shared_store_)) {}
+  WKHTTPSystemCookieStoreTestDelegate() {
+    web::WKWebViewConfigurationProvider& config_provider =
+        web::WKWebViewConfigurationProvider::FromBrowserState(&browser_state_);
+    shared_store_ = config_provider.GetWebViewConfiguration()
+                        .websiteDataStore.httpCookieStore;
+    store_ = std::make_unique<web::WKHTTPSystemCookieStore>(&config_provider);
+  }
 
   bool IsCookieSet(NSHTTPCookie* system_cookie, NSURL* url) {
     // Verify that cookie is set in system storage.
@@ -90,7 +96,8 @@
 
  private:
   web::TestWebThreadBundle web_thread_;
-  WKHTTPCookieStore* shared_store_;
+  web::TestBrowserState browser_state_;
+  WKHTTPCookieStore* shared_store_ = nil;
   std::unique_ptr<web::WKHTTPSystemCookieStore> store_;
 };
 
diff --git a/ios/web/test/fakes/BUILD.gn b/ios/web/test/fakes/BUILD.gn
index 10bc6fdb..569ea755 100644
--- a/ios/web/test/fakes/BUILD.gn
+++ b/ios/web/test/fakes/BUILD.gn
@@ -12,6 +12,7 @@
     "//ios/web/navigation:core",
     "//ios/web/public:public",
     "//ios/web/web_state/ui:crw_web_view_navigation_proxy",
+    "//ios/web/web_state/ui:wk_web_view_configuration_provider",
     "//testing/gmock",
     "//third_party/ocmock:ocmock",
   ]
@@ -31,6 +32,8 @@
     "crw_fake_wk_navigation_response.mm",
     "fake_navigation_manager_delegate.h",
     "fake_navigation_manager_delegate.mm",
+    "fake_wk_configuration_provider_observer.h",
+    "fake_wk_configuration_provider_observer.mm",
     "mock_interstitial_delegate.h",
     "mock_interstitial_delegate.mm",
   ]
diff --git a/ios/web/test/fakes/fake_wk_configuration_provider_observer.h b/ios/web/test/fakes/fake_wk_configuration_provider_observer.h
new file mode 100644
index 0000000..1575bbd1
--- /dev/null
+++ b/ios/web/test/fakes/fake_wk_configuration_provider_observer.h
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_TEST_FAKES_FAKE_WK_CONFIGURATION_PROVIDER_OBSERVER_H_
+#define IOS_WEB_TEST_FAKES_FAKE_WK_CONFIGURATION_PROVIDER_OBSERVER_H_
+
+#import "ios/web/web_state/ui/wk_web_view_configuration_provider_observer.h"
+
+#import <WebKit/WebKit.h>
+
+namespace web {
+// Fake implementation of WKWebViewConfigurationProviderObserver.
+class FakeWKConfigurationProviderObserver
+    : public WKWebViewConfigurationProviderObserver {
+ public:
+  explicit FakeWKConfigurationProviderObserver(
+      WKWebViewConfigurationProvider* config_provider);
+  // Returns the WKWebViewConfiguration object that was passed to
+  // DidCreateNewConfiguration method.
+  WKWebViewConfiguration* GetLastCreatedWKConfiguration();
+
+  bool IsProviderDestroyed() const;
+
+  void ResetLastCreatedWKConfig();
+
+ private:
+  // Sets the |last_created_wk_config| with |new_config|.
+  void DidCreateNewConfiguration(
+      WKWebViewConfigurationProvider* config_provider,
+      WKWebViewConfiguration* new_config) override;
+  void ConfigurationProviderDestroyed(
+      WKWebViewConfigurationProvider* config_provider) override;
+  // The last created configuration that was passed to
+  // DidCreateNewConfiguration.
+  WKWebViewConfiguration* last_created_wk_config_ = nil;
+  // True after ConfigurationProviderDestroyed is called.
+  bool is_provider_destroyed_ = false;
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_TEST_FAKES_FAKE_WK_CONFIGURATION_PROVIDER_OBSERVER_H_
diff --git a/ios/web/test/fakes/fake_wk_configuration_provider_observer.mm b/ios/web/test/fakes/fake_wk_configuration_provider_observer.mm
new file mode 100644
index 0000000..9058d46e
--- /dev/null
+++ b/ios/web/test/fakes/fake_wk_configuration_provider_observer.mm
@@ -0,0 +1,44 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/test/fakes/fake_wk_configuration_provider_observer.h"
+
+#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace web {
+FakeWKConfigurationProviderObserver::FakeWKConfigurationProviderObserver(
+    WKWebViewConfigurationProvider* config_provider) {
+  config_provider->AddObserver(this);
+}
+
+WKWebViewConfiguration*
+FakeWKConfigurationProviderObserver::GetLastCreatedWKConfiguration() {
+  return last_created_wk_config_;
+}
+
+void FakeWKConfigurationProviderObserver::ResetLastCreatedWKConfig() {
+  last_created_wk_config_ = nil;
+}
+
+void FakeWKConfigurationProviderObserver::DidCreateNewConfiguration(
+    WKWebViewConfigurationProvider* config_provider,
+    WKWebViewConfiguration* new_config) {
+  last_created_wk_config_ = new_config;
+}
+
+bool FakeWKConfigurationProviderObserver::IsProviderDestroyed() const {
+  return is_provider_destroyed_;
+}
+
+void FakeWKConfigurationProviderObserver::ConfigurationProviderDestroyed(
+    WKWebViewConfigurationProvider* config_provider) {
+  config_provider->RemoveObserver(this);
+  is_provider_destroyed_ = true;
+}
+
+}  // namespace web
diff --git a/ios/web/web_state/ui/BUILD.gn b/ios/web/web_state/ui/BUILD.gn
index cbd7b5fe..14cb032 100644
--- a/ios/web/web_state/ui/BUILD.gn
+++ b/ios/web/web_state/ui/BUILD.gn
@@ -141,6 +141,7 @@
   sources = [
     "wk_web_view_configuration_provider.h",
     "wk_web_view_configuration_provider.mm",
+    "wk_web_view_configuration_provider_observer.h",
   ]
 
   libs = [ "WebKit.framework" ]
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider.h b/ios/web/web_state/ui/wk_web_view_configuration_provider.h
index 82a8eb1..26f8591 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider.h
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider.h
@@ -6,6 +6,7 @@
 #define IOS_WEB_WEB_STATE_UI_WK_WEB_VIEW_CONFIGURATION_PROVIDER_H_
 
 #include "base/macros.h"
+#include "base/observer_list.h"
 #include "base/supports_user_data.h"
 
 @class CRWWebUISchemeHandler;
@@ -15,6 +16,7 @@
 namespace web {
 
 class BrowserState;
+class WKWebViewConfigurationProviderObserver;
 
 // A provider class associated with a single web::BrowserState object. Manages
 // the lifetime and performs setup of WKWebViewConfiguration and
@@ -47,15 +49,24 @@
   // be enforced in debug builds).
   void Purge();
 
+  // Adds |observer| to monitor changes to the ConfigurationProvider.
+  void AddObserver(WKWebViewConfigurationProviderObserver* observer);
+
+  // Stop |observer| from monitoring changes to the ConfigurationProvider.
+  void RemoveObserver(WKWebViewConfigurationProviderObserver* observer);
+
  private:
   explicit WKWebViewConfigurationProvider(BrowserState* browser_state);
   WKWebViewConfigurationProvider() = delete;
-
   CRWWebUISchemeHandler* scheme_handler_ = nil;
   WKWebViewConfiguration* configuration_;
   CRWWKScriptMessageRouter* router_;
   BrowserState* browser_state_;
 
+  // A list of observers notified when WKWebViewConfiguration changes.
+  base::ObserverList<WKWebViewConfigurationProviderObserver, true>::Unchecked
+      observers_;
+
   DISALLOW_COPY_AND_ASSIGN(WKWebViewConfigurationProvider);
 };
 
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider.mm b/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
index d19d598..a36a01c3 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
@@ -16,6 +16,7 @@
 #include "ios/web/public/web_client.h"
 #import "ios/web/web_state/js/page_script_util.h"
 #import "ios/web/web_state/ui/crw_wk_script_message_router.h"
+#import "ios/web/web_state/ui/wk_web_view_configuration_provider_observer.h"
 #import "ios/web/webui/crw_web_ui_scheme_handler.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -80,6 +81,8 @@
     : browser_state_(browser_state) {}
 
 WKWebViewConfigurationProvider::~WKWebViewConfigurationProvider() {
+  for (auto& observer : observers_)
+    observer.ConfigurationProviderDestroyed(this);
 }
 
 WKWebViewConfiguration*
@@ -126,6 +129,18 @@
                                forURLScheme:base::SysUTF8ToNSString(scheme)];
       }
     }
+
+    for (auto& observer : observers_)
+      observer.DidCreateNewConfiguration(this, configuration_);
+
+    // Workaround to force the creation of the WKWebsiteDataStore. This
+    // workaround need to be done here, because this method returns a copy of
+    // the already created configuration.
+    NSSet* data_types = [NSSet setWithObject:WKWebsiteDataTypeCookies];
+    [configuration_.websiteDataStore
+        fetchDataRecordsOfTypes:data_types
+              completionHandler:^(NSArray<WKWebsiteDataRecord*>* records){
+              }];
   }
 
   // This is a shallow copy to prevent callers from changing the internals of
@@ -151,4 +166,14 @@
   router_ = nil;
 }
 
+void WKWebViewConfigurationProvider::AddObserver(
+    WKWebViewConfigurationProviderObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void WKWebViewConfigurationProvider::RemoveObserver(
+    WKWebViewConfigurationProviderObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 }  // namespace web
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider_observer.h b/ios/web/web_state/ui/wk_web_view_configuration_provider_observer.h
new file mode 100644
index 0000000..f8bcb225
--- /dev/null
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider_observer.h
@@ -0,0 +1,39 @@
+// 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 IOS_WEB_WEB_STATE_UI_WK_WEB_VIEW_CONFIGURATION_PROVIDER_OBSERVER_H_
+#define IOS_WEB_WEB_STATE_UI_WK_WEB_VIEW_CONFIGURATION_PROVIDER_OBSERVER_H_
+
+#include "base/macros.h"
+
+@class WKWebViewConfiguration;
+
+namespace web {
+
+class WKWebViewConfigurationProvider;
+
+class WKWebViewConfigurationProviderObserver {
+ public:
+  // Called when the observed WKWebViewConfigurationProvider creates a new
+  // WKWebViewConfiguration.
+  virtual void DidCreateNewConfiguration(
+      WKWebViewConfigurationProvider* config_provider,
+      WKWebViewConfiguration* new_config) {}
+
+  // Called when the observed WKWebViewConfigurationProvider is being destroyed.
+  virtual void ConfigurationProviderDestroyed(
+      WKWebViewConfigurationProvider* config_provider) {}
+
+  virtual ~WKWebViewConfigurationProviderObserver() = default;
+
+ protected:
+  WKWebViewConfigurationProviderObserver() = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WKWebViewConfigurationProviderObserver);
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_WEB_STATE_UI_WK_WEB_VIEW_CONFIGURATION_PROVIDER_OBSERVER_H_
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm b/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
index 5438ec0..e7257e5 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
@@ -10,6 +10,7 @@
 #include "ios/web/public/test/fakes/test_browser_state.h"
 #include "ios/web/public/test/scoped_testing_web_client.h"
 #import "ios/web/public/web_client.h"
+#import "ios/web/test/fakes/fake_wk_configuration_provider_observer.h"
 #import "ios/web/web_state/js/page_script_util.h"
 #import "ios/web/web_state/ui/crw_wk_script_message_router.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -159,5 +160,27 @@
             [[scripts[2] source] rangeOfString:late_all_frames_script].length);
 }
 
+// Tests that observers methods are correctly triggered when observing the
+// WKWebViewConfigurationProvider
+TEST_F(WKWebViewConfigurationProviderTest, Observers) {
+  std::unique_ptr<TestBrowserState> browser_state =
+      std::make_unique<TestBrowserState>();
+  WKWebViewConfigurationProvider* provider = &GetProvider(browser_state.get());
+
+  FakeWKConfigurationProviderObserver observer(provider);
+  EXPECT_FALSE(observer.GetLastCreatedWKConfiguration());
+  WKWebViewConfiguration* config = provider->GetWebViewConfiguration();
+  EXPECT_NSEQ(config.preferences,
+              observer.GetLastCreatedWKConfiguration().preferences);
+  observer.ResetLastCreatedWKConfig();
+  config = provider->GetWebViewConfiguration();
+  EXPECT_FALSE(observer.GetLastCreatedWKConfiguration());
+
+  // Test that ConfigurationProviderDestroyed is called.
+  ASSERT_FALSE(observer.IsProviderDestroyed());
+  browser_state.reset();
+  EXPECT_TRUE(observer.IsProviderDestroyed());
+}
+
 }  // namespace
 }  // namespace web
diff --git a/media/filters/audio_video_metadata_extractor_unittest.cc b/media/filters/audio_video_metadata_extractor_unittest.cc
index 237ee48..df1cb13 100644
--- a/media/filters/audio_video_metadata_extractor_unittest.cc
+++ b/media/filters/audio_video_metadata_extractor_unittest.cc
@@ -47,7 +47,12 @@
     const media::AudioVideoMetadataExtractor::TagDictionary& tags,
     const char* tag_name) {
   auto tag_data = tags.find(tag_name);
-  return tag_data == tags.end() ? "" : tag_data->second;
+  if (tag_data == tags.end()) {
+    DLOG(WARNING) << "Tag name \"" << tag_name << "\" not found!";
+    return "";
+  }
+
+  return tag_data->second;
 }
 
 TEST(AudioVideoMetadataExtractorTest, InvalidFile) {
@@ -67,7 +72,7 @@
   EXPECT_EQ(1u, extractor->stream_infos()[1].tags.size());
   EXPECT_EQ("vorbis", extractor->stream_infos()[1].type);
   EXPECT_EQ("Processed by SoX",
-            GetTagValue(extractor->stream_infos()[1].tags, "COMMENT"));
+            GetTagValue(extractor->stream_infos()[1].tags, "Comment"));
 
   EXPECT_EQ(0u, extractor->attached_images_bytes().size());
 }
@@ -104,9 +109,9 @@
 
   EXPECT_EQ(2u, extractor->stream_infos()[0].tags.size());
   EXPECT_EQ("Lavf55.43.100",
-            GetTagValue(extractor->stream_infos()[0].tags, "ENCODER"));
+            GetTagValue(extractor->stream_infos()[0].tags, "encoder"));
   EXPECT_EQ("Amadeus Pro",
-            GetTagValue(extractor->stream_infos()[0].tags, "ENCODED_BY"));
+            GetTagValue(extractor->stream_infos()[0].tags, "encoded_by"));
 
   EXPECT_EQ("flac", extractor->stream_infos()[1].type);
   EXPECT_EQ(0u, extractor->stream_infos()[1].tags.size());
diff --git a/mojo/core/channel_fuchsia.cc b/mojo/core/channel_fuchsia.cc
index e6037317..826238e 100644
--- a/mojo/core/channel_fuchsia.cc
+++ b/mojo/core/channel_fuchsia.cc
@@ -300,7 +300,7 @@
       zx_handle_t handles[ZX_CHANNEL_MAX_MSG_HANDLES] = {};
 
       zx_status_t read_result =
-          handle_.rea2(0, buffer, handles, buffer_capacity, base::size(handles),
+          handle_.read(0, buffer, handles, buffer_capacity, base::size(handles),
                        &bytes_read, &handles_read);
       if (read_result == ZX_OK) {
         for (size_t i = 0; i < handles_read; ++i) {
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index c2a0f444..5310784 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -11,6 +11,7 @@
   "//chromecast/typemaps.gni",
   "//chromeos/typemaps.gni",
   "//chromeos/components/multidevice/mojom/typemaps.gni",
+  "//chromeos/services/power/public/mojom/typemaps.gni",
   "//chromeos/services/secure_channel/public/mojom/typemaps.gni",
   "//components/arc/common/typemaps.gni",
   "//components/chromeos_camera/common/typemaps.gni",
diff --git a/net/filter/brotli_source_stream.cc b/net/filter/brotli_source_stream.cc
index bef693e..887a0f0 100644
--- a/net/filter/brotli_source_stream.cc
+++ b/net/filter/brotli_source_stream.cc
@@ -17,7 +17,6 @@
 namespace {
 
 const char kBrotli[] = "BROTLI";
-const uint8_t kGzipHeader[] = {0x1f, 0x8b, 0x08};
 
 // BrotliSourceStream applies Brotli content decoding to a data stream.
 // Brotli format specification: http://www.ietf.org/id/draft-alakuijala-brotli.
@@ -29,8 +28,7 @@
         used_memory_(0),
         used_memory_maximum_(0),
         consumed_bytes_(0),
-        produced_bytes_(0),
-        gzip_header_detected_(true) {
+        produced_bytes_(0) {
     brotli_state_ =
         BrotliDecoderCreateInstance(AllocateMemory, FreeMemory, this);
     CHECK(brotli_state_);
@@ -43,14 +41,10 @@
     brotli_state_ = nullptr;
     DCHECK_EQ(0u, used_memory_);
 
-    // Don't report that gzip header was detected in case of lack of input.
-    gzip_header_detected_ &= (consumed_bytes_ >= sizeof(kGzipHeader));
 
     UMA_HISTOGRAM_ENUMERATION(
         "BrotliFilter.Status", static_cast<int>(decoding_status_),
         static_cast<int>(DecodingStatus::DECODING_STATUS_COUNT));
-    UMA_HISTOGRAM_BOOLEAN("BrotliFilter.GzipHeaderDetected",
-                          gzip_header_detected_);
     if (decoding_status_ == DecodingStatus::DECODING_DONE) {
       // CompressionPercent is undefined when there is no output produced.
       if (produced_bytes_ != 0) {
@@ -106,14 +100,6 @@
     size_t available_in = input_buffer_size;
     uint8_t* next_out = bit_cast<uint8_t*>(output_buffer->data());
     size_t available_out = output_buffer_size;
-    // Check if start of the input stream looks like gzip stream.
-    for (size_t i = consumed_bytes_; i < sizeof(kGzipHeader); ++i) {
-      if (!gzip_header_detected_)
-        break;
-      size_t j = i - consumed_bytes_;
-      if (j < available_in && kGzipHeader[i] != next_in[j])
-        gzip_header_detected_ = false;
-    }
 
     BrotliDecoderResult result =
         BrotliDecoderDecompressStream(brotli_state_, &available_in, &next_in,
@@ -187,8 +173,6 @@
   size_t consumed_bytes_;
   size_t produced_bytes_;
 
-  bool gzip_header_detected_;
-
   DISALLOW_COPY_AND_ASSIGN(BrotliSourceStream);
 };
 
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
index cdeb210..40fcebf 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -10,7 +10,9 @@
 #include <sched.h>
 #include <signal.h>
 #include <stddef.h>
+#include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
 #include <sys/socket.h>
@@ -130,6 +132,33 @@
   BPF_ASSERT_EQ(EPERM, fork_errno);
 }
 
+BPF_TEST_C(BaselinePolicy, SystemEperm, BaselinePolicy) {
+  errno = 0;
+  int ret_val = system("echo SHOULD NEVER RUN");
+  BPF_ASSERT_EQ(-1, ret_val);
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_TEST_C(BaselinePolicy, CloneVforkEperm, BaselinePolicy) {
+  errno = 0;
+  // Allocate a couple pages for the child's stack even though the child should
+  // never start.
+  constexpr size_t kStackSize = 4096 * 4;
+  void* child_stack = mmap(nullptr, kStackSize, PROT_READ | PROT_WRITE,
+                           MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+  BPF_ASSERT_NE(child_stack, nullptr);
+  pid_t pid = syscall(__NR_clone, CLONE_VM | CLONE_VFORK | SIGCHLD,
+                      static_cast<char*>(child_stack) + kStackSize, nullptr,
+                      nullptr, nullptr);
+  const int clone_errno = errno;
+  TestUtils::HandlePostForkReturn(pid);
+
+  munmap(child_stack, kStackSize);
+
+  BPF_ASSERT_EQ(-1, pid);
+  BPF_ASSERT_EQ(EPERM, clone_errno);
+}
+
 BPF_TEST_C(BaselinePolicy, CreateThread, BaselinePolicy) {
   base::Thread thread("sandbox_tests");
   BPF_ASSERT(thread.Start());
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
index 100afe5..348ab6e 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -135,7 +135,8 @@
 #if !defined(OS_NACL_NONSFI)
 // Allow Glibc's and Android pthread creation flags, crash on any other
 // thread creation attempts and EPERM attempts to use neither
-// CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations.
+// CLONE_VM nor CLONE_THREAD (all fork implementations), unless CLONE_VFORK is
+// present (as in newer versions of posix_spawn).
 ResultExpr RestrictCloneToThreadsAndEPERMFork() {
   const Arg<unsigned long> flags(0);
 
@@ -154,8 +155,16 @@
       AnyOf(flags == kAndroidCloneMask, flags == kObsoleteAndroidCloneMask,
             flags == kGlibcPthreadFlags);
 
+  // The following two flags are the two important flags in any vfork-emulating
+  // clone call. EPERM any clone call that contains both of them.
+  const uint64_t kImportantCloneVforkFlags = CLONE_VFORK | CLONE_VM;
+
+  const BoolExpr is_fork_or_clone_vfork =
+      AnyOf((flags & (CLONE_VM | CLONE_THREAD)) == 0,
+            (flags & kImportantCloneVforkFlags) == kImportantCloneVforkFlags);
+
   return If(IsAndroid() ? android_test : glibc_test, Allow())
-      .ElseIf((flags & (CLONE_VM | CLONE_THREAD)) == 0, Error(EPERM))
+      .ElseIf(is_fork_or_clone_vfork, Error(EPERM))
       .Else(CrashSIGSYSClone());
 }
 
diff --git a/services/viz/public/cpp/compositing/quads_struct_traits.cc b/services/viz/public/cpp/compositing/quads_struct_traits.cc
index af727cb..d30caac8 100644
--- a/services/viz/public/cpp/compositing/quads_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/quads_struct_traits.cc
@@ -16,39 +16,39 @@
   switch (material) {
     case viz::mojom::DrawQuadStateDataView::Tag::DEBUG_BORDER_QUAD_STATE:
       quad = list->AllocateAndConstruct<viz::DebugBorderDrawQuad>();
-      quad->material = viz::DrawQuad::DEBUG_BORDER;
+      quad->material = viz::DrawQuad::Material::kDebugBorder;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::RENDER_PASS_QUAD_STATE:
       quad = list->AllocateAndConstruct<viz::RenderPassDrawQuad>();
-      quad->material = viz::DrawQuad::RENDER_PASS;
+      quad->material = viz::DrawQuad::Material::kRenderPass;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::SOLID_COLOR_QUAD_STATE:
       quad = list->AllocateAndConstruct<viz::SolidColorDrawQuad>();
-      quad->material = viz::DrawQuad::SOLID_COLOR;
+      quad->material = viz::DrawQuad::Material::kSolidColor;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::STREAM_VIDEO_QUAD_STATE:
       quad = list->AllocateAndConstruct<viz::StreamVideoDrawQuad>();
-      quad->material = viz::DrawQuad::STREAM_VIDEO_CONTENT;
+      quad->material = viz::DrawQuad::Material::kStreamVideoContent;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::SURFACE_QUAD_STATE:
       quad = list->AllocateAndConstruct<viz::SurfaceDrawQuad>();
-      quad->material = viz::DrawQuad::SURFACE_CONTENT;
+      quad->material = viz::DrawQuad::Material::kSurfaceContent;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::TEXTURE_QUAD_STATE:
       quad = list->AllocateAndConstruct<viz::TextureDrawQuad>();
-      quad->material = viz::DrawQuad::TEXTURE_CONTENT;
+      quad->material = viz::DrawQuad::Material::kTextureContent;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::TILE_QUAD_STATE:
       quad = list->AllocateAndConstruct<viz::TileDrawQuad>();
-      quad->material = viz::DrawQuad::TILED_CONTENT;
+      quad->material = viz::DrawQuad::Material::kTiledContent;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::VIDEO_HOLE_QUAD_STATE:
       quad = list->AllocateAndConstruct<viz::VideoHoleDrawQuad>();
-      quad->material = viz::DrawQuad::VIDEO_HOLE;
+      quad->material = viz::DrawQuad::Material::kVideoHole;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::YUV_VIDEO_QUAD_STATE:
       quad = list->AllocateAndConstruct<viz::YUVVideoDrawQuad>();
-      quad->material = viz::DrawQuad::YUV_VIDEO_CONTENT;
+      quad->material = viz::DrawQuad::Material::kYuvVideoContent;
       return quad;
   }
   NOTREACHED();
diff --git a/services/viz/public/cpp/compositing/quads_struct_traits.h b/services/viz/public/cpp/compositing/quads_struct_traits.h
index ab57c29c..565c832 100644
--- a/services/viz/public/cpp/compositing/quads_struct_traits.h
+++ b/services/viz/public/cpp/compositing/quads_struct_traits.h
@@ -70,27 +70,27 @@
   static viz::mojom::DrawQuadStateDataView::Tag GetTag(
       const viz::DrawQuad& quad) {
     switch (quad.material) {
-      case viz::DrawQuad::INVALID:
+      case viz::DrawQuad::Material::kInvalid:
         break;
-      case viz::DrawQuad::DEBUG_BORDER:
+      case viz::DrawQuad::Material::kDebugBorder:
         return viz::mojom::DrawQuadStateDataView::Tag::DEBUG_BORDER_QUAD_STATE;
-      case viz::DrawQuad::PICTURE_CONTENT:
+      case viz::DrawQuad::Material::kPictureContent:
         break;
-      case viz::DrawQuad::RENDER_PASS:
+      case viz::DrawQuad::Material::kRenderPass:
         return viz::mojom::DrawQuadStateDataView::Tag::RENDER_PASS_QUAD_STATE;
-      case viz::DrawQuad::SOLID_COLOR:
+      case viz::DrawQuad::Material::kSolidColor:
         return viz::mojom::DrawQuadStateDataView::Tag::SOLID_COLOR_QUAD_STATE;
-      case viz::DrawQuad::STREAM_VIDEO_CONTENT:
+      case viz::DrawQuad::Material::kStreamVideoContent:
         return viz::mojom::DrawQuadStateDataView::Tag::STREAM_VIDEO_QUAD_STATE;
-      case viz::DrawQuad::SURFACE_CONTENT:
+      case viz::DrawQuad::Material::kSurfaceContent:
         return viz::mojom::DrawQuadStateDataView::Tag::SURFACE_QUAD_STATE;
-      case viz::DrawQuad::TEXTURE_CONTENT:
+      case viz::DrawQuad::Material::kTextureContent:
         return viz::mojom::DrawQuadStateDataView::Tag::TEXTURE_QUAD_STATE;
-      case viz::DrawQuad::TILED_CONTENT:
+      case viz::DrawQuad::Material::kTiledContent:
         return viz::mojom::DrawQuadStateDataView::Tag::TILE_QUAD_STATE;
-      case viz::DrawQuad::VIDEO_HOLE:
+      case viz::DrawQuad::Material::kVideoHole:
         return viz::mojom::DrawQuadStateDataView::Tag::VIDEO_HOLE_QUAD_STATE;
-      case viz::DrawQuad::YUV_VIDEO_CONTENT:
+      case viz::DrawQuad::Material::kYuvVideoContent:
         return viz::mojom::DrawQuadStateDataView::Tag::YUV_VIDEO_QUAD_STATE;
     }
     NOTREACHED();
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index f4f8459..d6018b81 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -1143,7 +1143,7 @@
   std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
   render_pass->SetNew(1, gfx::Rect(), gfx::Rect(), gfx::Transform());
 
-  const DrawQuad::Material material = DrawQuad::YUV_VIDEO_CONTENT;
+  const DrawQuad::Material material = DrawQuad::Material::kYuvVideoContent;
   const gfx::Rect rect(1234, 4321, 1357, 7531);
   const gfx::Rect visible_rect(1337, 7331, 561, 293);
   const bool needs_blending = true;
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 4debb14..b53d3aa 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -56,7 +56,7 @@
   defines = [
     "SK_HAS_PNG_LIBRARY",
     "SK_HAS_WEBP_LIBRARY",
-    "SK_USER_CONFIG_HEADER=\"" + rebase_path("config/SkUserConfig.h") + "\"",
+    "SK_USER_CONFIG_HEADER=\"../../skia/config/SkUserConfig.h\"",
   ]
 
   if (!is_ios) {
diff --git a/storage/browser/fileapi/obfuscated_file_util.cc b/storage/browser/fileapi/obfuscated_file_util.cc
index 7618f796..842d407 100644
--- a/storage/browser/fileapi/obfuscated_file_util.cc
+++ b/storage/browser/fileapi/obfuscated_file_util.cc
@@ -339,8 +339,8 @@
   int64_t growth = UsageForPath(file_info.name.size());
   if (!AllocateQuota(context, growth))
     return base::File::FILE_ERROR_NO_SPACE;
-  base::File::Error error = CreateFile(context, base::FilePath(), url,
-                                       &file_info);
+  base::File::Error error = CreateFile(
+      context, base::FilePath(), false /* foreign_source */, url, &file_info);
   if (created && base::File::FILE_OK == error) {
     *created = true;
     UpdateUsage(context, url, growth);
@@ -599,7 +599,8 @@
           src_local_path, dest_local_path, option,
           delegate_->CopyOrMoveModeForDestination(dest_url, true /* copy */));
     } else {  // non-overwrite
-      error = CreateFile(context, src_local_path, dest_url, &dest_file_info);
+      error = CreateFile(context, src_local_path, false /* foreign_source */,
+                         dest_url, &dest_file_info);
     }
   } else {
     if (overwrite) {
@@ -651,8 +652,10 @@
     return base::File::FILE_ERROR_FAILED;
 
   base::File::Info src_platform_file_info;
-  if (delegate_->GetFileInfo(src_file_path, &src_platform_file_info) !=
-      base::File::FILE_OK)
+  // Foreign files are from another on-disk file system and don't require path
+  // conversion.
+  if (ObfuscatedFileUtilDiskDelegate().GetFileInfo(
+          src_file_path, &src_platform_file_info) != base::File::FILE_OK)
     return base::File::FILE_ERROR_NOT_FOUND;
 
   FileId dest_file_id;
@@ -697,11 +700,12 @@
   if (overwrite) {
     base::FilePath dest_local_path =
         DataPathToLocalPath(dest_url, dest_file_info.data_path);
-    error = delegate_->CopyOrMoveFile(
+    error = delegate_->CopyInForeignFile(
         src_file_path, dest_local_path, FileSystemOperation::OPTION_NONE,
         delegate_->CopyOrMoveModeForDestination(dest_url, true /* copy */));
   } else {
-    error = CreateFile(context, src_file_path, dest_url, &dest_file_info);
+    error = CreateFile(context, src_file_path, true /* foreign_source */,
+                       dest_url, &dest_file_info);
   }
 
   if (error != base::File::FILE_OK)
@@ -1120,6 +1124,7 @@
 base::File::Error ObfuscatedFileUtil::CreateFile(
     FileSystemOperationContext* context,
     const base::FilePath& src_file_path,
+    bool foreign_source,
     const FileSystemURL& dest_url,
     FileInfo* dest_file_info) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -1143,9 +1148,15 @@
 
     error = delegate_->EnsureFileExists(dest_local_path, &created);
   } else {
-    error = delegate_->CopyOrMoveFile(
-        src_file_path, dest_local_path, FileSystemOperation::OPTION_NONE,
-        delegate_->CopyOrMoveModeForDestination(dest_url, true /* copy */));
+    if (foreign_source) {
+      error = delegate_->CopyInForeignFile(
+          src_file_path, dest_local_path, FileSystemOperation::OPTION_NONE,
+          delegate_->CopyOrMoveModeForDestination(dest_url, true /* copy */));
+    } else {
+      error = delegate_->CopyOrMoveFile(
+          src_file_path, dest_local_path, FileSystemOperation::OPTION_NONE,
+          delegate_->CopyOrMoveModeForDestination(dest_url, true /* copy */));
+    }
     created = true;
   }
 
diff --git a/storage/browser/fileapi/obfuscated_file_util.h b/storage/browser/fileapi/obfuscated_file_util.h
index e80c1d6b..2d004f5 100644
--- a/storage/browser/fileapi/obfuscated_file_util.h
+++ b/storage/browser/fileapi/obfuscated_file_util.h
@@ -264,12 +264,14 @@
 
   // The same as CreateAndOpenFile except that a file is not returned and if a
   // path is provided in |source_path|, it will be used as a source from which
-  // to COPY data.
-  base::File::Error CreateFile(
-      FileSystemOperationContext* context,
-      const base::FilePath& source_file_path,
-      const FileSystemURL& dest_url,
-      FileInfo* dest_file_info);
+  // to COPY data. If |foreign_source| is true, the source file is considered
+  // from another (on disk) file system and its path is considered not
+  // obfuscated.
+  base::File::Error CreateFile(FileSystemOperationContext* context,
+                               const base::FilePath& source_file_path,
+                               bool foreign_source,
+                               const FileSystemURL& dest_url,
+                               FileInfo* dest_file_info);
 
   // Updates |db| and |dest_file_info| at the end of creating a new file.
   base::File::Error CommitCreateFile(
diff --git a/storage/browser/fileapi/obfuscated_file_util_delegate.h b/storage/browser/fileapi/obfuscated_file_util_delegate.h
index 7b9a1d0..722d79d 100644
--- a/storage/browser/fileapi/obfuscated_file_util_delegate.h
+++ b/storage/browser/fileapi/obfuscated_file_util_delegate.h
@@ -48,6 +48,11 @@
       const base::FilePath& dest_path,
       FileSystemOperation::CopyOrMoveOption option,
       NativeFileUtil::CopyOrMoveMode mode) = 0;
+  virtual base::File::Error CopyInForeignFile(
+      const base::FilePath& src_path,
+      const base::FilePath& dest_path,
+      FileSystemOperation::CopyOrMoveOption option,
+      NativeFileUtil::CopyOrMoveMode mode) = 0;
   virtual base::File::Error DeleteFile(const base::FilePath& path) = 0;
 
  private:
diff --git a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc
index fbd2a32e..84d415b 100644
--- a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc
+++ b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc
@@ -88,6 +88,14 @@
   return NativeFileUtil::CopyOrMoveFile(src_path, dest_path, option, mode);
 }
 
+base::File::Error ObfuscatedFileUtilDiskDelegate::CopyInForeignFile(
+    const base::FilePath& src_path,
+    const base::FilePath& dest_path,
+    FileSystemOperation::CopyOrMoveOption option,
+    NativeFileUtil::CopyOrMoveMode mode) {
+  return NativeFileUtil::CopyOrMoveFile(src_path, dest_path, option, mode);
+}
+
 base::File::Error ObfuscatedFileUtilDiskDelegate::DeleteFile(
     const base::FilePath& path) {
   return NativeFileUtil::DeleteFile(path);
diff --git a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h
index 05ea948..ebb81a40 100644
--- a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h
+++ b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h
@@ -49,6 +49,11 @@
       const base::FilePath& dest_path,
       FileSystemOperation::CopyOrMoveOption option,
       NativeFileUtil::CopyOrMoveMode mode) override;
+  base::File::Error CopyInForeignFile(
+      const base::FilePath& src_path,
+      const base::FilePath& dest_path,
+      FileSystemOperation::CopyOrMoveOption option,
+      NativeFileUtil::CopyOrMoveMode mode) override;
   base::File::Error DeleteFile(const base::FilePath& path) override;
 
   DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilDiskDelegate);
diff --git a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc
index 5e93db97..356308d9 100644
--- a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc
+++ b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/files/file_util.h"
 #include "base/numerics/checked_math.h"
 #include "build/build_config.h"
 #include "net/base/io_buffer.h"
@@ -491,4 +492,52 @@
 
   return base::File::FILE_OK;
 }
+
+base::File::Error ObfuscatedFileUtilMemoryDelegate::CopyInForeignFile(
+    const base::FilePath& src_path,
+    const base::FilePath& dest_path,
+    FileSystemOperation::CopyOrMoveOption /* option */,
+    NativeFileUtil::CopyOrMoveMode /* mode */) {
+  base::Optional<DecomposedPath> dest_dp = ParsePath(dest_path);
+
+  if (!dest_dp || !dest_dp->parent)
+    return base::File::FILE_ERROR_NOT_FOUND;
+
+  base::File::Info source_info;
+  if (!base::GetFileInfo(src_path, &source_info))
+    return base::File::FILE_ERROR_NOT_FOUND;
+
+  if (source_info.is_directory)
+    return base::File::FILE_ERROR_NOT_A_FILE;
+
+  // |size_t| limits the maximum size that the memory file can keep and |int|
+  // limits the maximum size that base::ReadFile function reads.
+  if (source_info.size > std::numeric_limits<size_t>::max() ||
+      source_info.size > std::numeric_limits<int>::max()) {
+    return base::File::FILE_ERROR_NO_SPACE;
+  }
+
+  // Create file.
+  Entry* entry = &dest_dp->parent->directory_content
+                      .emplace(dest_dp->components.back(), Entry::kFile)
+                      .first->second;
+  entry->creation_time = source_info.creation_time;
+  entry->last_modified = source_info.last_modified;
+  entry->last_accessed = source_info.last_accessed;
+
+  // Read content.
+  entry->file_content.resize(source_info.size);
+  int read_bytes = base::ReadFile(
+      src_path, reinterpret_cast<char*>(entry->file_content.data()),
+      source_info.size);
+
+  if (read_bytes != source_info.size) {
+    // Delete file and return error if source could not be fully read or any
+    // error happens.
+    dest_dp->parent->directory_content.erase(dest_dp->components.back());
+    return base::File::FILE_ERROR_FAILED;
+  }
+
+  return base::File::FILE_OK;
+}
 }  // namespace storage
diff --git a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h
index 2ce6d15..c64200c 100644
--- a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h
+++ b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h
@@ -71,6 +71,11 @@
       const base::FilePath& dest_path,
       FileSystemOperation::CopyOrMoveOption option,
       NativeFileUtil::CopyOrMoveMode mode) override;
+  base::File::Error CopyInForeignFile(
+      const base::FilePath& src_path,
+      const base::FilePath& dest_path,
+      FileSystemOperation::CopyOrMoveOption option,
+      NativeFileUtil::CopyOrMoveMode mode) override;
   base::File::Error DeleteFile(const base::FilePath& path) override;
 
   // Returns the total number of bytes used by all the files under |path|.
diff --git a/storage/browser/fileapi/obfuscated_file_util_memory_delegate_unittest.cc b/storage/browser/fileapi/obfuscated_file_util_memory_delegate_unittest.cc
index 90f23a0..dff4215 100644
--- a/storage/browser/fileapi/obfuscated_file_util_memory_delegate_unittest.cc
+++ b/storage/browser/fileapi/obfuscated_file_util_memory_delegate_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "net/base/io_buffer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace storage {
@@ -299,6 +300,51 @@
   EXPECT_EQ(1020, GetSize(to_dir_file));
 }
 
+TEST_F(ObfuscatedFileUtilMemoryDelegateTest, CopyForeignFile) {
+  base::ScopedTempDir source_dir;
+  ASSERT_TRUE(source_dir.CreateUniqueTempDir());
+  base::FilePath from_file = source_dir.GetPath().AppendASCII("from_file");
+
+  base::FilePath valid_to_file = Path("to_file");
+  base::FilePath invalid_to_file = Path("dir").AppendASCII("to_file");
+
+  char test_data[] = "0123456789";
+  const int test_data_len = strlen(test_data);
+
+  const storage::NativeFileUtil::CopyOrMoveMode sync =
+      storage::NativeFileUtil::COPY_SYNC;
+
+  // Test copying nonexistent file.
+  EXPECT_EQ(
+      base::File::FILE_ERROR_NOT_FOUND,
+      file_util()->CopyInForeignFile(from_file, valid_to_file,
+                                     FileSystemOperation::OPTION_NONE, sync));
+
+  // Create source file.
+  EXPECT_EQ(test_data_len,
+            base::WriteFile(from_file, test_data, test_data_len));
+
+  // Test copying to a nonexistent directory.
+  EXPECT_EQ(
+      base::File::FILE_ERROR_NOT_FOUND,
+      file_util()->CopyInForeignFile(from_file, invalid_to_file,
+                                     FileSystemOperation::OPTION_NONE, sync));
+  EXPECT_FALSE(FileExists(invalid_to_file));
+
+  // Test copying to a valid path.
+  EXPECT_EQ(base::File::FILE_OK, file_util()->CopyInForeignFile(
+                                     from_file, valid_to_file,
+                                     FileSystemOperation::OPTION_NONE, sync));
+  EXPECT_TRUE(FileExists(valid_to_file));
+  EXPECT_EQ(test_data_len, GetSize(valid_to_file));
+  scoped_refptr<net::IOBuffer> content =
+      base::MakeRefCounted<net::IOBuffer>(static_cast<size_t>(test_data_len));
+  EXPECT_EQ(test_data_len, file_util()->ReadFile(valid_to_file, 0,
+                                                 content.get(), test_data_len));
+  EXPECT_EQ(std::string(test_data),
+            std::string(content->data(), test_data_len));
+}
+
 TEST_F(ObfuscatedFileUtilMemoryDelegateTest, CopyFileNonExistingFile) {
   const storage::NativeFileUtil::CopyOrMoveMode nosync =
       storage::NativeFileUtil::COPY_NOSYNC;
diff --git a/storage/browser/fileapi/obfuscated_file_util_unittest.cc b/storage/browser/fileapi/obfuscated_file_util_unittest.cc
index 73c9ec7..97d10558 100644
--- a/storage/browser/fileapi/obfuscated_file_util_unittest.cc
+++ b/storage/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -659,8 +659,8 @@
               ofu()->GetFileInfo(context.get(), dest_url, &file_info,
                                  &data_path));
     EXPECT_NE(data_path, src_file_path);
-    EXPECT_TRUE(FileExists(data_path));
-    EXPECT_EQ(src_file_length, GetLocalFileSize(data_path));
+    EXPECT_TRUE(PathExists(dest_url));
+    EXPECT_EQ(src_file_length, GetPathSize(dest_url));
 
     EXPECT_EQ(base::File::FILE_OK,
               ofu()->DeleteFile(context.get(), dest_url));
@@ -1573,9 +1573,6 @@
 }
 
 TEST_P(ObfuscatedFileUtilTest, TestCopyInForeignFile) {
-  // TODO(crbug.com/93417): Update test for in-memory mode.
-  if (in_memory_test())
-    return;
   TestCopyInForeignFileHelper(false /* overwrite */);
   TestCopyInForeignFileHelper(true /* overwrite */);
 }
@@ -1946,23 +1943,20 @@
 
   // CopyInForeignFile, create case.
   url = FileSystemURLAppendUTF8(dir_url, "CopyInForeignFile_file");
-  FileSystemURL src_path = FileSystemURLAppendUTF8(
-      dir_url, "CopyInForeignFile_src_file");
-  context.reset(NewContext(nullptr));
-  EXPECT_EQ(base::File::FILE_OK,
-            ofu()->EnsureFileExists(context.get(), src_path, &created));
+  base::ScopedTempDir foreign_source_dir;
+  ASSERT_TRUE(foreign_source_dir.CreateUniqueTempDir());
+  base::FilePath foreign_src_file_path =
+      foreign_source_dir.GetPath().AppendASCII("file_name");
+
+  EXPECT_EQ(base::File::FILE_OK, storage::NativeFileUtil::EnsureFileExists(
+                                     foreign_src_file_path, &created));
   EXPECT_TRUE(created);
-  base::FilePath src_local_path;
-  context.reset(NewContext(nullptr));
-  EXPECT_EQ(base::File::FILE_OK,
-            ofu()->GetLocalFilePath(context.get(), src_path, &src_local_path));
 
   ClearTimestamp(dir_url);
   context.reset(NewContext(nullptr));
-  EXPECT_EQ(base::File::FILE_OK,
-            ofu()->CopyInForeignFile(context.get(),
-                                     src_local_path,
-                                     url));
+  EXPECT_EQ(
+      base::File::FILE_OK,
+      ofu()->CopyInForeignFile(context.get(), foreign_src_file_path, url));
   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
 }
 
diff --git a/testing/scripts/test_traffic_annotation_auditor.py b/testing/scripts/test_traffic_annotation_auditor.py
index 0dc8e17..44970cf 100755
--- a/testing/scripts/test_traffic_annotation_auditor.py
+++ b/testing/scripts/test_traffic_annotation_auditor.py
@@ -55,6 +55,7 @@
     config_file.close()
 
     command_line = [
+      sys.executable,
       os.path.join(common.SRC_DIR, 'tools', 'traffic_annotation', 'scripts',
                    'update_annotations_sheet.py'),
       '--force',
diff --git a/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl
index 40f1f25a..6ed62df 100644
--- a/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/element_factory.cc.tmpl
@@ -13,6 +13,7 @@
 {% if fallback_interface %}
 #include "third_party/blink/renderer/core/{{namespace|lower}}/{{fallback_interface_header}}"
 {% endif %}
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
@@ -30,9 +31,9 @@
     Document& document, const CreateElementFlags flags) {
   {% if tag.runtimeEnabled %}
   if (!RuntimeEnabledFeatures::{{tag.runtimeEnabled}}Enabled())
-    return {{fallback_interface}}::Create({{cpp_namespace}}::{{tag|symbol}}Tag, document);
+    return MakeGarbageCollected<{{fallback_interface}}>({{cpp_namespace}}::{{tag|symbol}}Tag, document);
   {% endif %}
-  return {{tag.interface}}::Create(
+  return MakeGarbageCollected<{{tag.interface}}>(
       {%- if tag.multipleTagNames %}{{cpp_namespace}}::{{tag|symbol}}Tag, {% endif -%}
       document
       {%- if tag.constructorNeedsCreateElementFlags %}, flags{% endif -%}
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index 37364a49..f86fe6f 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -648,34 +648,40 @@
   play(exception_state);
 }
 
+// https://drafts.csswg.org/web-animations/#finishing-an-animation-section
 void Animation::finish(ExceptionState& exception_state) {
-  PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand);
+  // Force resolution of PlayStateUpdateScope to enable immediate queuing of
+  // the finished event.
+  {
+    PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand);
 
-  if (!playback_rate_) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "Cannot finish Animation with a playbackRate of 0.");
-    return;
+    if (!playback_rate_) {
+      exception_state.ThrowDOMException(
+          DOMExceptionCode::kInvalidStateError,
+          "Cannot finish Animation with a playbackRate of 0.");
+      return;
+    }
+    if (playback_rate_ > 0 &&
+        EffectEnd() == std::numeric_limits<double>::infinity()) {
+      exception_state.ThrowDOMException(
+          DOMExceptionCode::kInvalidStateError,
+          "Cannot finish Animation with an infinite target effect end.");
+      return;
+    }
+
+    // Avoid updating start time when already finished.
+    if (CalculatePlayState() == kFinished)
+      return;
+
+    double new_current_time = playback_rate_ < 0 ? 0 : EffectEnd();
+    SetCurrentTimeInternal(new_current_time, kTimingUpdateOnDemand);
+    paused_ = false;
+    current_time_pending_ = false;
+    start_time_ = CalculateStartTime(new_current_time);
+    play_state_ = kFinished;
   }
-  if (playback_rate_ > 0 &&
-      EffectEnd() == std::numeric_limits<double>::infinity()) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "Cannot finish Animation with an infinite target effect end.");
-    return;
-  }
-
-  // Avoid updating start time when already finished.
-  if (CalculatePlayState() == kFinished)
-    return;
-
-  double new_current_time = playback_rate_ < 0 ? 0 : EffectEnd();
-  SetCurrentTimeInternal(new_current_time, kTimingUpdateOnDemand);
-  paused_ = false;
-  current_time_pending_ = false;
-  start_time_ = CalculateStartTime(new_current_time);
-  play_state_ = kFinished;
-  ForceServiceOnNextFrame();
+  // Resolve finished event immediately.
+  QueueFinishedEvent();
 }
 
 ScriptPromise Animation::finished(ScriptState* script_state) {
@@ -979,18 +985,7 @@
               pending_cancelled_event_);
         }
       } else {
-        const AtomicString& event_type = event_type_names::kFinish;
-        if (GetExecutionContext() && HasEventListeners(event_type)) {
-          double event_current_time = CurrentTimeInternal() * 1000;
-          pending_finished_event_ =
-              MakeGarbageCollected<AnimationPlaybackEvent>(
-                  event_type, event_current_time,
-                  TimelineInternal()->currentTime());
-          pending_finished_event_->SetTarget(this);
-          pending_finished_event_->SetCurrentTarget(this);
-          timeline_->GetDocument()->EnqueueAnimationFrameEvent(
-              pending_finished_event_);
-        }
+        QueueFinishedEvent();
       }
       finished_ = true;
     }
@@ -999,6 +994,19 @@
   return !finished_ || std::isfinite(TimeToEffectChange());
 }
 
+void Animation::QueueFinishedEvent() {
+  const AtomicString& event_type = event_type_names::kFinish;
+  if (GetExecutionContext() && HasEventListeners(event_type)) {
+    double event_current_time = CurrentTimeInternal() * 1000;
+    pending_finished_event_ = MakeGarbageCollected<AnimationPlaybackEvent>(
+        event_type, event_current_time, TimelineInternal()->currentTime());
+    pending_finished_event_->SetTarget(this);
+    pending_finished_event_->SetCurrentTarget(this);
+    timeline_->GetDocument()->EnqueueAnimationFrameEvent(
+        pending_finished_event_);
+  }
+}
+
 void Animation::UpdateIfNecessary() {
   if (Outdated())
     Update(kTimingUpdateOnDemand);
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h
index d42c992..a0c1f56 100644
--- a/third_party/blink/renderer/core/animation/animation.h
+++ b/third_party/blink/renderer/core/animation/animation.h
@@ -272,6 +272,8 @@
   void RejectAndResetPromise(AnimationPromise*);
   void RejectAndResetPromiseMaybeAsync(AnimationPromise*);
 
+  void QueueFinishedEvent();
+
   String id_;
 
   AnimationPlayState play_state_;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 51ad3ef..5ab6b864 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -943,7 +943,7 @@
   } else if (qname.NamespaceURI() == svg_names::kNamespaceURI) {
     element = SVGElementFactory::Create(qname.LocalName(), *this, flags);
     if (!element)
-      element = SVGUnknownElement::Create(qname, *this);
+      element = MakeGarbageCollected<SVGUnknownElement>(qname, *this);
     saw_elements_in_known_namespaces_ = true;
   } else {
     element = Element::Create(qname, this);
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index acc32e5..e41cf5d 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -123,7 +123,7 @@
 
 }  // namespace
 
-inline HTMLCanvasElement::HTMLCanvasElement(Document& document)
+HTMLCanvasElement::HTMLCanvasElement(Document& document)
     : HTMLElement(kCanvasTag, document),
       ContextLifecycleObserver(&document),
       PageVisibilityObserver(document.GetPage()),
diff --git a/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc b/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
index f1c895d..ada96095 100644
--- a/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
+++ b/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
@@ -80,7 +80,7 @@
   if (html_names::xhtmlNamespaceURI == tag_name.NamespaceURI()) {
     element = MakeGarbageCollected<HTMLElement>(tag_name, document);
   } else if (svg_names::kNamespaceURI == tag_name.NamespaceURI()) {
-    element = SVGUnknownElement::Create(tag_name, document);
+    element = MakeGarbageCollected<SVGUnknownElement>(tag_name, document);
   } else {
     // XML elements are not custom elements, so return early.
     return Element::Create(tag_name, &document);
diff --git a/third_party/blink/renderer/core/html/forms/html_button_element.cc b/third_party/blink/renderer/core/html/forms/html_button_element.cc
index f779e24..1cc4b35 100644
--- a/third_party/blink/renderer/core/html/forms/html_button_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_button_element.cc
@@ -37,7 +37,7 @@
 
 using namespace html_names;
 
-inline HTMLButtonElement::HTMLButtonElement(Document& document)
+HTMLButtonElement::HTMLButtonElement(Document& document)
     : HTMLFormControlElement(kButtonTag, document),
       type_(SUBMIT),
       is_activated_submit_(false) {}
diff --git a/third_party/blink/renderer/core/html/forms/html_data_list_element.cc b/third_party/blink/renderer/core/html/forms/html_data_list_element.cc
index e769bce..c58ae1d 100644
--- a/third_party/blink/renderer/core/html/forms/html_data_list_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_data_list_element.cc
@@ -39,12 +39,9 @@
 
 namespace blink {
 
-inline HTMLDataListElement::HTMLDataListElement(Document& document)
-    : HTMLElement(html_names::kDatalistTag, document) {}
-
-HTMLDataListElement* HTMLDataListElement::Create(Document& document) {
+HTMLDataListElement::HTMLDataListElement(Document& document)
+    : HTMLElement(html_names::kDatalistTag, document) {
   UseCounter::Count(document, WebFeature::kDataListElement);
-  return MakeGarbageCollected<HTMLDataListElement>(document);
 }
 
 HTMLDataListOptionsCollection* HTMLDataListElement::options() {
diff --git a/third_party/blink/renderer/core/html/forms/html_data_list_element.h b/third_party/blink/renderer/core/html/forms/html_data_list_element.h
index 4215b7d..07460b9 100644
--- a/third_party/blink/renderer/core/html/forms/html_data_list_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_data_list_element.h
@@ -42,8 +42,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static HTMLDataListElement* Create(Document&);
-
   HTMLDataListElement(Document&);
 
   HTMLDataListOptionsCollection* options();
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
index aef54f6..eba435c 100644
--- a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
@@ -40,7 +40,7 @@
 
 using namespace html_names;
 
-inline HTMLFieldSetElement::HTMLFieldSetElement(Document& document)
+HTMLFieldSetElement::HTMLFieldSetElement(Document& document)
     : HTMLFormControlElement(kFieldsetTag, document) {}
 
 HTMLFieldSetElement* HTMLFieldSetElement::Create(Document& document) {
diff --git a/third_party/blink/renderer/core/html/forms/html_input_element.cc b/third_party/blink/renderer/core/html/forms/html_input_element.cc
index 34d36eb93..12a24f7f4 100644
--- a/third_party/blink/renderer/core/html/forms/html_input_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_input_element.cc
@@ -123,17 +123,17 @@
                                             : InputType::CreateText(*this)),
       input_type_view_(input_type_ ? input_type_->CreateView() : nullptr) {
   SetHasCustomStyleCallbacks();
+
+  if (!flags.IsCreatedByParser()) {
+    DCHECK(input_type_view_->NeedsShadowSubtree());
+    CreateUserAgentShadowRoot();
+    CreateShadowSubtree();
+  }
 }
 
 HTMLInputElement* HTMLInputElement::Create(Document& document,
                                            const CreateElementFlags flags) {
-  auto* input_element = MakeGarbageCollected<HTMLInputElement>(document, flags);
-  if (!flags.IsCreatedByParser()) {
-    DCHECK(input_element->input_type_view_->NeedsShadowSubtree());
-    input_element->CreateUserAgentShadowRoot();
-    input_element->CreateShadowSubtree();
-  }
-  return input_element;
+  return MakeGarbageCollected<HTMLInputElement>(document, flags);
 }
 
 void HTMLInputElement::Trace(Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/html/forms/html_legend_element.cc b/third_party/blink/renderer/core/html/forms/html_legend_element.cc
index a17111c22..78199ce6 100644
--- a/third_party/blink/renderer/core/html/forms/html_legend_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_legend_element.cc
@@ -32,7 +32,7 @@
 
 using namespace html_names;
 
-inline HTMLLegendElement::HTMLLegendElement(Document& document)
+HTMLLegendElement::HTMLLegendElement(Document& document)
     : HTMLElement(kLegendTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLLegendElement)
diff --git a/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc b/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc
index 7e934dbb..499874c 100644
--- a/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc
@@ -39,8 +39,10 @@
 
 using namespace html_names;
 
-inline HTMLOptGroupElement::HTMLOptGroupElement(Document& document)
-    : HTMLElement(kOptgroupTag, document) {}
+HTMLOptGroupElement::HTMLOptGroupElement(Document& document)
+    : HTMLElement(kOptgroupTag, document) {
+  EnsureUserAgentShadowRoot();
+}
 
 // An explicit empty destructor should be in html_opt_group_element.cc, because
 // if an implicit destructor is used or an empty destructor is defined in
@@ -49,13 +51,6 @@
 // a compile error because of lack of ComputedStyle definition.
 HTMLOptGroupElement::~HTMLOptGroupElement() = default;
 
-HTMLOptGroupElement* HTMLOptGroupElement::Create(Document& document) {
-  HTMLOptGroupElement* opt_group_element =
-      MakeGarbageCollected<HTMLOptGroupElement>(document);
-  opt_group_element->EnsureUserAgentShadowRoot();
-  return opt_group_element;
-}
-
 // static
 bool HTMLOptGroupElement::CanAssignToOptGroupSlot(const Node& node) {
   return node.HasTagName(kOptionTag) || node.HasTagName(kHrTag);
diff --git a/third_party/blink/renderer/core/html/forms/html_opt_group_element.h b/third_party/blink/renderer/core/html/forms/html_opt_group_element.h
index c2580c73..693aa166 100644
--- a/third_party/blink/renderer/core/html/forms/html_opt_group_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_opt_group_element.h
@@ -36,8 +36,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static HTMLOptGroupElement* Create(Document&);
-
   explicit HTMLOptGroupElement(Document&);
 
   bool IsDisabledFormControl() const override;
diff --git a/third_party/blink/renderer/core/html/forms/html_option_element.cc b/third_party/blink/renderer/core/html/forms/html_option_element.cc
index a1091269..202cf9b 100644
--- a/third_party/blink/renderer/core/html/forms/html_option_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_option_element.cc
@@ -47,7 +47,9 @@
 using namespace html_names;
 
 HTMLOptionElement::HTMLOptionElement(Document& document)
-    : HTMLElement(kOptionTag, document), is_selected_(false) {}
+    : HTMLElement(kOptionTag, document), is_selected_(false) {
+  EnsureUserAgentShadowRoot();
+}
 
 // An explicit empty destructor should be in html_option_element.cc, because
 // if an implicit destructor is used or an empty destructor is defined in
@@ -57,9 +59,7 @@
 HTMLOptionElement::~HTMLOptionElement() = default;
 
 HTMLOptionElement* HTMLOptionElement::Create(Document& document) {
-  HTMLOptionElement* option = MakeGarbageCollected<HTMLOptionElement>(document);
-  option->EnsureUserAgentShadowRoot();
-  return option;
+  return MakeGarbageCollected<HTMLOptionElement>(document);
 }
 
 HTMLOptionElement* HTMLOptionElement::CreateForJSConstructor(
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc
index 4356a348..b95d81350 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -97,12 +97,11 @@
       index_to_select_on_cancel_(-1),
       popup_is_visible_(false) {
   SetHasCustomStyleCallbacks();
+  EnsureUserAgentShadowRoot();
 }
 
 HTMLSelectElement* HTMLSelectElement::Create(Document& document) {
-  HTMLSelectElement* select = MakeGarbageCollected<HTMLSelectElement>(document);
-  select->EnsureUserAgentShadowRoot();
-  return select;
+  return MakeGarbageCollected<HTMLSelectElement>(document);
 }
 
 HTMLSelectElement::~HTMLSelectElement() = default;
diff --git a/third_party/blink/renderer/core/html/forms/html_text_area_element.cc b/third_party/blink/renderer/core/html/forms/html_text_area_element.cc
index 64ffadd..2c1150ee 100644
--- a/third_party/blink/renderer/core/html/forms/html_text_area_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_text_area_element.cc
@@ -75,13 +75,12 @@
       cols_(kDefaultCols),
       wrap_(kSoftWrap),
       is_dirty_(false),
-      is_placeholder_visible_(false) {}
+      is_placeholder_visible_(false) {
+  EnsureUserAgentShadowRoot();
+}
 
 HTMLTextAreaElement* HTMLTextAreaElement::Create(Document& document) {
-  HTMLTextAreaElement* text_area =
-      MakeGarbageCollected<HTMLTextAreaElement>(document);
-  text_area->EnsureUserAgentShadowRoot();
-  return text_area;
+  return MakeGarbageCollected<HTMLTextAreaElement>(document);
 }
 
 void HTMLTextAreaElement::DidAddUserAgentShadowRoot(ShadowRoot& root) {
diff --git a/third_party/blink/renderer/core/html/forms/option_list_test.cc b/third_party/blink/renderer/core/html/forms/option_list_test.cc
index 714bbc38..d734e41 100644
--- a/third_party/blink/renderer/core/html/forms/option_list_test.cc
+++ b/third_party/blink/renderer/core/html/forms/option_list_test.cc
@@ -23,7 +23,7 @@
  protected:
   void SetUp() override {
     HTMLDocument* document = HTMLDocument::CreateForTest();
-    HTMLSelectElement* select = HTMLSelectElement::Create(*document);
+    auto* select = MakeGarbageCollected<HTMLSelectElement>(*document);
     document->AppendChild(select);
     select_ = select;
   }
diff --git a/third_party/blink/renderer/core/html/html_area_element.cc b/third_party/blink/renderer/core/html/html_area_element.cc
index 389f334..940cb3f 100644
--- a/third_party/blink/renderer/core/html/html_area_element.cc
+++ b/third_party/blink/renderer/core/html/html_area_element.cc
@@ -44,7 +44,7 @@
 
 using namespace html_names;
 
-inline HTMLAreaElement::HTMLAreaElement(Document& document)
+HTMLAreaElement::HTMLAreaElement(Document& document)
     : HTMLAnchorElement(kAreaTag, document), shape_(kRect) {}
 
 // An explicit empty destructor should be in html_area_element.cc, because
diff --git a/third_party/blink/renderer/core/html/html_content_element.cc b/third_party/blink/renderer/core/html/html_content_element.cc
index 02dea31..9e5c7ae 100644
--- a/third_party/blink/renderer/core/html/html_content_element.cc
+++ b/third_party/blink/renderer/core/html/html_content_element.cc
@@ -40,7 +40,7 @@
 
 DEFINE_NODE_FACTORY(HTMLContentElement)
 
-inline HTMLContentElement::HTMLContentElement(Document& document)
+HTMLContentElement::HTMLContentElement(Document& document)
     : V0InsertionPoint(kContentTag, document),
       should_parse_select_(false),
       is_valid_selector_(true) {
diff --git a/third_party/blink/renderer/core/html/html_details_element.cc b/third_party/blink/renderer/core/html/html_details_element.cc
index 1741855f..ec9b8bb 100644
--- a/third_party/blink/renderer/core/html/html_details_element.cc
+++ b/third_party/blink/renderer/core/html/html_details_element.cc
@@ -43,16 +43,10 @@
 
 using namespace html_names;
 
-HTMLDetailsElement* HTMLDetailsElement::Create(Document& document) {
-  HTMLDetailsElement* details =
-      MakeGarbageCollected<HTMLDetailsElement>(document);
-  details->EnsureUserAgentShadowRoot();
-  return details;
-}
-
 HTMLDetailsElement::HTMLDetailsElement(Document& document)
     : HTMLElement(kDetailsTag, document), is_open_(false) {
   UseCounter::Count(document, WebFeature::kDetailsElement);
+  EnsureUserAgentShadowRoot();
 }
 
 HTMLDetailsElement::~HTMLDetailsElement() = default;
diff --git a/third_party/blink/renderer/core/html/html_details_element.h b/third_party/blink/renderer/core/html/html_details_element.h
index 13e5401..d6429c1 100644
--- a/third_party/blink/renderer/core/html/html_details_element.h
+++ b/third_party/blink/renderer/core/html/html_details_element.h
@@ -30,7 +30,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static HTMLDetailsElement* Create(Document&);
   void ToggleOpen();
 
   explicit HTMLDetailsElement(Document&);
diff --git a/third_party/blink/renderer/core/html/html_dialog_element.cc b/third_party/blink/renderer/core/html/html_dialog_element.cc
index 71fc70b..8e2bac3 100644
--- a/third_party/blink/renderer/core/html/html_dialog_element.cc
+++ b/third_party/blink/renderer/core/html/html_dialog_element.cc
@@ -95,7 +95,7 @@
   document.ClearAXObjectCache();
 }
 
-inline HTMLDialogElement::HTMLDialogElement(Document& document)
+HTMLDialogElement::HTMLDialogElement(Document& document)
     : HTMLElement(kDialogTag, document),
       centering_mode_(kNotCentered),
       centered_position_(0),
diff --git a/third_party/blink/renderer/core/html/html_directory_element.cc b/third_party/blink/renderer/core/html/html_directory_element.cc
index 35f7b1a..36b8252 100644
--- a/third_party/blink/renderer/core/html/html_directory_element.cc
+++ b/third_party/blink/renderer/core/html/html_directory_element.cc
@@ -28,7 +28,7 @@
 
 using namespace html_names;
 
-inline HTMLDirectoryElement::HTMLDirectoryElement(Document& document)
+HTMLDirectoryElement::HTMLDirectoryElement(Document& document)
     : HTMLElement(kDirTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLDirectoryElement)
diff --git a/third_party/blink/renderer/core/html/html_dlist_element.cc b/third_party/blink/renderer/core/html/html_dlist_element.cc
index 1dc74690..500dedf 100644
--- a/third_party/blink/renderer/core/html/html_dlist_element.cc
+++ b/third_party/blink/renderer/core/html/html_dlist_element.cc
@@ -28,7 +28,7 @@
 
 using namespace html_names;
 
-inline HTMLDListElement::HTMLDListElement(Document& document)
+HTMLDListElement::HTMLDListElement(Document& document)
     : HTMLElement(kDlTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLDListElement)
diff --git a/third_party/blink/renderer/core/html/html_embed_element.cc b/third_party/blink/renderer/core/html/html_embed_element.cc
index 11a62a51..99b1b78 100644
--- a/third_party/blink/renderer/core/html/html_embed_element.cc
+++ b/third_party/blink/renderer/core/html/html_embed_element.cc
@@ -42,18 +42,18 @@
 
 using namespace html_names;
 
-inline HTMLEmbedElement::HTMLEmbedElement(Document& document,
-                                          const CreateElementFlags flags)
+HTMLEmbedElement::HTMLEmbedElement(Document& document,
+                                   const CreateElementFlags flags)
     : HTMLPlugInElement(kEmbedTag,
                         document,
                         flags,
-                        kShouldPreferPlugInsForImages) {}
+                        kShouldPreferPlugInsForImages) {
+  EnsureUserAgentShadowRoot();
+}
 
 HTMLEmbedElement* HTMLEmbedElement::Create(Document& document,
                                            const CreateElementFlags flags) {
-  auto* element = MakeGarbageCollected<HTMLEmbedElement>(document, flags);
-  element->EnsureUserAgentShadowRoot();
-  return element;
+  return MakeGarbageCollected<HTMLEmbedElement>(document, flags);
 }
 
 const AttrNameToTrustedType& HTMLEmbedElement::GetCheckedAttributeTypes()
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.cc b/third_party/blink/renderer/core/html/html_frame_set_element.cc
index 4facd6d..eb49f1b 100644
--- a/third_party/blink/renderer/core/html/html_frame_set_element.cc
+++ b/third_party/blink/renderer/core/html/html_frame_set_element.cc
@@ -41,7 +41,7 @@
 
 using namespace html_names;
 
-inline HTMLFrameSetElement::HTMLFrameSetElement(Document& document)
+HTMLFrameSetElement::HTMLFrameSetElement(Document& document)
     : HTMLElement(kFramesetTag, document),
       border_(6),
       border_set_(false),
diff --git a/third_party/blink/renderer/core/html/html_heading_element.cc b/third_party/blink/renderer/core/html/html_heading_element.cc
index 0b561696..5e216dee 100644
--- a/third_party/blink/renderer/core/html/html_heading_element.cc
+++ b/third_party/blink/renderer/core/html/html_heading_element.cc
@@ -24,8 +24,8 @@
 
 namespace blink {
 
-inline HTMLHeadingElement::HTMLHeadingElement(const QualifiedName& tag_name,
-                                              Document& document)
+HTMLHeadingElement::HTMLHeadingElement(const QualifiedName& tag_name,
+                                       Document& document)
     : HTMLElement(tag_name, document) {}
 
 DEFINE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLHeadingElement)
diff --git a/third_party/blink/renderer/core/html/html_heading_element.h b/third_party/blink/renderer/core/html/html_heading_element.h
index 73b8fe3..02243d7 100644
--- a/third_party/blink/renderer/core/html/html_heading_element.h
+++ b/third_party/blink/renderer/core/html/html_heading_element.h
@@ -33,7 +33,6 @@
  public:
   DECLARE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLHeadingElement);
 
- private:
   HTMLHeadingElement(const QualifiedName&, Document&);
 };
 
diff --git a/third_party/blink/renderer/core/html/html_image_element.cc b/third_party/blink/renderer/core/html/html_image_element.cc
index 19f3fbd3..04c1fee 100644
--- a/third_party/blink/renderer/core/html/html_image_element.cc
+++ b/third_party/blink/renderer/core/html/html_image_element.cc
@@ -90,6 +90,10 @@
   Member<HTMLImageElement> element_;
 };
 
+HTMLImageElement::HTMLImageElement(Document& document,
+                                   const CreateElementFlags flags)
+    : HTMLImageElement(document, flags.IsCreatedByParser()) {}
+
 HTMLImageElement::HTMLImageElement(Document& document, bool created_by_parser)
     : HTMLElement(kImgTag, document),
       image_loader_(MakeGarbageCollected<HTMLImageLoader>(this)),
diff --git a/third_party/blink/renderer/core/html/html_image_element.h b/third_party/blink/renderer/core/html/html_image_element.h
index d1badfef..175d429b 100644
--- a/third_party/blink/renderer/core/html/html_image_element.h
+++ b/third_party/blink/renderer/core/html/html_image_element.h
@@ -70,6 +70,7 @@
                                                   unsigned width,
                                                   unsigned height);
 
+  HTMLImageElement(Document&, const CreateElementFlags);
   explicit HTMLImageElement(Document&, bool created_by_parser = false);
   ~HTMLImageElement() override;
   void Trace(Visitor*) override;
diff --git a/third_party/blink/renderer/core/html/html_map_element.cc b/third_party/blink/renderer/core/html/html_map_element.cc
index f4dfd2d..925f07ea 100644
--- a/third_party/blink/renderer/core/html/html_map_element.cc
+++ b/third_party/blink/renderer/core/html/html_map_element.cc
@@ -35,7 +35,7 @@
 
 using namespace html_names;
 
-inline HTMLMapElement::HTMLMapElement(Document& document)
+HTMLMapElement::HTMLMapElement(Document& document)
     : HTMLElement(kMapTag, document) {
   UseCounter::Count(document, WebFeature::kMapElement);
 }
diff --git a/third_party/blink/renderer/core/html/html_marquee_element.cc b/third_party/blink/renderer/core/html/html_marquee_element.cc
index 8c1b99b..efef0f5 100644
--- a/third_party/blink/renderer/core/html/html_marquee_element.cc
+++ b/third_party/blink/renderer/core/html/html_marquee_element.cc
@@ -51,16 +51,10 @@
 
 namespace blink {
 
-inline HTMLMarqueeElement::HTMLMarqueeElement(Document& document)
+HTMLMarqueeElement::HTMLMarqueeElement(Document& document)
     : HTMLElement(html_names::kMarqueeTag, document) {
   UseCounter::Count(document, WebFeature::kHTMLMarqueeElement);
-}
-
-HTMLMarqueeElement* HTMLMarqueeElement::Create(Document& document) {
-  HTMLMarqueeElement* marquee_element =
-      MakeGarbageCollected<HTMLMarqueeElement>(document);
-  marquee_element->EnsureUserAgentShadowRoot();
-  return marquee_element;
+  EnsureUserAgentShadowRoot();
 }
 
 void HTMLMarqueeElement::DidAddUserAgentShadowRoot(ShadowRoot& shadow_root) {
diff --git a/third_party/blink/renderer/core/html/html_marquee_element.h b/third_party/blink/renderer/core/html/html_marquee_element.h
index d9cb385..a9461ed 100644
--- a/third_party/blink/renderer/core/html/html_marquee_element.h
+++ b/third_party/blink/renderer/core/html/html_marquee_element.h
@@ -35,8 +35,6 @@
  public:
   void Trace(Visitor*) override;
 
-  static HTMLMarqueeElement* Create(Document&);
-
   explicit HTMLMarqueeElement(Document&);
 
   InsertionNotificationRequest InsertedInto(ContainerNode&) final;
diff --git a/third_party/blink/renderer/core/html/html_menu_element.cc b/third_party/blink/renderer/core/html/html_menu_element.cc
index 784d144b..9378c1d 100644
--- a/third_party/blink/renderer/core/html/html_menu_element.cc
+++ b/third_party/blink/renderer/core/html/html_menu_element.cc
@@ -28,7 +28,7 @@
 
 using namespace html_names;
 
-inline HTMLMenuElement::HTMLMenuElement(Document& document)
+HTMLMenuElement::HTMLMenuElement(Document& document)
     : HTMLElement(kMenuTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLMenuElement)
diff --git a/third_party/blink/renderer/core/html/html_meter_element.cc b/third_party/blink/renderer/core/html/html_meter_element.cc
index 6556eff..634e40cf 100644
--- a/third_party/blink/renderer/core/html/html_meter_element.cc
+++ b/third_party/blink/renderer/core/html/html_meter_element.cc
@@ -37,16 +37,11 @@
 HTMLMeterElement::HTMLMeterElement(Document& document)
     : HTMLElement(kMeterTag, document) {
   UseCounter::Count(document, WebFeature::kMeterElement);
+  EnsureUserAgentShadowRoot();
 }
 
 HTMLMeterElement::~HTMLMeterElement() = default;
 
-HTMLMeterElement* HTMLMeterElement::Create(Document& document) {
-  HTMLMeterElement* meter = MakeGarbageCollected<HTMLMeterElement>(document);
-  meter->EnsureUserAgentShadowRoot();
-  return meter;
-}
-
 LayoutObject* HTMLMeterElement::CreateLayoutObject(const ComputedStyle& style,
                                                    LegacyLayout legacy) {
   switch (style.Appearance()) {
diff --git a/third_party/blink/renderer/core/html/html_meter_element.h b/third_party/blink/renderer/core/html/html_meter_element.h
index eab8d9dc..c71725eb 100644
--- a/third_party/blink/renderer/core/html/html_meter_element.h
+++ b/third_party/blink/renderer/core/html/html_meter_element.h
@@ -32,8 +32,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static HTMLMeterElement* Create(Document&);
-
   explicit HTMLMeterElement(Document&);
 
   enum GaugeRegion {
diff --git a/third_party/blink/renderer/core/html/html_mod_element.cc b/third_party/blink/renderer/core/html/html_mod_element.cc
index 4087cbd..a557b2c6 100644
--- a/third_party/blink/renderer/core/html/html_mod_element.cc
+++ b/third_party/blink/renderer/core/html/html_mod_element.cc
@@ -28,8 +28,8 @@
 
 using namespace html_names;
 
-inline HTMLModElement::HTMLModElement(const QualifiedName& tag_name,
-                                      Document& document)
+HTMLModElement::HTMLModElement(const QualifiedName& tag_name,
+                               Document& document)
     : HTMLElement(tag_name, document) {}
 
 DEFINE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLModElement)
diff --git a/third_party/blink/renderer/core/html/html_mod_element.h b/third_party/blink/renderer/core/html/html_mod_element.h
index 4eb8e3b..3326c22 100644
--- a/third_party/blink/renderer/core/html/html_mod_element.h
+++ b/third_party/blink/renderer/core/html/html_mod_element.h
@@ -34,9 +34,9 @@
  public:
   DECLARE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLModElement);
 
- private:
   HTMLModElement(const QualifiedName&, Document&);
 
+ private:
   bool IsURLAttribute(const Attribute&) const override;
   bool HasLegalLinkAttribute(const QualifiedName&) const override;
   const QualifiedName& SubResourceAttributeName() const override;
diff --git a/third_party/blink/renderer/core/html/html_no_embed_element.cc b/third_party/blink/renderer/core/html/html_no_embed_element.cc
index b2ac3a0..8be7a981 100644
--- a/third_party/blink/renderer/core/html/html_no_embed_element.cc
+++ b/third_party/blink/renderer/core/html/html_no_embed_element.cc
@@ -39,7 +39,7 @@
 
 using namespace html_names;
 
-inline HTMLNoEmbedElement::HTMLNoEmbedElement(Document& document)
+HTMLNoEmbedElement::HTMLNoEmbedElement(Document& document)
     : HTMLElement(kNoembedTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLNoEmbedElement)
diff --git a/third_party/blink/renderer/core/html/html_no_script_element.cc b/third_party/blink/renderer/core/html/html_no_script_element.cc
index 3d9e5cd2..9ada838 100644
--- a/third_party/blink/renderer/core/html/html_no_script_element.cc
+++ b/third_party/blink/renderer/core/html/html_no_script_element.cc
@@ -39,7 +39,7 @@
 
 using namespace html_names;
 
-inline HTMLNoScriptElement::HTMLNoScriptElement(Document& document)
+HTMLNoScriptElement::HTMLNoScriptElement(Document& document)
     : HTMLElement(kNoscriptTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLNoScriptElement)
diff --git a/third_party/blink/renderer/core/html/html_object_element.cc b/third_party/blink/renderer/core/html/html_object_element.cc
index f69f7230..70af5c52 100644
--- a/third_party/blink/renderer/core/html/html_object_element.cc
+++ b/third_party/blink/renderer/core/html/html_object_element.cc
@@ -48,23 +48,18 @@
 
 using namespace html_names;
 
-inline HTMLObjectElement::HTMLObjectElement(Document& document,
-                                            const CreateElementFlags flags)
+HTMLObjectElement::HTMLObjectElement(Document& document,
+                                     const CreateElementFlags flags)
     : HTMLPlugInElement(kObjectTag,
                         document,
                         flags,
                         kShouldNotPreferPlugInsForImages),
-      use_fallback_content_(false) {}
+      use_fallback_content_(false) {
+  EnsureUserAgentShadowRoot();
+}
 
 inline HTMLObjectElement::~HTMLObjectElement() = default;
 
-HTMLObjectElement* HTMLObjectElement::Create(Document& document,
-                                             const CreateElementFlags flags) {
-  auto* element = MakeGarbageCollected<HTMLObjectElement>(document, flags);
-  element->EnsureUserAgentShadowRoot();
-  return element;
-}
-
 void HTMLObjectElement::Trace(Visitor* visitor) {
   ListedElement::Trace(visitor);
   HTMLPlugInElement::Trace(visitor);
diff --git a/third_party/blink/renderer/core/html/html_object_element.h b/third_party/blink/renderer/core/html/html_object_element.h
index d04d10d0..d3421468 100644
--- a/third_party/blink/renderer/core/html/html_object_element.h
+++ b/third_party/blink/renderer/core/html/html_object_element.h
@@ -44,8 +44,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(HTMLObjectElement);
 
  public:
-  static HTMLObjectElement* Create(Document&, const CreateElementFlags);
-
   HTMLObjectElement(Document&, const CreateElementFlags);
   ~HTMLObjectElement() override;
   void Trace(Visitor*) override;
diff --git a/third_party/blink/renderer/core/html/html_olist_element.cc b/third_party/blink/renderer/core/html/html_olist_element.cc
index 0ec2b17..08fd8db1 100644
--- a/third_party/blink/renderer/core/html/html_olist_element.cc
+++ b/third_party/blink/renderer/core/html/html_olist_element.cc
@@ -34,7 +34,7 @@
 
 using namespace html_names;
 
-inline HTMLOListElement::HTMLOListElement(Document& document)
+HTMLOListElement::HTMLOListElement(Document& document)
     : HTMLElement(kOlTag, document),
       start_(0xBADBEEF),
       item_count_(0),
diff --git a/third_party/blink/renderer/core/html/html_param_element.cc b/third_party/blink/renderer/core/html/html_param_element.cc
index c910bed..84e81c5 100644
--- a/third_party/blink/renderer/core/html/html_param_element.cc
+++ b/third_party/blink/renderer/core/html/html_param_element.cc
@@ -30,7 +30,7 @@
 
 using namespace html_names;
 
-inline HTMLParamElement::HTMLParamElement(Document& document)
+HTMLParamElement::HTMLParamElement(Document& document)
     : HTMLElement(kParamTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLParamElement)
diff --git a/third_party/blink/renderer/core/html/html_picture_element.cc b/third_party/blink/renderer/core/html/html_picture_element.cc
index a2bf86e..172bf152 100644
--- a/third_party/blink/renderer/core/html/html_picture_element.cc
+++ b/third_party/blink/renderer/core/html/html_picture_element.cc
@@ -15,7 +15,7 @@
 
 using namespace html_names;
 
-inline HTMLPictureElement::HTMLPictureElement(Document& document)
+HTMLPictureElement::HTMLPictureElement(Document& document)
     : HTMLElement(kPictureTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLPictureElement)
diff --git a/third_party/blink/renderer/core/html/html_pre_element.cc b/third_party/blink/renderer/core/html/html_pre_element.cc
index 78e2ef69..99177a5 100644
--- a/third_party/blink/renderer/core/html/html_pre_element.cc
+++ b/third_party/blink/renderer/core/html/html_pre_element.cc
@@ -31,8 +31,8 @@
 
 using namespace html_names;
 
-inline HTMLPreElement::HTMLPreElement(const QualifiedName& tag_name,
-                                      Document& document)
+HTMLPreElement::HTMLPreElement(const QualifiedName& tag_name,
+                               Document& document)
     : HTMLElement(tag_name, document) {}
 
 DEFINE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLPreElement)
diff --git a/third_party/blink/renderer/core/html/html_pre_element.h b/third_party/blink/renderer/core/html/html_pre_element.h
index 91b8ec8..f4bff2f 100644
--- a/third_party/blink/renderer/core/html/html_pre_element.h
+++ b/third_party/blink/renderer/core/html/html_pre_element.h
@@ -33,9 +33,9 @@
  public:
   DECLARE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLPreElement);
 
- private:
   HTMLPreElement(const QualifiedName&, Document&);
 
+ private:
   bool IsPresentationAttribute(const QualifiedName&) const override;
   void CollectStyleForPresentationAttribute(
       const QualifiedName&,
diff --git a/third_party/blink/renderer/core/html/html_progress_element.cc b/third_party/blink/renderer/core/html/html_progress_element.cc
index 552ec47..8767c92 100644
--- a/third_party/blink/renderer/core/html/html_progress_element.cc
+++ b/third_party/blink/renderer/core/html/html_progress_element.cc
@@ -38,17 +38,11 @@
 HTMLProgressElement::HTMLProgressElement(Document& document)
     : HTMLElement(kProgressTag, document), value_(nullptr) {
   UseCounter::Count(document, WebFeature::kProgressElement);
+  EnsureUserAgentShadowRoot();
 }
 
 HTMLProgressElement::~HTMLProgressElement() = default;
 
-HTMLProgressElement* HTMLProgressElement::Create(Document& document) {
-  HTMLProgressElement* progress =
-      MakeGarbageCollected<HTMLProgressElement>(document);
-  progress->EnsureUserAgentShadowRoot();
-  return progress;
-}
-
 LayoutObject* HTMLProgressElement::CreateLayoutObject(
     const ComputedStyle& style,
     LegacyLayout legacy) {
diff --git a/third_party/blink/renderer/core/html/html_progress_element.h b/third_party/blink/renderer/core/html/html_progress_element.h
index 510236b8..3b7dab2f 100644
--- a/third_party/blink/renderer/core/html/html_progress_element.h
+++ b/third_party/blink/renderer/core/html/html_progress_element.h
@@ -23,6 +23,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 
 namespace blink {
 
@@ -35,8 +36,6 @@
   static const double kIndeterminatePosition;
   static const double kInvalidPosition;
 
-  static HTMLProgressElement* Create(Document&);
-
   explicit HTMLProgressElement(Document&);
 
   double value() const;
diff --git a/third_party/blink/renderer/core/html/html_quote_element.cc b/third_party/blink/renderer/core/html/html_quote_element.cc
index 8d9fe5eb..74d985a 100644
--- a/third_party/blink/renderer/core/html/html_quote_element.cc
+++ b/third_party/blink/renderer/core/html/html_quote_element.cc
@@ -29,8 +29,8 @@
 
 using namespace html_names;
 
-inline HTMLQuoteElement::HTMLQuoteElement(const QualifiedName& tag_name,
-                                          Document& document)
+HTMLQuoteElement::HTMLQuoteElement(const QualifiedName& tag_name,
+                                   Document& document)
     : HTMLElement(tag_name, document) {
   DCHECK(HasTagName(kQTag) || HasTagName(kBlockquoteTag));
 }
diff --git a/third_party/blink/renderer/core/html/html_quote_element.h b/third_party/blink/renderer/core/html/html_quote_element.h
index f2eb658..7efdb8d 100644
--- a/third_party/blink/renderer/core/html/html_quote_element.h
+++ b/third_party/blink/renderer/core/html/html_quote_element.h
@@ -35,9 +35,9 @@
  public:
   DECLARE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLQuoteElement);
 
- private:
   HTMLQuoteElement(const QualifiedName&, Document&);
 
+ private:
   bool IsURLAttribute(const Attribute&) const override;
   bool HasLegalLinkAttribute(const QualifiedName&) const override;
   const QualifiedName& SubResourceAttributeName() const override;
diff --git a/third_party/blink/renderer/core/html/html_rt_element.cc b/third_party/blink/renderer/core/html/html_rt_element.cc
index c6695257..d8699b5 100644
--- a/third_party/blink/renderer/core/html/html_rt_element.cc
+++ b/third_party/blink/renderer/core/html/html_rt_element.cc
@@ -11,7 +11,7 @@
 
 using namespace html_names;
 
-inline HTMLRTElement::HTMLRTElement(Document& document)
+HTMLRTElement::HTMLRTElement(Document& document)
     : HTMLElement(kRtTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLRTElement)
diff --git a/third_party/blink/renderer/core/html/html_ruby_element.cc b/third_party/blink/renderer/core/html/html_ruby_element.cc
index 3ec7bd5..d5710b4b 100644
--- a/third_party/blink/renderer/core/html/html_ruby_element.cc
+++ b/third_party/blink/renderer/core/html/html_ruby_element.cc
@@ -11,7 +11,7 @@
 
 using namespace html_names;
 
-inline HTMLRubyElement::HTMLRubyElement(Document& document)
+HTMLRubyElement::HTMLRubyElement(Document& document)
     : HTMLElement(kRubyTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLRubyElement)
diff --git a/third_party/blink/renderer/core/html/html_shadow_element.cc b/third_party/blink/renderer/core/html/html_shadow_element.cc
index db8da59..31b6c9613 100644
--- a/third_party/blink/renderer/core/html/html_shadow_element.cc
+++ b/third_party/blink/renderer/core/html/html_shadow_element.cc
@@ -40,7 +40,7 @@
 
 class Document;
 
-inline HTMLShadowElement::HTMLShadowElement(Document& document)
+HTMLShadowElement::HTMLShadowElement(Document& document)
     : V0InsertionPoint(html_names::kShadowTag, document) {
   UseCounter::Count(document, WebFeature::kHTMLShadowElement);
 }
diff --git a/third_party/blink/renderer/core/html/html_slot_element.cc b/third_party/blink/renderer/core/html/html_slot_element.cc
index e33da81b..ad1aed6f 100644
--- a/third_party/blink/renderer/core/html/html_slot_element.cc
+++ b/third_party/blink/renderer/core/html/html_slot_element.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/core/html/html_slot_element.h"
 
 #include <array>
+
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
@@ -75,7 +76,7 @@
   return slot;
 }
 
-inline HTMLSlotElement::HTMLSlotElement(Document& document)
+HTMLSlotElement::HTMLSlotElement(Document& document)
     : HTMLElement(kSlotTag, document) {
   UseCounter::Count(document, WebFeature::kHTMLSlotElement);
   SetHasCustomStyleCallbacks();
diff --git a/third_party/blink/renderer/core/html/html_summary_element.cc b/third_party/blink/renderer/core/html/html_summary_element.cc
index 92545e80..f3172e2e 100644
--- a/third_party/blink/renderer/core/html/html_summary_element.cc
+++ b/third_party/blink/renderer/core/html/html_summary_element.cc
@@ -38,15 +38,13 @@
 using namespace html_names;
 
 HTMLSummaryElement* HTMLSummaryElement::Create(Document& document) {
-  HTMLSummaryElement* summary =
-      MakeGarbageCollected<HTMLSummaryElement>(document);
-  summary->EnsureUserAgentShadowRoot();
-  return summary;
+  return MakeGarbageCollected<HTMLSummaryElement>(document);
 }
 
 HTMLSummaryElement::HTMLSummaryElement(Document& document)
     : HTMLElement(kSummaryTag, document) {
   SetHasCustomStyleCallbacks();
+  EnsureUserAgentShadowRoot();
 }
 
 LayoutObject* HTMLSummaryElement::CreateLayoutObject(const ComputedStyle& style,
diff --git a/third_party/blink/renderer/core/html/html_table_col_element.cc b/third_party/blink/renderer/core/html/html_table_col_element.cc
index 48a4a2d2..1a42a94 100644
--- a/third_party/blink/renderer/core/html/html_table_col_element.cc
+++ b/third_party/blink/renderer/core/html/html_table_col_element.cc
@@ -37,8 +37,8 @@
 
 using namespace html_names;
 
-inline HTMLTableColElement::HTMLTableColElement(const QualifiedName& tag_name,
-                                                Document& document)
+HTMLTableColElement::HTMLTableColElement(const QualifiedName& tag_name,
+                                         Document& document)
     : HTMLTablePartElement(tag_name, document), span_(kDefaultColSpan) {}
 
 DEFINE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLTableColElement)
diff --git a/third_party/blink/renderer/core/html/html_table_col_element.h b/third_party/blink/renderer/core/html/html_table_col_element.h
index 0d0e3a3..edbfbfd 100644
--- a/third_party/blink/renderer/core/html/html_table_col_element.h
+++ b/third_party/blink/renderer/core/html/html_table_col_element.h
@@ -36,6 +36,8 @@
  public:
   DECLARE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLTableColElement);
 
+  HTMLTableColElement(const QualifiedName& tag_name, Document&);
+
   unsigned span() const { return span_; }
   void setSpan(unsigned);
 
@@ -44,8 +46,6 @@
   bool HasNonInBodyInsertionMode() const override { return true; }
 
  private:
-  HTMLTableColElement(const QualifiedName& tag_name, Document&);
-
   void ParseAttribute(const AttributeModificationParams&) override;
   bool IsPresentationAttribute(const QualifiedName&) const override;
   void CollectStyleForPresentationAttribute(
diff --git a/third_party/blink/renderer/core/html/html_tag_names.json5 b/third_party/blink/renderer/core/html/html_tag_names.json5
index c94a0b9d..9150a6d 100644
--- a/third_party/blink/renderer/core/html/html_tag_names.json5
+++ b/third_party/blink/renderer/core/html/html_tag_names.json5
@@ -362,6 +362,7 @@
       name: "portal",
       interfaceName: "HTMLPortalElement",
       interfaceHeaderDir: "third_party/blink/renderer/core/html/portal",
+      runtimeEnabled: "Portals",
     },
     "pre",
     {
diff --git a/third_party/blink/renderer/core/html/html_template_element.cc b/third_party/blink/renderer/core/html/html_template_element.cc
index 8b9caec..fbf70042 100644
--- a/third_party/blink/renderer/core/html/html_template_element.cc
+++ b/third_party/blink/renderer/core/html/html_template_element.cc
@@ -39,7 +39,7 @@
 
 using namespace html_names;
 
-inline HTMLTemplateElement::HTMLTemplateElement(Document& document)
+HTMLTemplateElement::HTMLTemplateElement(Document& document)
     : HTMLElement(kTemplateTag, document) {
   UseCounter::Count(document, WebFeature::kHTMLTemplateElement);
 }
diff --git a/third_party/blink/renderer/core/html/html_wbr_element.cc b/third_party/blink/renderer/core/html/html_wbr_element.cc
index 788ee11..ec31043 100644
--- a/third_party/blink/renderer/core/html/html_wbr_element.cc
+++ b/third_party/blink/renderer/core/html/html_wbr_element.cc
@@ -37,7 +37,7 @@
 
 using namespace html_names;
 
-inline HTMLWBRElement::HTMLWBRElement(Document& document)
+HTMLWBRElement::HTMLWBRElement(Document& document)
     : HTMLElement(kWbrTag, document) {}
 
 DEFINE_NODE_FACTORY(HTMLWBRElement)
diff --git a/third_party/blink/renderer/core/html/media/html_audio_element.cc b/third_party/blink/renderer/core/html/media/html_audio_element.cc
index c1fecb4..79368e1 100644
--- a/third_party/blink/renderer/core/html/media/html_audio_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_audio_element.cc
@@ -33,24 +33,22 @@
 using namespace html_names;
 
 HTMLAudioElement::HTMLAudioElement(Document& document)
-    : HTMLMediaElement(kAudioTag, document) {}
+    : HTMLMediaElement(kAudioTag, document) {
+  EnsureUserAgentShadowRoot();
+  UpdateStateIfNeeded();
+}
 
 HTMLAudioElement* HTMLAudioElement::Create(Document& document) {
-  HTMLAudioElement* audio = MakeGarbageCollected<HTMLAudioElement>(document);
-  audio->EnsureUserAgentShadowRoot();
-  audio->UpdateStateIfNeeded();
-  return audio;
+  return MakeGarbageCollected<HTMLAudioElement>(document);
 }
 
 HTMLAudioElement* HTMLAudioElement::CreateForJSConstructor(
     Document& document,
     const AtomicString& src) {
   HTMLAudioElement* audio = MakeGarbageCollected<HTMLAudioElement>(document);
-  audio->EnsureUserAgentShadowRoot();
   audio->setPreload(AtomicString("auto"));
   if (!src.IsNull())
     audio->SetSrc(src);
-  audio->UpdateStateIfNeeded();
   return audio;
 }
 
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index 07f6c29..8e10478e 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -26,6 +26,7 @@
 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
 
 #include <memory>
+
 #include "base/bind_helpers.h"
 #include "cc/paint/paint_canvas.h"
 #include "third_party/blink/public/platform/web_fullscreen_video_status.h"
@@ -78,7 +79,7 @@
 
 }  // anonymous namespace
 
-inline HTMLVideoElement::HTMLVideoElement(Document& document)
+HTMLVideoElement::HTMLVideoElement(Document& document)
     : HTMLMediaElement(kVideoTag, document),
       remoting_interstitial_(nullptr),
       picture_in_picture_interstitial_(nullptr),
@@ -101,13 +102,13 @@
   }
 
   wake_lock_ = MakeGarbageCollected<VideoWakeLock>(*this);
+
+  EnsureUserAgentShadowRoot();
+  UpdateStateIfNeeded();
 }
 
 HTMLVideoElement* HTMLVideoElement::Create(Document& document) {
-  HTMLVideoElement* video = MakeGarbageCollected<HTMLVideoElement>(document);
-  video->EnsureUserAgentShadowRoot();
-  video->UpdateStateIfNeeded();
-  return video;
+  return MakeGarbageCollected<HTMLVideoElement>(document);
 }
 
 void HTMLVideoElement::Trace(Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/html/track/html_track_element.cc b/third_party/blink/renderer/core/html/track/html_track_element.cc
index 2188829..63f49f68 100644
--- a/third_party/blink/renderer/core/html/track/html_track_element.cc
+++ b/third_party/blink/renderer/core/html/track/html_track_element.cc
@@ -48,7 +48,7 @@
   return url.GetString().Substring(0, kMaximumURLLengthForLogging) + "...";
 }
 
-inline HTMLTrackElement::HTMLTrackElement(Document& document)
+HTMLTrackElement::HTMLTrackElement(Document& document)
     : HTMLElement(kTrackTag, document),
       load_timer_(document.GetTaskRunner(TaskType::kNetworking),
                   this,
diff --git a/third_party/blink/renderer/core/input/event_handler_test.cc b/third_party/blink/renderer/core/input/event_handler_test.cc
index 0cff945..0ef358e 100644
--- a/third_party/blink/renderer/core/input/event_handler_test.cc
+++ b/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -24,6 +24,7 @@
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/loader/empty_clients.h"
 #include "third_party/blink/renderer/core/page/autoscroll_controller.h"
 #include "third_party/blink/renderer/core/page/page.h"
@@ -1443,6 +1444,78 @@
   EXPECT_EQ("hover over me", element3.InnerHTML().Utf8());
 }
 
+// Test that the hover is updated at the next begin frame after the smooth JS
+// scroll ends.
+TEST_F(EventHandlerSimTest, TestUpdateHoverAfterJSScrollAtBeginFrame) {
+  RuntimeEnabledFeatures::SetUpdateHoverFromScrollAtBeginFrameEnabled(true);
+  WebView().MainFrameWidget()->Resize(WebSize(800, 500));
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <style>
+      body, html {
+        margin: 0;
+        height: 500vh;
+      }
+      div {
+        height: 500px;
+        width: 100%;
+      }
+    </style>
+    <body>
+    <div class="hoverme" id="hoverarea">hover over me</div>
+    </body>
+  )HTML");
+  Compositor().BeginFrame();
+
+  // Set mouse position and active web view.
+  WebMouseEvent mouse_move_event(
+      WebMouseEvent::kMouseMove, WebFloatPoint(100, 100),
+      WebFloatPoint(100, 100), WebPointerProperties::Button::kNoButton, 0,
+      WebInputEvent::Modifiers::kNoModifiers,
+      WebInputEvent::GetStaticTimeStampForTests());
+  mouse_move_event.SetFrameScale(1);
+  GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
+      mouse_move_event, Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
+
+  WebView().MainFrameWidget()->SetFocus(true);
+  WebView().SetIsActive(true);
+
+  Element* element = GetDocument().getElementById("hoverarea");
+  EXPECT_TRUE(element->IsHovered());
+
+  // Find the scrollable area and set scroll offset.
+  ScrollableArea* scrollable_area =
+      GetDocument().GetLayoutView()->GetScrollableArea();
+  bool finished = false;
+  scrollable_area->SetScrollOffset(
+      ScrollOffset(0, 1000), kProgrammaticScroll, kScrollBehaviorSmooth,
+      ScrollableArea::ScrollCallback(
+          base::BindOnce([](bool* finished) { *finished = true; }, &finished)));
+  Compositor().BeginFrame();
+  LocalFrameView* frame_view = GetDocument().View();
+  ASSERT_EQ(0, frame_view->LayoutViewport()->GetScrollOffset().Height());
+  ASSERT_FALSE(finished);
+  // Scrolling is in progress but the hover is not updated yet.
+  Compositor().BeginFrame();
+  // Start scroll animation, but it is not finished.
+  Compositor().BeginFrame();
+  ASSERT_GT(frame_view->LayoutViewport()->GetScrollOffset().Height(), 0);
+  ASSERT_FALSE(finished);
+
+  // Mark hover state dirty but the hover state does not change after the
+  // animation finishes.
+  Compositor().BeginFrame(1);
+  ASSERT_EQ(1000, frame_view->LayoutViewport()->GetScrollOffset().Height());
+  ASSERT_TRUE(finished);
+  EXPECT_TRUE(element->IsHovered());
+
+  // Hover state is updated after the begin frame.
+  Compositor().BeginFrame();
+  EXPECT_FALSE(element->IsHovered());
+}
+
 TEST_F(EventHandlerSimTest, LargeCustomCursorIntersectsViewport) {
   WebView().MainFrameWidget()->Resize(WebSize(800, 600));
   SimRequest request("https://example.com/test.html", "text/html");
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 16510c6..2012c88 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2384,18 +2384,41 @@
   bool is_exclusion_space_equal =
       new_space.ExclusionSpace() == old_space.ExclusionSpace();
 
+  LayoutUnit old_clearance_offset = old_space.ClearanceOffset();
+  LayoutUnit new_clearance_offset = new_space.ClearanceOffset();
+
   // If anything changes within the layout regarding floats, we need to perform
   // a series of additional checks to see if the result can still be reused.
   if (!is_bfc_offset_equal || !is_exclusion_space_equal ||
-      new_space.ClearanceOffset() != old_space.ClearanceOffset()) {
-    // We can't reuse a result if it was previously affected by clearance.
-    //
-    // TODO(layout-dev): There may be cases where we can re-use results here.
-    // However as there are complexities regarding margin-collapsing and
-    // clearance we currently don't attempt to cache anything.
-    if (cached_layout_result->IsPushedByFloats()) {
+      new_clearance_offset != old_clearance_offset) {
+    // Determine if we can reuse a result if it was affected by clearance.
+    bool is_pushed_by_floats = cached_layout_result->IsPushedByFloats();
+    if (is_pushed_by_floats) {
       DCHECK(old_space.HasFloats());
-      return nullptr;
+
+      // We don't attempt to reuse the cached result if the clearance offset
+      // differs from the final BFC-block-offset.
+      //
+      // The |is_pushed_by_floats| flag is also used by nodes who have a
+      // *child* which was pushed by floats. In this case the node may not have
+      // a BFC-block-offset or one equal to the clearance offset.
+      if (!cached_layout_result->BfcBlockOffset() ||
+          *cached_layout_result->BfcBlockOffset() !=
+              old_space.ClearanceOffset())
+        return nullptr;
+
+      // We only reuse the cached result if the delta between the
+      // BFC-block-offset, and the clearance offset grows or remains the same.
+      // If it shrinks it may not be affected by clearance anymore as a margin
+      // may push the fragment below the clearance offset instead.
+      //
+      // TODO(layout-dev): If we track if any margins affected this calculation
+      // (with an additional bit on the layout result) we could potentially
+      // skip this check.
+      if (old_clearance_offset - old_space.BfcOffset().block_offset >
+          new_clearance_offset - new_space.BfcOffset().block_offset) {
+        return nullptr;
+      }
     }
 
     // Check we have a descendant that *may* be positioned above the block-start
@@ -2413,9 +2436,14 @@
           old_space.ExclusionSpace().ClearanceOffset(EClear::kBoth))
         return nullptr;
 
-      bfc_block_offset = *bfc_block_offset -
-                         old_space.BfcOffset().block_offset +
-                         new_space.BfcOffset().block_offset;
+      if (is_pushed_by_floats) {
+        DCHECK_EQ(*bfc_block_offset, old_clearance_offset);
+        bfc_block_offset = new_clearance_offset;
+      } else {
+        bfc_block_offset = *bfc_block_offset -
+                           old_space.BfcOffset().block_offset +
+                           new_space.BfcOffset().block_offset;
+      }
 
       // Check if the new position may intersect with any floats.
       if (*bfc_block_offset <
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index 909cc2e..fe3a1fc 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -330,8 +330,7 @@
     if (!ShouldCreateBoxFragment()) {
       UpdateShouldCreateBoxFragment();
     }
-    if (old_style &&
-        new_style.GetUnicodeBidi() != old_style->GetUnicodeBidi()) {
+    if (diff.NeedsCollectInlines()) {
       SetNeedsCollectInlines();
     }
   }
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index 56fbebcd..dab1e93 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -200,9 +200,7 @@
   if (!old_style && text_autosizer)
     text_autosizer->Record(this);
 
-  // |NeedsFullLayout| includes changes in fonts, which require reshape.
-  // TODO(kojii): Not all |NeedsFullLayout| properties require re-shape.
-  if (diff.NeedsFullLayout()) {
+  if (diff.NeedsReshape()) {
     valid_ng_items_ = false;
     SetNeedsCollectInlines();
   }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
index 2851a3b..acc0c5c 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -591,10 +591,10 @@
     {"#parent.after { display: list-item; }", StyleChangeData::kContainer},
     {"#parent { display: list-item; list-style-type: none; }"
      "#parent.after { list-style-type: disc; }",
-     StyleChangeData::kTextAndParent},
+     StyleChangeData::kParent},
     {"#parent { display: list-item; }"
      "#container.after { list-style-type: none; }",
-     StyleChangeData::kTextAndParent},
+     StyleChangeData::kParent},
     // Changing properties related with bidi resolution should re-run
     // |CollectInlines()|.
     {"#parent.after { unicode-bidi: bidi-override; }",
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 45ae19674..f2a3afc 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -46,9 +46,7 @@
                                          const ComputedStyle* old_style) {
   Base::StyleDidChange(diff, old_style);
 
-  const ComputedStyle& new_style = Base::StyleRef();
-  if (old_style && Base::ChildrenInline() &&
-      new_style.GetUnicodeBidi() != old_style->GetUnicodeBidi()) {
+  if (diff.NeedsCollectInlines()) {
     Base::SetNeedsCollectInlines();
   }
 }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc
index 1a98c06..423a333c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc
@@ -326,7 +326,7 @@
   EXPECT_EQ(result.get(), nullptr);
 }
 
-TEST_F(NGLayoutResultCachingTest, MissPushedByFloats1) {
+TEST_F(NGLayoutResultCachingTest, HitPushedByFloats1) {
   ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
 
   // Same BFC offset, different exclusion space, pushed by floats.
@@ -343,7 +343,76 @@
     </div>
     <div class="bfc">
       <div style="height: 50px;">
-        <div class="float" style="height: 40px;"></div>
+        <div class="float" style="height: 70px;"></div>
+      </div>
+      <div id="src" style="height: 20px; clear: left;"></div>
+    </div>
+  )HTML");
+
+  auto* test = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test"));
+  auto* src = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src"));
+
+  const NGConstraintSpace& space =
+      src->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+  scoped_refptr<const NGLayoutResult> result =
+      test->CachedLayoutResult(space, nullptr);
+
+  EXPECT_NE(result.get(), nullptr);
+}
+
+TEST_F(NGLayoutResultCachingTest, HitPushedByFloats2) {
+  ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
+
+  // Different BFC offset, same exclusion space, pushed by floats.
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      .bfc { display: flow-root; width: 300px; height: 300px; }
+      .float { float: left; width: 50px; }
+    </style>
+    <div class="bfc">
+      <div style="height: 50px;">
+        <div class="float" style="height: 60px;"></div>
+      </div>
+      <div id="test" style="height: 20px; clear: left;"></div>
+    </div>
+    <div class="bfc">
+      <div style="height: 30px;">
+        <div class="float" style="height: 60px;"></div>
+      </div>
+      <div id="src" style="height: 20px; clear: left;"></div>
+    </div>
+  )HTML");
+
+  auto* test = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test"));
+  auto* src = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src"));
+
+  const NGConstraintSpace& space =
+      src->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+  scoped_refptr<const NGLayoutResult> result =
+      test->CachedLayoutResult(space, nullptr);
+
+  EXPECT_NE(result.get(), nullptr);
+}
+
+TEST_F(NGLayoutResultCachingTest, MissPushedByFloats1) {
+  ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
+
+  // Same BFC offset, different exclusion space, pushed by floats.
+  // Miss due to shrinking offset.
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      .bfc { display: flow-root; width: 300px; height: 300px; }
+      .float { float: left; width: 50px; }
+    </style>
+    <div class="bfc">
+      <div style="height: 50px;">
+        <div class="float" style="height: 70px;"></div>
+      </div>
+      <div id="test" style="height: 20px; clear: left;"></div>
+    </div>
+    <div class="bfc">
+      <div style="height: 50px;">
+        <div class="float" style="height: 60px;"></div>
       </div>
       <div id="src" style="height: 20px; clear: left;"></div>
     </div>
@@ -364,19 +433,20 @@
   ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
 
   // Different BFC offset, same exclusion space, pushed by floats.
+  // Miss due to shrinking offset.
   SetBodyInnerHTML(R"HTML(
     <style>
       .bfc { display: flow-root; width: 300px; height: 300px; }
       .float { float: left; width: 50px; }
     </style>
     <div class="bfc">
-      <div style="height: 50px;">
+      <div style="height: 30px;">
         <div class="float" style="height: 60px;"></div>
       </div>
       <div id="test" style="height: 20px; clear: left;"></div>
     </div>
     <div class="bfc">
-      <div style="height: 30px;">
+      <div style="height: 50px;">
         <div class="float" style="height: 60px;"></div>
       </div>
       <div id="src" style="height: 20px; clear: left;"></div>
diff --git a/third_party/blink/renderer/core/script/script_loader.cc b/third_party/blink/renderer/core/script/script_loader.cc
index 3d166cbb..449ce7d3 100644
--- a/third_party/blink/renderer/core/script/script_loader.cc
+++ b/third_party/blink/renderer/core/script/script_loader.cc
@@ -943,14 +943,14 @@
   for_attribute = for_attribute.StripWhiteSpace();
   // <spec step="14.4">If for is not an ASCII case-insensitive match for the
   // string "window", then return. The script is not executed.</spec>
-  if (!DeprecatedEqualIgnoringCase(for_attribute, "window"))
+  if (!EqualIgnoringASCIICase(for_attribute, "window"))
     return false;
   event_attribute = event_attribute.StripWhiteSpace();
   // <spec step="14.5">If event is not an ASCII case-insensitive match for
   // either the string "onload" or the string "onload()", then return. The
   // script is not executed.</spec>
-  return DeprecatedEqualIgnoringCase(event_attribute, "onload") ||
-         DeprecatedEqualIgnoringCase(event_attribute, "onload()");
+  return EqualIgnoringASCIICase(event_attribute, "onload") ||
+         EqualIgnoringASCIICase(event_attribute, "onload()");
 }
 
 PendingScript*
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.cc b/third_party/blink/renderer/core/scroll/scrollable_area.cc
index 27affd6..2d52a40 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.cc
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -31,12 +31,15 @@
 
 #include "third_party/blink/renderer/core/scroll/scrollable_area.h"
 
+#include "base/bind.h"
 #include "build/build_config.h"
 #include "cc/input/main_thread_scrolling_reason.h"
 #include "cc/input/scrollbar.h"
 #include "cc/layers/picture_layer.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/input/event_handler.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
@@ -275,14 +278,27 @@
                                               ScrollCallback on_finish) {
   CancelScrollAnimation();
 
+  ScrollCallback callback = std::move(on_finish);
+  if (RuntimeEnabledFeatures::UpdateHoverFromScrollAtBeginFrameEnabled()) {
+    callback = ScrollCallback(base::BindOnce(
+        [](ScrollCallback original_callback,
+           WeakPersistent<ScrollableArea> area) {
+          if (area)
+            area->MarkHoverStateDirty();
+          if (original_callback)
+            std::move(original_callback).Run();
+        },
+        std::move(callback), WrapWeakPersistent(this)));
+  }
+
   if (scroll_behavior == kScrollBehaviorSmooth) {
     GetProgrammaticScrollAnimator().AnimateToOffset(offset, is_sequenced_scroll,
-                                                    std::move(on_finish));
+                                                    std::move(callback));
   } else {
     GetProgrammaticScrollAnimator().ScrollToOffsetWithoutAnimation(
         offset, is_sequenced_scroll);
-    if (on_finish)
-      std::move(on_finish).Run();
+    if (callback)
+      std::move(callback).Run();
   }
 }
 
@@ -757,6 +773,10 @@
       scrollable_element_id.GetInternalValue(), element_id_namespace);
 }
 
+void ScrollableArea::MarkHoverStateDirty() {
+  GetLayoutBox()->GetFrame()->GetEventHandler().MarkHoverStateDirty();
+}
+
 void ScrollableArea::Trace(blink::Visitor* visitor) {
   visitor->Trace(scroll_animator_);
   visitor->Trace(programmatic_scroll_animator_);
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.h b/third_party/blink/renderer/core/scroll/scrollable_area.h
index 7672dd0..d2dde161 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.h
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -405,6 +405,8 @@
 
   virtual ScrollbarTheme& GetPageScrollbarTheme() const = 0;
 
+  virtual void MarkHoverStateDirty();
+
   float ScrollStep(ScrollGranularity, ScrollbarOrientation) const;
 
  protected:
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index e5f0efa..55acc69b81 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -531,6 +531,22 @@
   if (svg_style_.Get() != other.svg_style_.Get())
     diff = svg_style_->Diff(*other.svg_style_);
 
+  if ((!diff.NeedsReshape() || !diff.NeedsFullLayout() ||
+       !diff.NeedsFullPaintInvalidation()) &&
+      DiffNeedsReshapeAndFullLayoutAndPaintInvalidation(*this, other)) {
+    diff.SetNeedsReshape();
+    diff.SetNeedsFullLayout();
+    diff.SetNeedsPaintInvalidationObject();
+  }
+
+  if ((!diff.NeedsCollectInlines() || !diff.NeedsFullLayout() ||
+       !diff.NeedsFullPaintInvalidation()) &&
+      DiffNeedsCollectInlinesAndFullLayoutAndPaintInvalidation(*this, other)) {
+    diff.SetNeedsCollectInlines();
+    diff.SetNeedsFullLayout();
+    diff.SetNeedsPaintInvalidationObject();
+  }
+
   if ((!diff.NeedsFullLayout() || !diff.NeedsFullPaintInvalidation()) &&
       DiffNeedsFullLayoutAndPaintInvalidation(other)) {
     diff.SetNeedsFullLayout();
diff --git a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
index 0b8ef22..5cc6a3a43 100644
--- a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
+++ b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
@@ -43,6 +43,41 @@
         ]
     },
     {
+        name: "DiffNeedsReshapeAndFullLayoutAndPaintInvalidation",
+        fields_to_diff: ["font"],
+        methods_to_diff: [
+          {
+            method: "FontInternal().LoadingCustomFonts()",
+            field_dependencies: ["font"]
+          },
+          {
+            method: "TextTransform()",
+            field_dependencies: ["text-transform"]
+          },
+          {
+            method: "WhiteSpace()",
+            field_dependencies: ["white-space"]
+          },
+        ]
+    },
+    {
+        name: "DiffNeedsCollectInlinesAndFullLayoutAndPaintInvalidation",
+        methods_to_diff: [
+          {
+            method: "Direction()",
+            field_dependencies: ["direction"]
+          },
+          {
+            method: "RtlOrdering()",
+            field_dependencies: ["-webkit-rtl-ordering"]
+          },
+          {
+            method: "GetUnicodeBidi()",
+            field_dependencies: ["unicode-bidi"]
+          },
+        ]
+    },
+    {
         name: "DiffNeedsFullLayoutAndPaintInvalidation",
         fields_to_diff: ["padding-top", "padding-left", "padding-right", 
                 "padding-bottom", "-webkit-appearance",
@@ -58,7 +93,7 @@
                 "TextEmphasisCustomMark", "text-justify", "text-orientation", 
                 "text-combine-upright", "tab-size", "text-size-adjust", 
                 "list-style-image", "line-height-step", 
-                "-webkit-text-stroke-width", "line-height", "font", 
+                "-webkit-text-stroke-width", "line-height",
                 "-webkit-border-horizontal-spacing", 
                 "-webkit-border-vertical-spacing", "TextAutosizingMultiplier", 
                 "NamedGridColumnLines", "NamedGridRowLines", "OrderedNamedGridColumnLines", 
@@ -99,10 +134,6 @@
             field_dependencies: ["filter"]
           },
           {
-            method: "FontInternal().LoadingCustomFonts()",
-            field_dependencies: ["font"]
-          },
-          {
             method: "HasPseudoStyle(kPseudoIdScrollbar)",
             field_dependencies: ["StyleType"]
           },
@@ -111,26 +142,10 @@
             field_dependencies: ["-webkit-box-direction"]
           },
           {
-            method: "RtlOrdering()",
-            field_dependencies: ["-webkit-rtl-ordering"]
-          },
-          {
             method: "GetTextAlign()",
             field_dependencies: ["text-align"]
           },
           {
-            method: "TextTransform()",
-            field_dependencies: ["text-transform"]
-          },
-          {
-            method: "Direction()",
-            field_dependencies: ["direction"]
-          },
-          {
-            method: "WhiteSpace()",
-            field_dependencies: ["white-space"]
-          },
-          {
             method: "GetWritingMode()",
             field_dependencies: ["writing-mode"]
           },
@@ -147,10 +162,6 @@
             field_dependencies: ["clear"]
           },
           {
-            method: "GetUnicodeBidi()",
-            field_dependencies: ["unicode-bidi"]
-          },
-          {
             method: "Floating()",
             field_dependencies: ["float"]
           },
diff --git a/third_party/blink/renderer/core/style/style_difference.cc b/third_party/blink/renderer/core/style/style_difference.cc
index a4869fa5..49ef5c4 100644
--- a/third_party/blink/renderer/core/style/style_difference.cc
+++ b/third_party/blink/renderer/core/style/style_difference.cc
@@ -24,6 +24,9 @@
       break;
   }
 
+  out << ", collectInlines=" << diff.needs_collect_inlines_;
+  out << ", reshape=" << diff.needs_reshape_;
+
   out << ", paintInvalidationType=";
   switch (diff.paint_invalidation_type_) {
     case StyleDifference::kNoPaintInvalidation:
diff --git a/third_party/blink/renderer/core/style/style_difference.h b/third_party/blink/renderer/core/style/style_difference.h
index 4e80373..a005d4c 100644
--- a/third_party/blink/renderer/core/style/style_difference.h
+++ b/third_party/blink/renderer/core/style/style_difference.h
@@ -36,6 +36,8 @@
   StyleDifference()
       : paint_invalidation_type_(kNoPaintInvalidation),
         layout_type_(kNoLayout),
+        needs_collect_inlines_(false),
+        needs_reshape_(false),
         recompute_overflow_(false),
         visual_rect_update_(false),
         property_specific_differences_(0),
@@ -43,9 +45,10 @@
         compositing_reasons_changed_(false) {}
 
   bool HasDifference() const {
-    return paint_invalidation_type_ || layout_type_ ||
-           property_specific_differences_ || recompute_overflow_ ||
-           visual_rect_update_ || scroll_anchor_disabling_property_changed_ ||
+    return paint_invalidation_type_ || layout_type_ || needs_collect_inlines_ ||
+           needs_reshape_ || property_specific_differences_ ||
+           recompute_overflow_ || visual_rect_update_ ||
+           scroll_anchor_disabling_property_changed_ ||
            compositing_reasons_changed_;
   }
 
@@ -91,6 +94,12 @@
   bool NeedsFullLayout() const { return layout_type_ == kFullLayout; }
   void SetNeedsFullLayout() { layout_type_ = kFullLayout; }
 
+  bool NeedsCollectInlines() const { return needs_collect_inlines_; }
+  void SetNeedsCollectInlines() { needs_collect_inlines_ = true; }
+
+  bool NeedsReshape() const { return needs_reshape_; }
+  void SetNeedsReshape() { needs_reshape_ = true; }
+
   bool NeedsRecomputeOverflow() const { return recompute_overflow_; }
   void SetNeedsRecomputeOverflow() { recompute_overflow_ = true; }
 
@@ -187,6 +196,8 @@
 
   enum LayoutType { kNoLayout = 0, kPositionedMovement, kFullLayout };
   unsigned layout_type_ : 2;
+  unsigned needs_collect_inlines_ : 1;
+  unsigned needs_reshape_ : 1;
   unsigned recompute_overflow_ : 1;
   unsigned visual_rect_update_ : 1;
   unsigned property_specific_differences_ : kPropertyDifferenceCount;
diff --git a/third_party/blink/renderer/core/style/style_difference_test.cc b/third_party/blink/renderer/core/style/style_difference_test.cc
index 349b863..f45ae9b 100644
--- a/third_party/blink/renderer/core/style/style_difference_test.cc
+++ b/third_party/blink/renderer/core/style/style_difference_test.cc
@@ -15,6 +15,7 @@
   string_stream << diff;
   EXPECT_EQ(
       "StyleDifference{layoutType=NoLayout, "
+      "collectInlines=0, reshape=0, "
       "paintInvalidationType=NoPaintInvalidation, recomputeOverflow=0, "
       "visualRectUpdate=0, propertySpecificDifferences=, "
       "scrollAnchorDisablingPropertyChanged=0}",
@@ -26,6 +27,8 @@
   StyleDifference diff;
   diff.SetNeedsPaintInvalidationObject();
   diff.SetNeedsPositionedMovementLayout();
+  diff.SetNeedsReshape();
+  diff.SetNeedsCollectInlines();
   diff.SetNeedsRecomputeOverflow();
   diff.SetNeedsVisualRectUpdate();
   diff.SetTransformChanged();
@@ -33,6 +36,7 @@
   string_stream << diff;
   EXPECT_EQ(
       "StyleDifference{layoutType=PositionedMovement, "
+      "collectInlines=1, reshape=1, "
       "paintInvalidationType=PaintInvalidationObject, recomputeOverflow=1, "
       "visualRectUpdate=1, propertySpecificDifferences=TransformChanged, "
       "scrollAnchorDisablingPropertyChanged=1}",
@@ -53,6 +57,7 @@
   string_stream << diff;
   EXPECT_EQ(
       "StyleDifference{layoutType=NoLayout, "
+      "collectInlines=0, reshape=0, "
       "paintInvalidationType=NoPaintInvalidation, recomputeOverflow=0, "
       "visualRectUpdate=0, "
       "propertySpecificDifferences=TransformChanged|OpacityChanged|"
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
index 39c1afc0..b266eb3 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -49,11 +49,6 @@
 
 class RepeatEvent final : public Event {
  public:
-  static RepeatEvent* Create(const AtomicString& type, int repeat) {
-    return MakeGarbageCollected<RepeatEvent>(type, Bubbles::kNo,
-                                             Cancelable::kNo, repeat);
-  }
-
   RepeatEvent(const AtomicString& type, int repeat)
       : RepeatEvent(type, Bubbles::kNo, Cancelable::kNo, repeat) {}
   RepeatEvent(const AtomicString& type,
diff --git a/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.cc b/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.cc
index 73d1f564..550c0ad8 100644
--- a/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.cc
+++ b/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.cc
@@ -65,23 +65,6 @@
   FilterEffect::Trace(visitor);
 }
 
-FEImage* FEImage::CreateWithImage(
-    Filter* filter,
-    scoped_refptr<Image> image,
-    SVGPreserveAspectRatio* preserve_aspect_ratio) {
-  return MakeGarbageCollected<FEImage>(filter, std::move(image),
-                                       preserve_aspect_ratio);
-}
-
-FEImage* FEImage::CreateWithIRIReference(
-    Filter* filter,
-    TreeScope& tree_scope,
-    const String& href,
-    SVGPreserveAspectRatio* preserve_aspect_ratio) {
-  return MakeGarbageCollected<FEImage>(filter, tree_scope, href,
-                                       preserve_aspect_ratio);
-}
-
 static FloatRect GetLayoutObjectRepaintRect(LayoutObject* layout_object) {
   return layout_object->LocalToSVGParentTransform().MapRect(
       layout_object->VisualRectInLocalSVGCoordinates());
diff --git a/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.h b/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.h
index 7e318ce..05c641a 100644
--- a/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.h
+++ b/third_party/blink/renderer/core/svg/graphics/filters/svg_fe_image.h
@@ -35,14 +35,6 @@
 
 class FEImage final : public FilterEffect {
  public:
-  static FEImage* CreateWithImage(Filter*,
-                                  scoped_refptr<Image>,
-                                  SVGPreserveAspectRatio*);
-  static FEImage* CreateWithIRIReference(Filter*,
-                                         TreeScope&,
-                                         const String&,
-                                         SVGPreserveAspectRatio*);
-
   FEImage(Filter*, scoped_refptr<Image>, SVGPreserveAspectRatio*);
   FEImage(Filter*, TreeScope&, const String&, SVGPreserveAspectRatio*);
 
diff --git a/third_party/blink/renderer/core/svg/linear_gradient_attributes.h b/third_party/blink/renderer/core/svg/linear_gradient_attributes.h
index 26c26add..f42ab8e 100644
--- a/third_party/blink/renderer/core/svg/linear_gradient_attributes.h
+++ b/third_party/blink/renderer/core/svg/linear_gradient_attributes.h
@@ -95,10 +95,6 @@
 class LinearGradientAttributesWrapper
     : public GarbageCollectedFinalized<LinearGradientAttributesWrapper> {
  public:
-  static LinearGradientAttributesWrapper* Create() {
-    return MakeGarbageCollected<LinearGradientAttributesWrapper>();
-  }
-
   LinearGradientAttributesWrapper() = default;
 
   LinearGradientAttributes& Attributes() { return attributes_; }
diff --git a/third_party/blink/renderer/core/svg/pattern_attributes.h b/third_party/blink/renderer/core/svg/pattern_attributes.h
index 970243f..9f17ae8c 100644
--- a/third_party/blink/renderer/core/svg/pattern_attributes.h
+++ b/third_party/blink/renderer/core/svg/pattern_attributes.h
@@ -172,10 +172,6 @@
 class PatternAttributesWrapper
     : public GarbageCollected<PatternAttributesWrapper> {
  public:
-  static PatternAttributesWrapper* Create() {
-    return MakeGarbageCollected<PatternAttributesWrapper>();
-  }
-
   PatternAttributesWrapper() = default;
 
   PatternAttributes& Attributes() { return attributes_; }
diff --git a/third_party/blink/renderer/core/svg/properties/svg_animated_property.h b/third_party/blink/renderer/core/svg/properties/svg_animated_property.h
index 66ed2fb..6297db55 100644
--- a/third_party/blink/renderer/core/svg/properties/svg_animated_property.h
+++ b/third_party/blink/renderer/core/svg/properties/svg_animated_property.h
@@ -235,14 +235,16 @@
 class SVGAnimatedProperty<Property, TearOffType, void>
     : public SVGAnimatedPropertyCommon<Property> {
  public:
-  static SVGAnimatedProperty<Property>* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name,
-      Property* initial_value,
-      CSSPropertyID css_property_id = CSSPropertyID::kInvalid) {
-    return new SVGAnimatedProperty<Property>(context_element, attribute_name,
-                                             initial_value, css_property_id);
-  }
+  SVGAnimatedProperty(SVGElement* context_element,
+                      const QualifiedName& attribute_name,
+                      Property* initial_value,
+                      CSSPropertyID css_property_id = CSSPropertyID::kInvalid,
+                      unsigned initial_value_bits = 0)
+      : SVGAnimatedPropertyCommon<Property>(context_element,
+                                            attribute_name,
+                                            initial_value,
+                                            css_property_id,
+                                            initial_value_bits) {}
 
   void SetAnimatedValue(SVGPropertyBase* value) override {
     SVGAnimatedPropertyCommon<Property>::SetAnimatedValue(value);
@@ -280,18 +282,6 @@
     SVGAnimatedPropertyCommon<Property>::Trace(visitor);
   }
 
- protected:
-  SVGAnimatedProperty(SVGElement* context_element,
-                      const QualifiedName& attribute_name,
-                      Property* initial_value,
-                      CSSPropertyID css_property_id = CSSPropertyID::kInvalid,
-                      unsigned initial_value_bits = 0)
-      : SVGAnimatedPropertyCommon<Property>(context_element,
-                                            attribute_name,
-                                            initial_value,
-                                            css_property_id,
-                                            initial_value_bits) {}
-
  private:
   void UpdateAnimValTearOffIfNeeded() {
     if (anim_val_tear_off_)
@@ -314,16 +304,6 @@
 class SVGAnimatedProperty<Property, void, void>
     : public SVGAnimatedPropertyCommon<Property> {
  public:
-  static SVGAnimatedProperty<Property>* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name,
-      Property* initial_value,
-      CSSPropertyID css_property_id = CSSPropertyID::kInvalid) {
-    return new SVGAnimatedProperty<Property>(context_element, attribute_name,
-                                             initial_value, css_property_id);
-  }
-
- protected:
   SVGAnimatedProperty(SVGElement* context_element,
                       const QualifiedName& attribute_name,
                       Property* initial_value,
diff --git a/third_party/blink/renderer/core/svg/properties/svg_list_property_tear_off_helper.h b/third_party/blink/renderer/core/svg/properties/svg_list_property_tear_off_helper.h
index d450ef9..6435cba 100644
--- a/third_party/blink/renderer/core/svg/properties/svg_list_property_tear_off_helper.h
+++ b/third_party/blink/renderer/core/svg/properties/svg_list_property_tear_off_helper.h
@@ -70,14 +70,6 @@
     new_item->Bind(binding);
     return new_item->Target();
   }
-
-  static ItemTearOffType* CreateTearOff(
-      ItemPropertyType* value,
-      SVGAnimatedPropertyBase* binding,
-      PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<ItemTearOffType>(value, binding,
-                                                 property_is_anim_val);
-  }
 };
 
 template <typename Derived, typename ListProperty>
@@ -198,10 +190,11 @@
       return nullptr;
 
     if (value->OwnerList() == ToDerived()->Target()) {
-      return ItemTraits::CreateTearOff(value, ToDerived()->GetBinding(),
-                                       ToDerived()->PropertyIsAnimVal());
+      return MakeGarbageCollected<ItemTearOffType>(
+          value, ToDerived()->GetBinding(), ToDerived()->PropertyIsAnimVal());
     }
-    return ItemTraits::CreateTearOff(value, nullptr, kPropertyIsNotAnimVal);
+    return MakeGarbageCollected<ItemTearOffType>(value, nullptr,
+                                                 kPropertyIsNotAnimVal);
   }
 
  private:
diff --git a/third_party/blink/renderer/core/svg/radial_gradient_attributes.h b/third_party/blink/renderer/core/svg/radial_gradient_attributes.h
index 0811e08..7f54ba02 100644
--- a/third_party/blink/renderer/core/svg/radial_gradient_attributes.h
+++ b/third_party/blink/renderer/core/svg/radial_gradient_attributes.h
@@ -117,10 +117,6 @@
 class RadialGradientAttributesWrapper
     : public GarbageCollectedFinalized<RadialGradientAttributesWrapper> {
  public:
-  static RadialGradientAttributesWrapper* Create() {
-    return MakeGarbageCollected<RadialGradientAttributesWrapper>();
-  }
-
   RadialGradientAttributesWrapper() = default;
 
   RadialGradientAttributes& Attributes() { return attributes_; }
diff --git a/third_party/blink/renderer/core/svg/svg_a_element.cc b/third_party/blink/renderer/core/svg/svg_a_element.cc
index 51ab5f3..c5d1e2b 100644
--- a/third_party/blink/renderer/core/svg/svg_a_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_a_element.cc
@@ -65,8 +65,6 @@
   SVGURIReference::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGAElement)
-
 String SVGAElement::title() const {
   // If the xlink:title is set (non-empty string), use it.
   const AtomicString& title = FastGetAttribute(xlink_names::kTitleAttr);
diff --git a/third_party/blink/renderer/core/svg/svg_a_element.h b/third_party/blink/renderer/core/svg/svg_a_element.h
index 80bcaebbd58..0302bca 100644
--- a/third_party/blink/renderer/core/svg/svg_a_element.h
+++ b/third_party/blink/renderer/core/svg/svg_a_element.h
@@ -34,7 +34,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAElement);
 
  public:
-  DECLARE_NODE_FACTORY(SVGAElement);
   SVGAnimatedString* svgTarget() { return svg_target_.Get(); }
 
   explicit SVGAElement(Document&);
diff --git a/third_party/blink/renderer/core/svg/svg_angle.h b/third_party/blink/renderer/core/svg/svg_angle.h
index 0ceab5ed..04c0617 100644
--- a/third_party/blink/renderer/core/svg/svg_angle.h
+++ b/third_party/blink/renderer/core/svg/svg_angle.h
@@ -43,10 +43,6 @@
 class SVGMarkerOrientEnumeration final
     : public SVGEnumeration<SVGMarkerOrientType> {
  public:
-  static SVGMarkerOrientEnumeration* Create(SVGAngle* angle) {
-    return MakeGarbageCollected<SVGMarkerOrientEnumeration>(angle);
-  }
-
   SVGMarkerOrientEnumeration(SVGAngle*);
   ~SVGMarkerOrientEnumeration() override;
 
@@ -81,8 +77,6 @@
     kSvgAngletypeTurn = 5
   };
 
-  static SVGAngle* Create() { return MakeGarbageCollected<SVGAngle>(); }
-
   SVGAngle();
   SVGAngle(SVGAngleType, float, SVGMarkerOrientType);
   ~SVGAngle() override;
diff --git a/third_party/blink/renderer/core/svg/svg_angle_tear_off.h b/third_party/blink/renderer/core/svg/svg_angle_tear_off.h
index da1d1331..0774b85 100644
--- a/third_party/blink/renderer/core/svg/svg_angle_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_angle_tear_off.h
@@ -40,12 +40,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGAngleTearOff* Create(SVGAngle* target,
-                                 SVGAnimatedPropertyBase* binding,
-                                 PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGAngleTearOff>(target, binding,
-                                                 property_is_anim_val);
-  }
   static SVGAngleTearOff* CreateDetached();
 
   enum {
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.cc b/third_party/blink/renderer/core/svg/svg_animate_element.cc
index 4bca86c8..44f1293f 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_element.cc
@@ -111,11 +111,6 @@
       to_property_value_type_(kRegularPropertyValue),
       attribute_type_(kAttributeTypeAuto) {}
 
-SVGAnimateElement* SVGAnimateElement::Create(Document& document) {
-  return MakeGarbageCollected<SVGAnimateElement>(svg_names::kAnimateTag,
-                                                 document);
-}
-
 SVGAnimateElement::~SVGAnimateElement() = default;
 
 bool SVGAnimateElement::IsSVGAnimationAttributeSettingJavaScriptURL(
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.h b/third_party/blink/renderer/core/svg/svg_animate_element.h
index 5a7e54c..04d0666 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animate_element.h
@@ -40,8 +40,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGAnimateElement* Create(Document&);
-
   explicit SVGAnimateElement(Document&);
   SVGAnimateElement(const QualifiedName&, Document&);
   ~SVGAnimateElement() override;
diff --git a/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc b/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
index 689f7f8..fa8c8d5 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
@@ -62,8 +62,6 @@
   SetCalcMode(kCalcModePaced);
 }
 
-DEFINE_NODE_FACTORY(SVGAnimateMotionElement)
-
 SVGAnimateMotionElement::~SVGAnimateMotionElement() = default;
 
 bool SVGAnimateMotionElement::HasValidTarget() {
diff --git a/third_party/blink/renderer/core/svg/svg_animate_motion_element.h b/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
index 39f64675..2b0eba2a 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
@@ -33,7 +33,6 @@
   explicit SVGAnimateMotionElement(Document&);
   ~SVGAnimateMotionElement() override;
 
-  DECLARE_NODE_FACTORY(SVGAnimateMotionElement);
   void UpdateAnimationPath();
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc b/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
index cd853e05..c7a94f3 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
@@ -25,6 +25,7 @@
 #include "third_party/blink/renderer/core/svg/properties/svg_animated_property.h"
 #include "third_party/blink/renderer/core/svg/svg_transform_list.h"
 #include "third_party/blink/renderer/core/svg_names.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 
 namespace blink {
 
@@ -32,8 +33,6 @@
     : SVGAnimateElement(svg_names::kAnimateTransformTag, document),
       transform_type_(SVGTransformType::kUnknown) {}
 
-DEFINE_NODE_FACTORY(SVGAnimateTransformElement)
-
 bool SVGAnimateTransformElement::HasValidTarget() {
   if (!SVGAnimateElement::HasValidTarget())
     return false;
@@ -61,7 +60,7 @@
 SVGPropertyBase* SVGAnimateTransformElement::CreatePropertyForAnimation(
     const String& value) const {
   DCHECK(IsAnimatingSVGDom());
-  return SVGTransformList::Create(transform_type_, value);
+  return MakeGarbageCollected<SVGTransformList>(transform_type_, value);
 }
 
 void SVGAnimateTransformElement::ParseAttribute(
diff --git a/third_party/blink/renderer/core/svg/svg_animate_transform_element.h b/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
index 3704f7c..102b4c3f 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animate_transform_element.h
@@ -32,8 +32,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGAnimateTransformElement);
-
   explicit SVGAnimateTransformElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_animated_angle.h b/third_party/blink/renderer/core/svg/svg_animated_angle.h
index a7edb0ac..ae5b0bdd 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_angle.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_angle.h
@@ -44,10 +44,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedAngle);
 
  public:
-  static SVGAnimatedAngle* Create(SVGElement* context_element) {
-    return MakeGarbageCollected<SVGAnimatedAngle>(context_element);
-  }
-
   explicit SVGAnimatedAngle(SVGElement* context_element);
   ~SVGAnimatedAngle() override;
 
diff --git a/third_party/blink/renderer/core/svg/svg_animated_boolean.h b/third_party/blink/renderer/core/svg/svg_animated_boolean.h
index 1cb9ca3..f657aaa 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_boolean.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_boolean.h
@@ -44,12 +44,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedBoolean);
 
  public:
-  static SVGAnimatedBoolean* Create(SVGElement* context_element,
-                                    const QualifiedName& attribute_name) {
-    return MakeGarbageCollected<SVGAnimatedBoolean>(context_element,
-                                                    attribute_name);
-  }
-
   SVGAnimatedBoolean(SVGElement* context_element,
                      const QualifiedName& attribute_name)
       : SVGAnimatedProperty<SVGBoolean>(context_element,
diff --git a/third_party/blink/renderer/core/svg/svg_animated_color.h b/third_party/blink/renderer/core/svg/svg_animated_color.h
index f59a49d..2bd1e68 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_color.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_color.h
@@ -43,10 +43,6 @@
 // are implemented in WebAnimations.
 class SVGColorProperty final : public SVGPropertyBase {
  public:
-  static SVGColorProperty* Create(const String& color_string) {
-    return MakeGarbageCollected<SVGColorProperty>(color_string);
-  }
-
   explicit SVGColorProperty(const String&);
 
   SVGPropertyBase* CloneForAnimation(const String&) const override;
diff --git a/third_party/blink/renderer/core/svg/svg_animated_enumeration.h b/third_party/blink/renderer/core/svg/svg_animated_enumeration.h
index a1512dc..74b39a2 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_enumeration.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_enumeration.h
@@ -39,16 +39,6 @@
 template <typename Enum>
 class SVGAnimatedEnumeration : public SVGAnimatedEnumerationBase {
  public:
-  static SVGAnimatedEnumeration<Enum>* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name,
-      Enum initial_value) {
-    return MakeGarbageCollected<SVGAnimatedEnumeration>(
-        context_element, attribute_name,
-        SVGEnumeration<Enum>::Create(initial_value),
-        static_cast<unsigned>(initial_value));
-  }
-
   SVGAnimatedEnumeration(SVGElement* context_element,
                          const QualifiedName& attribute_name,
                          Enum initial_value)
@@ -58,15 +48,6 @@
             MakeGarbageCollected<SVGEnumeration<Enum>>(initial_value),
             static_cast<unsigned>(initial_value)) {}
 
-  static SVGAnimatedEnumeration<Enum>* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name,
-      SVGEnumeration<Enum>* initial_value) {
-    return MakeGarbageCollected<SVGAnimatedEnumeration>(
-        context_element, attribute_name, initial_value,
-        static_cast<unsigned>(initial_value->EnumValue()));
-  }
-
   SVGAnimatedEnumeration(SVGElement* context_element,
                          const QualifiedName& attribute_name,
                          SVGEnumeration<Enum>* initial_value)
diff --git a/third_party/blink/renderer/core/svg/svg_animated_href.cc b/third_party/blink/renderer/core/svg/svg_animated_href.cc
index d8fbab4..c914410 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_href.cc
+++ b/third_party/blink/renderer/core/svg/svg_animated_href.cc
@@ -12,10 +12,6 @@
 
 namespace blink {
 
-SVGAnimatedHref* SVGAnimatedHref::Create(SVGElement* context_element) {
-  return MakeGarbageCollected<SVGAnimatedHref>(context_element);
-}
-
 void SVGAnimatedHref::Trace(blink::Visitor* visitor) {
   visitor->Trace(xlink_href_);
   SVGAnimatedString::Trace(visitor);
diff --git a/third_party/blink/renderer/core/svg/svg_animated_href.h b/third_party/blink/renderer/core/svg/svg_animated_href.h
index 041276d..77bb26b 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_href.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_href.h
@@ -19,8 +19,6 @@
 // or the wrapped object and forwards the operation to it.)
 class SVGAnimatedHref final : public SVGAnimatedString {
  public:
-  static SVGAnimatedHref* Create(SVGElement* context_element);
-
   explicit SVGAnimatedHref(SVGElement* context_element);
 
   SVGString* CurrentValue();
diff --git a/third_party/blink/renderer/core/svg/svg_animated_integer.h b/third_party/blink/renderer/core/svg/svg_animated_integer.h
index 10f7207..0f35ecc 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_integer.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_integer.h
@@ -48,20 +48,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedInteger);
 
  public:
-  static SVGAnimatedInteger* Create(SVGElement* context_element,
-                                    const QualifiedName& attribute_name,
-                                    int initial) {
-    SVGInteger* initial_value = SVGInteger::Create(initial);
-    return MakeGarbageCollected<SVGAnimatedInteger>(
-        context_element, attribute_name, initial_value);
-  }
-  static SVGAnimatedInteger* Create(SVGElement* context_element,
-                                    const QualifiedName& attribute_name,
-                                    SVGInteger* initial_value) {
-    return MakeGarbageCollected<SVGAnimatedInteger>(
-        context_element, attribute_name, initial_value);
-  }
-
   SVGAnimatedInteger(SVGElement* context_element,
                      const QualifiedName& attribute_name,
                      int initial)
diff --git a/third_party/blink/renderer/core/svg/svg_animated_integer_optional_integer.h b/third_party/blink/renderer/core/svg/svg_animated_integer_optional_integer.h
index 776c9a5..97a6a6e 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_integer_optional_integer.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_integer_optional_integer.h
@@ -49,14 +49,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedIntegerOptionalInteger);
 
  public:
-  static SVGAnimatedIntegerOptionalInteger* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name,
-      int initial_value) {
-    return MakeGarbageCollected<SVGAnimatedIntegerOptionalInteger>(
-        context_element, attribute_name, initial_value);
-  }
-
   SVGAnimatedIntegerOptionalInteger(SVGElement* context_element,
                                     const QualifiedName& attribute_name,
                                     int initial_value);
diff --git a/third_party/blink/renderer/core/svg/svg_animated_length.h b/third_party/blink/renderer/core/svg/svg_animated_length.h
index 8e141b64..2c134fe 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_length.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_length.h
@@ -44,16 +44,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedLength);
 
  public:
-  static SVGAnimatedLength* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name,
-      SVGLengthMode mode,
-      SVGLength::Initial initial_value,
-      CSSPropertyID css_property_id = CSSPropertyID::kInvalid) {
-    return MakeGarbageCollected<SVGAnimatedLength>(
-        context_element, attribute_name, mode, initial_value, css_property_id);
-  }
-
   SVGAnimatedLength(SVGElement* context_element,
                     const QualifiedName& attribute_name,
                     SVGLengthMode mode,
diff --git a/third_party/blink/renderer/core/svg/svg_animated_length_list.h b/third_party/blink/renderer/core/svg/svg_animated_length_list.h
index 9190517..56960d00 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_length_list.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_length_list.h
@@ -45,13 +45,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedLengthList);
 
  public:
-  static SVGAnimatedLengthList* Create(SVGElement* context_element,
-                                       const QualifiedName& attribute_name,
-                                       SVGLengthList* initial_value) {
-    return MakeGarbageCollected<SVGAnimatedLengthList>(
-        context_element, attribute_name, initial_value);
-  }
-
   SVGAnimatedLengthList(SVGElement* context_element,
                         const QualifiedName& attribute_name,
                         SVGLengthList* initial_value)
diff --git a/third_party/blink/renderer/core/svg/svg_animated_number.h b/third_party/blink/renderer/core/svg/svg_animated_number.h
index a4be80d..6ac2295 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_number.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_number.h
@@ -48,20 +48,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedNumber);
 
  public:
-  static SVGAnimatedNumber* Create(SVGElement* context_element,
-                                   const QualifiedName& attribute_name,
-                                   float initial_number) {
-    SVGNumber* initial_value = SVGNumber::Create(initial_number);
-    return MakeGarbageCollected<SVGAnimatedNumber>(
-        context_element, attribute_name, initial_value);
-  }
-  static SVGAnimatedNumber* Create(SVGElement* context_element,
-                                   const QualifiedName& attribute_name,
-                                   SVGNumber* initial_value) {
-    return MakeGarbageCollected<SVGAnimatedNumber>(
-        context_element, attribute_name, initial_value);
-  }
-
   SVGAnimatedNumber(SVGElement* context_element,
                     const QualifiedName& attribute_name,
                     float initial_number)
diff --git a/third_party/blink/renderer/core/svg/svg_animated_number_list.h b/third_party/blink/renderer/core/svg/svg_animated_number_list.h
index f09dd2e..64c96c1b 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_number_list.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_number_list.h
@@ -46,12 +46,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedNumberList);
 
  public:
-  static SVGAnimatedNumberList* Create(SVGElement* context_element,
-                                       const QualifiedName& attribute_name) {
-    return MakeGarbageCollected<SVGAnimatedNumberList>(context_element,
-                                                       attribute_name);
-  }
-
   SVGAnimatedNumberList(SVGElement* context_element,
                         const QualifiedName& attribute_name)
       : SVGAnimatedProperty<SVGNumberList>(
diff --git a/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.h b/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.h
index b8185ca..b18b31d 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.h
@@ -49,14 +49,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedNumberOptionalNumber);
 
  public:
-  static SVGAnimatedNumberOptionalNumber* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name,
-      float initial_value) {
-    return MakeGarbageCollected<SVGAnimatedNumberOptionalNumber>(
-        context_element, attribute_name, initial_value);
-  }
-
   SVGAnimatedNumberOptionalNumber(SVGElement* context_element,
                                   const QualifiedName& attribute_name,
                                   float initial_value);
diff --git a/third_party/blink/renderer/core/svg/svg_animated_path.h b/third_party/blink/renderer/core/svg/svg_animated_path.h
index abb5013d..efc68744 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_path.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_path.h
@@ -43,14 +43,6 @@
  public:
   ~SVGAnimatedPath() override;
 
-  static SVGAnimatedPath* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name,
-      CSSPropertyID css_property_id = CSSPropertyID::kInvalid) {
-    return MakeGarbageCollected<SVGAnimatedPath>(
-        context_element, attribute_name, css_property_id);
-  }
-
   SVGAnimatedPath(SVGElement*,
                   const QualifiedName&,
                   CSSPropertyID = CSSPropertyID::kInvalid);
diff --git a/third_party/blink/renderer/core/svg/svg_animated_point_list.h b/third_party/blink/renderer/core/svg/svg_animated_point_list.h
index dd63243..d6af8b6b 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_point_list.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_point_list.h
@@ -42,15 +42,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedPointList);
 
  public:
-  static SVGAnimatedPointList* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name,
-      SVGPointList* initial_value,
-      CSSPropertyID css_property_id = CSSPropertyID::kInvalid) {
-    return MakeGarbageCollected<SVGAnimatedPointList>(
-        context_element, attribute_name, initial_value, css_property_id);
-  }
-
   SVGAnimatedPointList(SVGElement* context_element,
                        const QualifiedName& attribute_name,
                        SVGPointList* initial_value,
diff --git a/third_party/blink/renderer/core/svg/svg_animated_preserve_aspect_ratio.h b/third_party/blink/renderer/core/svg/svg_animated_preserve_aspect_ratio.h
index d2861f6d..99ef12f 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_preserve_aspect_ratio.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_preserve_aspect_ratio.h
@@ -45,13 +45,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedPreserveAspectRatio);
 
  public:
-  static SVGAnimatedPreserveAspectRatio* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name) {
-    return MakeGarbageCollected<SVGAnimatedPreserveAspectRatio>(context_element,
-                                                                attribute_name);
-  }
-
   SVGAnimatedPreserveAspectRatio(SVGElement* context_element,
                                  const QualifiedName& attribute_name)
       : SVGAnimatedProperty<SVGPreserveAspectRatio>(
diff --git a/third_party/blink/renderer/core/svg/svg_animated_rect.h b/third_party/blink/renderer/core/svg/svg_animated_rect.h
index ad95d13..e23c0802 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_rect.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_rect.h
@@ -43,12 +43,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedRect);
 
  public:
-  static SVGAnimatedRect* Create(SVGElement* context_element,
-                                 const QualifiedName& attribute_name) {
-    return MakeGarbageCollected<SVGAnimatedRect>(context_element,
-                                                 attribute_name);
-  }
-
   SVGAnimatedRect(SVGElement* context_element,
                   const QualifiedName& attribute_name)
       : SVGAnimatedProperty<SVGRect>(context_element,
diff --git a/third_party/blink/renderer/core/svg/svg_animated_string.h b/third_party/blink/renderer/core/svg/svg_animated_string.h
index 01e3d81..cf8f5e4 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_string.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_string.h
@@ -44,12 +44,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedString);
 
  public:
-  static SVGAnimatedString* Create(SVGElement* context_element,
-                                   const QualifiedName& attribute_name) {
-    return MakeGarbageCollected<SVGAnimatedString>(context_element,
-                                                   attribute_name);
-  }
-
   SVGAnimatedString(SVGElement* context_element,
                     const QualifiedName& attribute_name)
       : SVGAnimatedProperty<SVGString>(context_element,
diff --git a/third_party/blink/renderer/core/svg/svg_animated_transform_list.h b/third_party/blink/renderer/core/svg/svg_animated_transform_list.h
index 6e49d276..c5cad77f 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_transform_list.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_transform_list.h
@@ -47,14 +47,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGAnimatedTransformList);
 
  public:
-  static SVGAnimatedTransformList* Create(
-      SVGElement* context_element,
-      const QualifiedName& attribute_name,
-      CSSPropertyID css_property_id = CSSPropertyID::kInvalid) {
-    return MakeGarbageCollected<SVGAnimatedTransformList>(
-        context_element, attribute_name, css_property_id);
-  }
-
   SVGAnimatedTransformList(SVGElement* context_element,
                            const QualifiedName& attribute_name,
                            CSSPropertyID css_property_id)
diff --git a/third_party/blink/renderer/core/svg/svg_boolean.h b/third_party/blink/renderer/core/svg/svg_boolean.h
index 1144823..878ae33 100644
--- a/third_party/blink/renderer/core/svg/svg_boolean.h
+++ b/third_party/blink/renderer/core/svg/svg_boolean.h
@@ -43,10 +43,6 @@
   typedef void TearOffType;
   typedef bool PrimitiveType;
 
-  static SVGBoolean* Create(bool value = false) {
-    return MakeGarbageCollected<SVGBoolean>(value);
-  }
-
   SVGBoolean(bool value = false) : value_(value) {}
 
   SVGBoolean* Clone() const { return MakeGarbageCollected<SVGBoolean>(value_); }
diff --git a/third_party/blink/renderer/core/svg/svg_circle_element.cc b/third_party/blink/renderer/core/svg/svg_circle_element.cc
index c75cf02..56a3470 100644
--- a/third_party/blink/renderer/core/svg/svg_circle_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_circle_element.cc
@@ -58,8 +58,6 @@
   SVGGeometryElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGCircleElement)
-
 Path SVGCircleElement::AsPath() const {
   Path path;
 
diff --git a/third_party/blink/renderer/core/svg/svg_circle_element.h b/third_party/blink/renderer/core/svg/svg_circle_element.h
index 977fecf7..fcc8e535 100644
--- a/third_party/blink/renderer/core/svg/svg_circle_element.h
+++ b/third_party/blink/renderer/core/svg/svg_circle_element.h
@@ -31,8 +31,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGCircleElement);
-
   explicit SVGCircleElement(Document&);
 
   Path AsPath() const override;
diff --git a/third_party/blink/renderer/core/svg/svg_clip_path_element.cc b/third_party/blink/renderer/core/svg/svg_clip_path_element.cc
index ac4060b..9767ed1 100644
--- a/third_party/blink/renderer/core/svg/svg_clip_path_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_clip_path_element.cc
@@ -41,8 +41,6 @@
   SVGGraphicsElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGClipPathElement)
-
 void SVGClipPathElement::SvgAttributeChanged(const QualifiedName& attr_name) {
   if (attr_name == svg_names::kClipPathUnitsAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
diff --git a/third_party/blink/renderer/core/svg/svg_clip_path_element.h b/third_party/blink/renderer/core/svg/svg_clip_path_element.h
index 7c12cd2a..ed32c00b 100644
--- a/third_party/blink/renderer/core/svg/svg_clip_path_element.h
+++ b/third_party/blink/renderer/core/svg/svg_clip_path_element.h
@@ -34,8 +34,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGClipPathElement);
-
   explicit SVGClipPathElement(Document&);
 
   SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>* clipPathUnits() {
diff --git a/third_party/blink/renderer/core/svg/svg_defs_element.cc b/third_party/blink/renderer/core/svg/svg_defs_element.cc
index 91cbff54..a5a7576 100644
--- a/third_party/blink/renderer/core/svg/svg_defs_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_defs_element.cc
@@ -28,8 +28,6 @@
 SVGDefsElement::SVGDefsElement(Document& document)
     : SVGGraphicsElement(svg_names::kDefsTag, document) {}
 
-DEFINE_NODE_FACTORY(SVGDefsElement)
-
 LayoutObject* SVGDefsElement::CreateLayoutObject(const ComputedStyle&,
                                                  LegacyLayout) {
   return new LayoutSVGHiddenContainer(this);
diff --git a/third_party/blink/renderer/core/svg/svg_defs_element.h b/third_party/blink/renderer/core/svg/svg_defs_element.h
index 7e94d32..c9f54368 100644
--- a/third_party/blink/renderer/core/svg/svg_defs_element.h
+++ b/third_party/blink/renderer/core/svg/svg_defs_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGDefsElement);
-
   explicit SVGDefsElement(Document&);
 
   bool SupportsFocus() const override { return false; }
diff --git a/third_party/blink/renderer/core/svg/svg_desc_element.cc b/third_party/blink/renderer/core/svg/svg_desc_element.cc
index 5d0f2eb..2245eadd 100644
--- a/third_party/blink/renderer/core/svg/svg_desc_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_desc_element.cc
@@ -26,6 +26,4 @@
 
 SVGDescElement::SVGDescElement(Document& document)
     : SVGElement(svg_names::kDescTag, document) {}
-
-DEFINE_NODE_FACTORY(SVGDescElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_desc_element.h b/third_party/blink/renderer/core/svg/svg_desc_element.h
index ab3670f..579d1f25 100644
--- a/third_party/blink/renderer/core/svg/svg_desc_element.h
+++ b/third_party/blink/renderer/core/svg/svg_desc_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGDescElement);
-
   explicit SVGDescElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_discard_element.cc b/third_party/blink/renderer/core/svg/svg_discard_element.cc
index a56d937..d5f6cc9 100644
--- a/third_party/blink/renderer/core/svg/svg_discard_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_discard_element.cc
@@ -37,6 +37,4 @@
 SVGDiscardElement::SVGDiscardElement(Document& document)
     : SVGSMILElement(svg_names::kDiscardTag, document) {}
 
-DEFINE_NODE_FACTORY(SVGDiscardElement)
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_discard_element.h b/third_party/blink/renderer/core/svg/svg_discard_element.h
index 972f5f0..7b9d414 100644
--- a/third_party/blink/renderer/core/svg/svg_discard_element.h
+++ b/third_party/blink/renderer/core/svg/svg_discard_element.h
@@ -39,8 +39,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGDiscardElement);
-
   explicit SVGDiscardElement(Document&);
 
   bool IsSVGDiscardElement() const override { return true; }
diff --git a/third_party/blink/renderer/core/svg/svg_ellipse_element.cc b/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
index 0fa63d2..a677606e 100644
--- a/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
@@ -66,8 +66,6 @@
   SVGGeometryElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGEllipseElement)
-
 Path SVGEllipseElement::AsPath() const {
   Path path;
 
diff --git a/third_party/blink/renderer/core/svg/svg_ellipse_element.h b/third_party/blink/renderer/core/svg/svg_ellipse_element.h
index ce132b9..82546ae 100644
--- a/third_party/blink/renderer/core/svg/svg_ellipse_element.h
+++ b/third_party/blink/renderer/core/svg/svg_ellipse_element.h
@@ -31,8 +31,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGEllipseElement);
-
   explicit SVGEllipseElement(Document&);
 
   Path AsPath() const override;
diff --git a/third_party/blink/renderer/core/svg/svg_enumeration.h b/third_party/blink/renderer/core/svg/svg_enumeration.h
index 9000e13..ffc9a87 100644
--- a/third_party/blink/renderer/core/svg/svg_enumeration.h
+++ b/third_party/blink/renderer/core/svg/svg_enumeration.h
@@ -104,10 +104,6 @@
 template <typename Enum>
 class SVGEnumeration : public SVGEnumerationBase {
  public:
-  static SVGEnumeration<Enum>* Create(Enum new_value) {
-    return MakeGarbageCollected<SVGEnumeration<Enum>>(new_value);
-  }
-
   explicit SVGEnumeration(Enum new_value)
       : SVGEnumerationBase(new_value, GetEnumerationMap<Enum>()) {}
   ~SVGEnumeration() override = default;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc b/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc
index 3c48b7b4..f54e33a 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc
@@ -101,8 +101,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEBlendElement)
-
 bool SVGFEBlendElement::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_blend_element.h b/third_party/blink/renderer/core/svg/svg_fe_blend_element.h
index 002967b..04f23d4 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_blend_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_blend_element.h
@@ -53,7 +53,6 @@
 
   explicit SVGFEBlendElement(Document&);
 
-  DECLARE_NODE_FACTORY(SVGFEBlendElement);
   SVGAnimatedString* in1() { return in1_.Get(); }
   SVGAnimatedString* in2() { return in2_.Get(); }
   SVGAnimatedEnumeration<Mode>* mode() { return mode_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc b/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc
index a4aec29..7f330c5 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc
@@ -62,8 +62,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEColorMatrixElement)
-
 bool SVGFEColorMatrixElement::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h b/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h
index d569e80..4485776 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.h
@@ -36,8 +36,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEColorMatrixElement);
-
   explicit SVGFEColorMatrixElement(Document&);
 
   SVGAnimatedNumberList* values() { return values_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc b/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc
index db5359e..7a2bcc3 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc
@@ -44,8 +44,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEComponentTransferElement)
-
 void SVGFEComponentTransferElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
   if (attr_name == svg_names::kInAttr) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h b/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h
index be88645..bde46e74 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.h
@@ -31,8 +31,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEComponentTransferElement);
-
   explicit SVGFEComponentTransferElement(Document&);
 
   SVGAnimatedString* in1() { return in1_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc b/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
index 33d7e05..f5111a66 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
@@ -85,8 +85,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFECompositeElement)
-
 bool SVGFECompositeElement::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_composite_element.h b/third_party/blink/renderer/core/svg/svg_fe_composite_element.h
index da1f5ff..e00672c 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_composite_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_composite_element.h
@@ -36,8 +36,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFECompositeElement);
-
   explicit SVGFECompositeElement(Document&);
 
   SVGAnimatedNumber* k1() { return k1_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
index 48580c7..c1037941 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
@@ -42,10 +42,6 @@
 
 class SVGAnimatedOrder : public SVGAnimatedIntegerOptionalInteger {
  public:
-  static SVGAnimatedOrder* Create(SVGElement* context_element) {
-    return MakeGarbageCollected<SVGAnimatedOrder>(context_element);
-  }
-
   SVGAnimatedOrder(SVGElement* context_element)
       : SVGAnimatedIntegerOptionalInteger(context_element,
                                           svg_names::kOrderAttr,
@@ -134,8 +130,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEConvolveMatrixElement)
-
 IntSize SVGFEConvolveMatrixElement::MatrixOrder() const {
   if (!order_->IsSpecified())
     return IntSize(3, 3);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
index c4f9502..8653b5d5 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
@@ -40,8 +40,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEConvolveMatrixElement);
-
   explicit SVGFEConvolveMatrixElement(Document&);
 
   SVGAnimatedBoolean* preserveAlpha() { return preserve_alpha_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
index 4e8d66ae..40ef837 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
@@ -58,8 +58,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEDiffuseLightingElement)
-
 bool SVGFEDiffuseLightingElement::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h
index f95e373..840cbaf 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.h
@@ -34,8 +34,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEDiffuseLightingElement);
-
   explicit SVGFEDiffuseLightingElement(Document&);
 
   void LightElementAttributeChanged(const SVGFELightElement*,
diff --git a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
index 76b9626..429abf4 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
@@ -69,8 +69,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEDisplacementMapElement)
-
 bool SVGFEDisplacementMapElement::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h
index 958cef73..c29316a6 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.h
@@ -35,8 +35,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEDisplacementMapElement);
-
   explicit SVGFEDisplacementMapElement(Document&);
 
   static ChannelSelectorType StringToChannel(const String&);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.cc b/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.cc
index d477634..b62b614 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.cc
@@ -27,8 +27,6 @@
 SVGFEDistantLightElement::SVGFEDistantLightElement(Document& document)
     : SVGFELightElement(svg_names::kFEDistantLightTag, document) {}
 
-DEFINE_NODE_FACTORY(SVGFEDistantLightElement)
-
 scoped_refptr<LightSource> SVGFEDistantLightElement::GetLightSource(
     Filter* filter) const {
   return DistantLightSource::Create(azimuth()->CurrentValue()->Value(),
diff --git a/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.h b/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.h
index 981be2c..99894238 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.h
@@ -28,8 +28,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEDistantLightElement);
-
   explicit SVGFEDistantLightElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
index d4290f5d..abe97601 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
@@ -53,8 +53,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEDropShadowElement)
-
 void SVGFEDropShadowElement::setStdDeviation(float x, float y) {
   stdDeviationX()->BaseValue()->SetValue(x);
   stdDeviationY()->BaseValue()->SetValue(y);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h
index c9e3344..86079275 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.h
@@ -32,8 +32,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEDropShadowElement);
-
   explicit SVGFEDropShadowElement(Document&);
 
   void setStdDeviation(float std_deviation_x, float std_deviation_y);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc b/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
index e9bbec68..37fc529 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
@@ -32,8 +32,6 @@
 SVGFEFloodElement::SVGFEFloodElement(Document& document)
     : SVGFilterPrimitiveStandardAttributes(svg_names::kFEFloodTag, document) {}
 
-DEFINE_NODE_FACTORY(SVGFEFloodElement)
-
 bool SVGFEFloodElement::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_flood_element.h b/third_party/blink/renderer/core/svg/svg_fe_flood_element.h
index 1a3fc21..0543dbbc 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_flood_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_flood_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEFloodElement);
-
   explicit SVGFEFloodElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_a_element.cc b/third_party/blink/renderer/core/svg/svg_fe_func_a_element.cc
index fea7438..1d79d250 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_a_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_a_element.cc
@@ -24,6 +24,4 @@
 
 SVGFEFuncAElement::SVGFEFuncAElement(Document& document)
     : SVGComponentTransferFunctionElement(svg_names::kFEFuncATag, document) {}
-
-DEFINE_NODE_FACTORY(SVGFEFuncAElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_a_element.h b/third_party/blink/renderer/core/svg/svg_fe_func_a_element.h
index 9cc64d3..162da06 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_a_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_a_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEFuncAElement);
-
   explicit SVGFEFuncAElement(Document&);
 };
 
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_b_element.cc b/third_party/blink/renderer/core/svg/svg_fe_func_b_element.cc
index 59fe60b7..b627d33c 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_b_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_b_element.cc
@@ -24,6 +24,4 @@
 
 SVGFEFuncBElement::SVGFEFuncBElement(Document& document)
     : SVGComponentTransferFunctionElement(svg_names::kFEFuncBTag, document) {}
-
-DEFINE_NODE_FACTORY(SVGFEFuncBElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_b_element.h b/third_party/blink/renderer/core/svg/svg_fe_func_b_element.h
index 68996954..da07af0 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_b_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_b_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEFuncBElement);
-
   explicit SVGFEFuncBElement(Document&);
 };
 
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_g_element.cc b/third_party/blink/renderer/core/svg/svg_fe_func_g_element.cc
index 73abfba..5fdde65 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_g_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_g_element.cc
@@ -24,6 +24,4 @@
 
 SVGFEFuncGElement::SVGFEFuncGElement(Document& document)
     : SVGComponentTransferFunctionElement(svg_names::kFEFuncGTag, document) {}
-
-DEFINE_NODE_FACTORY(SVGFEFuncGElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_g_element.h b/third_party/blink/renderer/core/svg/svg_fe_func_g_element.h
index 61884a4..43183da 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_g_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_g_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEFuncGElement);
-
   explicit SVGFEFuncGElement(Document&);
 };
 
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_r_element.cc b/third_party/blink/renderer/core/svg/svg_fe_func_r_element.cc
index 1dc71766f..817d89c 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_r_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_r_element.cc
@@ -24,6 +24,4 @@
 
 SVGFEFuncRElement::SVGFEFuncRElement(Document& document)
     : SVGComponentTransferFunctionElement(svg_names::kFEFuncRTag, document) {}
-
-DEFINE_NODE_FACTORY(SVGFEFuncRElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_r_element.h b/third_party/blink/renderer/core/svg/svg_fe_func_r_element.h
index cc5550c..a620686 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_r_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_r_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEFuncRElement);
-
   explicit SVGFEFuncRElement(Document&);
 };
 
diff --git a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
index c7d8a05..a7d0e05 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
@@ -45,8 +45,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEGaussianBlurElement)
-
 void SVGFEGaussianBlurElement::setStdDeviation(float x, float y) {
   stdDeviationX()->BaseValue()->SetValue(x);
   stdDeviationY()->BaseValue()->SetValue(y);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h
index 4fda9b8..3096ffcf 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.h
@@ -32,8 +32,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEGaussianBlurElement);
-
   explicit SVGFEGaussianBlurElement(Document&);
 
   void setStdDeviation(float std_deviation_x, float std_deviation_y);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_image_element.cc b/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
index 34671bd..8c8a219 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
@@ -45,8 +45,6 @@
   AddToPropertyMap(preserve_aspect_ratio_);
 }
 
-DEFINE_NODE_FACTORY(SVGFEImageElement)
-
 SVGFEImageElement::~SVGFEImageElement() {
   ClearImageResource();
 }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_image_element.h b/third_party/blink/renderer/core/svg/svg_fe_image_element.h
index c59802c1..af5dcd70 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_image_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_image_element.h
@@ -38,8 +38,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGFEImageElement);
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEImageElement);
-
   bool CurrentFrameHasSingleSecurityOrigin() const;
 
   explicit SVGFEImageElement(Document&);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_merge_element.cc b/third_party/blink/renderer/core/svg/svg_fe_merge_element.cc
index efe3d4a..336dd4ce 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_merge_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_merge_element.cc
@@ -31,8 +31,6 @@
 SVGFEMergeElement::SVGFEMergeElement(Document& document)
     : SVGFilterPrimitiveStandardAttributes(svg_names::kFEMergeTag, document) {}
 
-DEFINE_NODE_FACTORY(SVGFEMergeElement)
-
 FilterEffect* SVGFEMergeElement::Build(SVGFilterBuilder* filter_builder,
                                        Filter* filter) {
   FilterEffect* effect = MakeGarbageCollected<FEMerge>(filter);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_merge_element.h b/third_party/blink/renderer/core/svg/svg_fe_merge_element.h
index d39a831..1544563c 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_merge_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_merge_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEMergeElement);
-
   explicit SVGFEMergeElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc b/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc
index d12ae5a9..c1c49c5 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc
@@ -36,8 +36,6 @@
   SVGElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEMergeNodeElement)
-
 void SVGFEMergeNodeElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
   if (attr_name == svg_names::kInAttr) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h b/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h
index e1bd771..0a6ebe1 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.h
@@ -31,8 +31,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEMergeNodeElement);
-
   explicit SVGFEMergeNodeElement(Document&);
 
   SVGAnimatedString* in1() { return in1_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
index 16c0c5d9..b833298 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
@@ -61,8 +61,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEMorphologyElement)
-
 bool SVGFEMorphologyElement::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h
index 7e7c722..198840c 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.h
@@ -35,8 +35,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEMorphologyElement);
-
   explicit SVGFEMorphologyElement(Document&);
 
   SVGAnimatedNumber* radiusX() { return radius_->FirstNumber(); }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc b/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
index 9f7d52e..17df70a 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
@@ -48,8 +48,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFEOffsetElement)
-
 void SVGFEOffsetElement::SvgAttributeChanged(const QualifiedName& attr_name) {
   if (attr_name == svg_names::kInAttr || attr_name == svg_names::kDxAttr ||
       attr_name == svg_names::kDyAttr) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_offset_element.h b/third_party/blink/renderer/core/svg/svg_fe_offset_element.h
index 7dec229c..4fd07aa 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_offset_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_offset_element.h
@@ -31,8 +31,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEOffsetElement);
-
   explicit SVGFEOffsetElement(Document&);
 
   SVGAnimatedNumber* dx() { return dx_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_point_light_element.cc b/third_party/blink/renderer/core/svg/svg_fe_point_light_element.cc
index dea2fc20..4d90fa0 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_point_light_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_point_light_element.cc
@@ -28,8 +28,6 @@
 SVGFEPointLightElement::SVGFEPointLightElement(Document& document)
     : SVGFELightElement(svg_names::kFEPointLightTag, document) {}
 
-DEFINE_NODE_FACTORY(SVGFEPointLightElement)
-
 scoped_refptr<LightSource> SVGFEPointLightElement::GetLightSource(
     Filter* filter) const {
   return PointLightSource::Create(filter->Resolve3dPoint(GetPosition()));
diff --git a/third_party/blink/renderer/core/svg/svg_fe_point_light_element.h b/third_party/blink/renderer/core/svg/svg_fe_point_light_element.h
index 710c32b..fe92923 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_point_light_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_point_light_element.h
@@ -28,8 +28,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFEPointLightElement);
-
   explicit SVGFEPointLightElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
index 018d11d..d334feb9 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
@@ -66,8 +66,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFESpecularLightingElement)
-
 bool SVGFESpecularLightingElement::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h
index e0aad86..e653aca0 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.h
@@ -35,8 +35,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFESpecularLightingElement);
-
   explicit SVGFESpecularLightingElement(Document&);
 
   void LightElementAttributeChanged(const SVGFELightElement*,
diff --git a/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.cc b/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.cc
index 7af592b..8641411 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.cc
@@ -28,8 +28,6 @@
 SVGFESpotLightElement::SVGFESpotLightElement(Document& document)
     : SVGFELightElement(svg_names::kFESpotLightTag, document) {}
 
-DEFINE_NODE_FACTORY(SVGFESpotLightElement)
-
 scoped_refptr<LightSource> SVGFESpotLightElement::GetLightSource(
     Filter* filter) const {
   return SpotLightSource::Create(filter->Resolve3dPoint(GetPosition()),
diff --git a/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.h b/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.h
index 6fd49e7e..bd4e6bc 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.h
@@ -28,8 +28,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFESpotLightElement);
-
   explicit SVGFESpotLightElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc b/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc
index d37599a..bb89fb4 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc
@@ -38,8 +38,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFETileElement)
-
 void SVGFETileElement::SvgAttributeChanged(const QualifiedName& attr_name) {
   if (attr_name == svg_names::kInAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_tile_element.h b/third_party/blink/renderer/core/svg/svg_fe_tile_element.h
index 3659be8..c2583c3 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_tile_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_tile_element.h
@@ -30,8 +30,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFETileElement);
-
   explicit SVGFETileElement(Document&);
 
   SVGAnimatedString* in1() { return in1_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
index 91566bdd..704eb3a6 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
@@ -84,8 +84,6 @@
   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGFETurbulenceElement)
-
 bool SVGFETurbulenceElement::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
diff --git a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h
index 821a963..d3a6e6094 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.h
@@ -45,8 +45,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGFETurbulenceElement);
-
   explicit SVGFETurbulenceElement(Document&);
 
   SVGAnimatedNumber* baseFrequencyX() { return base_frequency_->FirstNumber(); }
diff --git a/third_party/blink/renderer/core/svg/svg_filter_element.cc b/third_party/blink/renderer/core/svg/svg_filter_element.cc
index 4ca300c..bf723f0f 100644
--- a/third_party/blink/renderer/core/svg/svg_filter_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_filter_element.cc
@@ -77,8 +77,6 @@
 
 SVGFilterElement::~SVGFilterElement() = default;
 
-DEFINE_NODE_FACTORY(SVGFilterElement)
-
 void SVGFilterElement::Trace(blink::Visitor* visitor) {
   visitor->Trace(x_);
   visitor->Trace(y_);
diff --git a/third_party/blink/renderer/core/svg/svg_filter_element.h b/third_party/blink/renderer/core/svg/svg_filter_element.h
index 07e76b2ac..02c1c25 100644
--- a/third_party/blink/renderer/core/svg/svg_filter_element.h
+++ b/third_party/blink/renderer/core/svg/svg_filter_element.h
@@ -42,7 +42,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGFilterElement);
 
  public:
-  DECLARE_NODE_FACTORY(SVGFilterElement);
   void Trace(blink::Visitor*) override;
 
   explicit SVGFilterElement(Document&);
diff --git a/third_party/blink/renderer/core/svg/svg_fit_to_view_box.cc b/third_party/blink/renderer/core/svg/svg_fit_to_view_box.cc
index 700a1222..5c76ecd 100644
--- a/third_party/blink/renderer/core/svg/svg_fit_to_view_box.cc
+++ b/third_party/blink/renderer/core/svg/svg_fit_to_view_box.cc
@@ -32,10 +32,6 @@
 
 class SVGAnimatedViewBoxRect : public SVGAnimatedRect {
  public:
-  static SVGAnimatedRect* Create(SVGElement* context_element) {
-    return MakeGarbageCollected<SVGAnimatedViewBoxRect>(context_element);
-  }
-
   SVGAnimatedViewBoxRect(SVGElement* context_element)
       : SVGAnimatedRect(context_element, svg_names::kViewBoxAttr) {}
 
diff --git a/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc b/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc
index c87dd10..a440a44 100644
--- a/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc
@@ -71,8 +71,6 @@
   SVGGraphicsElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGForeignObjectElement)
-
 void SVGForeignObjectElement::CollectStyleForPresentationAttribute(
     const QualifiedName& name,
     const AtomicString& value,
diff --git a/third_party/blink/renderer/core/svg/svg_foreign_object_element.h b/third_party/blink/renderer/core/svg/svg_foreign_object_element.h
index a4d3786..94edd3e 100644
--- a/third_party/blink/renderer/core/svg/svg_foreign_object_element.h
+++ b/third_party/blink/renderer/core/svg/svg_foreign_object_element.h
@@ -30,8 +30,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGForeignObjectElement);
-
   explicit SVGForeignObjectElement(Document&);
 
   SVGAnimatedLength* x() const { return x_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_g_element.cc b/third_party/blink/renderer/core/svg/svg_g_element.cc
index 160c5de..6e85fca 100644
--- a/third_party/blink/renderer/core/svg/svg_g_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_g_element.cc
@@ -29,8 +29,6 @@
 SVGGElement::SVGGElement(Document& document, ConstructionType construction_type)
     : SVGGraphicsElement(svg_names::kGTag, document, construction_type) {}
 
-DEFINE_NODE_FACTORY(SVGGElement)
-
 LayoutObject* SVGGElement::CreateLayoutObject(const ComputedStyle& style,
                                               LegacyLayout) {
   // SVG 1.1 testsuite explicitly uses constructs like
diff --git a/third_party/blink/renderer/core/svg/svg_g_element.h b/third_party/blink/renderer/core/svg/svg_g_element.h
index c01149a..f9d8bff 100644
--- a/third_party/blink/renderer/core/svg/svg_g_element.h
+++ b/third_party/blink/renderer/core/svg/svg_g_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGGElement);
-
   explicit SVGGElement(Document&, ConstructionType = kCreateSVGElement);
 
  protected:
diff --git a/third_party/blink/renderer/core/svg/svg_geometry_element.cc b/third_party/blink/renderer/core/svg/svg_geometry_element.cc
index 2b5703b..f1994d1 100644
--- a/third_party/blink/renderer/core/svg/svg_geometry_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_geometry_element.cc
@@ -43,10 +43,6 @@
 
 class SVGAnimatedPathLength final : public SVGAnimatedNumber {
  public:
-  static SVGAnimatedPathLength* Create(SVGGeometryElement* context_element) {
-    return MakeGarbageCollected<SVGAnimatedPathLength>(context_element);
-  }
-
   explicit SVGAnimatedPathLength(SVGGeometryElement* context_element)
       : SVGAnimatedNumber(context_element,
                           svg_names::kPathLengthAttr,
diff --git a/third_party/blink/renderer/core/svg/svg_image_element.cc b/third_party/blink/renderer/core/svg/svg_image_element.cc
index c044634..da3cb080 100644
--- a/third_party/blink/renderer/core/svg/svg_image_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_image_element.cc
@@ -82,8 +82,6 @@
   }
 }
 
-DEFINE_NODE_FACTORY(SVGImageElement)
-
 void SVGImageElement::Trace(blink::Visitor* visitor) {
   visitor->Trace(x_);
   visitor->Trace(y_);
diff --git a/third_party/blink/renderer/core/svg/svg_image_element.h b/third_party/blink/renderer/core/svg/svg_image_element.h
index 19b5b80..7c7c3ee0 100644
--- a/third_party/blink/renderer/core/svg/svg_image_element.h
+++ b/third_party/blink/renderer/core/svg/svg_image_element.h
@@ -41,8 +41,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGImageElement);
 
  public:
-  DECLARE_NODE_FACTORY(SVGImageElement);
-
   explicit SVGImageElement(Document&);
 
   void Trace(blink::Visitor*) override;
diff --git a/third_party/blink/renderer/core/svg/svg_image_loader.h b/third_party/blink/renderer/core/svg/svg_image_loader.h
index 3b13811..e9be1b8 100644
--- a/third_party/blink/renderer/core/svg/svg_image_loader.h
+++ b/third_party/blink/renderer/core/svg/svg_image_loader.h
@@ -28,10 +28,6 @@
 
 class SVGImageLoader final : public ImageLoader {
  public:
-  static SVGImageLoader* Create(SVGImageElement* element) {
-    return MakeGarbageCollected<SVGImageLoader>(element);
-  }
-
   explicit SVGImageLoader(SVGImageElement*);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_integer.h b/third_party/blink/renderer/core/svg/svg_integer.h
index f614b899..9eb66c2 100644
--- a/third_party/blink/renderer/core/svg/svg_integer.h
+++ b/third_party/blink/renderer/core/svg/svg_integer.h
@@ -41,10 +41,6 @@
   typedef void TearOffType;
   typedef int PrimitiveType;
 
-  static SVGInteger* Create(int value = 0) {
-    return MakeGarbageCollected<SVGInteger>(value);
-  }
-
   explicit SVGInteger(int = 0);
 
   virtual SVGInteger* Clone() const;
diff --git a/third_party/blink/renderer/core/svg/svg_integer_optional_integer.h b/third_party/blink/renderer/core/svg/svg_integer_optional_integer.h
index 50acdcd..f04ac9b8 100644
--- a/third_party/blink/renderer/core/svg/svg_integer_optional_integer.h
+++ b/third_party/blink/renderer/core/svg/svg_integer_optional_integer.h
@@ -43,12 +43,6 @@
   typedef void TearOffType;
   typedef void PrimitiveType;
 
-  static SVGIntegerOptionalInteger* Create(SVGInteger* first_integer,
-                                           SVGInteger* second_integer) {
-    return MakeGarbageCollected<SVGIntegerOptionalInteger>(first_integer,
-                                                           second_integer);
-  }
-
   SVGIntegerOptionalInteger(SVGInteger* first_integer,
                             SVGInteger* second_integer);
 
diff --git a/third_party/blink/renderer/core/svg/svg_length.h b/third_party/blink/renderer/core/svg/svg_length.h
index 2b78846..5e598038 100644
--- a/third_party/blink/renderer/core/svg/svg_length.h
+++ b/third_party/blink/renderer/core/svg/svg_length.h
@@ -37,10 +37,6 @@
  public:
   typedef SVGLengthTearOff TearOffType;
 
-  static SVGLength* Create(SVGLengthMode mode = SVGLengthMode::kOther) {
-    return MakeGarbageCollected<SVGLength>(mode);
-  }
-
   // Initial values for SVGLength properties. If adding a new initial value,
   // keep the list sorted within the same unit. The table containing the actual
   // values are in the .cc file.
@@ -55,7 +51,6 @@
     kNumValues
   };
   static constexpr int kInitialValueBits = 3;
-  static SVGLength* Create(Initial, SVGLengthMode);
 
   explicit SVGLength(SVGLengthMode = SVGLengthMode::kOther);
   SVGLength(Initial, SVGLengthMode);
diff --git a/third_party/blink/renderer/core/svg/svg_length_list.h b/third_party/blink/renderer/core/svg/svg_length_list.h
index 1407280f9..dbc1900 100644
--- a/third_party/blink/renderer/core/svg/svg_length_list.h
+++ b/third_party/blink/renderer/core/svg/svg_length_list.h
@@ -44,10 +44,6 @@
  public:
   typedef SVGLengthListTearOff TearOffType;
 
-  static SVGLengthList* Create(SVGLengthMode mode = SVGLengthMode::kOther) {
-    return MakeGarbageCollected<SVGLengthList>(mode);
-  }
-
   explicit SVGLengthList(SVGLengthMode = SVGLengthMode::kOther);
   ~SVGLengthList() override;
 
diff --git a/third_party/blink/renderer/core/svg/svg_length_list_tear_off.h b/third_party/blink/renderer/core/svg/svg_length_list_tear_off.h
index fac130c0..bd2a953 100644
--- a/third_party/blink/renderer/core/svg/svg_length_list_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_length_list_tear_off.h
@@ -41,14 +41,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGLengthListTearOff* Create(
-      SVGLengthList* target,
-      SVGAnimatedPropertyBase* binding,
-      PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGLengthListTearOff>(target, binding,
-                                                      property_is_anim_val);
-  }
-
   SVGLengthListTearOff(SVGLengthList* target,
                        SVGAnimatedPropertyBase* binding,
                        PropertyIsAnimValType property_is_anim_val)
diff --git a/third_party/blink/renderer/core/svg/svg_length_tear_off.h b/third_party/blink/renderer/core/svg/svg_length_tear_off.h
index 244acc3..c760a000 100644
--- a/third_party/blink/renderer/core/svg/svg_length_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_length_tear_off.h
@@ -55,12 +55,6 @@
     kSvgLengthtypePc = 10
   };
 
-  static SVGLengthTearOff* Create(SVGLength* target,
-                                  SVGAnimatedPropertyBase* binding,
-                                  PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGLengthTearOff>(target, binding,
-                                                  property_is_anim_val);
-  }
   static SVGLengthTearOff* CreateDetached();
 
   SVGLengthTearOff(SVGLength*,
diff --git a/third_party/blink/renderer/core/svg/svg_line_element.cc b/third_party/blink/renderer/core/svg/svg_line_element.cc
index 1f86dc25..7d3911a 100644
--- a/third_party/blink/renderer/core/svg/svg_line_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_line_element.cc
@@ -62,8 +62,6 @@
   SVGGeometryElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGLineElement)
-
 Path SVGLineElement::AsPath() const {
   Path path;
 
diff --git a/third_party/blink/renderer/core/svg/svg_line_element.h b/third_party/blink/renderer/core/svg/svg_line_element.h
index 291cc01..ce6fcf16 100644
--- a/third_party/blink/renderer/core/svg/svg_line_element.h
+++ b/third_party/blink/renderer/core/svg/svg_line_element.h
@@ -31,8 +31,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGLineElement);
-
   explicit SVGLineElement(Document&);
 
   Path AsPath() const override;
diff --git a/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc b/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc
index 5c16603..5f202953 100644
--- a/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc
@@ -70,8 +70,6 @@
   SVGGradientElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGLinearGradientElement)
-
 void SVGLinearGradientElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
   if (attr_name == svg_names::kX1Attr || attr_name == svg_names::kX2Attr ||
diff --git a/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h b/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h
index 99aa090..9ba60cc 100644
--- a/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h
+++ b/third_party/blink/renderer/core/svg/svg_linear_gradient_element.h
@@ -33,8 +33,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGLinearGradientElement);
-
   explicit SVGLinearGradientElement(Document&);
 
   bool CollectGradientAttributes(LinearGradientAttributes&);
diff --git a/third_party/blink/renderer/core/svg/svg_marker_element.cc b/third_party/blink/renderer/core/svg/svg_marker_element.cc
index 7066bd7..287c258 100644
--- a/third_party/blink/renderer/core/svg/svg_marker_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_marker_element.cc
@@ -90,8 +90,6 @@
   SVGFitToViewBox::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGMarkerElement)
-
 AffineTransform SVGMarkerElement::ViewBoxToViewTransform(
     float view_width,
     float view_height) const {
diff --git a/third_party/blink/renderer/core/svg/svg_marker_element.h b/third_party/blink/renderer/core/svg/svg_marker_element.h
index 819bf3d..316b517 100644
--- a/third_party/blink/renderer/core/svg/svg_marker_element.h
+++ b/third_party/blink/renderer/core/svg/svg_marker_element.h
@@ -56,8 +56,6 @@
     kSvgMarkerOrientAngle = kSVGMarkerOrientAngle
   };
 
-  DECLARE_NODE_FACTORY(SVGMarkerElement);
-
   explicit SVGMarkerElement(Document&);
 
   AffineTransform ViewBoxToViewTransform(float view_width,
diff --git a/third_party/blink/renderer/core/svg/svg_mask_element.cc b/third_party/blink/renderer/core/svg/svg_mask_element.cc
index 601fd96..827e479 100644
--- a/third_party/blink/renderer/core/svg/svg_mask_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_mask_element.cc
@@ -89,8 +89,6 @@
   SVGTests::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGMaskElement)
-
 void SVGMaskElement::CollectStyleForPresentationAttribute(
     const QualifiedName& name,
     const AtomicString& value,
diff --git a/third_party/blink/renderer/core/svg/svg_mask_element.h b/third_party/blink/renderer/core/svg/svg_mask_element.h
index 1e40afc4..ebb6a52 100644
--- a/third_party/blink/renderer/core/svg/svg_mask_element.h
+++ b/third_party/blink/renderer/core/svg/svg_mask_element.h
@@ -34,8 +34,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGMaskElement);
 
  public:
-  DECLARE_NODE_FACTORY(SVGMaskElement);
-
   explicit SVGMaskElement(Document&);
 
   SVGAnimatedLength* x() const { return x_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_matrix_tear_off.h b/third_party/blink/renderer/core/svg/svg_matrix_tear_off.h
index 1cf767e..e36d7163 100644
--- a/third_party/blink/renderer/core/svg/svg_matrix_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_matrix_tear_off.h
@@ -49,14 +49,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGMatrixTearOff* Create(const AffineTransform& value) {
-    return MakeGarbageCollected<SVGMatrixTearOff>(value);
-  }
-
-  static SVGMatrixTearOff* Create(SVGTransformTearOff* target) {
-    return MakeGarbageCollected<SVGMatrixTearOff>(target);
-  }
-
   explicit SVGMatrixTearOff(const AffineTransform&);
   explicit SVGMatrixTearOff(SVGTransformTearOff*);
 
diff --git a/third_party/blink/renderer/core/svg/svg_metadata_element.cc b/third_party/blink/renderer/core/svg/svg_metadata_element.cc
index 05cca08..c34b4ae 100644
--- a/third_party/blink/renderer/core/svg/svg_metadata_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_metadata_element.cc
@@ -26,6 +26,4 @@
 
 SVGMetadataElement::SVGMetadataElement(Document& document)
     : SVGElement(svg_names::kMetadataTag, document) {}
-
-DEFINE_NODE_FACTORY(SVGMetadataElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_metadata_element.h b/third_party/blink/renderer/core/svg/svg_metadata_element.h
index 0a7d94c..3a6ba9c4 100644
--- a/third_party/blink/renderer/core/svg/svg_metadata_element.h
+++ b/third_party/blink/renderer/core/svg/svg_metadata_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGMetadataElement);
-
   explicit SVGMetadataElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_mpath_element.cc b/third_party/blink/renderer/core/svg/svg_mpath_element.cc
index 932c1ab..7336ab8 100644
--- a/third_party/blink/renderer/core/svg/svg_mpath_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_mpath_element.cc
@@ -36,8 +36,6 @@
   SVGURIReference::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGMPathElement)
-
 SVGMPathElement::~SVGMPathElement() = default;
 
 void SVGMPathElement::BuildPendingResource() {
diff --git a/third_party/blink/renderer/core/svg/svg_mpath_element.h b/third_party/blink/renderer/core/svg/svg_mpath_element.h
index 4339ad71..ee6fa88 100644
--- a/third_party/blink/renderer/core/svg/svg_mpath_element.h
+++ b/third_party/blink/renderer/core/svg/svg_mpath_element.h
@@ -32,8 +32,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGMPathElement);
 
  public:
-  DECLARE_NODE_FACTORY(SVGMPathElement);
-
   explicit SVGMPathElement(Document&);
   ~SVGMPathElement() override;
 
diff --git a/third_party/blink/renderer/core/svg/svg_number.h b/third_party/blink/renderer/core/svg/svg_number.h
index b04aa1c..6d8aed8d 100644
--- a/third_party/blink/renderer/core/svg/svg_number.h
+++ b/third_party/blink/renderer/core/svg/svg_number.h
@@ -44,10 +44,6 @@
   typedef SVGNumberTearOff TearOffType;
   typedef float PrimitiveType;
 
-  static SVGNumber* Create(float value = 0.0f) {
-    return MakeGarbageCollected<SVGNumber>(value);
-  }
-
   explicit SVGNumber(float = 0.0f);
 
   virtual SVGNumber* Clone() const;
@@ -89,10 +85,6 @@
 //   offset = "<number> | <percentage>"
 class SVGNumberAcceptPercentage final : public SVGNumber {
  public:
-  static SVGNumberAcceptPercentage* Create(float value = 0) {
-    return MakeGarbageCollected<SVGNumberAcceptPercentage>(value);
-  }
-
   explicit SVGNumberAcceptPercentage(float = 0);
 
   SVGNumber* Clone() const override;
diff --git a/third_party/blink/renderer/core/svg/svg_number_list.h b/third_party/blink/renderer/core/svg/svg_number_list.h
index ca3c6c4..19906730 100644
--- a/third_party/blink/renderer/core/svg/svg_number_list.h
+++ b/third_party/blink/renderer/core/svg/svg_number_list.h
@@ -44,10 +44,6 @@
  public:
   typedef SVGNumberListTearOff TearOffType;
 
-  static SVGNumberList* Create() {
-    return MakeGarbageCollected<SVGNumberList>();
-  }
-
   SVGNumberList();
   ~SVGNumberList() override;
 
diff --git a/third_party/blink/renderer/core/svg/svg_number_list_tear_off.h b/third_party/blink/renderer/core/svg/svg_number_list_tear_off.h
index 7e5878f..8177fc4 100644
--- a/third_party/blink/renderer/core/svg/svg_number_list_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_number_list_tear_off.h
@@ -41,14 +41,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGNumberListTearOff* Create(
-      SVGNumberList* target,
-      SVGAnimatedPropertyBase* binding,
-      PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGNumberListTearOff>(target, binding,
-                                                      property_is_anim_val);
-  }
-
   SVGNumberListTearOff(SVGNumberList* target,
                        SVGAnimatedPropertyBase* binding,
                        PropertyIsAnimValType property_is_anim_val)
diff --git a/third_party/blink/renderer/core/svg/svg_number_optional_number.h b/third_party/blink/renderer/core/svg/svg_number_optional_number.h
index 5224a522..752e627d 100644
--- a/third_party/blink/renderer/core/svg/svg_number_optional_number.h
+++ b/third_party/blink/renderer/core/svg/svg_number_optional_number.h
@@ -43,12 +43,6 @@
   typedef void TearOffType;
   typedef void PrimitiveType;
 
-  static SVGNumberOptionalNumber* Create(SVGNumber* first_number,
-                                         SVGNumber* second_number) {
-    return MakeGarbageCollected<SVGNumberOptionalNumber>(first_number,
-                                                         second_number);
-  }
-
   SVGNumberOptionalNumber(SVGNumber* first_number, SVGNumber* second_number);
 
   SVGNumberOptionalNumber* Clone() const;
diff --git a/third_party/blink/renderer/core/svg/svg_number_tear_off.h b/third_party/blink/renderer/core/svg/svg_number_tear_off.h
index 7748b33..2f50047 100644
--- a/third_party/blink/renderer/core/svg/svg_number_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_number_tear_off.h
@@ -40,12 +40,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGNumberTearOff* Create(SVGNumber* target,
-                                  SVGAnimatedPropertyBase* binding,
-                                  PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGNumberTearOff>(target, binding,
-                                                  property_is_anim_val);
-  }
   static SVGNumberTearOff* CreateDetached();
 
   SVGNumberTearOff(SVGNumber*,
diff --git a/third_party/blink/renderer/core/svg/svg_path.h b/third_party/blink/renderer/core/svg/svg_path.h
index 696cc58d..68e719e 100644
--- a/third_party/blink/renderer/core/svg/svg_path.h
+++ b/third_party/blink/renderer/core/svg/svg_path.h
@@ -42,11 +42,6 @@
  public:
   typedef void TearOffType;
 
-  static SVGPath* Create() { return MakeGarbageCollected<SVGPath>(); }
-  static SVGPath* Create(cssvalue::CSSPathValue* path_value) {
-    return MakeGarbageCollected<SVGPath>(path_value);
-  }
-
   SVGPath();
   explicit SVGPath(cssvalue::CSSPathValue*);
   ~SVGPath() override;
diff --git a/third_party/blink/renderer/core/svg/svg_path_element.cc b/third_party/blink/renderer/core/svg/svg_path_element.cc
index 1939e02..cb1383fe 100644
--- a/third_party/blink/renderer/core/svg/svg_path_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_element.cc
@@ -42,8 +42,6 @@
   SVGGeometryElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGPathElement)
-
 Path SVGPathElement::AttributePath() const {
   return path_->CurrentValue()->GetStylePath()->GetPath();
 }
diff --git a/third_party/blink/renderer/core/svg/svg_path_element.h b/third_party/blink/renderer/core/svg/svg_path_element.h
index 29cafef..beaa41b 100644
--- a/third_party/blink/renderer/core/svg/svg_path_element.h
+++ b/third_party/blink/renderer/core/svg/svg_path_element.h
@@ -33,8 +33,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGPathElement);
-
   explicit SVGPathElement(Document&);
 
   Path AsPath() const override;
diff --git a/third_party/blink/renderer/core/svg/svg_pattern_element.cc b/third_party/blink/renderer/core/svg/svg_pattern_element.cc
index aff9cdf..d147e41 100644
--- a/third_party/blink/renderer/core/svg/svg_pattern_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_pattern_element.cc
@@ -97,8 +97,6 @@
   SVGFitToViewBox::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGPatternElement)
-
 void SVGPatternElement::BuildPendingResource() {
   ClearResourceReferences();
   if (!isConnected())
diff --git a/third_party/blink/renderer/core/svg/svg_pattern_element.h b/third_party/blink/renderer/core/svg/svg_pattern_element.h
index aeaa7e3..45b7af1 100644
--- a/third_party/blink/renderer/core/svg/svg_pattern_element.h
+++ b/third_party/blink/renderer/core/svg/svg_pattern_element.h
@@ -45,8 +45,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGPatternElement);
 
  public:
-  DECLARE_NODE_FACTORY(SVGPatternElement);
-
   explicit SVGPatternElement(Document&);
 
   void CollectPatternAttributes(PatternAttributes&) const;
diff --git a/third_party/blink/renderer/core/svg/svg_point.h b/third_party/blink/renderer/core/svg/svg_point.h
index 13c5246..0186fbb 100644
--- a/third_party/blink/renderer/core/svg/svg_point.h
+++ b/third_party/blink/renderer/core/svg/svg_point.h
@@ -44,12 +44,6 @@
  public:
   typedef SVGPointTearOff TearOffType;
 
-  static SVGPoint* Create() { return MakeGarbageCollected<SVGPoint>(); }
-
-  static SVGPoint* Create(const FloatPoint& point) {
-    return MakeGarbageCollected<SVGPoint>(point);
-  }
-
   SVGPoint();
   explicit SVGPoint(const FloatPoint&);
 
diff --git a/third_party/blink/renderer/core/svg/svg_point_list.h b/third_party/blink/renderer/core/svg/svg_point_list.h
index 76a1973..a25b1b2 100644
--- a/third_party/blink/renderer/core/svg/svg_point_list.h
+++ b/third_party/blink/renderer/core/svg/svg_point_list.h
@@ -44,8 +44,6 @@
  public:
   typedef SVGPointListTearOff TearOffType;
 
-  static SVGPointList* Create() { return MakeGarbageCollected<SVGPointList>(); }
-
   SVGPointList();
   ~SVGPointList() override;
 
diff --git a/third_party/blink/renderer/core/svg/svg_point_list_tear_off.h b/third_party/blink/renderer/core/svg/svg_point_list_tear_off.h
index 0dacaf3..719fff5 100644
--- a/third_party/blink/renderer/core/svg/svg_point_list_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_point_list_tear_off.h
@@ -41,14 +41,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGPointListTearOff* Create(
-      SVGPointList* target,
-      SVGAnimatedPropertyBase* binding,
-      PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGPointListTearOff>(target, binding,
-                                                     property_is_anim_val);
-  }
-
   SVGPointListTearOff(SVGPointList* target,
                       SVGAnimatedPropertyBase* binding,
                       PropertyIsAnimValType property_is_anim_val)
diff --git a/third_party/blink/renderer/core/svg/svg_point_tear_off.h b/third_party/blink/renderer/core/svg/svg_point_tear_off.h
index dcc63e1..e12ea265 100644
--- a/third_party/blink/renderer/core/svg/svg_point_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_point_tear_off.h
@@ -42,16 +42,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGPointTearOff* Create(SVGPoint* target,
-                                 SVGAnimatedPropertyBase* binding,
-                                 PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGPointTearOff>(target, binding,
-                                                 property_is_anim_val);
-  }
-  static SVGPointTearOff* Create(SVGPoint* target,
-                                 SVGElement* context_element) {
-    return MakeGarbageCollected<SVGPointTearOff>(target, context_element);
-  }
   static SVGPointTearOff* CreateDetached(const FloatPoint&);
 
   SVGPointTearOff(SVGPoint*,
diff --git a/third_party/blink/renderer/core/svg/svg_polygon_element.cc b/third_party/blink/renderer/core/svg/svg_polygon_element.cc
index f68bd9e5..5418966 100644
--- a/third_party/blink/renderer/core/svg/svg_polygon_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_polygon_element.cc
@@ -27,8 +27,6 @@
 SVGPolygonElement::SVGPolygonElement(Document& document)
     : SVGPolyElement(svg_names::kPolygonTag, document) {}
 
-DEFINE_NODE_FACTORY(SVGPolygonElement)
-
 Path SVGPolygonElement::AsPath() const {
   Path path = AsPathFromPoints();
   path.CloseSubpath();
diff --git a/third_party/blink/renderer/core/svg/svg_polygon_element.h b/third_party/blink/renderer/core/svg/svg_polygon_element.h
index 442f0b09..b4d1b56d 100644
--- a/third_party/blink/renderer/core/svg/svg_polygon_element.h
+++ b/third_party/blink/renderer/core/svg/svg_polygon_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGPolygonElement);
-
   explicit SVGPolygonElement(Document&);
 
   Path AsPath() const override;
diff --git a/third_party/blink/renderer/core/svg/svg_polyline_element.cc b/third_party/blink/renderer/core/svg/svg_polyline_element.cc
index 1d2b1f1..19f8fc7 100644
--- a/third_party/blink/renderer/core/svg/svg_polyline_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_polyline_element.cc
@@ -27,8 +27,6 @@
 SVGPolylineElement::SVGPolylineElement(Document& document)
     : SVGPolyElement(svg_names::kPolylineTag, document) {}
 
-DEFINE_NODE_FACTORY(SVGPolylineElement)
-
 Path SVGPolylineElement::AsPath() const {
   return AsPathFromPoints();
 }
diff --git a/third_party/blink/renderer/core/svg/svg_polyline_element.h b/third_party/blink/renderer/core/svg/svg_polyline_element.h
index e4d98e4..7c0fc55 100644
--- a/third_party/blink/renderer/core/svg/svg_polyline_element.h
+++ b/third_party/blink/renderer/core/svg/svg_polyline_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGPolylineElement);
-
   explicit SVGPolylineElement(Document&);
 
   Path AsPath() const override;
diff --git a/third_party/blink/renderer/core/svg/svg_preserve_aspect_ratio.h b/third_party/blink/renderer/core/svg/svg_preserve_aspect_ratio.h
index 24750be..9d3c7e5b 100644
--- a/third_party/blink/renderer/core/svg/svg_preserve_aspect_ratio.h
+++ b/third_party/blink/renderer/core/svg/svg_preserve_aspect_ratio.h
@@ -55,10 +55,6 @@
 
   typedef SVGPreserveAspectRatioTearOff TearOffType;
 
-  static SVGPreserveAspectRatio* Create() {
-    return MakeGarbageCollected<SVGPreserveAspectRatio>();
-  }
-
   SVGPreserveAspectRatio();
 
   virtual SVGPreserveAspectRatio* Clone() const;
diff --git a/third_party/blink/renderer/core/svg/svg_preserve_aspect_ratio_tear_off.h b/third_party/blink/renderer/core/svg/svg_preserve_aspect_ratio_tear_off.h
index c774215..109bba0 100644
--- a/third_party/blink/renderer/core/svg/svg_preserve_aspect_ratio_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_preserve_aspect_ratio_tear_off.h
@@ -73,14 +73,6 @@
     kSvgMeetorsliceSlice = SVGPreserveAspectRatio::kSvgMeetorsliceSlice
   };
 
-  static SVGPreserveAspectRatioTearOff* Create(
-      SVGPreserveAspectRatio* target,
-      SVGAnimatedPropertyBase* binding,
-      PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGPreserveAspectRatioTearOff>(
-        target, binding, property_is_anim_val);
-  }
-
   SVGPreserveAspectRatioTearOff(SVGPreserveAspectRatio*,
                                 SVGAnimatedPropertyBase* binding,
                                 PropertyIsAnimValType);
diff --git a/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc b/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc
index 6745501..7f070031 100644
--- a/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc
@@ -83,8 +83,6 @@
   SVGGradientElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGRadialGradientElement)
-
 void SVGRadialGradientElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
   if (attr_name == svg_names::kCxAttr || attr_name == svg_names::kCyAttr ||
diff --git a/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h b/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h
index d5d7a83bb..b37d29259 100644
--- a/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h
+++ b/third_party/blink/renderer/core/svg/svg_radial_gradient_element.h
@@ -33,8 +33,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGRadialGradientElement);
-
   explicit SVGRadialGradientElement(Document&);
 
   bool CollectGradientAttributes(RadialGradientAttributes&);
diff --git a/third_party/blink/renderer/core/svg/svg_rect.h b/third_party/blink/renderer/core/svg/svg_rect.h
index de2a678..9f32545d 100644
--- a/third_party/blink/renderer/core/svg/svg_rect.h
+++ b/third_party/blink/renderer/core/svg/svg_rect.h
@@ -33,18 +33,12 @@
  public:
   typedef SVGRectTearOff TearOffType;
 
-  static SVGRect* Create() { return MakeGarbageCollected<SVGRect>(); }
-
   static SVGRect* CreateInvalid() {
     SVGRect* rect = MakeGarbageCollected<SVGRect>();
     rect->SetInvalid();
     return rect;
   }
 
-  static SVGRect* Create(const FloatRect& rect) {
-    return MakeGarbageCollected<SVGRect>(rect);
-  }
-
   SVGRect();
   SVGRect(const FloatRect&);
 
diff --git a/third_party/blink/renderer/core/svg/svg_rect_element.cc b/third_party/blink/renderer/core/svg/svg_rect_element.cc
index 3337cf2..d8be687b 100644
--- a/third_party/blink/renderer/core/svg/svg_rect_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_rect_element.cc
@@ -82,8 +82,6 @@
   SVGGeometryElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGRectElement)
-
 Path SVGRectElement::AsPath() const {
   Path path;
 
diff --git a/third_party/blink/renderer/core/svg/svg_rect_element.h b/third_party/blink/renderer/core/svg/svg_rect_element.h
index 54919be..1de73b6 100644
--- a/third_party/blink/renderer/core/svg/svg_rect_element.h
+++ b/third_party/blink/renderer/core/svg/svg_rect_element.h
@@ -31,8 +31,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGRectElement);
-
   explicit SVGRectElement(Document&);
 
   Path AsPath() const override;
diff --git a/third_party/blink/renderer/core/svg/svg_rect_tear_off.h b/third_party/blink/renderer/core/svg/svg_rect_tear_off.h
index 36976210..c0218a169 100644
--- a/third_party/blink/renderer/core/svg/svg_rect_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_rect_tear_off.h
@@ -40,12 +40,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGRectTearOff* Create(SVGRect* target,
-                                SVGAnimatedPropertyBase* binding,
-                                PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGRectTearOff>(target, binding,
-                                                property_is_anim_val);
-  }
   static SVGRectTearOff* CreateDetached(const FloatRect&);
 
   SVGRectTearOff(SVGRect*,
diff --git a/third_party/blink/renderer/core/svg/svg_script_element.cc b/third_party/blink/renderer/core/svg/svg_script_element.cc
index 66eec634..ade3c08 100644
--- a/third_party/blink/renderer/core/svg/svg_script_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_script_element.cc
@@ -40,11 +40,6 @@
       loader_(InitializeScriptLoader(flags.IsCreatedByParser(),
                                      flags.WasAlreadyStarted())) {}
 
-SVGScriptElement* SVGScriptElement::Create(Document& document,
-                                           const CreateElementFlags flags) {
-  return MakeGarbageCollected<SVGScriptElement>(document, flags);
-}
-
 void SVGScriptElement::ParseAttribute(
     const AttributeModificationParams& params) {
   if (params.name == html_names::kOnerrorAttr) {
diff --git a/third_party/blink/renderer/core/svg/svg_script_element.h b/third_party/blink/renderer/core/svg/svg_script_element.h
index 6299da1..c1222ee2 100644
--- a/third_party/blink/renderer/core/svg/svg_script_element.h
+++ b/third_party/blink/renderer/core/svg/svg_script_element.h
@@ -39,8 +39,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGScriptElement);
 
  public:
-  static SVGScriptElement* Create(Document&, const CreateElementFlags);
-
   SVGScriptElement(Document&, const CreateElementFlags);
 
   ScriptLoader* Loader() const final { return loader_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_set_element.cc b/third_party/blink/renderer/core/svg/svg_set_element.cc
index d2b9b9d..b87929e 100644
--- a/third_party/blink/renderer/core/svg/svg_set_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_set_element.cc
@@ -29,8 +29,6 @@
   SetAnimationMode(kToAnimation);
 }
 
-DEFINE_NODE_FACTORY(SVGSetElement)
-
 void SVGSetElement::UpdateAnimationMode() {
   // No-op, as <set> has a constant animation mode of ToAnimation.
   // See: http://www.w3.org/TR/SVG/single-page.html#animate-SetElement
diff --git a/third_party/blink/renderer/core/svg/svg_set_element.h b/third_party/blink/renderer/core/svg/svg_set_element.h
index ab2cd1d..5f41a2e 100644
--- a/third_party/blink/renderer/core/svg/svg_set_element.h
+++ b/third_party/blink/renderer/core/svg/svg_set_element.h
@@ -31,8 +31,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGSetElement);
-
   explicit SVGSetElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_stop_element.cc b/third_party/blink/renderer/core/svg/svg_stop_element.cc
index 44f91e6..7d73cf8 100644
--- a/third_party/blink/renderer/core/svg/svg_stop_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_stop_element.cc
@@ -45,8 +45,6 @@
   SVGElement::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGStopElement)
-
 namespace {
 
 void InvalidateInstancesAndAncestorResources(SVGStopElement* stop_element) {
diff --git a/third_party/blink/renderer/core/svg/svg_stop_element.h b/third_party/blink/renderer/core/svg/svg_stop_element.h
index e5dd57f..b8e3f0f 100644
--- a/third_party/blink/renderer/core/svg/svg_stop_element.h
+++ b/third_party/blink/renderer/core/svg/svg_stop_element.h
@@ -33,8 +33,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGStopElement);
-
   explicit SVGStopElement(Document&);
 
   Color StopColorIncludingOpacity() const;
diff --git a/third_party/blink/renderer/core/svg/svg_string.h b/third_party/blink/renderer/core/svg/svg_string.h
index 399179e..428a40a 100644
--- a/third_party/blink/renderer/core/svg/svg_string.h
+++ b/third_party/blink/renderer/core/svg/svg_string.h
@@ -43,12 +43,6 @@
   typedef void TearOffType;
   typedef String PrimitiveType;
 
-  static SVGString* Create() { return MakeGarbageCollected<SVGString>(); }
-
-  static SVGString* Create(const String& value) {
-    return MakeGarbageCollected<SVGString>(value);
-  }
-
   SVGString() = default;
   explicit SVGString(const String& value) : value_(value) {}
 
diff --git a/third_party/blink/renderer/core/svg/svg_string_list.h b/third_party/blink/renderer/core/svg/svg_string_list.h
index ec8f192f..7c11786 100644
--- a/third_party/blink/renderer/core/svg/svg_string_list.h
+++ b/third_party/blink/renderer/core/svg/svg_string_list.h
@@ -112,10 +112,6 @@
 template <char list_delimiter>
 class SVGStringList final : public SVGStringListBase {
  public:
-  static SVGStringList<list_delimiter>* Create() {
-    return MakeGarbageCollected<SVGStringList<list_delimiter>>();
-  }
-
   SVGStringList() = default;
   ~SVGStringList() override = default;
 
diff --git a/third_party/blink/renderer/core/svg/svg_string_list_tear_off.h b/third_party/blink/renderer/core/svg/svg_string_list_tear_off.h
index 48d730e..f941d7c 100644
--- a/third_party/blink/renderer/core/svg/svg_string_list_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_string_list_tear_off.h
@@ -40,14 +40,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGStringListTearOff* Create(
-      SVGStringListBase* target,
-      SVGAnimatedPropertyBase* binding,
-      PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGStringListTearOff>(target, binding,
-                                                      property_is_anim_val);
-  }
-
   SVGStringListTearOff(SVGStringListBase*,
                        SVGAnimatedPropertyBase* binding,
                        PropertyIsAnimValType);
diff --git a/third_party/blink/renderer/core/svg/svg_style_element.cc b/third_party/blink/renderer/core/svg/svg_style_element.cc
index 05187c3..78852ec 100644
--- a/third_party/blink/renderer/core/svg/svg_style_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_style_element.cc
@@ -38,11 +38,6 @@
 
 SVGStyleElement::~SVGStyleElement() = default;
 
-SVGStyleElement* SVGStyleElement::Create(Document& document,
-                                         const CreateElementFlags flags) {
-  return MakeGarbageCollected<SVGStyleElement>(document, flags);
-}
-
 bool SVGStyleElement::disabled() const {
   if (!sheet_)
     return false;
diff --git a/third_party/blink/renderer/core/svg/svg_style_element.h b/third_party/blink/renderer/core/svg/svg_style_element.h
index 8fba25f..1c540a0 100644
--- a/third_party/blink/renderer/core/svg/svg_style_element.h
+++ b/third_party/blink/renderer/core/svg/svg_style_element.h
@@ -32,8 +32,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGStyleElement);
 
  public:
-  static SVGStyleElement* Create(Document&, const CreateElementFlags);
-
   SVGStyleElement(Document&, const CreateElementFlags);
   ~SVGStyleElement() override;
 
diff --git a/third_party/blink/renderer/core/svg/svg_svg_element.cc b/third_party/blink/renderer/core/svg/svg_svg_element.cc
index 8cc7914..3ca5f74 100644
--- a/third_party/blink/renderer/core/svg/svg_svg_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_svg_element.cc
@@ -100,8 +100,6 @@
   UseCounter::Count(doc, WebFeature::kSVGSVGElement);
 }
 
-DEFINE_NODE_FACTORY(SVGSVGElement)
-
 SVGSVGElement::~SVGSVGElement() = default;
 
 float SVGSVGElement::currentScale() const {
@@ -122,10 +120,6 @@
 
 class SVGCurrentTranslateTearOff : public SVGPointTearOff {
  public:
-  static SVGCurrentTranslateTearOff* Create(SVGSVGElement* context_element) {
-    return MakeGarbageCollected<SVGCurrentTranslateTearOff>(context_element);
-  }
-
   SVGCurrentTranslateTearOff(SVGSVGElement* context_element)
       : SVGPointTearOff(context_element->translation_, context_element) {}
 
diff --git a/third_party/blink/renderer/core/svg/svg_svg_element.h b/third_party/blink/renderer/core/svg/svg_svg_element.h
index fb913e7..86c730cf 100644
--- a/third_party/blink/renderer/core/svg/svg_svg_element.h
+++ b/third_party/blink/renderer/core/svg/svg_svg_element.h
@@ -47,8 +47,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGSVGElement);
 
  public:
-  DECLARE_NODE_FACTORY(SVGSVGElement);
-
   explicit SVGSVGElement(Document&);
 
   float IntrinsicWidth() const;
diff --git a/third_party/blink/renderer/core/svg/svg_switch_element.cc b/third_party/blink/renderer/core/svg/svg_switch_element.cc
index 284be64..73be72c 100644
--- a/third_party/blink/renderer/core/svg/svg_switch_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_switch_element.cc
@@ -31,8 +31,6 @@
   UseCounter::Count(document, WebFeature::kSVGSwitchElement);
 }
 
-DEFINE_NODE_FACTORY(SVGSwitchElement)
-
 LayoutObject* SVGSwitchElement::CreateLayoutObject(const ComputedStyle&,
                                                    LegacyLayout) {
   return new LayoutSVGTransformableContainer(this);
diff --git a/third_party/blink/renderer/core/svg/svg_switch_element.h b/third_party/blink/renderer/core/svg/svg_switch_element.h
index b837381..161110e 100644
--- a/third_party/blink/renderer/core/svg/svg_switch_element.h
+++ b/third_party/blink/renderer/core/svg/svg_switch_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGSwitchElement);
-
   explicit SVGSwitchElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_symbol_element.cc b/third_party/blink/renderer/core/svg/svg_symbol_element.cc
index f472636..1b8ebcd 100644
--- a/third_party/blink/renderer/core/svg/svg_symbol_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_symbol_element.cc
@@ -33,8 +33,6 @@
   SVGFitToViewBox::Trace(visitor);
 }
 
-DEFINE_NODE_FACTORY(SVGSymbolElement)
-
 void SVGSymbolElement::SvgAttributeChanged(const QualifiedName& attr_name) {
   if (SVGFitToViewBox::IsKnownAttribute(attr_name))
     InvalidateInstances();
diff --git a/third_party/blink/renderer/core/svg/svg_symbol_element.h b/third_party/blink/renderer/core/svg/svg_symbol_element.h
index 836588f..580a3b5 100644
--- a/third_party/blink/renderer/core/svg/svg_symbol_element.h
+++ b/third_party/blink/renderer/core/svg/svg_symbol_element.h
@@ -31,8 +31,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGSymbolElement);
 
  public:
-  DECLARE_NODE_FACTORY(SVGSymbolElement);
-
   explicit SVGSymbolElement(Document&);
 
   void Trace(blink::Visitor*) override;
diff --git a/third_party/blink/renderer/core/svg/svg_text_content_element.cc b/third_party/blink/renderer/core/svg/svg_text_content_element.cc
index 6d670f6..1da22aa 100644
--- a/third_party/blink/renderer/core/svg/svg_text_content_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_text_content_element.cc
@@ -53,10 +53,6 @@
 // manually.
 class SVGAnimatedTextLength final : public SVGAnimatedLength {
  public:
-  static SVGAnimatedTextLength* Create(SVGTextContentElement* context_element) {
-    return MakeGarbageCollected<SVGAnimatedTextLength>(context_element);
-  }
-
   SVGAnimatedTextLength(SVGTextContentElement* context_element)
       : SVGAnimatedLength(context_element,
                           svg_names::kTextLengthAttr,
@@ -78,7 +74,7 @@
 SVGTextContentElement::SVGTextContentElement(const QualifiedName& tag_name,
                                              Document& document)
     : SVGGraphicsElement(tag_name, document),
-      text_length_(SVGAnimatedTextLength::Create(this)),
+      text_length_(MakeGarbageCollected<SVGAnimatedTextLength>(this)),
       text_length_is_specified_by_user_(false),
       length_adjust_(
           MakeGarbageCollected<SVGAnimatedEnumeration<SVGLengthAdjustType>>(
diff --git a/third_party/blink/renderer/core/svg/svg_text_element.cc b/third_party/blink/renderer/core/svg/svg_text_element.cc
index 24e23a2..daabb81 100644
--- a/third_party/blink/renderer/core/svg/svg_text_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_text_element.cc
@@ -27,8 +27,6 @@
 SVGTextElement::SVGTextElement(Document& doc)
     : SVGTextPositioningElement(svg_names::kTextTag, doc) {}
 
-DEFINE_NODE_FACTORY(SVGTextElement)
-
 LayoutObject* SVGTextElement::CreateLayoutObject(const ComputedStyle&,
                                                  LegacyLayout) {
   return new LayoutSVGText(this);
diff --git a/third_party/blink/renderer/core/svg/svg_text_element.h b/third_party/blink/renderer/core/svg/svg_text_element.h
index 90961df..e695e6f 100644
--- a/third_party/blink/renderer/core/svg/svg_text_element.h
+++ b/third_party/blink/renderer/core/svg/svg_text_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGTextElement);
-
   explicit SVGTextElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_text_path_element.cc b/third_party/blink/renderer/core/svg/svg_text_path_element.cc
index 4b1cf72a..9687187 100644
--- a/third_party/blink/renderer/core/svg/svg_text_path_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_text_path_element.cc
@@ -69,8 +69,6 @@
   AddToPropertyMap(spacing_);
 }
 
-DEFINE_NODE_FACTORY(SVGTextPathElement)
-
 SVGTextPathElement::~SVGTextPathElement() = default;
 
 void SVGTextPathElement::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/svg/svg_text_path_element.h b/third_party/blink/renderer/core/svg/svg_text_path_element.h
index 978ac4b..0576602 100644
--- a/third_party/blink/renderer/core/svg/svg_text_path_element.h
+++ b/third_party/blink/renderer/core/svg/svg_text_path_element.h
@@ -56,8 +56,6 @@
     kTextpathSpacingtypeExact = kSVGTextPathSpacingExact
   };
 
-  DECLARE_NODE_FACTORY(SVGTextPathElement);
-
   explicit SVGTextPathElement(Document&);
 
   SVGAnimatedLength* startOffset() const { return start_offset_.Get(); }
diff --git a/third_party/blink/renderer/core/svg/svg_title_element.cc b/third_party/blink/renderer/core/svg/svg_title_element.cc
index 36e60b4..06f0c17 100644
--- a/third_party/blink/renderer/core/svg/svg_title_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_title_element.cc
@@ -32,8 +32,6 @@
     : SVGElement(svg_names::kTitleTag, document),
       ignore_title_updates_when_children_change_(false) {}
 
-DEFINE_NODE_FACTORY(SVGTitleElement)
-
 Node::InsertionNotificationRequest SVGTitleElement::InsertedInto(
     ContainerNode& root_parent) {
   SVGElement::InsertedInto(root_parent);
diff --git a/third_party/blink/renderer/core/svg/svg_title_element.h b/third_party/blink/renderer/core/svg/svg_title_element.h
index 38021cb..de14e80 100644
--- a/third_party/blink/renderer/core/svg/svg_title_element.h
+++ b/third_party/blink/renderer/core/svg/svg_title_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGTitleElement);
-
   explicit SVGTitleElement(Document&);
 
   void SetText(const String&);
diff --git a/third_party/blink/renderer/core/svg/svg_transform.h b/third_party/blink/renderer/core/svg/svg_transform.h
index 5f77e3a..7c06b79 100644
--- a/third_party/blink/renderer/core/svg/svg_transform.h
+++ b/third_party/blink/renderer/core/svg/svg_transform.h
@@ -50,18 +50,6 @@
     kConstructZeroTransform
   };
 
-  static SVGTransform* Create() { return MakeGarbageCollected<SVGTransform>(); }
-
-  static SVGTransform* Create(
-      SVGTransformType type,
-      ConstructionMode mode = kConstructIdentityTransform) {
-    return MakeGarbageCollected<SVGTransform>(type, mode);
-  }
-
-  static SVGTransform* Create(const AffineTransform& affine_transform) {
-    return MakeGarbageCollected<SVGTransform>(affine_transform);
-  }
-
   SVGTransform();
   explicit SVGTransform(SVGTransformType,
                         ConstructionMode = kConstructIdentityTransform);
diff --git a/third_party/blink/renderer/core/svg/svg_transform_list.cc b/third_party/blink/renderer/core/svg/svg_transform_list.cc
index 69eefa468..c24b8c2 100644
--- a/third_party/blink/renderer/core/svg/svg_transform_list.cc
+++ b/third_party/blink/renderer/core/svg/svg_transform_list.cc
@@ -38,8 +38,145 @@
 
 namespace blink {
 
+namespace {
+
+// These should be kept in sync with enum SVGTransformType
+const unsigned kRequiredValuesForType[] = {0, 6, 1, 1, 1, 1, 1};
+const unsigned kOptionalValuesForType[] = {0, 0, 1, 1, 2, 0, 0};
+static_assert(static_cast<int>(SVGTransformType::kUnknown) == 0,
+              "index of SVGTransformType::kUnknown has changed");
+static_assert(static_cast<int>(SVGTransformType::kMatrix) == 1,
+              "index of SVGTransformType::kMatrix has changed");
+static_assert(static_cast<int>(SVGTransformType::kTranslate) == 2,
+              "index of SVGTransformType::kTranslate has changed");
+static_assert(static_cast<int>(SVGTransformType::kScale) == 3,
+              "index of SVGTransformType::kScale has changed");
+static_assert(static_cast<int>(SVGTransformType::kRotate) == 4,
+              "index of SVGTransformType::kRotate has changed");
+static_assert(static_cast<int>(SVGTransformType::kSkewx) == 5,
+              "index of SVGTransformType::kSkewx has changed");
+static_assert(static_cast<int>(SVGTransformType::kSkewy) == 6,
+              "index of SVGTransformType::kSkewy has changed");
+static_assert(base::size(kRequiredValuesForType) - 1 ==
+                  static_cast<int>(SVGTransformType::kSkewy),
+              "the number of transform types have changed");
+static_assert(base::size(kRequiredValuesForType) ==
+                  base::size(kOptionalValuesForType),
+              "the arrays should have the same number of elements");
+
+const unsigned kMaxTransformArguments = 6;
+
+using TransformArguments = Vector<float, kMaxTransformArguments>;
+
+template <typename CharType>
+SVGParseStatus ParseTransformArgumentsForType(SVGTransformType type,
+                                              const CharType*& ptr,
+                                              const CharType* end,
+                                              TransformArguments& arguments) {
+  const size_t required = kRequiredValuesForType[static_cast<int>(type)];
+  const size_t optional = kOptionalValuesForType[static_cast<int>(type)];
+  const size_t required_with_optional = required + optional;
+  DCHECK_LE(required_with_optional, kMaxTransformArguments);
+  DCHECK(arguments.IsEmpty());
+
+  bool trailing_delimiter = false;
+
+  while (arguments.size() < required_with_optional) {
+    float argument_value = 0;
+    if (!ParseNumber(ptr, end, argument_value, kAllowLeadingWhitespace))
+      break;
+
+    arguments.push_back(argument_value);
+    trailing_delimiter = false;
+
+    if (arguments.size() == required_with_optional)
+      break;
+
+    if (SkipOptionalSVGSpaces(ptr, end) && *ptr == ',') {
+      ++ptr;
+      trailing_delimiter = true;
+    }
+  }
+
+  if (arguments.size() != required &&
+      arguments.size() != required_with_optional)
+    return SVGParseStatus::kExpectedNumber;
+  if (trailing_delimiter)
+    return SVGParseStatus::kTrailingGarbage;
+
+  return SVGParseStatus::kNoError;
+}
+
+SVGTransform* CreateTransformFromValues(SVGTransformType type,
+                                        const TransformArguments& arguments) {
+  auto* transform = MakeGarbageCollected<SVGTransform>();
+  switch (type) {
+    case SVGTransformType::kSkewx:
+      transform->SetSkewX(arguments[0]);
+      break;
+    case SVGTransformType::kSkewy:
+      transform->SetSkewY(arguments[0]);
+      break;
+    case SVGTransformType::kScale:
+      // Spec: if only one param given, assume uniform scaling.
+      if (arguments.size() == 1)
+        transform->SetScale(arguments[0], arguments[0]);
+      else
+        transform->SetScale(arguments[0], arguments[1]);
+      break;
+    case SVGTransformType::kTranslate:
+      // Spec: if only one param given, assume 2nd param to be 0.
+      if (arguments.size() == 1)
+        transform->SetTranslate(arguments[0], 0);
+      else
+        transform->SetTranslate(arguments[0], arguments[1]);
+      break;
+    case SVGTransformType::kRotate:
+      if (arguments.size() == 1)
+        transform->SetRotate(arguments[0], 0, 0);
+      else
+        transform->SetRotate(arguments[0], arguments[1], arguments[2]);
+      break;
+    case SVGTransformType::kMatrix:
+      transform->SetMatrix(AffineTransform(arguments[0], arguments[1],
+                                           arguments[2], arguments[3],
+                                           arguments[4], arguments[5]));
+      break;
+    case SVGTransformType::kUnknown:
+      NOTREACHED();
+      break;
+  }
+  return transform;
+}
+
+}  // namespace
+
 SVGTransformList::SVGTransformList() = default;
 
+SVGTransformList::SVGTransformList(SVGTransformType transform_type,
+                                   const String& value) {
+  TransformArguments arguments;
+  bool at_end_of_value = false;
+  SVGParseStatus status = SVGParseStatus::kParsingFailed;
+  if (value.IsEmpty()) {
+  } else if (value.Is8Bit()) {
+    const LChar* ptr = value.Characters8();
+    const LChar* end = ptr + value.length();
+    status =
+        ParseTransformArgumentsForType(transform_type, ptr, end, arguments);
+    at_end_of_value = !SkipOptionalSVGSpaces(ptr, end);
+  } else {
+    const UChar* ptr = value.Characters16();
+    const UChar* end = ptr + value.length();
+    status =
+        ParseTransformArgumentsForType(transform_type, ptr, end, arguments);
+    at_end_of_value = !SkipOptionalSVGSpaces(ptr, end);
+  }
+
+  if (at_end_of_value && status == SVGParseStatus::kNoError)
+    Append(CreateTransformFromValues(transform_type, arguments));
+}
+
 SVGTransformList::~SVGTransformList() = default;
 
 SVGTransform* SVGTransformList::Consolidate() {
@@ -190,115 +327,6 @@
   return SVGTransformType::kUnknown;
 }
 
-// These should be kept in sync with enum SVGTransformType
-const unsigned kRequiredValuesForType[] = {0, 6, 1, 1, 1, 1, 1};
-const unsigned kOptionalValuesForType[] = {0, 0, 1, 1, 2, 0, 0};
-static_assert(static_cast<int>(SVGTransformType::kUnknown) == 0,
-              "index of SVGTransformType::kUnknown has changed");
-static_assert(static_cast<int>(SVGTransformType::kMatrix) == 1,
-              "index of SVGTransformType::kMatrix has changed");
-static_assert(static_cast<int>(SVGTransformType::kTranslate) == 2,
-              "index of SVGTransformType::kTranslate has changed");
-static_assert(static_cast<int>(SVGTransformType::kScale) == 3,
-              "index of SVGTransformType::kScale has changed");
-static_assert(static_cast<int>(SVGTransformType::kRotate) == 4,
-              "index of SVGTransformType::kRotate has changed");
-static_assert(static_cast<int>(SVGTransformType::kSkewx) == 5,
-              "index of SVGTransformType::kSkewx has changed");
-static_assert(static_cast<int>(SVGTransformType::kSkewy) == 6,
-              "index of SVGTransformType::kSkewy has changed");
-static_assert(base::size(kRequiredValuesForType) - 1 ==
-                  static_cast<int>(SVGTransformType::kSkewy),
-              "the number of transform types have changed");
-static_assert(base::size(kRequiredValuesForType) ==
-                  base::size(kOptionalValuesForType),
-              "the arrays should have the same number of elements");
-
-const unsigned kMaxTransformArguments = 6;
-
-using TransformArguments = Vector<float, kMaxTransformArguments>;
-
-template <typename CharType>
-SVGParseStatus ParseTransformArgumentsForType(SVGTransformType type,
-                                              const CharType*& ptr,
-                                              const CharType* end,
-                                              TransformArguments& arguments) {
-  const size_t required = kRequiredValuesForType[static_cast<int>(type)];
-  const size_t optional = kOptionalValuesForType[static_cast<int>(type)];
-  const size_t required_with_optional = required + optional;
-  DCHECK_LE(required_with_optional, kMaxTransformArguments);
-  DCHECK(arguments.IsEmpty());
-
-  bool trailing_delimiter = false;
-
-  while (arguments.size() < required_with_optional) {
-    float argument_value = 0;
-    if (!ParseNumber(ptr, end, argument_value, kAllowLeadingWhitespace))
-      break;
-
-    arguments.push_back(argument_value);
-    trailing_delimiter = false;
-
-    if (arguments.size() == required_with_optional)
-      break;
-
-    if (SkipOptionalSVGSpaces(ptr, end) && *ptr == ',') {
-      ++ptr;
-      trailing_delimiter = true;
-    }
-  }
-
-  if (arguments.size() != required &&
-      arguments.size() != required_with_optional)
-    return SVGParseStatus::kExpectedNumber;
-  if (trailing_delimiter)
-    return SVGParseStatus::kTrailingGarbage;
-
-  return SVGParseStatus::kNoError;
-}
-
-SVGTransform* CreateTransformFromValues(SVGTransformType type,
-                                        const TransformArguments& arguments) {
-  auto* transform = MakeGarbageCollected<SVGTransform>();
-  switch (type) {
-    case SVGTransformType::kSkewx:
-      transform->SetSkewX(arguments[0]);
-      break;
-    case SVGTransformType::kSkewy:
-      transform->SetSkewY(arguments[0]);
-      break;
-    case SVGTransformType::kScale:
-      // Spec: if only one param given, assume uniform scaling.
-      if (arguments.size() == 1)
-        transform->SetScale(arguments[0], arguments[0]);
-      else
-        transform->SetScale(arguments[0], arguments[1]);
-      break;
-    case SVGTransformType::kTranslate:
-      // Spec: if only one param given, assume 2nd param to be 0.
-      if (arguments.size() == 1)
-        transform->SetTranslate(arguments[0], 0);
-      else
-        transform->SetTranslate(arguments[0], arguments[1]);
-      break;
-    case SVGTransformType::kRotate:
-      if (arguments.size() == 1)
-        transform->SetRotate(arguments[0], 0, 0);
-      else
-        transform->SetRotate(arguments[0], arguments[1], arguments[2]);
-      break;
-    case SVGTransformType::kMatrix:
-      transform->SetMatrix(AffineTransform(arguments[0], arguments[1],
-                                           arguments[2], arguments[3],
-                                           arguments[4], arguments[5]));
-      break;
-    case SVGTransformType::kUnknown:
-      NOTREACHED();
-      break;
-  }
-  return transform;
-}
-
 }  // namespace
 
 template <typename CharType>
@@ -400,33 +428,6 @@
   return SVGListPropertyHelper::CloneForAnimation(value);
 }
 
-SVGTransformList* SVGTransformList::Create(SVGTransformType transform_type,
-                                           const String& value) {
-  TransformArguments arguments;
-  bool at_end_of_value = false;
-  SVGParseStatus status = SVGParseStatus::kParsingFailed;
-  if (value.IsEmpty()) {
-  } else if (value.Is8Bit()) {
-    const LChar* ptr = value.Characters8();
-    const LChar* end = ptr + value.length();
-    status =
-        ParseTransformArgumentsForType(transform_type, ptr, end, arguments);
-    at_end_of_value = !SkipOptionalSVGSpaces(ptr, end);
-  } else {
-    const UChar* ptr = value.Characters16();
-    const UChar* end = ptr + value.length();
-    status =
-        ParseTransformArgumentsForType(transform_type, ptr, end, arguments);
-    at_end_of_value = !SkipOptionalSVGSpaces(ptr, end);
-  }
-
-  auto* svg_transform_list = MakeGarbageCollected<SVGTransformList>();
-  if (at_end_of_value && status == SVGParseStatus::kNoError)
-    svg_transform_list->Append(
-        CreateTransformFromValues(transform_type, arguments));
-  return svg_transform_list;
-}
-
 void SVGTransformList::Add(SVGPropertyBase* other,
                            SVGElement* context_element) {
   if (IsEmpty())
diff --git a/third_party/blink/renderer/core/svg/svg_transform_list.h b/third_party/blink/renderer/core/svg/svg_transform_list.h
index 561f854..3e582d69 100644
--- a/third_party/blink/renderer/core/svg/svg_transform_list.h
+++ b/third_party/blink/renderer/core/svg/svg_transform_list.h
@@ -44,13 +44,8 @@
  public:
   typedef SVGTransformListTearOff TearOffType;
 
-  static SVGTransformList* Create() {
-    return MakeGarbageCollected<SVGTransformList>();
-  }
-
-  static SVGTransformList* Create(SVGTransformType, const String&);
-
   SVGTransformList();
+  SVGTransformList(SVGTransformType, const String&);
   ~SVGTransformList() override;
 
   SVGTransform* Consolidate();
diff --git a/third_party/blink/renderer/core/svg/svg_transform_list_tear_off.h b/third_party/blink/renderer/core/svg/svg_transform_list_tear_off.h
index 70fcd0a..f3650ea 100644
--- a/third_party/blink/renderer/core/svg/svg_transform_list_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_transform_list_tear_off.h
@@ -45,14 +45,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SVGTransformListTearOff* Create(
-      SVGTransformList* target,
-      SVGAnimatedPropertyBase* binding,
-      PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGTransformListTearOff>(target, binding,
-                                                         property_is_anim_val);
-  }
-
   SVGTransformListTearOff(SVGTransformList*,
                           SVGAnimatedPropertyBase* binding,
                           PropertyIsAnimValType);
diff --git a/third_party/blink/renderer/core/svg/svg_transform_tear_off.cc b/third_party/blink/renderer/core/svg/svg_transform_tear_off.cc
index ab0fb1a..d147771 100644
--- a/third_party/blink/renderer/core/svg/svg_transform_tear_off.cc
+++ b/third_party/blink/renderer/core/svg/svg_transform_tear_off.cc
@@ -59,11 +59,6 @@
       nullptr, kPropertyIsNotAnimVal);
 }
 
-SVGTransformTearOff* SVGTransformTearOff::Create(SVGMatrixTearOff* matrix) {
-  return Create(SVGTransform::Create(matrix->Value()), nullptr,
-                kPropertyIsNotAnimVal);
-}
-
 SVGMatrixTearOff* SVGTransformTearOff::matrix() {
   if (!matrix_tearoff_)
     matrix_tearoff_ = MakeGarbageCollected<SVGMatrixTearOff>(this);
diff --git a/third_party/blink/renderer/core/svg/svg_transform_tear_off.h b/third_party/blink/renderer/core/svg/svg_transform_tear_off.h
index f405af2..7d79e107 100644
--- a/third_party/blink/renderer/core/svg/svg_transform_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_transform_tear_off.h
@@ -53,15 +53,7 @@
     kSvgTransformSkewy = static_cast<int>(blink::SVGTransformType::kSkewy),
   };
 
-  static SVGTransformTearOff* Create(
-      SVGTransform* target,
-      SVGAnimatedPropertyBase* binding,
-      PropertyIsAnimValType property_is_anim_val) {
-    return MakeGarbageCollected<SVGTransformTearOff>(target, binding,
-                                                     property_is_anim_val);
-  }
   static SVGTransformTearOff* CreateDetached();
-  static SVGTransformTearOff* Create(SVGMatrixTearOff*);
 
   SVGTransformTearOff(SVGMatrixTearOff*);
   SVGTransformTearOff(SVGTransform*,
diff --git a/third_party/blink/renderer/core/svg/svg_tspan_element.cc b/third_party/blink/renderer/core/svg/svg_tspan_element.cc
index 3855127..5b876af 100644
--- a/third_party/blink/renderer/core/svg/svg_tspan_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_tspan_element.cc
@@ -28,8 +28,6 @@
 SVGTSpanElement::SVGTSpanElement(Document& document)
     : SVGTextPositioningElement(svg_names::kTSpanTag, document) {}
 
-DEFINE_NODE_FACTORY(SVGTSpanElement)
-
 LayoutObject* SVGTSpanElement::CreateLayoutObject(const ComputedStyle&,
                                                   LegacyLayout) {
   return new LayoutSVGTSpan(this);
diff --git a/third_party/blink/renderer/core/svg/svg_tspan_element.h b/third_party/blink/renderer/core/svg/svg_tspan_element.h
index 725e409..d74f798 100644
--- a/third_party/blink/renderer/core/svg/svg_tspan_element.h
+++ b/third_party/blink/renderer/core/svg/svg_tspan_element.h
@@ -29,8 +29,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  DECLARE_NODE_FACTORY(SVGTSpanElement);
-
   explicit SVGTSpanElement(Document&);
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_unknown_element.cc b/third_party/blink/renderer/core/svg/svg_unknown_element.cc
index 48ce4711..d843125 100644
--- a/third_party/blink/renderer/core/svg/svg_unknown_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_unknown_element.cc
@@ -36,6 +36,4 @@
                                      Document& document)
     : SVGElement(tag_name, document) {}
 
-DEFINE_ELEMENT_FACTORY_WITH_TAGNAME(SVGUnknownElement)
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_unknown_element.h b/third_party/blink/renderer/core/svg/svg_unknown_element.h
index 8bef130a..fb9404a2 100644
--- a/third_party/blink/renderer/core/svg/svg_unknown_element.h
+++ b/third_party/blink/renderer/core/svg/svg_unknown_element.h
@@ -45,7 +45,6 @@
 // layout such elements.
 class SVGUnknownElement final : public SVGElement {
  public:
-  DECLARE_ELEMENT_FACTORY_WITH_TAGNAME(SVGUnknownElement);
 
   SVGUnknownElement(const QualifiedName&, Document&);
 
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.cc b/third_party/blink/renderer/core/svg/svg_use_element.cc
index e0b505a5..dcd726de 100644
--- a/third_party/blink/renderer/core/svg/svg_use_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_use_element.cc
@@ -83,13 +83,8 @@
   AddToPropertyMap(y_);
   AddToPropertyMap(width_);
   AddToPropertyMap(height_);
-}
 
-SVGUseElement* SVGUseElement::Create(Document& document) {
-  // Always build a user agent #shadow-root for SVGUseElement.
-  SVGUseElement* use = MakeGarbageCollected<SVGUseElement>(document);
-  use->AttachShadowRootInternal(ShadowRootType::kClosed);
-  return use;
+  AttachShadowRootInternal(ShadowRootType::kClosed);
 }
 
 SVGUseElement::~SVGUseElement() = default;
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.h b/third_party/blink/renderer/core/svg/svg_use_element.h
index bb58c25..7c40606 100644
--- a/third_party/blink/renderer/core/svg/svg_use_element.h
+++ b/third_party/blink/renderer/core/svg/svg_use_element.h
@@ -39,8 +39,6 @@
   USING_PRE_FINALIZER(SVGUseElement, Dispose);
 
  public:
-  static SVGUseElement* Create(Document&);
-
   explicit SVGUseElement(Document&);
   ~SVGUseElement() override;
 
diff --git a/third_party/blink/renderer/core/svg/svg_view_element.cc b/third_party/blink/renderer/core/svg/svg_view_element.cc
index 695e6c0..53e9262b 100644
--- a/third_party/blink/renderer/core/svg/svg_view_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_view_element.cc
@@ -30,8 +30,6 @@
   UseCounter::Count(document, WebFeature::kSVGViewElement);
 }
 
-DEFINE_NODE_FACTORY(SVGViewElement)
-
 void SVGViewElement::Trace(blink::Visitor* visitor) {
   SVGElement::Trace(visitor);
   SVGFitToViewBox::Trace(visitor);
diff --git a/third_party/blink/renderer/core/svg/svg_view_element.h b/third_party/blink/renderer/core/svg/svg_view_element.h
index ba9c3388..bdde4bf 100644
--- a/third_party/blink/renderer/core/svg/svg_view_element.h
+++ b/third_party/blink/renderer/core/svg/svg_view_element.h
@@ -35,8 +35,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGViewElement);
 
  public:
-  DECLARE_NODE_FACTORY(SVGViewElement);
-
   explicit SVGViewElement(Document&);
 
   void Trace(blink::Visitor*) override;
diff --git a/third_party/blink/renderer/modules/encoding/OWNERS b/third_party/blink/renderer/modules/encoding/OWNERS
index 524b726..b589432 100644
--- a/third_party/blink/renderer/modules/encoding/OWNERS
+++ b/third_party/blink/renderer/modules/encoding/OWNERS
@@ -1,4 +1,5 @@
 jsbell@chromium.org
+ricea@chromium.org
 kbr@chromium.org
 
 # COMPONENT: Blink>TextEncoding
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc b/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc
index ce9144d..bfe2b0e 100644
--- a/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc
+++ b/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.cc
@@ -9,10 +9,11 @@
 #include "media/base/video_types.h"
 #include "media/base/video_util.h"
 #include "skia/ext/platform_canvas.h"
-#include "third_party/blink/public/platform/web_callbacks.h"
 #include "third_party/blink/public/platform/web_media_stream_source.h"
 #include "third_party/blink/public/platform/web_media_stream_track.h"
+#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
 #include "third_party/libyuv/include/libyuv.h"
 #include "third_party/skia/include/core/SkImage.h"
@@ -22,7 +23,7 @@
 
 namespace {
 
-void OnError(std::unique_ptr<WebImageCaptureGrabFrameCallbacks> callbacks) {
+void OnError(std::unique_ptr<ImageCaptureGrabFrameCallbacks> callbacks) {
   callbacks->OnError();
 }
 
@@ -51,6 +52,7 @@
 
   // Receives a |frame| and converts its pixels into a SkImage via an internal
   // PaintSurface and SkPixmap. Alpha channel, if any, is copied.
+  using SkImageDeliverCB = WTF::CrossThreadFunction<void(sk_sp<SkImage>)>;
   void OnVideoFrameOnIOThread(
       SkImageDeliverCB callback,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
@@ -134,7 +136,7 @@
 
 void ImageCaptureFrameGrabber::GrabFrame(
     WebMediaStreamTrack* track,
-    std::unique_ptr<WebImageCaptureGrabFrameCallbacks> callbacks,
+    std::unique_ptr<ImageCaptureGrabFrameCallbacks> callbacks,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!!callbacks);
@@ -170,7 +172,7 @@
 }
 
 void ImageCaptureFrameGrabber::OnSkImage(
-    ScopedWebCallbacks<WebImageCaptureGrabFrameCallbacks> callbacks,
+    ScopedWebCallbacks<ImageCaptureGrabFrameCallbacks> callbacks,
     sk_sp<SkImage> image) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.h b/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.h
index 60ffa2a..a360819 100644
--- a/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.h
+++ b/third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.h
@@ -12,20 +12,19 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_checker.h"
 #include "third_party/blink/public/platform/scoped_web_callbacks.h"
-#include "third_party/blink/public/platform/web_callbacks.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_sink.h"
-#include "third_party/blink/renderer/platform/wtf/functional.h"
+#include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
 class SkImage;
 
 namespace blink {
 
+class ImageBitmap;
 class WebMediaStreamTrack;
 
-// TODO(crbug.com/945851): Avoid referencing to WebCallbacks, and reference to
-// CallbackPromiseAdapter directly.
-using WebImageCaptureGrabFrameCallbacks = WebCallbacks<sk_sp<SkImage>, void>;
+using ImageCaptureGrabFrameCallbacks =
+    CallbackPromiseAdapter<ImageBitmap, void>;
 
 // This class grabs Video Frames from a given Media Stream Video Track, binding
 // a method of an ephemeral SingleShotFrameHandler every time grabFrame() is
@@ -34,22 +33,19 @@
 // OnSkBitmap(). This class is single threaded throughout.
 class ImageCaptureFrameGrabber final : public MediaStreamVideoSink {
  public:
-  using SkImageDeliverCB = WTF::CrossThreadFunction<void(sk_sp<SkImage>)>;
-
   ImageCaptureFrameGrabber();
   ~ImageCaptureFrameGrabber() override;
 
   void GrabFrame(WebMediaStreamTrack* track,
-                 std::unique_ptr<WebImageCaptureGrabFrameCallbacks> callbacks,
+                 std::unique_ptr<ImageCaptureGrabFrameCallbacks> callbacks,
                  scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
  private:
   // Internal class to receive, convert and forward one frame.
   class SingleShotFrameHandler;
 
-  void OnSkImage(
-      ScopedWebCallbacks<WebImageCaptureGrabFrameCallbacks> callbacks,
-      sk_sp<SkImage> image);
+  void OnSkImage(ScopedWebCallbacks<ImageCaptureGrabFrameCallbacks> callbacks,
+                 sk_sp<SkImage> image);
 
   // Flag to indicate that there is a frame grabbing in progress.
   bool frame_grab_in_progress_;
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc
index 1ad8b25c..1201aea 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc
@@ -185,10 +185,7 @@
 MediaControlInputElement::MediaControlInputElement(
     MediaControlsImpl& media_controls)
     : HTMLInputElement(media_controls.GetDocument(), CreateElementFlags()),
-      MediaControlElementBase(media_controls, this) {
-  CreateUserAgentShadowRoot();
-  CreateShadowSubtree();
-}
+      MediaControlElementBase(media_controls, this) {}
 
 WebLocalizedString::Name MediaControlInputElement::GetOverflowStringName()
     const {
diff --git a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
index 037d6673..593782c9 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
@@ -835,7 +835,7 @@
   background: #FFFFFF;
   box-shadow: 0 1px 9px 0 rgba(0,0,0,0.40);
   border-radius: 2px;
-  transition: transform .4s ease-out, opacity .3s linear;
+  transition: transform .3s ease-out, opacity .2s linear;
   transform-origin: bottom right;
 }
 
@@ -933,42 +933,42 @@
 
 audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i],
 video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i] {
-  transition: transform .3s, opacity .5s;
+  transition: transform .2s, opacity .4s;
 }
 
 audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-0,
 video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-0 {
-  transition: opacity .5s .2s ease-in;
+  transition: opacity .4s .1s ease-in;
 }
 
 audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-1,
 video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-1 {
-  transition-delay: .25s;
+  transition-delay: .15s;
 }
 
 audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-2,
 video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-2 {
-  transition-delay: .3s;
+  transition-delay: .2s;
 }
 
 audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-3,
 video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-3 {
-  transition-delay: .35s;
+  transition-delay: .25s;
 }
 
 audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-4,
 video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-4 {
-  transition-delay: .4s;
+  transition-delay: .3s;
 }
 
 audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-5,
 video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-5 {
-  transition-delay: .45s
+  transition-delay: .35s
 }
 
 audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-6,
 video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-6 {
-  transition-delay: .5s
+  transition-delay: .4s
 }
 
 audio::-internal-media-controls-text-track-list-header:focus,
diff --git a/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc b/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc
index e40b02a..db3a8c6 100644
--- a/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc
+++ b/third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.cc
@@ -25,6 +25,8 @@
 
 #include "third_party/blink/renderer/modules/webgl/khr_parallel_shader_compile.h"
 
+#include <thread>
+
 #include "gpu/command_buffer/client/gles2_interface.h"
 
 namespace blink {
@@ -34,8 +36,9 @@
     : WebGLExtension(context) {
   context->ExtensionsUtil()->EnsureExtensionEnabled(
       "GL_KHR_parallel_shader_compile");
-  // Use 2 background threads per WebGL context by default.
-  context->ContextGL()->MaxShaderCompilerThreadsKHR(2);
+
+  GLuint max_threads = std::max(4u, std::thread::hardware_concurrency() / 2);
+  context->ContextGL()->MaxShaderCompilerThreadsKHR(max_threads);
 }
 
 WebGLExtensionName KHRParallelShaderCompile::GetName() const {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 84cacc3..2aaf558c 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1226,6 +1226,11 @@
   for (int i = 0; i < kWebGLExtensionNameCount; ++i)
     extension_enabled_[i] = false;
 
+  // This limits the count of threads if the extension is yet to be requested.
+  if (String(ContextGL()->GetString(GL_EXTENSIONS))
+          .Contains("GL_KHR_parallel_shader_compile")) {
+    ContextGL()->MaxShaderCompilerThreadsKHR(2);
+  }
   is_web_gl2_formats_types_added_ = false;
   is_web_gl2_tex_image_source_formats_types_added_ = false;
   is_web_gl2_internal_formats_copy_tex_image_added_ = false;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
index 6110954..91cf635 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
@@ -247,7 +247,7 @@
                       gfx::Rect(kDamageWidth, kDamageHeight));
 
             const auto* quad = render_pass->quad_list.front();
-            EXPECT_EQ(quad->material, viz::DrawQuad::TEXTURE_CONTENT);
+            EXPECT_EQ(quad->material, viz::DrawQuad::Material::kTextureContent);
             EXPECT_EQ(quad->rect, gfx::Rect(kWidth, kHeight));
             EXPECT_EQ(quad->visible_rect, gfx::Rect(kWidth, kHeight));
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index 5589b5cf..9c150be 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -1083,13 +1083,8 @@
   TRACE_EVENT0("blink", "CanvasResourceProvider::WritePixels");
 
   DCHECK(IsValid());
-  if (GetSkSurface()->getCanvas()->writePixels(orig_info, pixels, row_bytes, x,
-                                               y)) {
-    FlushSkia();
-    return true;
-  }
-
-  return false;
+  return GetSkSurface()->getCanvas()->writePixels(orig_info, pixels, row_bytes,
+                                                  x, y);
 }
 
 void CanvasResourceProvider::Clear() {
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
index d30e6974..25dcfc7 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -175,15 +175,14 @@
   // (for example, due to a misconfigured web server), then it is possible that
   // the wrong compression format will be returned. However, this case should be
   // exceedingly rare.
-  if (image_data &&
-      ImageDecoder::HasSufficientDataToSniffImageType(*image_data.get())) {
+  if (image_data && HasSufficientDataToSniffImageType(*image_data.get()))
     mime_type = SniffImageType(image_data);
-  }
   if (!mime_type)
     return kUndefinedFormat;
 
   // Attempt to sniff whether a WebP image is using a lossy or lossless
-  // compression algorithm.
+  // compression algorithm. Note: Will return kUndefinedFormat in the case of an
+  // animated WebP image.
   size_t available_data = image_data ? image_data->size() : 0;
   if (EqualIgnoringASCIICase(mime_type, "image/webp") && available_data >= 16) {
     // Attempt to sniff only 8 bytes (the second half of the first 16). This
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 376bb50..7dbb71a 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2729,8 +2729,6 @@
 crbug.com/453002 [ Win ] fast/text/orientation-sideways.html [ Failure Pass ]
 
 crbug.com/600248 external/wpt/web-animations/interfaces/Animation/oncancel.html [ Pass Failure ]
-crbug.com/771977 external/wpt/web-animations/interfaces/Animation/onfinish.html [ Failure ]
-crbug.com/772048 crbug.com/772060 external/wpt/web-animations/timing-model/animations/updating-the-finished-state.html [ Timeout ]
 crbug.com/771722 external/wpt/web-animations/timing-model/animations/the-current-time-of-an-animation.html [ Failure ]
 crbug.com/771722 crbug.com/771751 crbug.com/772060 external/wpt/web-animations/timing-model/animations/setting-the-start-time-of-an-animation.html [ Failure ]
 
@@ -2868,7 +2866,7 @@
 crbug.com/723741 virtual/threaded/http/tests/devtools/tracing/idle-callback.js [ Failure Crash Pass Timeout ]
 
 # Sheriff 2019-03-08
-crbug.com/940050 virtual/threaded/external/wpt/animation-worklet/playback-rate.https.html [ Failure Timeout ]
+crbug.com/940050 virtual/threaded/external/wpt/animation-worklet/playback-rate.https.html [ Pass Timeout ]
 
 # Untriaged failures after https://crrev.com/c/543695/.
 # These need to be updated but appear not to be related to that change.
@@ -3007,6 +3005,7 @@
 # needs implementation of test_driver_internal.action_sequence
 crbug.com/893480 external/wpt/infrastructure/testdriver/actions/elementTiming.html [ Timeout ]
 crbug.com/893480 external/wpt/infrastructure/testdriver/actions/multiDevice.html [ Failure Timeout ]
+crbug.com/893480 external/wpt/infrastructure/testdriver/actions/actionsWithKeyPressed.html [ Failure Timeout ]
 
 # Hit a DCHECK
 crbug.com/918664 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/block-size-with-min-or-max-content-table-1a.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 26cea39..6104568 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -161142,11 +161142,6 @@
      {}
     ]
    ],
-   "domxpath/001-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "domxpath/002-expected.txt": [
     [
      {}
@@ -166697,11 +166692,6 @@
      {}
     ]
    ],
-   "html/browsers/browsing-the-web/unloading-documents/beforeunload-synchronous-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/browsers/browsing-the-web/unloading-documents/contains.json": [
     [
      {}
@@ -175252,11 +175242,6 @@
      {}
     ]
    ],
-   "html/semantics/forms/textfieldselection/selection-start-end-extra-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/semantics/forms/the-button-element/button-activate-frame.html": [
     [
      {}
@@ -175672,11 +175657,6 @@
      {}
     ]
    ],
-   "html/semantics/scripting-1/the-script-element/execution-timing/028-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/semantics/scripting-1/the-script-element/execution-timing/083-expected.txt": [
     [
      {}
@@ -192247,6 +192227,11 @@
      {}
     ]
    ],
+   "tools/mypy.ini": [
+    [
+     {}
+    ]
+   ],
    "tools/py27-flake8.ini": [
     [
      {}
@@ -192582,6 +192567,11 @@
      {}
     ]
    ],
+   "tools/requirements_mypy.txt": [
+    [
+     {}
+    ]
+   ],
    "tools/runner/css/bootstrap-theme.min.css": [
     [
      {}
@@ -343254,7 +343244,7 @@
    "support"
   ],
   "common/security-features/resources/common.js": [
-   "936b39e50ed57fdf9293333658fe8966c130712b",
+   "b42a909044c3c72e05b2f4ad1812ce259824c4ad",
    "support"
   ],
   "common/security-features/subresource/__init__.py": [
@@ -429265,10 +429255,6 @@
    "9dac65d3053a6f5e531888a7b470051389840f89",
    "testharness"
   ],
-  "domxpath/001-expected.txt": [
-   "e8e17ecc74a88b5dba9635f36af32f1a7a17bfa4",
-   "support"
-  ],
   "domxpath/001.html": [
    "c26795a3115f8bb16174163a58b3a5a9dcc25183",
    "testharness"
@@ -437489,10 +437475,6 @@
    "96d49567f365b00a741bb64a7f8cb2efa1427349",
    "testharness"
   ],
-  "html/browsers/browsing-the-web/unloading-documents/beforeunload-synchronous-expected.txt": [
-   "06da69d5a0920af8d09d4d8824a0487be48fe7e3",
-   "support"
-  ],
   "html/browsers/browsing-the-web/unloading-documents/beforeunload-synchronous.html": [
    "6806eaf7a390e9a195b2f7f69d2cf16f4362a0f1",
    "testharness"
@@ -450021,12 +450003,8 @@
    "04b4fdd4f7872d3416db35e57c5ab176ca2e87e5",
    "testharness"
   ],
-  "html/semantics/forms/textfieldselection/selection-start-end-extra-expected.txt": [
-   "eaab1e2c51b9aff9898b07168bcb389c427fd1a0",
-   "support"
-  ],
   "html/semantics/forms/textfieldselection/selection-start-end-extra.html": [
-   "e76f5f6ea70c2ba769fe6a75e9aa1c95d98e2760",
+   "c8ba83bb988006daec57eb2f0ccf9e9dcf421f5d",
    "testharness"
   ],
   "html/semantics/forms/textfieldselection/selection-start-end.html": [
@@ -451545,10 +451523,6 @@
    "e9fbe7f15c06ae54814c9d4e03f961c39dbab92c",
    "testharness"
   ],
-  "html/semantics/scripting-1/the-script-element/execution-timing/028-expected.txt": [
-   "fce75485ee5d429c33d121d4a6620ddf21b00130",
-   "support"
-  ],
   "html/semantics/scripting-1/the-script-element/execution-timing/028.html": [
    "e383d4f1a648917d068b6fdfd4aa0f6e5edec2f5",
    "testharness"
@@ -490098,11 +490072,11 @@
    "support"
   ],
   "tools/lint/lint.py": [
-   "19d0c112186a09ab2ca5fb449faf4ea90bb66e04",
+   "dd06e0a02fc694129d38288b5de55e22af43022b",
    "support"
   ],
   "tools/lint/rules.py": [
-   "78f9d072a8a71c7af0494dc3625bd7aa937a5554",
+   "76d5d3e99264de999e999086436c8b524c62a297",
    "support"
   ],
   "tools/localpaths.py": [
@@ -490110,7 +490084,7 @@
    "support"
   ],
   "tools/manifest/XMLParser.py": [
-   "523f544b7c4e834b85d970a352aab28d3c846145",
+   "212bd7f32f48e05531607a436fa151f6f29d43de",
    "support"
   ],
   "tools/manifest/__init__.py": [
@@ -490130,7 +490104,7 @@
    "support"
   ],
   "tools/manifest/item.py": [
-   "b6d33e8452cde01b525a3336c8a11d0012c7037c",
+   "1556bfafdafb47d9a44629b33a3e376e85c4af6c",
    "support"
   ],
   "tools/manifest/log.py": [
@@ -490138,15 +490112,15 @@
    "support"
   ],
   "tools/manifest/manifest.py": [
-   "dc38d3819883ce049af8447b8e1f87d308b48e23",
+   "dd2e3627f478bbabdad532185b17cf6769381086",
    "support"
   ],
   "tools/manifest/sourcefile.py": [
-   "56b938d64ba939e4bf0bc98b6dfe1228aa54cae6",
+   "cd5261183ee8b1b67796ef7a7a8696faabc4b68d",
    "support"
   ],
   "tools/manifest/update.py": [
-   "f1a70930bb3377d86164767b71d985bad42c0104",
+   "013ec2147bc7218b736a9f3989d929078ec73bfc",
    "support"
   ],
   "tools/manifest/utils.py": [
@@ -490154,7 +490128,11 @@
    "support"
   ],
   "tools/manifest/vcs.py": [
-   "b63df4d0a8ae750a3a1edc7ee6c9eaa5fcc3718b",
+   "d900012212eb32b2a4df01c781cabf0b48968bad",
+   "support"
+  ],
+  "tools/mypy.ini": [
+   "710df96244a978275e3395262a7f4d0f46cce530",
    "support"
   ],
   "tools/py27-flake8.ini": [
@@ -490425,6 +490403,10 @@
    "cc9098d218acfef3c23ea14b4fa176997c281365",
    "support"
   ],
+  "tools/requirements_mypy.txt": [
+   "4d99b81211b2ef60c5bdac263533b77e399282d2",
+   "support"
+  ],
   "tools/runner/css/bootstrap-theme.min.css": [
    "61358b13d045694a6963c5334eab2831e53978ac",
    "support"
@@ -494266,7 +494248,7 @@
    "support"
   ],
   "tools/tox.ini": [
-   "bb9873d5bc67cb15de4bd29cab6c1729ea5b94ce",
+   "d0b186428eda92cc5c65f0ca98703811cdf1f445",
    "support"
   ],
   "tools/webdriver/README.md": [
@@ -494334,7 +494316,7 @@
    "support"
   ],
   "tools/wpt/testfiles.py": [
-   "7f0f221a1f6be5eb3959184a86e7fe7958554dc6",
+   "09dd45bcbd8dd4c865310a64f612c5e1262133f9",
    "support"
   ],
   "tools/wpt/tox.ini": [
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/actions/actionsWithKeyPressed.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/actions/actionsWithKeyPressed.html.ini
new file mode 100644
index 0000000..f62bf62a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/actions/actionsWithKeyPressed.html.ini
@@ -0,0 +1,9 @@
+[actionsWithKeyPressed.html]
+  expected:
+    if product == "safari" or product == "firefox": ERROR
+
+
+  [TestDriver actions: actions with key pressed]
+    expected:
+      if product == "chrome": FAIL
+
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/actionsWithKeyPressed.html b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/actionsWithKeyPressed.html
new file mode 100644
index 0000000..74e939f5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/actionsWithKeyPressed.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver actions: actions with key pressed</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+div#test1, div#test2 {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100px;
+  height: 100px;
+  background-color: blue;
+}
+
+div#test2 {
+  position: fixed;
+  top: 100px;
+  left: 0;
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+
+<div id="test1">
+</div>
+
+<div id="test2">
+</div>
+
+<script>
+let keys = [];
+
+async_test(t => {
+  let test1 = document.getElementById("test1");
+  let test2 = document.getElementById("test2");
+  document.getElementById("test1").addEventListener("click",
+    e => {keys.push(e.getModifierState("Control"))});
+  document.getElementById("test2").addEventListener("click",
+    e => {keys.push(e.getModifierState("Control"))});
+
+  let actions = new test_driver.Actions()
+    .keyDown("\uE009")
+    .addTick()
+    .pointerMove(0, 0, {origin: test1})
+    .pointerDown()
+    .pointerUp()
+    .pointerMove(0, 0, {origin: test2})
+    .pointerDown()
+    .pointerUp()
+    .addTick()
+    .keyUp("\uE009")
+    .addTick()
+    .pointerMove(0, 0, {origin: test1})
+    .pointerDown()
+    .pointerUp();
+
+  actions.send()
+    .then(t.step_func_done(() => assert_array_equals(keys, [true, true, false])))
+    .catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e)));
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/tools/lint/lint.py b/third_party/blink/web_tests/external/wpt/tools/lint/lint.py
index 19d0c112..dd06e0a 100644
--- a/third_party/blink/web_tests/external/wpt/tools/lint/lint.py
+++ b/third_party/blink/web_tests/external/wpt/tools/lint/lint.py
@@ -4,6 +4,7 @@
 import argparse
 import ast
 import json
+import logging
 import os
 import re
 import subprocess
@@ -19,12 +20,15 @@
 from ..wpt import testfiles
 from ..manifest.vcs import walk
 
-from manifest.sourcefile import SourceFile, js_meta_re, python_meta_re, space_chars, get_any_variants, get_default_any_variants
-from six import binary_type, iteritems, itervalues
+from ..manifest.sourcefile import SourceFile, js_meta_re, python_meta_re, space_chars, get_any_variants, get_default_any_variants
+from six import binary_type, iteritems, itervalues, with_metaclass
 from six.moves import range
 from six.moves.urllib.parse import urlsplit, urljoin
 
-import logging
+MYPY = False
+if MYPY:
+    # MYPY is set to True when run under Mypy.
+    from typing import Type
 
 logger = None
 
@@ -330,7 +334,7 @@
     return [item for i, item in enumerate(errors) if not whitelisted[i]]
 
 
-regexps = [item() for item in
+regexps = [item() for item in  # type: ignore
            [rules.TrailingWhitespaceRegexp,
             rules.TabsRegexp,
             rules.CRRegexp,
@@ -503,9 +507,11 @@
 
     return errors
 
-class ASTCheck(object):
-    __metaclass__ = abc.ABCMeta
-    rule = None
+class ASTCheck(with_metaclass(abc.ABCMeta)):
+    @abc.abstractproperty
+    def rule(self):
+        # type: () -> Type[rules.Rule]
+        pass
 
     @abc.abstractmethod
     def check(self, root):
diff --git a/third_party/blink/web_tests/external/wpt/tools/lint/rules.py b/third_party/blink/web_tests/external/wpt/tools/lint/rules.py
index 78f9d07..76d5d3e 100644
--- a/third_party/blink/web_tests/external/wpt/tools/lint/rules.py
+++ b/third_party/blink/web_tests/external/wpt/tools/lint/rules.py
@@ -1,11 +1,29 @@
 from __future__ import unicode_literals
+
+import abc
 import os
 import re
 
-class Rule(object):
-    name = None
-    description = None
-    to_fix = None
+import six
+
+MYPY = False
+if MYPY:
+    # MYPY is set to True when run under Mypy.
+    from typing import List, Optional, Pattern, Text, Match
+
+
+class Rule(six.with_metaclass(abc.ABCMeta)):
+    @abc.abstractproperty
+    def name(self):
+        # type: () -> Text
+        pass
+
+    @abc.abstractproperty
+    def description(self):
+        # type: () -> Text
+        pass
+
+    to_fix = None  # type: Optional[Text]
 
     @classmethod
     def error(cls, path, context=(), line_no=None):
@@ -232,19 +250,30 @@
     description = "Metadata comment is not formatted correctly"
 
 
-class Regexp(Rule):
-    pattern = None
-    file_extensions = None
-    _re = None
+class Regexp(six.with_metaclass(abc.ABCMeta)):
+    @abc.abstractproperty
+    def pattern(self):
+        # type: () -> bytes
+        pass
+
+    @abc.abstractproperty
+    def description(self):
+        # type: () -> Text
+        pass
+
+    file_extensions = None  # type: Optional[List[Text]]
 
     def __init__(self):
-        self._re = re.compile(self.pattern)
+        # type: () -> None
+        self._re = re.compile(self.pattern)  # type: Pattern
 
     def applies(self, path):
+        # type: (str) -> bool
         return (self.file_extensions is None or
                 os.path.splitext(path)[1] in self.file_extensions)
 
     def search(self, line):
+        # type: (bytes) -> Optional[Match[bytes]]
         return self._re.search(line)
 
 
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/XMLParser.py b/third_party/blink/web_tests/external/wpt/tools/manifest/XMLParser.py
index 523f544..212bd7f 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/XMLParser.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/XMLParser.py
@@ -5,6 +5,11 @@
 from xml.parsers import expat
 import xml.etree.ElementTree as etree
 
+MYPY = False
+if MYPY:
+    # MYPY is set to True when run under Mypy.
+    from typing import Dict
+
 _catalog = join(dirname(__file__), "catalog")
 
 def _wrap_error(e):
@@ -13,7 +18,7 @@
     err.position = e.lineno, e.offset
     raise err
 
-_names = {}
+_names = {}  # type: Dict[str, str]
 def _fixname(key):
     try:
         name = _names[key]
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/item.py b/third_party/blink/web_tests/external/wpt/tools/manifest/item.py
index b6d33e8..1556bfa 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/item.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/item.py
@@ -3,6 +3,11 @@
 from six.moves.urllib.parse import urljoin, urlparse
 from abc import ABCMeta, abstractproperty
 
+MYPY = False
+if MYPY:
+    # MYPY is set to True when run under Mypy.
+    from typing import Optional
+
 item_types = {}
 
 
@@ -24,7 +29,7 @@
 
     __slots__ = ("_tests_root", "path")
 
-    item_type = None
+    item_type = None  # type: Optional[str]
 
     def __init__(self, tests_root=None, path=None):
         self._tests_root = tests_root
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py b/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
index dc38d38..dd2e3627 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
@@ -10,8 +10,15 @@
 from .log import get_logger
 from .utils import from_os_path, to_os_path
 
+MYPY = False
+if MYPY:
+    # MYPY is set to True when run under Mypy.
+    from typing import Dict
+    from types import ModuleType
+
 try:
-    import ujson as fast_json
+    import ujson
+    fast_json = ujson  # type: ModuleType
 except ImportError:
     fast_json = json
 
@@ -418,7 +425,7 @@
     return _load(logger, tests_root, manifest, types)
 
 
-__load_cache = {}
+__load_cache = {}  # type: Dict[str, Manifest]
 
 
 def _load(logger, tests_root, manifest, types=None, allow_cached=True):
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/sourcefile.py b/third_party/blink/web_tests/external/wpt/tools/manifest/sourcefile.py
index 56b938d..cd526118 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/sourcefile.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/sourcefile.py
@@ -5,10 +5,18 @@
 from six import binary_type
 from six.moves.urllib.parse import urljoin
 from fnmatch import fnmatch
+
+MYPY = False
+if MYPY:
+    # MYPY is set to True when run under Mypy.
+    from types import ModuleType
+
 try:
-    from xml.etree import cElementTree as ElementTree
+    from xml.etree import cElementTree
+    ElementTree = cElementTree  # type: ModuleType
 except ImportError:
-    from xml.etree import ElementTree
+    from xml.etree import ElementTree as _ElementTree
+    ElementTree = _ElementTree
 
 import html5lib
 
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/update.py b/third_party/blink/web_tests/external/wpt/tools/manifest/update.py
index f1a7093..013ec214 100755
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/update.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/update.py
@@ -2,7 +2,7 @@
 import argparse
 import os
 
-import manifest
+from . import manifest
 from . import vcs
 from .log import get_logger
 from .download import download_from_github
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/vcs.py b/third_party/blink/web_tests/external/wpt/tools/manifest/vcs.py
index b63df4d..d900012 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/vcs.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/vcs.py
@@ -78,7 +78,7 @@
 
 class FileSystem(object):
     def __init__(self, root, url_base, cache_path, manifest_path=None, rebuild=False):
-        from gitignore import gitignore
+        from gitignore import gitignore  # type: ignore
         self.root = os.path.abspath(root)
         self.url_base = url_base
         self.ignore_cache = None
@@ -115,7 +115,7 @@
 
 
 class CacheFile(object):
-    file_name = None
+    file_name = None  # type: Optional[str]
 
     def __init__(self, cache_root, tests_root, rebuild=False):
         self.tests_root = tests_root
diff --git a/third_party/blink/web_tests/external/wpt/tools/mypy.ini b/third_party/blink/web_tests/external/wpt/tools/mypy.ini
new file mode 100644
index 0000000..710df962
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/tools/mypy.ini
@@ -0,0 +1,25 @@
+[mypy]
+#check_untyped_defs = True
+#disallow_any_generics = True
+#disallow_untyped_calls = True
+#disallow_untyped_defs = True
+disallow_incomplete_defs = True
+disallow_subclassing_any = True
+disallow_untyped_decorators = True
+no_implicit_optional = True
+warn_redundant_casts = True
+warn_return_any = True
+warn_unused_configs = True
+warn_unused_ignores = True
+
+[mypy-html5lib.*]
+ignore_missing_imports = True
+
+[mypy-hypothesis.*]
+ignore_missing_imports = True
+
+[mypy-pytest.*]
+ignore_missing_imports = True
+
+[mypy-zstandard.*]
+ignore_missing_imports = True
diff --git a/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt b/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt
new file mode 100644
index 0000000..4d99b81
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt
@@ -0,0 +1,3 @@
+mypy==0.700
+mypy-extensions==0.4.1
+typed-ast==1.3.1
diff --git a/third_party/blink/web_tests/external/wpt/tools/tox.ini b/third_party/blink/web_tests/external/wpt/tools/tox.ini
index bb9873d..d0b1864 100644
--- a/third_party/blink/web_tests/external/wpt/tools/tox.ini
+++ b/third_party/blink/web_tests/external/wpt/tools/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py27,py36,pypy,{py27,py36}-flake8
+envlist = py27,py36,pypy,{py27,py36}-flake8,py36-mypy
 skipsdist=True
 
 [testenv]
@@ -21,3 +21,10 @@
 [testenv:py36-flake8]
 deps = -rrequirements_flake8.txt
 commands = flake8 --append-config={toxinidir}/py36-flake8.ini {posargs}
+
+[testenv:py36-mypy]
+deps = -rrequirements_mypy.txt
+changedir = {toxinidir}/..
+commands =
+  mypy --config-file={toxinidir}/mypy.ini --no-incremental --py2 -p tools.manifest -p tools.lint -p tools.gitignore
+  mypy --config-file={toxinidir}/mypy.ini --no-incremental -p tools.manifest -p tools.lint -p tools.gitignore
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/testfiles.py b/third_party/blink/web_tests/external/wpt/tools/wpt/testfiles.py
index 7f0f221..09dd45b 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wpt/testfiles.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wpt/testfiles.py
@@ -185,7 +185,7 @@
     # Delay import after localpaths sets up sys.path, because otherwise the
     # import path will be "..manifest" and Python will treat it as a different
     # manifest module.
-    from manifest import manifest
+    from manifest import manifest  # type: ignore
     if manifest_path is None:
         manifest_path = os.path.join(wpt_root, "MANIFEST.json")
     return manifest.load_and_update(wpt_root, manifest_path, "/",
diff --git a/third_party/blink/web_tests/fast/scrolling/no-hover-during-js-scroll.html b/third_party/blink/web_tests/fast/scrolling/no-hover-during-js-scroll.html
new file mode 100644
index 0000000..0ad6159e3
--- /dev/null
+++ b/third_party/blink/web_tests/fast/scrolling/no-hover-during-js-scroll.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
+<script src='../../resources/gesture-util.js'></script>
+
+<style>
+  body, html {
+    margin: 0;
+    height: 500vh;
+  }
+  div {
+    height: 50px;
+    width: 100%;
+  }
+
+  .hoverme {
+    background-color: rgb(0, 0, 255);
+  }
+
+  .hoverme:hover {
+    background-color: rgb(255, 255, 0);
+  }
+
+  .message {
+    width: 100%;
+    text-align: left;
+  }
+</style>
+
+<div class="message">
+  First move your mouse cursor to the page, you will see the color under the mouse cursor changed from blue to yellow. <br>
+  Do a JS scroll, you will see the hover update on a text under the mouse cursor when the scrolling finishes.
+</div>
+<div class="hoverme">hover over me</div>
+<div class="hoverme">hover over me</div>
+<div class="hoverme">hover over me</div>
+<div class="hoverme">hover over me</div>
+<div class="hoverme">hover over me</div>
+
+<script>
+  const elementHeight = 50;
+
+  window.onload = async () => {
+    if (window.internals) {
+      internals.runtimeFlags.updateHoverFromScrollAtBeginFrameEnabled = true;
+    }
+
+    await waitForCompositorCommit();
+    array = document.getElementsByClassName('hoverme');
+
+    promise_test(async () => {
+      let x = array[0].offsetLeft + 10;
+      let y = array[0].offsetTop + 25;
+      // Move cursor to 1st element.
+      await mouseMoveTo(x, y);
+      await waitFor( () => { return array[0].matches(":hover");}, 'wait for move to 1st element');
+      assert_true(array[0].matches(":hover"));
+      assert_false(array[1].matches(":hover"));
+
+      // Scroll end up at 4th element. Hover state does not update during scrolling,
+      // only the 4th element has a hover effect.
+      assert_equals(document.scrollingElement.scrollTop, 0);
+      window.scrollTo({top: 150, left: 0});
+      // Wait enough time to see if we fire a fake mouse move event to update the hover state.
+      await waitForAnimationEnd(() => { return document.scrollingElement.scrollTop; }, 300, 60);
+      assert_approx_equals(document.scrollingElement.scrollTop, 3 * elementHeight, 25);
+      assert_false(array[0].matches(":hover"));
+      assert_false(array[1].matches(":hover"));
+      assert_false(array[2].matches(":hover"));
+      assert_true(array[3].matches(":hover"));
+      assert_false(array[4].matches(":hover"));
+    }, 'JS scroll on the page, no hover update during scrolling, but updating hover at the end of scroll.');
+  }
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/scrolling/no-hover-during-smooth-js-scroll.html b/third_party/blink/web_tests/fast/scrolling/no-hover-during-smooth-js-scroll.html
new file mode 100644
index 0000000..cfd37780
--- /dev/null
+++ b/third_party/blink/web_tests/fast/scrolling/no-hover-during-smooth-js-scroll.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
+<script src='../../resources/gesture-util.js'></script>
+
+<style>
+  body, html {
+    margin: 0;
+    height: 500vh;
+  }
+  div {
+    height: 50px;
+    width: 100%;
+  }
+
+  .hoverme {
+    background-color: rgb(0, 0, 255);
+  }
+
+  .hoverme:hover {
+    background-color: rgb(255, 255, 0);
+  }
+
+  .message {
+    width: 100%;
+    text-align: left;
+  }
+</style>
+
+<div class="message">
+  First move your mouse cursor to the page, you will see the color under the mouse cursor changed from blue to yellow. <br>
+  Do a smooth JS scroll, you will see the hover update on a text under the mouse cursor when the scrolling finishes.
+</div>
+<div class="hoverme">hover over me</div>
+<div class="hoverme">hover over me</div>
+<div class="hoverme">hover over me</div>
+<div class="hoverme">hover over me</div>
+<div class="hoverme">hover over me</div>
+
+<script>
+  const elementHeight = 50;
+
+  window.onload = async () => {
+    if (window.internals) {
+      internals.runtimeFlags.updateHoverFromScrollAtBeginFrameEnabled = true;
+    }
+
+    await waitForCompositorCommit();
+    array = document.getElementsByClassName('hoverme');
+
+    promise_test(async () => {
+      let x = array[0].offsetLeft + 10;
+      let y = array[0].offsetTop + 25;
+      // Move cursor to 1st element.
+      await mouseMoveTo(x, y);
+      await waitFor( () => { return array[0].matches(":hover");}, 'wait for move to 1st element');
+      assert_true(array[0].matches(":hover"));
+      assert_false(array[1].matches(":hover"));
+
+      // Scroll end up at 4th element. Hover state does not update during scrolling,
+      // only the 4th element has a hover effect.
+      assert_equals(document.scrollingElement.scrollTop, 0);
+      window.scrollTo({top: 150, left: 0, behavior: 'smooth'});
+      // Wait enough time to see if we fire a fake mouse move event to update the hover state.
+      await waitForAnimationEnd(() => { return document.scrollingElement.scrollTop; }, 300, 60);
+      assert_approx_equals(document.scrollingElement.scrollTop, 3 * elementHeight, 25);
+      assert_false(array[0].matches(":hover"));
+      assert_false(array[1].matches(":hover"));
+      assert_false(array[2].matches(":hover"));
+      assert_true(array[3].matches(":hover"));
+      assert_false(array[4].matches(":hover"));
+    }, 'JS smooth scroll on the page, no hover update during scrolling, but updating hover at the end of scroll.');
+  }
+
+</script>
\ No newline at end of file
diff --git a/third_party/closure_compiler/externs/pending.js b/third_party/closure_compiler/externs/pending.js
index 0fcefd4..ea5cbb6 100644
--- a/third_party/closure_compiler/externs/pending.js
+++ b/third_party/closure_compiler/externs/pending.js
@@ -133,6 +133,21 @@
 
 /**
  * @see
+ * https://polymer-library.polymer-project.org/2.0/api/elements/Polymer.DomIf
+ * @constructor
+ */
+Polymer.DomIf = function() {};
+
+/**
+ * @param {!HTMLTemplateElement} template
+ * @return {!HTMLElement}
+ * TODO(dpapad): Figure out if there is a better way to type-check Polymer2
+ * while still using legacy Polymer1 syntax.
+ */
+Polymer.DomIf._contentForTemplate = function(template) {};
+
+/**
+ * @see
  * https://github.com/tc39/proposal-bigint
  * This supports wrapping and operating on arbitrarily large integers.
  *
diff --git a/third_party/tcmalloc/README.chromium b/third_party/tcmalloc/README.chromium
index c23835f..682daa9 100644
--- a/third_party/tcmalloc/README.chromium
+++ b/third_party/tcmalloc/README.chromium
@@ -117,3 +117,5 @@
 - Fixed line endings in vendor/README_windows.txt to Unix (LF)
 - Removed have_futex from spinlock_linux-inl.h; assume it's always there
 - Add thread-safe support to query and update the heap sampling period
+- Remove use of LINKER_INITIALIZED in page_heap_allocator.h, to enable the
+  compiler to optimize away a static constructor
diff --git a/third_party/tcmalloc/chromium/src/page_heap_allocator.h b/third_party/tcmalloc/chromium/src/page_heap_allocator.h
index ad7e1c9..add1701 100644
--- a/third_party/tcmalloc/chromium/src/page_heap_allocator.h
+++ b/third_party/tcmalloc/chromium/src/page_heap_allocator.h
@@ -163,15 +163,15 @@
 
  private:
   struct Storage {
-    explicit Storage(base::LinkerInitialized x) {}
     PageHeapAllocator<T> allocator;
     bool initialized;
   };
   static Storage underlying_;
 };
 
-template<typename T, class LockingTag>
-typename STLPageHeapAllocator<T, LockingTag>::Storage STLPageHeapAllocator<T, LockingTag>::underlying_(base::LINKER_INITIALIZED);
+template <typename T, class LockingTag>
+typename STLPageHeapAllocator<T, LockingTag>::Storage
+    STLPageHeapAllocator<T, LockingTag>::underlying_;
 
 }  // namespace tcmalloc
 
diff --git a/tools/code_coverage/coverage.py b/tools/code_coverage/coverage.py
index 16e5f55..8d71110 100755
--- a/tools/code_coverage/coverage.py
+++ b/tools/code_coverage/coverage.py
@@ -14,8 +14,8 @@
   * Example usage:
 
   gn gen out/coverage \\
-      --args='use_clang_coverage=true is_component_build=false \\
-              dcheck_always_on=true'
+      --args="use_clang_coverage=true is_component_build=false\\
+              is_debug=false dcheck_always_on=true"
   gclient runhooks
   python tools/code_coverage/coverage.py crypto_unittests url_unittests \\
       -b out/coverage -o out/report -c 'out/coverage/crypto_unittests' \\
@@ -166,6 +166,7 @@
                                 'both \'%s\' and \'%s\' exist.') % (
                                     LLVM_COV_PATH, LLVM_PROFDATA_PATH)
 
+
 def _GetPathWithLLVMSymbolizerDir():
   """Add llvm-symbolizer directory to path for symbolized stacks."""
   path = os.getenv('PATH')
@@ -190,7 +191,6 @@
   return _GetTargetOS() == 'ios'
 
 
-
 def _GeneratePerFileLineByLineCoverageInHtml(binary_paths, profdata_file_path,
                                              filters, ignore_filename_regex):
   """Generates per file line-by-line coverage in html using 'llvm-cov show'.
diff --git a/tools/code_coverage/run_fuzz_target.py b/tools/code_coverage/run_fuzz_target.py
index ba5e46a..4b54822c 100755
--- a/tools/code_coverage/run_fuzz_target.py
+++ b/tools/code_coverage/run_fuzz_target.py
@@ -215,13 +215,11 @@
           },
           'num_regressions': 0,
           'tests': {
-            fuzzer_name: {
-                'expected': 'PASS',
-                'actual': 'PASS',
-                'times': [
-                    int(end_time - start_time),
-                ]
-            },
+              fuzzer_name: {
+                  'expected': 'PASS',
+                  'actual': 'PASS',
+                  'times': [int(end_time - start_time),]
+              },
           }
       }, f)
 
diff --git a/tools/code_coverage/update_clang_coverage_tools.py b/tools/code_coverage/update_clang_coverage_tools.py
index 8da3ef89..2e013c88 100755
--- a/tools/code_coverage/update_clang_coverage_tools.py
+++ b/tools/code_coverage/update_clang_coverage_tools.py
@@ -62,8 +62,7 @@
       coverage_revision_stamp_file)
 
   has_coverage_tools = (
-      os.path.exists(cov_path)
-      and os.path.exists(profdata_path))
+      os.path.exists(cov_path) and os.path.exists(profdata_path))
 
   if (has_coverage_tools and coverage_revision == clang_revision and
       coverage_sub_revision == clang_sub_revision):
@@ -84,8 +83,8 @@
     coverage_tools_url = (clang_update.CDS_URL + '/Win/' + coverage_tools_file)
 
   try:
-    clang_update.DownloadAndUnpack(
-        coverage_tools_url, clang_update.LLVM_BUILD_DIR)
+    clang_update.DownloadAndUnpack(coverage_tools_url,
+                                   clang_update.LLVM_BUILD_DIR)
     with open(coverage_revision_stamp_file, 'w') as file_handle:
       file_handle.write('%s,%s' % (package_version, host_platform))
       file_handle.write('\n')
diff --git a/tools/gritsettings/translation_expectations.pyl b/tools/gritsettings/translation_expectations.pyl
index 66d8d430..8d45a90 100644
--- a/tools/gritsettings/translation_expectations.pyl
+++ b/tools/gritsettings/translation_expectations.pyl
@@ -37,6 +37,7 @@
       "chrome/browser/resources/chromeos/camera/src/strings/camera_strings.grd",
       "chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd",
       "chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd",
+      "chrome/browser/resources/chromeos/switch_access/strings/switch_access_strings.grd",
       "chrome/credential_provider/gaiacp/gaia_resources.grd",
       "chromeos/chromeos_strings.grd",
       "components/autofill/android/java/strings/autofill_strings.grd",
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 7f0a1b3..360e33c 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -671,7 +671,6 @@
       'try-nougat-phone-tester': 'android_debug_trybot_arm64',
     },
 
-    # TODO(crbug/786044): Remove non-compile debug configs when migrated.
     'tryserver.chromium.angle': {
       'android_angle_rel_ng': 'gpu_tests_android_release_trybot_arm64',
       'android_angle_vk32_rel_ng': 'gpu_tests_android_vulkan_release_trybot',
@@ -681,16 +680,10 @@
       'android_angle_vk64_deqp_rel_ng': 'deqp_android_vulkan_release_trybot_arm64',
       'linux-angle-rel': 'gpu_fyi_tests_release_trybot',
       'linux_angle_ozone_rel_ng': 'gpu_fyi_tests_ozone_linux_system_gbm_libdrm_release_trybot',
-      'linux_angle_dbg_ng': 'gpu_fyi_tests_debug_trybot',
       'linux_angle_deqp_rel_ng': 'deqp_release_trybot',
       'mac-angle-rel': 'gpu_fyi_tests_release_trybot',
-      'mac_angle_dbg_ng': 'gpu_fyi_tests_debug_trybot',
       'win-angle-rel': 'gpu_fyi_tests_release_trybot_x86',
-      'win_angle_dbg_ng': 'gpu_fyi_tests_debug_trybot_x86',
       'win_angle_deqp_rel_ng': 'deqp_release_trybot_x86',
-      'win_angle_x64_dbg_ng': 'gpu_fyi_tests_debug_trybot',
-      'win_angle_x64_deqp_rel_ng': 'deqp_release_trybot',
-      'win_angle_x64_rel_ng': 'gpu_fyi_tests_release_trybot',
     },
 
     'tryserver.chromium.chrome': {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 76b86d69..4ee8b88 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -43043,6 +43043,14 @@
   <int value="1" label="DocumentLevelTouchPreventDefaultCalled"/>
 </enum>
 
+<enum name="PasswordApplySyncChangesState">
+  <int value="0" label="Apply OK"/>
+  <int value="1" label="Apply ADD failed"/>
+  <int value="2" label="Apply UPDATE failed"/>
+  <int value="3" label="Apply Delete failed"/>
+  <int value="4" label="Apply metadata changed failed"/>
+</enum>
+
 <enum name="PasswordBubbleDisplayDisposition">
   <int value="0" label="Opened automatically / Offering a password to save"/>
   <int value="1" label="Opened manually / Offering a password to save"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 9c50ecd97..658ec28 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -4344,6 +4344,22 @@
   </summary>
 </histogram>
 
+<histogram name="Apps.HomeLauncherTransition.AnimationSmoothness" units="%"
+    expires_after="2020-04-01">
+<!-- Name completed by histogram suffixes
+     name="AppListTabletModeTransition" -->
+
+  <owner>andrewxu@chromium.org</owner>
+  <owner>newcomer@chromium.org</owner>
+  <summary>
+    Relative smoothness of animations of launcher transitions in tablet mode.
+    100% represents ideally smooth 60 frames per second. 50% represents only 30
+    frames per second is achieved during the animations. 0% should not happen.
+    This metric is recorded exactly once when the user triggers launcher
+    animation in tablet mode.
+  </summary>
+</histogram>
+
 <histogram name="Apps.LockScreen.AppsProfile.Creation.Duration" units="ms"
     expires_after="M77">
   <owner>tbarzic@chromium.org</owner>
@@ -14528,7 +14544,10 @@
 </histogram>
 
 <histogram name="BrotliFilter.GzipHeaderDetected" enum="BooleanPresent"
-    expires_after="M77">
+    expires_after="M75">
+  <obsolete>
+    Removed in M76.
+  </obsolete>
   <owner>eustas@chromium.org</owner>
   <summary>Indicates whether the gzip-like header was detected.</summary>
 </histogram>
@@ -17443,7 +17462,10 @@
 </histogram>
 
 <histogram name="Compositing.Browser.RasterTask.RasterPixelsPerMs2"
-    units="pixels/ms">
+    units="pixels/ms" expires_after="2019-4-24">
+  <obsolete>
+    Removed 04/2019. Was unused.
+  </obsolete>
   <owner>paint-dev@chromium.org</owner>
   <summary>
     Rasterized area, in pixels, divided by rasterization time, in milliseconds,
@@ -17963,7 +17985,10 @@
 </histogram>
 
 <histogram name="Compositing.Renderer.RasterTask.RasterPixelsPerMs2"
-    units="pixels/ms">
+    units="pixels/ms" expires_after="2019-4-24">
+  <obsolete>
+    Removed 04/2019. Was unused.
+  </obsolete>
   <owner>paint-dev@chromium.org</owner>
   <summary>
     Rasterized area, in pixels, divided by rasterization time, in milliseconds,
@@ -87111,6 +87136,17 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.ApplySyncChangesState"
+    enum="PasswordApplySyncChangesState" expires_after="M80">
+  <owner>mamir@chromium.org</owner>
+  <owner>mastiz@chromium.org</owner>
+  <summary>
+    Records different states upon applying remote sync changes to the password
+    manager. It recorded everytime after receiving remote password incremental
+    updates from the server.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.AutocompletePopupSuppressedByGeneration"
     enum="BooleanSuppressed" expires_after="2019-02-14">
   <obsolete>
@@ -142903,6 +142939,16 @@
   <affected-histogram name="Apps.AppListAppLaunchedV2"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="AppListTabletModeTransition" separator=".">
+  <suffix name="DragReleaseHide" label="Release drag to hide the app list"/>
+  <suffix name="DragReleaseShow" label="Release drag to show the app list"/>
+  <suffix name="HideLauncherForWindow"
+      label="Active a window to hide the app list"/>
+  <suffix name="PressAppListButtonShow"
+      label="Press the AppList button to show the app list"/>
+  <affected-histogram name="Apps.HomeLauncherTransition.AnimationSmoothness"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="AppListTargetState" separator=".">
   <suffix name="Close.ClamshellMode" label="Closing the app list"/>
   <suffix name="FullscreenAllApps.ClamshellMode"
diff --git a/tools/resources/OWNERS b/tools/resources/OWNERS
index ea259a7..138419c 100644
--- a/tools/resources/OWNERS
+++ b/tools/resources/OWNERS
@@ -1,3 +1,7 @@
 agrieve@chromium.org
+
+per-file *svgo*=dbeam@chromium.org
+per-file PRESUBMIT.py=dbeam@chromium.org
+
 per-file filter_resource_whitelist.*=estevenson@chromium.org
 per-file generate_resource_whitelist.*=estevenson@chromium.org
diff --git a/tools/resources/PRESUBMIT.py b/tools/resources/PRESUBMIT.py
new file mode 100644
index 0000000..b378edc
--- /dev/null
+++ b/tools/resources/PRESUBMIT.py
@@ -0,0 +1,23 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+def CheckChangeOnUpload(*args):
+  return _CommonChecks(*args)
+
+
+def CheckChangeOnCommit(*args):
+  return _CommonChecks(*args)
+
+
+def _CommonChecks(input_api, output_api):
+  cwd = input_api.PresubmitLocalPath()
+  path = input_api.os_path
+  files = [path.basename(f.LocalPath()) for f in input_api.AffectedFiles()]
+
+  if any(f for f in files if f.startswith('svgo_presubmit')):
+    tests = [path.join(cwd, 'svgo_presubmit_test.py')]
+    return input_api.canned_checks.RunUnitTests(input_api, output_api, tests)
+
+  return []
diff --git a/tools/resources/__init__.py b/tools/resources/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/resources/__init__.py
diff --git a/tools/resources/svgo.py b/tools/resources/svgo.py
new file mode 100755
index 0000000..7b4089c
--- /dev/null
+++ b/tools/resources/svgo.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# 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.
+
+
+def Run(os_path=None, args=None):
+  _HERE_PATH = os_path.dirname(os_path.realpath(__file__))
+  _SRC_PATH = os_path.normpath(os_path.join(_HERE_PATH, '..', '..'))
+
+  import sys
+  old_sys_path = sys.path[:]
+  sys.path.append(os_path.join(_SRC_PATH, 'third_party', 'node'))
+
+  try:
+    import node, node_modules
+  finally:
+    sys.path = old_sys_path
+
+  return node.RunNode([node_modules.PathToSvgo()] + args)
+
+
+if __name__ == '__main__':
+  import os
+  import sys
+  print Run(os_path=os.path, args=sys.argv[1:])
diff --git a/tools/resources/svgo_presubmit.py b/tools/resources/svgo_presubmit.py
new file mode 100644
index 0000000..a32dfb33
--- /dev/null
+++ b/tools/resources/svgo_presubmit.py
@@ -0,0 +1,26 @@
+# 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.
+
+
+def CheckOptimized(input_api, output_api):
+  file_filter = lambda f: f.LocalPath().endswith('.svg')
+  svgs = input_api.AffectedFiles(file_filter=file_filter, include_deletes=False)
+
+  if not svgs:
+    return []
+
+  import svgo
+
+  unoptimized = []
+  for f in svgs:
+    output = svgo.Run(input_api.os_path, ['-o', '-', f.AbsoluteLocalPath()])
+    if output.strip() != '\n'.join(f.NewContents()).strip():
+      unoptimized.append(f.LocalPath())
+
+  if unoptimized:
+    instructions = 'Run tools/resources/svgo.py on these files to optimize:'
+    msg = '\n  '.join([instructions] + unoptimized)
+    return [output_api.PresubmitNotifyResult(msg)]
+
+  return []
diff --git a/tools/resources/svgo_presubmit_test.py b/tools/resources/svgo_presubmit_test.py
new file mode 100755
index 0000000..cb7427b0
--- /dev/null
+++ b/tools/resources/svgo_presubmit_test.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import svgo_presubmit
+import sys
+import tempfile
+import unittest
+
+
+_HERE_PATH = os.path.dirname(__file__)
+sys.path.append(os.path.join(_HERE_PATH, '..', '..'))
+
+from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi, MockFile
+
+_OPTIMIZED_SVG = '''
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#757575"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg>
+'''.strip()
+
+_UNOPTIMIZED_SVG = '''
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#757575">
+  <path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path>
+</svg>
+'''
+
+class SvgPresubmitTest(unittest.TestCase):
+  def tearDown(self):
+    os.remove(self._tmp_file)
+
+  def check_contents(self, file_contents):
+    tmp_args = {'suffix': '.svg', 'dir': _HERE_PATH, 'delete': False}
+    with tempfile.NamedTemporaryFile(**tmp_args) as f:
+      self._tmp_file = f.name
+      f.write(file_contents)
+
+    input_api = MockInputApi()
+    input_api.files = [MockFile(os.path.abspath(self._tmp_file), file_contents.splitlines())]
+    input_api.presubmit_local_path = _HERE_PATH
+
+    return svgo_presubmit.CheckOptimized(input_api, MockOutputApi())
+
+  def testUnoptimizedSvg(self):
+    results = self.check_contents(_UNOPTIMIZED_SVG)
+    self.assertEquals(len(results), 1)
+    self.assertTrue(results[0].type == 'notify')
+    self.assertTrue('svgo' in results[0].message)
+
+  def testOptimizedSvg(self):
+    self.assertEquals(len(self.check_contents(_OPTIMIZED_SVG)), 0)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/ui/accessibility/ax_range.h b/ui/accessibility/ax_range.h
index 734254f..6f312de 100644
--- a/ui/accessibility/ax_range.h
+++ b/ui/accessibility/ax_range.h
@@ -196,6 +196,7 @@
       if (current_line_start->GetAnchor()->data().role ==
           ax::mojom::Role::kInlineTextBox) {
         current_line_start = current_line_start->CreateParentPosition();
+        current_line_end = current_line_end->CreateParentPosition();
       }
 
       AXTreeID current_tree_id = current_line_start->tree_id();
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
index 4362131..6b54b21 100644
--- a/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_textprovider_win.cc
@@ -177,7 +177,11 @@
 
   AXNodePosition::AXPositionInstance end;
   if (owner()->GetChildCount() == 0) {
-    end = start->CreatePositionAtEndOfAnchor()->AsLeafTextPosition();
+    end = owner()
+              ->GetDelegate()
+              ->CreateTextPositionAt(0)
+              ->CreatePositionAtEndOfAnchor()
+              ->AsLeafTextPosition();
   } else {
     AXPlatformNode* deepest_last_child =
         AXPlatformNode::FromNativeViewAccessible(
diff --git a/ui/latency/mojo/latency_info.typemap b/ui/latency/mojo/latency_info.typemap
index 4450bfe..9802c0c 100644
--- a/ui/latency/mojo/latency_info.typemap
+++ b/ui/latency/mojo/latency_info.typemap
@@ -3,10 +3,7 @@
 # found in the LICENSE file.
 
 mojom = "//ui/latency/mojo/latency_info.mojom"
-public_headers = [
-  "//ipc/ipc_message_utils.h",
-  "//ui/latency/latency_info.h",
-]
+public_headers = [ "//ui/latency/latency_info.h" ]
 traits_headers = [ "//ui/latency/mojo/latency_info_struct_traits.h" ]
 sources = [
   "latency_info_struct_traits.cc",
diff --git a/ui/native_theme/BUILD.gn b/ui/native_theme/BUILD.gn
index e8745333..cccc696 100644
--- a/ui/native_theme/BUILD.gn
+++ b/ui/native_theme/BUILD.gn
@@ -14,6 +14,8 @@
     "caption_style_win.cc",
     "common_theme.cc",
     "common_theme.h",
+    "dark_mode_observer.cc",
+    "dark_mode_observer.h",
     "native_theme.cc",
     "native_theme.h",
     "native_theme_android.cc",
diff --git a/chrome/browser/ui/dark_mode_observer.cc b/ui/native_theme/dark_mode_observer.cc
similarity index 84%
rename from chrome/browser/ui/dark_mode_observer.cc
rename to ui/native_theme/dark_mode_observer.cc
index 342d00f..b4635c7 100644
--- a/chrome/browser/ui/dark_mode_observer.cc
+++ b/ui/native_theme/dark_mode_observer.cc
@@ -2,15 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/dark_mode_observer.h"
+#include "ui/native_theme/dark_mode_observer.h"
 
 #include "base/bind.h"
 #include "base/logging.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/native_theme/native_theme_observer.h"
 
+namespace ui {
+
 DarkModeObserver::DarkModeObserver(
-    ui::NativeTheme* theme,
+    NativeTheme* theme,
     const base::RepeatingCallback<void(bool)>& callback)
     : theme_(theme),
       callback_(callback),
@@ -28,7 +30,7 @@
   theme_observer_.RemoveAll();
 }
 
-void DarkModeObserver::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
+void DarkModeObserver::OnNativeThemeUpdated(NativeTheme* observed_theme) {
   DCHECK_EQ(observed_theme, theme_);
   RunCallbackIfChanged();
 }
@@ -40,3 +42,5 @@
   in_dark_mode_ = in_dark_mode;
   callback_.Run(in_dark_mode_);
 }
+
+}  // namespace ui
diff --git a/chrome/browser/ui/dark_mode_observer.h b/ui/native_theme/dark_mode_observer.h
similarity index 70%
rename from chrome/browser/ui/dark_mode_observer.h
rename to ui/native_theme/dark_mode_observer.h
index 2f81334..0f2c79e3 100644
--- a/chrome/browser/ui/dark_mode_observer.h
+++ b/ui/native_theme/dark_mode_observer.h
@@ -2,18 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_DARK_MODE_OBSERVER_H_
-#define CHROME_BROWSER_UI_DARK_MODE_OBSERVER_H_
+#ifndef UI_NATIVE_THEME_DARK_MODE_OBSERVER_H_
+#define UI_NATIVE_THEME_DARK_MODE_OBSERVER_H_
 
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "ui/native_theme/native_theme_observer.h"
 
-class DarkModeObserver : public ui::NativeThemeObserver {
+namespace ui {
+
+class NATIVE_THEME_EXPORT DarkModeObserver : public NativeThemeObserver {
  public:
   // Observe |theme| for changes and run |callback| if detected.
-  DarkModeObserver(ui::NativeTheme* theme,
+  DarkModeObserver(NativeTheme* theme,
                    const base::RepeatingCallback<void(bool)>& callback);
 
   ~DarkModeObserver() override;
@@ -29,22 +31,24 @@
   bool InDarkMode() const { return in_dark_mode_; }
 
  private:
-  // ui::NativeThemeObserver:
-  void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
+  // NativeThemeObserver:
+  void OnNativeThemeUpdated(NativeTheme* observed_theme) override;
 
   // Run |callback_| if |theme_->SystemDarkModeEnabled()| != |in_dark_mode_|.
   void RunCallbackIfChanged();
 
   // The theme to query/watch for changes.
-  ui::NativeTheme* const theme_;
+  NativeTheme* const theme_;
 
   base::RepeatingCallback<void(bool)> callback_;
 
   bool in_dark_mode_;
 
-  ScopedObserver<ui::NativeTheme, DarkModeObserver> theme_observer_;
+  ScopedObserver<NativeTheme, DarkModeObserver> theme_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(DarkModeObserver);
 };
 
-#endif  // CHROME_BROWSER_UI_DARK_MODE_OBSERVER_H_
+}  // namespace ui
+
+#endif  // UI_NATIVE_THEME_DARK_MODE_OBSERVER_H_
diff --git a/ui/webui/resources/PRESUBMIT.py b/ui/webui/resources/PRESUBMIT.py
index 92ee47d..d90bb04 100644
--- a/ui/webui/resources/PRESUBMIT.py
+++ b/ui/webui/resources/PRESUBMIT.py
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import os
 
 def CheckChangeOnUpload(input_api, output_api):
   return _CommonChecks(input_api, output_api)
@@ -50,11 +49,22 @@
 <cr-dialog>#closeText (http://bit.ly/2eLEsqh).""")]
 
 
-def _CommonChecks(input_api, output_api):
+def _CheckSvgsOptimized(input_api, output_api):
   results = []
-  results += _CheckForTranslations(input_api, output_api)
-  results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api,
-                                                         check_js=True)
+  try:
+    import sys
+    old_sys_path = sys.path[:]
+    cwd = input_api.PresubmitLocalPath()
+    sys.path += [input_api.os_path.join(cwd, '..', '..', '..', 'tools')]
+    from resources import svgo_presubmit
+    results += svgo_presubmit.CheckOptimized(input_api, output_api)
+  finally:
+    sys.path = old_sys_path
+  return results
+
+
+def _CheckWebDevStyle(input_api, output_api):
+  results = []
   try:
     import sys
     old_sys_path = sys.path[:]
@@ -67,3 +77,13 @@
   finally:
     sys.path = old_sys_path
   return results
+
+
+def _CommonChecks(input_api, output_api):
+  results = []
+  results += _CheckForTranslations(input_api, output_api)
+  results += _CheckSvgsOptimized(input_api, output_api)
+  results += _CheckWebDevStyle(input_api, output_api)
+  results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api,
+                                                         check_js=True)
+  return results